/* Beajify : couleurs, typo, et le header/hero en cours de construction. */

:root {
  --navy: #0B052F;
  --off-white: #FFFFFF;   /* ESSAI 08/08 : blanc pur. Valeur d origine : #FAFAFC */
  --gold-1: #F5E39A;
  --gold-2: #C4B876;
  --gold-3: #8F845A;
  --gold-gradient: linear-gradient(270deg, var(--gold-1) 0%, var(--gold-2) 50%, var(--gold-3) 100%);
  --text-on-dark: #FCFCFC;

  --ink: var(--navy);
  --ink-soft: rgba(11, 5, 47, 0.62);
  --ink-faint: rgba(11, 5, 47, 0.1);

  --fs-hero: clamp(2.25rem, 1.6rem + 2.2vw, 3.5rem);
  --fs-body: clamp(1rem, 0.94rem + 0.25vw, 1.0625rem);
  --fs-small: clamp(0.8125rem, 0.78rem + 0.1vw, 0.875rem);

  --space-lg: clamp(1.75rem, 1.4rem + 1.5vw, 3rem);
  --space-md: clamp(1.125rem, 0.95rem + 0.8vw, 1.75rem);
  --space-sm: clamp(0.75rem, 0.65rem + 0.4vw, 1rem);

  --container-max: 1200px;
  --edge: clamp(1.25rem, 1rem + 2vw, 4rem);

  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-smooth: cubic-bezier(0.65, 0, 0.35, 1);

  --radius-full: 999px;
}

/* Theme sombre : bascule via [data-theme="dark"] sur <html> (pose par le
   script anti-flash dans le head + le bouton toggle dans la nav). Redefinir
   --off-white et --ink ici reteinte automatiquement tout ce qui consomme
   deja ces deux tokens (body, hero, cartes, vision). .rise garde son navy
   d'origine tel quel (elle utilise --navy/--text-on-dark en dur, deja
   sombre). Les elements qui reposent sur un contraste navy-sur-clair en dur
   (pilules, fond teinte des cartes, badge) ont besoin d'un correctif dedie
   plus bas, sinon ils disparaissent une fois le fond passe en navy. */
html[data-theme="dark"] {
  --off-white: var(--navy);
  --ink: var(--text-on-dark);
  --ink-soft: rgba(252, 252, 252, 0.7);
  --ink-faint: rgba(252, 252, 252, 0.1);
}

/* Toutes les lignes manuscrites (Caveat) du site en gold en theme sombre
   (2026-08-04, demande explicite -- gold-2, pas gold-1 qui est trop pale
   / champagne). Un seul point de regroupement plutot que quatre regles
   eparpillees par section : plus simple a retrouver/ajuster si une future
   ligne manuscrite est ajoutee. Specificite html+attr+classe l'emporte
   sur chaque regle de base (color: var(--ink) ou var(--text-on-dark))
   sans les modifier -- le theme clair garde son rendu actuel intact. */
html[data-theme="dark"] .hero__script,
html[data-theme="dark"] .rise__script-echo,
html[data-theme="dark"] .conviction__script,
html[data-theme="dark"] .force__script,
html[data-theme="dark"] .bureau__script,
html[data-theme="dark"] .story__script,
html[data-theme="dark"] .story__reveal-text,
html[data-theme="dark"] .cards-rise__script {
  background: linear-gradient(135deg, var(--gold-1) 0%, var(--gold-2) 50%, var(--gold-3) 100%);
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  width: fit-content;
  padding-right: 0.35em;
}
/* PIEGE : un degrade de texte se peint sur la BOITE de l element, pas sur
   ses lettres. Un <p> pleine largeur dont le texte tient sur un tiers ne
   montre donc quun tiers du degrade (gold-1 pale si le texte est a gauche,
   gold-3 olive sil est a droite) au lieu du balayage complet. Do le
   width: fit-content ci-dessus, qui fait epouser la boite au texte.
   Sans effet sur .cards-rise__script (item flex) ni .conviction__script
   (absolu) : ces deux la epousent deja leur contenu, la regle est neutre.
   .rise__script-echo est ancre a gauche, fit-content ne le deplace pas.
   .hero__script en revanche est aligne a DROITE via une boite a 95% (voir
   Beajify.md, position calee volontairement en soiree du 2026-08-04) :
   passer en fit-content collerait la ligne au bord droit du conteneur.
   margin-left:auto + margin-right:5% reproduisent exactement le meme bord
   droit qu avant (0 -> 95% devient auto -> 95%), position inchangee.
   Tout ce bloc est scope au theme sombre : le theme clair ne voit aucun
   changement de boite, il garde color: var(--ink) et sa boite d origine. */
/* PIEGE 2 (suite du precedent) : Caveat est une cursive dont les lettres
   finales DEBORDENT de leur chasse (la remontee du e de controle depasse a
   droite). width: fit-content arrete la boite pile a la chasse, donc le
   degrade ne couvre pas ce debordement -- et comme le texte est en
   text-fill-color: transparent, la partie non couverte devient invisible.
   Le mot paraissait mange alors quil etait juste transparent au bout.
   padding-right elargit la zone peinte sans toucher au texte.
   Compensation sur les deux lignes alignees A DROITE uniquement, pour que
   leur bord droit reste exactement ou il etait : le hero via son
   margin-right (5% - le padding), .cards-rise__script via une marge
   negative de la meme valeur (item flex en justify-content:flex-end).
   Les deux autres lignes sont ancrees a gauche : le padding sallonge vers
   la droite dans le vide, aucun deplacement, aucune compensation utile. */
html[data-theme="dark"] .hero__script { margin-left: auto; margin-right: calc(5% - 0.35em); }
html[data-theme="dark"] .cards-rise__script { margin-right: -0.35em; }

/* Titres : Playfair Display. Texte courant : Inter. */

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
html, body { margin: 0; padding: 0; }

body {
  background: var(--off-white);
  color: var(--ink);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif;
  font-size: var(--fs-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

h1 {
  font-family: 'Playfair Display', Georgia, serif;
  margin: 0;
  line-height: 1.08;
  letter-spacing: -0.01em;
  font-weight: 700;
}

.container {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--edge);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  font-family: 'Inter', sans-serif;
  font-weight: 600;
  font-size: var(--fs-body);
  padding: 0.95rem 1.9rem;
  border-radius: var(--radius-full);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  transition: transform 0.5s var(--ease-out-expo), box-shadow 0.5s var(--ease-out-expo), background 0.4s ease, border-color 0.4s ease;
}
.btn-primary { background: var(--navy); color: var(--gold-2); border: 1px solid rgba(196, 184, 118, 0.55); }
.btn-ghost { background: var(--off-white); border: 1.5px solid var(--ink); color: var(--ink); }
@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 14px 32px rgba(11, 5, 47, 0.28); border-color: var(--gold-1); }
  .btn-ghost:hover { transform: translateY(-2px); background: rgba(11, 5, 47, 0.04); }
}

/* Navigation */
/* Nav pleine largeur (2026-08-04) : la classe .container est passee sur
   .nav__inner (voir home.html) pour que le fond de la nav couvre toute la
   largeur de l ecran, pas seulement les 1200px du container. La mise en
   page interne est identique (meme max-width, meme padding, juste porte
   par l element enfant). */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  padding: var(--space-sm) 0;
  background: transparent;
  transition: background 0.4s ease, backdrop-filter 0.4s ease;
}

/* Fond verre depoli une fois le hero depasse (2026-08-04). Motif : la nav
   est fixe ET transparente, donc TOUT le contenu du site reste lisible
   au travers en sortant par le haut (verifie : le paragraphe de
   .conviction est a top:45px en bas de page, en pleine zone de nav).
   Ce n est donc pas un souci propre a une section, mais une propriete de
   la nav elle-meme -- d ou un correctif unique ici plutot que du
   rafistolage section par section. Le flou rend ce qui passe dessous
   diffus au lieu de lisible, tout en gardant la nav visuellement legere.
   Reste 100% transparente sur le hero (classe nav-scrolled posee par
   navColorSwap seulement quand une section empilee atteint la nav). */
body.nav-scrolled .nav {
  background: rgba(250, 250, 252, 0.72);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
/* nav-over-dark couvre les deux cas d un coup : section sombre en theme
   clair, ET theme sombre integral (navColorSwap pose la classe dans les
   deux cas, voir main.js). */
body.nav-scrolled.nav-over-dark .nav {
  background: rgba(11, 5, 47, 0.72);
}
.nav__inner { display: flex; align-items: center; justify-content: space-between; gap: var(--space-md); }
.nav__logo img { height: 2.75rem; width: auto; transition: opacity 0.3s ease; }
.nav__links { display: flex; align-items: center; gap: 0.25rem; flex: 1; justify-content: center; }
.nav__links a, .nav__link-inert {
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--ink);
  padding: 0.5rem 0.9rem;
  border-radius: var(--radius-full);
  transition: background 0.3s ease, color 0.4s ease;
}
body.nav-over-dark .nav__links a, body.nav-over-dark .nav__link-inert,
html[data-theme="dark"] .nav__links a, html[data-theme="dark"] .nav__link-inert { color: var(--text-on-dark); }
.nav__link-inert { opacity: 0.55; }
@media (hover: hover) and (pointer: fine) {
  .nav__links a:hover { background: rgba(11, 5, 47, 0.05); }
}
.nav__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(2.75rem, 2.4rem + 1vw, 3.1rem);
  height: clamp(2.75rem, 2.4rem + 1vw, 3.1rem);
  border-radius: 50%;
  transition: background 0.3s ease, transform 0.4s var(--ease-out-expo);
}
.nav__cta img { height: 55%; width: 55%; display: block; transition: filter 0.4s ease; }
/* Blanc quand la nav passe sur une section sombre en theme clair (ex:
   scroll sur .rise). Scope explicitement a --icon-light (pas juste
   ".nav__cta img") : navColorSwap active nav-over-dark AUSSI en theme
   sombre integral (pas seulement au scroll sur une section sombre, voir
   main.js), donc un selecteur generique .nav__cta img aurait aussi
   force l'icone doree en blanc la-bas -- bug constate le 2026-08-04. */
body.nav-over-dark .nav__cta-icon--light { filter: brightness(0) invert(1); }

/* Icone telephone en theme sombre : asset dore fourni directement par
   l'utilisateur (Phone-Circle--Streamline-Ultimate.png), utilise tel
   quel -- deux <img> dans le HTML (voir home.html), bascule par simple
   display:none/block selon le theme, aucune recoloration CSS. Selecteurs
   qualifies avec .nav__cta + img (specificite 0,2,1) : necessaire pour
   l'emporter sur la regle generique ".nav__cta img { display:block }"
   ci-dessus (0,1,1) -- sans ca, les deux icones restaient visibles en
   meme temps en theme clair (bug constate le 2026-08-04). */
.nav__cta img.nav__cta-icon--dark { display: none; }
html[data-theme="dark"] .nav__cta img.nav__cta-icon--light { display: none; }
html[data-theme="dark"] .nav__cta img.nav__cta-icon--dark { display: block; }
@media (hover: hover) and (pointer: fine) {
  .nav__cta:hover { background: rgba(11, 5, 47, 0.06); transform: translateY(-2px); }
}

.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(2.5rem, 2.2rem + 0.8vw, 2.75rem);
  height: clamp(2.5rem, 2.2rem + 0.8vw, 2.75rem);
  border-radius: 50%;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  color: var(--ink);
  transition: background 0.3s ease, color 0.4s ease;
}
body.nav-over-dark .theme-toggle,
html[data-theme="dark"] .theme-toggle { color: var(--text-on-dark); }
.theme-toggle svg { width: 1.3rem; height: 1.3rem; }
.theme-toggle__moon { display: none; }
html[data-theme="dark"] .theme-toggle__sun { display: none; }
html[data-theme="dark"] .theme-toggle__moon { display: block; }
@media (hover: hover) and (pointer: fine) {
  .theme-toggle:hover { background: rgba(11, 5, 47, 0.06); }
  html[data-theme="dark"] .theme-toggle:hover { background: rgba(252, 252, 252, 0.08); }
}

@media (max-width: 900px) { .nav__links { display: none; } }

/* Hero */
.hero {
  position: sticky;
  top: 0;
  z-index: 0;
  min-height: 100vh; min-height: 100svh;
  background-color: var(--off-white);
  padding: clamp(4rem, 3rem + 4vw, 7rem) var(--edge) var(--space-lg);
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.hero > * { max-width: 78rem; margin-inline: auto; }

/* Entree en cascade au chargement : titre, sous-titre, CTA, puis ligne
   manuscrite. CSS pur (animation-delay), demarre automatiquement au
   rendu puisque le hero est le premier contenu visible - pas besoin de
   JS/IntersectionObserver comme pour le medaillon plus bas dans la page. */
@keyframes hero-cascade-in {
  from { opacity: 0; transform: translateY(18px); }
  to { opacity: 1; transform: translateY(0); }
}
.hero__title, .hero__lead, .hero__ctas, .hero__script {
  opacity: 0;
  animation: hero-cascade-in 0.55s var(--ease-out-expo) forwards;
}
.hero__title { animation-delay: 0.1s; }
.hero__lead { animation-delay: 0.25s; }
.hero__ctas { animation-delay: 0.4s; }
.hero__script { animation-delay: 0.55s; }
@media (prefers-reduced-motion: reduce) {
  .hero__title, .hero__lead, .hero__ctas, .hero__script {
    opacity: 1;
    animation: none;
    transform: none;
  }
}

.hero__title { font-size: var(--fs-hero); color: var(--ink); }
.hero__lead {
  font-family: 'Inter', sans-serif;
  font-weight: 400;
  font-size: var(--fs-lead, clamp(1.0625rem, 0.98rem + 0.4vw, 1.375rem));
  color: var(--ink-soft);
  max-width: 42ch;
  margin: var(--space-md) auto 0;
}

.hero__ctas { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-top: clamp(3rem, 2.2rem + 4vw, 6rem); justify-content: center; align-items: center; }
.hero__ctas a { display: inline-block; transition: transform 0.4s var(--ease-out-expo); }
.hero__cta--dark {
  border-radius: var(--radius-full);
  box-shadow: 0 0 0 0 rgba(196, 184, 118, 0);
  transition: transform 0.4s var(--ease-out-expo), box-shadow 0.4s var(--ease-out-expo);
}
.hero__ctas img {
  width: clamp(11.5rem, 9.45rem + 6vw, 14rem);
  height: clamp(3.05rem, 2.5rem + 1.6vw, 3.7rem);
  display: block;
}
@media (hover: hover) and (pointer: fine) {
  .hero__ctas a:hover { transform: translateY(-2px); }
  .hero__cta--dark:hover { box-shadow: 0 10px 32px rgba(196, 184, 118, 0.45); }
}

.hero__script {
  font-family: 'Caveat', cursive;
  font-size: clamp(1.375rem, 1.1rem + 1.1vw, 1.9rem);
  font-weight: 600;
  color: var(--ink);
  text-align: right;
  max-width: 95%;
  margin: clamp(4rem, 3rem + 4vw, 7rem) 0 0;
}
/* En dessous de ~600px, la phrase ne tient plus sur une ligne a la taille
   de base : on reduit un peu la police et on lui laisse toute la largeur
   pour qu'elle reste sur une seule ligne, comme sur desktop. */
@media (max-width: 600px) {
  .hero__script { font-size: 1.05rem; max-width: 100%; }
}


/* Section qui remonte par-dessus le hero (sticky) au scroll. Pur CSS,
   pas de JS : le hero reste fixe (position:sticky), cette section vient
   normalement par-dessus grace a l'ordre du DOM + son z-index. */
/* top negatif : le haut de la section (coin arrondi de 2.5rem inclus)
   reste toujours cale juste au-dessus du cadre visible, jamais montre une
   fois le sticky engage. Ne change pas la duree du palier, juste ce qui
   est visible pendant qu'il tient. */
.rise {
  position: sticky;
  top: -3rem;
  z-index: 1;
  overflow: hidden;
  min-height: 115vh;
  background: var(--navy);
  color: var(--text-on-dark);
  border-radius: 2.5rem 2.5rem 0 0;
  box-shadow: 0 -30px 60px rgba(11, 5, 47, 0.18);
}
/* Filigrane "0%" en fond de section, esprit du "Beajify" geant de la
   cloture : discret, jamais assez visible pour concurrencer le texte. */
.rise__watermark {
  position: absolute;
  top: clamp(9rem, 7rem + 6vw, 13rem);
  left: 56%;
  z-index: 0;
  margin: 0;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(11rem, 6rem + 24vw, 28rem);
  line-height: 1;
  color: rgba(252, 252, 252, 0.05);
  white-space: nowrap;
  pointer-events: none;
}
/* Mobile : le placement desktop (56% + tres grande taille) ne laisse voir
   que la moitie du "0%", coupe par l'overflow:hidden de .rise. On ne touche
   pas au calage desktop (deja valide) - juste une variante mobile recentree
   et plus modeste pour rester lisible en entier sans dominer la section. */
@media (max-width: 900px) {
  .rise__watermark {
    top: 5rem;
    left: 58%;
    transform: translateX(-50%);
    font-size: clamp(7rem, 5rem + 18vw, 11rem);
  }
}
.rise__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding-top: clamp(11rem, 8.5rem + 8vw, 16rem);
  padding-bottom: clamp(4rem, 3rem + 4vw, 7rem);
  text-align: left;
}
.rise__content { max-width: 58%; }
@media (max-width: 900px) {
  .rise__inner { align-items: center; text-align: center; }
  .rise__content { max-width: 100%; }
  .rise__link { align-self: center !important; }
}
.rise h2 {
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(1.875rem, 1.55rem + 1.6vw, 2.75rem);
  margin: 0 0 1rem;
}
.rise__lead {
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 600;
  font-size: clamp(1.375rem, 1.15rem + 1vw, 1.75rem);
  margin: 0 0 0.75rem;
  max-width: 32ch;
}
.rise__text { color: rgba(252, 252, 252, 0.7); margin: 0; max-width: 42ch; }
.rise__script-echo {
  font-family: 'Caveat', cursive;
  font-weight: 600;
  font-size: clamp(1.375rem, 1.1rem + 1.1vw, 1.9rem);
  color: var(--text-on-dark);
  margin: clamp(2.25rem, 1.75rem + 2vw, 3.5rem) 0 0;
}


/* Medaillon B anime : 3D natif CSS uniquement, perspective sur le parent,
   preserve-3d sur l'element qui tourne, zero librairie. L'animation ne
   tourne que quand la section est visible (classe posee par IntersectionObserver
   en JS, pas de recalcul de position par frame : seul un threshold declenche
   le pause/reprise, la rotation elle-meme reste 100% CSS/GPU). */
.medallion {
  position: relative;
  width: clamp(4.375rem, 4rem + 1vw, 5.625rem);
  margin: 0 0 clamp(1.75rem, 1.4rem + 1.5vw, 3rem);
  perspective: 500px;
}
.medallion__stage {
  position: relative;
  z-index: 1;
  width: 100%;
  aspect-ratio: 1 / 1;
}
.medallion__coin {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  animation: medallion-spin 12s ease-in-out infinite;
  animation-play-state: paused;
}
.medallion.is-visible .medallion__coin { animation-play-state: running; }

/* Face avant/arriere : la MEME image des deux cotes (aucun autre visuel
   fourni). La face arriere est pre-tournee de 180deg + son image mirroree,
   pour que le B se lise normalement (pas a l'envers) une fois retournee. */
.medallion__face {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  backface-visibility: hidden;
}
.medallion__face--front { transform: translateZ(5.5px); }
.medallion__face--back { transform: rotateY(180deg) translateZ(5.5px) scaleX(-1); }

/* Tranche : la meme image, en une dizaine de copies intactes (non
   recolorees) empilees en Z par incrementes de 1px, comme un jeu de cartes
   vu par la tranche. Alignees derriere la face avant donc invisibles de
   face ; visibles quand la rotation approche 90 degres. Epaisseur totale
   volontairement fine (~11px pour un diametre de 70-90px). */
.medallion__rim { position: absolute; inset: 0; transform-style: preserve-3d; }
.medallion__slice {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  backface-visibility: hidden;
  transform: translateZ(calc((var(--i) - 4.5) * 1px));
}

.medallion__shadow {
  position: absolute;
  left: 50%;
  bottom: -0.6rem;
  width: 70%;
  height: 0.9rem;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.5);
  filter: blur(4px);
  transform: translateX(-50%) scaleX(0.7);
  animation: medallion-shadow 12s ease-in-out infinite;
  animation-play-state: paused;
}
.medallion.is-visible .medallion__shadow { animation-play-state: running; }

/* Phase 1 (0-22%) : rotation horizontale, rotateY 0->360, piece de monnaie.
   Phase 2 (22-47%) : rotation verticale, rotateX 0->360, Y reste fixe.
   Phase 3 (47-72%) : rotation oblique, les deux axes avancent ensemble
   (equivalent a rotate3d(1,1,0,...) mais garde le meme couple de fonctions
   rotateY()/rotateX() tout du long, pour une interpolation fiable d'un
   keyframe a l'autre). Phase 4 (72-100%) : retour horizontal lent, X reste
   fixe, Y termine sur un multiple de 360 -> boucle sans a-coup. */
@keyframes medallion-spin {
  0%   { transform: rotateY(0deg)    rotateX(0deg); }
  22%  { transform: rotateY(360deg)  rotateX(0deg); }
  47%  { transform: rotateY(360deg)  rotateX(360deg); }
  72%  { transform: rotateY(720deg)  rotateX(720deg); }
  100% { transform: rotateY(1080deg) rotateX(720deg); }
}

/* Ombre : sombre et resserree quand la piece est de face, claire et etiree
   quand elle est de profil. Calee sur les memes points de cycle que la
   rotation (debut/fin de chaque phase = face, milieu de phase = profil). */
@keyframes medallion-shadow {
  0%   { opacity: 0.5; transform: translateX(-50%) scaleX(0.7); }
  11%  { opacity: 0.15; transform: translateX(-50%) scaleX(1.3); }
  22%  { opacity: 0.5; transform: translateX(-50%) scaleX(0.7); }
  34%  { opacity: 0.15; transform: translateX(-50%) scaleX(1.3); }
  47%  { opacity: 0.5; transform: translateX(-50%) scaleX(0.7); }
  59%  { opacity: 0.15; transform: translateX(-50%) scaleX(1.3); }
  72%  { opacity: 0.5; transform: translateX(-50%) scaleX(0.7); }
  86%  { opacity: 0.15; transform: translateX(-50%) scaleX(1.3); }
  100% { opacity: 0.5; transform: translateX(-50%) scaleX(0.7); }
}

@media (prefers-reduced-motion: reduce) {
  .medallion__coin {
    animation: none !important;
    animation-play-state: paused !important;
    transform: rotateY(0deg) rotateX(0deg);
  }
  .medallion__shadow {
    animation: none !important;
    animation-play-state: paused !important;
    opacity: 0.5;
    transform: translateX(-50%) scaleX(0.7);
  }
}

/* Lien discret vers la page Comparatif */
.rise__link {
  display: inline-flex;
  align-items: center;
  align-self: flex-end;
  gap: 0.4rem;
  margin-top: clamp(2.25rem, 1.9rem + 1.6vw, 3.25rem);
  font-family: 'Playfair Display', Georgia, serif;
  font-size: var(--fs-body);
  font-weight: 600;
}
.rise__link span {
  background: var(--gold-gradient);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
.rise__link-arrow { color: var(--gold-2); transition: transform 0.35s var(--ease-out-expo); }
@media (hover: hover) and (pointer: fine) {
  .rise__link:hover .rise__link-arrow { transform: translateX(0.3rem); }
}


/* Section cartes : meme principe que la remontee du .rise sur le hero
   (.rise est maintenant sticky, cette section vient normalement par-dessus
   grace a l'ordre du DOM + son z-index). Fond clair cette fois, coins
   arrondis en haut. Le rideau de cartes plus bas reutilise exactement la
   mecanique de pin + translation horizontale pilotee par le scroll. */
.cards-rise {
  position: relative;
  z-index: 2;
  background: var(--off-white);
  border-radius: 2.5rem 2.5rem 0 0;
  padding-top: clamp(6rem, 4rem + 6vw, 10rem);
}

/* Meme mecanique de pin + translation horizontale pilotee par le scroll,
   desktop ET mobile : sur petit ecran, une seule carte visible a la fois
   ne montrait aucun indice qu'il fallait swiper pour voir les suivantes,
   les clients passaient a cote. Le defilement vertical (deja naturel)
   revele maintenant les cartes suivantes tout seul, sans geste cache a
   decouvrir. */
.cards-rise__pin-wrap { position: relative; height: 150vh; }
/* flex-direction:column (2026-08-04, etait align-items:center en row) :
   empile le rideau de cartes ET le pied de section (script + lien) dans
   les memes 100vh, visibles ensemble des le debut du defilement horizontal
   plutot que le pied n'apparaisse qu'une fois le pin relache. Aucun impact
   sur le defilement horizontal : cardsHorizontalScroll ne lit que la
   hauteur de .cards-rise__pin-wrap et applique son transform directement
   sur #cardsTrack, jamais l'agencement vertical du pin. */
.cards-rise__pin {
  position: sticky;
  top: 0;
  height: 100vh; height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(5rem, 3rem + 8vw, 10rem);
  overflow: hidden;
}
/* Espace apres le pin : une fois le pin relache, laisse un peu de scroll
   avant que cards-rise elle-meme (non sticky) ne cede la place a la
   section suivante. Le pied de section vit desormais DANS le pin (voir
   plus haut), ce spacer est redevenu un simple espace de transition,
   purement visuel -- ne touche pas au pin-wrap/pin ni a la logique JS
   du scroll horizontal (cardsHorizontalScroll ne lit que
   .cards-rise__pin-wrap, jamais ce spacer). */
.cards-rise__spacer { height: 2vh; }

/* Reduced motion : le defilement horizontal pilote par le scroll reste
   coupe (voir cardsHorizontalScroll dans main.js), donc on retombe sur un
   rideau swipable au doigt/trackpad pour ne priver personne des cartes. */
@media (prefers-reduced-motion: reduce) {
  .cards-rise__pin-wrap { height: auto; padding-block: clamp(2rem, 1.5rem + 2vw, 3.5rem); }
  .cards-rise__pin { position: static; overflow-x: auto; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch; }
  .cards-rise__track { transform: none !important; }
  .cards-rise__spacer { display: none; }
}

.cards-rise__track {
  position: relative;
  display: flex;
  gap: clamp(1.25rem, 1rem + 1.5vw, 2rem);
  padding-inline: var(--edge);
  width: max-content;
}
.cards-rise__card {
  flex: 0 0 auto;
  height: 27rem;
  aspect-ratio: 16 / 9;
  border-radius: 1.5rem;
  /* THEME CLAIR : navy PLEIN (100%). C est ici que l opacite se voit, le
     fond de section etant en off-white : a 90% la carte virait au #231E44
     et perdait sa densite. */
  background: var(--navy);
  scroll-snap-align: start;
  padding: clamp(1.5rem, 1.2rem + 1.5vw, 2.5rem);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
/* CONSEQUENCE DU NAVY PLEIN : en theme sombre la page est elle aussi en
   --navy, la carte s y confond donc entierement avec le fond. Un filet a
   12% la borne sans rien changer a la couleur demandee. Il n existe qu en
   sombre : en clair, le contraste avec le fond off-white suffit. */
/* THEME SOMBRE : la carte s INVERSE -- fond clair et texte navy, quand le
   theme clair la garde en navy sur texte clair. Chaque theme presente donc
   la carte en contraste de son propre fond.
   Aucun filet ici, contrairement a la version navy-sur-navy : une carte
   #FCFCFC sur une page navy se detache d elle-meme.
   Les couleurs de texte sont posees en dur et NON via --ink / --ink-soft :
   ces deux tokens basculent en BLANC sous data-theme=dark, soit exactement
   l inverse de ce qu il faut ici. */
html[data-theme="dark"] .cards-rise__card { background: #FCFCFC; }
html[data-theme="dark"] .cards-rise__card::before,
html[data-theme="dark"] .cards-rise__card-title,
html[data-theme="dark"] .cards-rise__card-badge { color: var(--navy); }
html[data-theme="dark"] .cards-rise__card-text { color: rgba(11, 5, 47, 0.62); }
html[data-theme="dark"] .cards-rise__card-note { color: rgba(11, 5, 47, 0.5); }
@media (max-width: 767px) {
  .cards-rise__card { height: 14rem; }
}

/* --- [VALIDE] Numerotation des cartes (01 -> 05) ---
   Deux objectifs a la fois : donner un repere de progression pendant le
   defilement horizontal (rien n indiquait combien de cartes restaient)
   ET faire descendre le bloc titre+texte pour occuper le vide central
   de la carte, sans rien ajouter de decoratif ni de texture.
   Fait en compteur CSS + ::before plutot qu en HTML : le retour arriere
   est la suppression de ce seul bloc, aucun fichier HTML touche.
   Le ::before d un conteneur flex en colonne devient un item du flux :
   il pousse naturellement le titre vers le bas, donc pas de marge a
   ajouter sur .cards-rise__card-title.
   Marge reduite sous 768px : la carte mobile ne fait que 14rem de haut,
   la marge desktop la ferait deborder. */
.cards-rise__track { counter-reset: beajcard; }
.cards-rise__card::before {
  counter-increment: beajcard;
  content: counter(beajcard, decimal-leading-zero);
  font-family: "Playfair Display", Georgia, serif;
  font-weight: 600;
  font-size: clamp(1.0625rem, 0.95rem + 0.45vw, 1.25rem);
  /* HAUTEUR D ITEM VERROUILLEE sur l ancienne valeur (var(--fs-small) x 1.6,
     l interligne herite du body). Le ::before est un item du conteneur flex
     en colonne : sa hauteur pousse le titre, le texte et le badge. Agrandir
     le chiffre sans figer cette hauteur aurait tout decale, et fait deborder
     la carte mobile qui est a hauteur fixe (14rem). Le chiffre grossit donc
     DANS une boite inchangee -- la disposition ne bouge pas d un pixel. Ne
     jamais remplacer ce calc par un interligne sans unite. */
  line-height: calc(var(--fs-small) * 1.6);
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
  color: var(--gold-2);
  margin-bottom: clamp(2rem, 1.4rem + 2.4vw, 3.75rem);
}
/* Gold dans les DEUX themes depuis que la carte est navy partout : la
   distinction clair/sombre d avant n a plus d objet, le fond ne change
   plus. --gold-2 et non --gold-1, trop pale : meme choix que les lignes
   manuscrites. Gold uni plutot qu un degrade : sur deux chiffres de
   cette taille un degrade ne se lit pas, il salit juste la couleur. */
@media (max-width: 767px) {
  .cards-rise__card::before { margin-bottom: clamp(0.75rem, 0.5rem + 1.2vw, 1.25rem); }
}

.cards-rise__card-title {
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(1.625rem, 1.3rem + 1.6vw, 2.125rem);
  /* --text-on-dark en dur et NON --ink : --ink vaut le navy en theme
     clair, il aurait rendu le titre illisible sur le nouveau fond. */
  color: var(--text-on-dark);
  margin: 0 0 1.25rem;
}
.cards-rise__card-text {
  font-size: clamp(1.0625rem, 0.95rem + 0.6vw, 1.25rem);
  line-height: 1.5;
  color: rgba(252, 252, 252, 0.72);
  max-width: 34ch;
  margin: 0;
}
/* Le tag suit la maquette : Playfair dore pose a meme le fond, plus de
   pilule contournee. La pilule et son degrade de bordure en theme sombre
   (technique padding-box/border-box, qui imposait un span interne dedie
   au texte) n ont donc plus d objet et ont ete retires. Le span interne
   .cards-rise__card-badge-text reste dans le HTML mais herite simplement
   de sa couleur : rien a changer cote balisage. */
.cards-rise__card-badge {
  margin-top: auto;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: var(--fs-small);
  letter-spacing: 0.01em;
  color: var(--gold-2);
}
.cards-rise__card-note {
  margin-top: 0.6rem;
  font-size: clamp(0.75rem, 0.7rem + 0.1vw, 0.8125rem);
  color: rgba(252, 252, 252, 0.55);
}

/* En-tete de section (avant les cartes) : filigrane seul, resserre au
   maximum contre les cartes (2026-08-04 : phrase d'intro prevue au depart
   retiree, marge reduite en consequence -- plus besoin du positionnement
   absolu qui servait a superposer les deux). overflow:hidden pour eviter
   tout debordement horizontal sur mobile, meme technique que .rise. */
.cards-rise__header {
  position: relative;
  overflow: hidden;
  text-align: left;
}
.cards-rise__watermark {
  margin: 2rem 0 1rem;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(4rem, 2rem + 11vw, 12rem);
  line-height: 1;
  color: rgba(11, 5, 47, 1);
  white-space: nowrap;
}
html[data-theme="dark"] .cards-rise__watermark {
  color: rgba(252, 252, 252, 0.05);
}

/* Sortie de section (apres le defilement des cartes) : ligne manuscrite
   bas-gauche + lien bas-droite, meme structure que le pied de .rise__inner
   mais en ligne (space-between) plutot qu'en colonne, et couleur navy
   (var(--ink)) plutot que le gradient gold -- .rise est sur fond navy,
   .cards-rise est sur fond clair, le gold n'y rendait pas bien (meme
   constat que pour le spotlight du hero). var(--ink) plutot que var(--navy)
   en dur : reste "Navy" en theme clair tout en s'adaptant automatiquement
   en theme sombre (fond de la section devient navy via le meme token). */
/* Pas de classe .container ici (2026-08-04) : .container centre sur
   1200px max, alors que .cards-rise__track (les cartes) n'a PAS de
   container, juste padding-inline: var(--edge) -- sur grand ecran, les
   deux systemes divergent, ce qui desalignait "Votre" par rapport a la
   carte Designer. padding-inline directement ici, meme reference que le
   track : le V de "Votre" s'aligne desormais avec le bord de la premiere
   carte, "Nos offres" avec le bord droit correspondant. width:100%
   explicite plutot que compter sur le stretch implicite du flex parent
   (.cards-rise__pin, colonne) : plus fiable, ne laisse pas le footer se
   retrecir a la largeur de son contenu. */
.cards-rise__footer {
  display: flex;
  justify-content: flex-end;
  width: 100%;
  padding-inline: var(--edge);
}
.cards-rise__script {
  font-family: 'Caveat', cursive;
  font-weight: 600;
  font-size: clamp(1.375rem, 1.1rem + 1.1vw, 1.9rem);
  color: var(--ink);
  margin: 0;
}



/* Nouvelle section, etape 1 : vide, juste le fond, en continuite de couleur
   avec la section cartes (meme fond, pas de coin arrondi, pas de rupture
   visuelle). Contenu ajoute dans une etape suivante. */
/* Section vision : deux colonnes (label court a gauche, paragraphe a
   droite), fond clair pour ne pas dupliquer le navy de .rise. Simple
   section statique (pas de sticky) donc aucun impact sur la fluidite
   du scroll. z-index au-dessus de .rise/.cards-rise pour les memes
   raisons que .cards-rise lui-meme (voir commentaire plus haut). */
.conviction {
  position: relative;
  z-index: 3;
  background: var(--off-white);
  padding-top: clamp(1.5rem, 0.5rem + 3vw, 3.5rem);
  padding-bottom: clamp(5rem, 3.5rem + 7vw, 9rem);
}
.conviction__inner {
  position: relative;
  max-width: 1600px;
  margin-inline: auto;
  padding-inline: var(--edge);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: stretch;
}
.conviction__label {
  flex: 0 0 auto;
  margin: 0;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(2.25rem, 1.8rem + 2vw, 3.25rem);
  line-height: 1.15;
  color: var(--ink);
  white-space: nowrap;
}
/* Troisieme ligne manuscrite du site (hero + section navy) : meme police,
   meme poids, meme taille - regle fixe deja etablie, seul le texte change. */
/* Positionnee dans la colonne de gauche independamment de l'ordre du DOM
   (elle vit apres le texte en HTML pour que le mobile la place naturellement
   apres le paragraphe, voir media query plus bas) : absolute par rapport a
   .conviction__inner, callee a gauche comme le label, relevee du bas d'une
   valeur fixe pour un effet "note" volontairement asymetrique. */
.conviction__script {
  position: absolute;
  left: var(--edge);
  bottom: 9rem;
  font-family: 'Caveat', cursive;
  font-weight: 600;
  font-size: clamp(1.375rem, 1.1rem + 1.1vw, 1.9rem);
  color: var(--ink);
  max-width: 30rem;
  margin: 0;
}
.conviction__text {
  flex: 0 0 auto;
  width: 55%;
  margin: 0;
  font-family: 'Inter', sans-serif;
  font-weight: 600;
  font-size: clamp(1.625rem, 1.3rem + 1.4vw, 2.25rem);
  line-height: 1.5;
  color: var(--ink);
}
@media (max-width: 900px) {
  .conviction__inner { flex-direction: column; }
  .conviction__label { margin-bottom: 1.5rem; }
  .conviction__text { width: 100%; line-height: 1.85; }
  .conviction__script { position: static; margin-top: clamp(2rem, 1.5rem + 2vw, 3rem); }
}

/* Mots-cles en "coup de marqueur" (2026-08-04, remplace l'ancien style
   pilule/badge) : background-image SVG (trait ondule, imparfait, pas une
   forme geometrique) plutot qu'un aplat de couleur, pour un rendu fait
   main. Deux SVG differents (pas un seul recolorable) : un data-URI
   integre a un background-image est une ressource statique, sans acces
   a currentColor/aux variables CSS de l'element qui le reference -- la
   couleur et l'opacite sont donc figees dans chaque URI. Texte en
   var(--ink) (pas navy/text-on-dark en dur) : s'adapte deja tout seul au
   theme (navy en clair, blanc en sombre), demande de l'utilisateur
   satisfaite sans dupliquer la logique de theme. Padding volontairement
   minimal ("colle au texte") contrairement a l'ancien pill genereux. */
/* Forme FERMEE et remplie (fill), pas un trait (stroke) : un stroke ondule
   laisse des creux ou le fond de la page repasse au travers, rendant le
   texte illisible par endroits des que sa couleur se rapproche de celle
   du fond (invisible en theme sombre notamment -- bug constate le
   2026-08-04). Un fill garantit une couverture continue sous tout le mot.
   Texte navy fixe (pas de bascule par theme) : la bande gold est desormais
   pleine et couvrante dans les deux themes, donc le contraste navy tient
   sans conditionner quoi que ce soit. Couleur/opacite choisies pour le
   rendu, sans obligation de coller a la palette existante (demande
   explicite -- un surligneur invente est accepte s il rend bien). */
/* Taille/graisse forcees en inherit (2026-08-04) : meme si aucune regle
   ne definissait explicitement de font-size/weight avant, les mots
   surlignes paraissaient plus gros que le reste du paragraphe -- rendu
   explicite ici pour eliminer tout doute, quelle qu en soit la cause
   exacte (line-height d un inline-block, arrondi de rendu, etc). Couleur
   corail/terracotta (2026-08-04) : essai hors palette gold existante, a
   la demande explicite de l utilisateur ("meme inventee ne pose aucun
   probleme"). Texte navy en clair (fond pale, forte opacite basse) MAIS
   BLANC en theme sombre (contrainte explicite de l utilisateur, contraire
   au choix precedent) -- d ou une opacite nettement plus haute en sombre :
   il faut un fond assez soutenu pour que du blanc reste lisible dessus,
   pas juste un voile. */
.marker-highlight {
  display: inline-block;
  margin: 0 0.15em;
  padding: 0.05em 0.2em;
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 30' preserveAspectRatio='none'%3E%3Cpath d='M2,10 C20,5 40,12 60,7 C75,4 88,9 98,6 L98,23 C85,27 70,21 55,25 C38,29 20,24 2,26 Z' fill='%23E2795D' opacity='0.4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 100% 70%;
  color: var(--navy);
  white-space: nowrap;
}
html[data-theme="dark"] .marker-highlight {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 30' preserveAspectRatio='none'%3E%3Cpath d='M2,10 C20,5 40,12 60,7 C75,4 88,9 98,6 L98,23 C85,27 70,21 55,25 C38,29 20,24 2,26 Z' fill='%23E2795D' opacity='0.8'/%3E%3C/svg%3E");
  color: var(--text-on-dark);
}

/* Revelation mot par mot au scroll : gris jusqu'a ce que le mot soit
   "atteint" par la progression du scroll dans la section, puis navy
   (voir main.js, meme logique getBoundingClientRect() que le scroll
   horizontal des cartes plus haut - pas de conflit avec le smooth-scroll
   sitewide puisqu'on ne fait que lire la position, jamais l'ecrire). */
.reveal-word {
  color: rgba(11, 5, 47, 0.28);
  transition: color 0.75s ease;
}
.reveal-word.is-revealed { color: var(--ink); }
html[data-theme="dark"] .reveal-word { color: rgba(252, 252, 252, 0.28); }
html[data-theme="dark"] .reveal-word.is-revealed { color: var(--ink); }


/* --- [TEST] Hero Interactions (Piste 3 : magnet + spotlight) ---
   Bloc entierement autonome, retrait en un bloc : supprimer tout entre
   ces deux marqueurs [TEST]. Rien ici ne modifie une regle existante
   plus haut dans le fichier -- uniquement des ajouts scopes sous la
   classe .hero-dynamics-active (posee par hero-dynamic-test.js
   uniquement quand le JS tourne reellement : reduced-motion/touch
   gardent donc le comportement d'origine a l'identique, y compris la
   transition CSS normale sur le CTA). */

.hero.hero-dynamics-active {
  --mouse-x: 50%;
  --mouse-y: 40%;
}

/* Spotlight ambiant : theme sombre uniquement (valide par l'utilisateur
   le 2026-08-04, rendu gold sur navy). En theme clair, aucune teinte
   testee ne convainc sur le fond quasi blanc -- remplace par un halo
   navy localise sur le CTA au survol, juste en dessous. */
html[data-theme="dark"] .hero.hero-dynamics-active::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    clamp(400px, 40vw, 700px) circle at var(--mouse-x) var(--mouse-y),
    rgba(245, 227, 154, 0.14),
    transparent 70%
  );
  opacity: 0;
  transition: opacity 0.6s ease;
}
html[data-theme="dark"] .hero.hero-dynamics-active:hover::after {
  opacity: 1;
}

/* CTA magnetique : transform desormais pilote frame par frame par le JS
   (lerp). Retirer transform de la transition CSS ici, sinon la transition
   0.4s existante et le lerp JS se cumulent -> mouvement mou/en retard. */
.hero-dynamics-active .hero__cta--dark {
  transition: box-shadow 0.4s var(--ease-out-expo);
}

/* Theme clair : plus aucun effet dore au survol du CTA -- spotlight
   ambiant et halo navy deja retires ci-dessus, on neutralise ici en plus
   le halo gold PRE-EXISTANT (.hero__cta--dark:hover, defini plus haut
   dans le fichier, hors bloc [TEST], present avant Piste 3). Volontairement
   PAS gate derriere .hero-dynamics-active : c'est desormais une decision
   de design (aucune lueur en theme clair), pas un effet lie au test, donc
   ca doit s'appliquer aussi aux utilisateurs reduced-motion/tactile.
   Specificite plus elevee (html + :not + classe + :hover) pour l'emporter
   sans toucher a la regle d'origine, qui reste intacte pour le theme
   sombre. Reproduit la meme forme d'ombre "invisible" que l'etat de repos
   (0 0 0 0, alpha 0) plutot que "none", pour une transition fiable. */
html:not([data-theme="dark"]) .hero__cta--dark:hover {
  box-shadow: 0 0 0 0 rgba(196, 184, 118, 0);
}

@media (prefers-reduced-motion: reduce) {
  html[data-theme="dark"] .hero.hero-dynamics-active::after { display: none; }
}
/* --- [/TEST] Hero Interactions (Piste 3) --- */

/* --- [VALIDE] Profondeur du CTA sombre en theme CLAIR ---
   Asymetrie de fond entre les deux themes : sur navy, le CTA navy a
   lisere dore se lit comme une SOURCE DE LUMIERE, il y a de lobscurite
   autour pour que la lueur deborde -> le halo gold au survol est le bon
   vocabulaire. Sur du #FAFAFC on ne peut pas briller plus blanc que
   blanc : un objet fonce sur fond pale nemet pas, il POSE. Sa langue,
   cest le poids et la profondeur, donc une OMBRE, pas un halo.
   Ombre teintee NAVY et jamais noire : sous un bouton navy elle se lit
   comme son ombre propre et reste dans la palette, la ou du noir pur
   vire au gris sale sur un fond aussi clair.

   POURQUOI filter: drop-shadow() ET SURTOUT PAS box-shadow (mesure faite
   sur le fichier, pas supposee) : cta-rejoindre.png embarque DEJA sa
   propre ombre portee, cuite dans limage. Le pill reellement opaque
   (alpha >= 200) noccupe que x 16->1064 et y 0->288 dans une image de
   1080x320 : il reste une marge transparente de 16px sur les cotes et
   32px SOUS le bouton, remplie par un halo sombre a faible alpha.
   box-shadow se dessine sur la boite de lelement, donc autour de cette
   marge invisible et non autour du pill visible -> une bande de fond
   clair apparait entre le bouton et le debut de lombre (plus epaisse en
   bas, la ou la marge est la plus grande). Aucun reglage de box-shadow
   ne corrige ca : les retraits different selon les cotes (0 en haut,
   32 en bas) alors que le spread est uniforme.
   drop-shadow suit le CANAL ALPHA du contenu rendu : lombre epouse la
   silhouette reelle, la bande disparait.

   Filtre pose sur le <img> et non sur le <a> : le magnet de la Piste 3
   ecrit un transform inline sur le <a> a chaque frame. Garder filtre et
   transform sur deux elements distincts evite de reevaluer le filtre a
   chaque deplacement.
   Retrait : supprimer ce bloc, rien dautre. */
html:not([data-theme="dark"]) .hero__cta--dark img {
  filter:
    drop-shadow(0 2px 3px rgba(11, 5, 47, 0.24))
    drop-shadow(0 10px 20px rgba(11, 5, 47, 0.28));
  transition: filter 0.4s var(--ease-out-expo);
}
html:not([data-theme="dark"]) .hero__cta--dark:hover img {
  filter:
    drop-shadow(0 3px 5px rgba(11, 5, 47, 0.26))
    drop-shadow(0 18px 32px rgba(11, 5, 47, 0.34));
}

/* --- [VALIDE] Indice de decouverte du theme sombre ---
   Popover ancre sous le switch de theme. Verre depoli comme la nav
   (backdrop-filter), bordure fine navy tres douce. AUCUN dore ici :
   sur fond clair le gold vire au jaune sale, contrainte explicite.
   Oeil en SVG natif inline, clin doeil 100% CSS, zero dependance.
   Retrait complet : ce bloc + le <div class="theme-switch"> dans
   home.html (degrafer le bouton) + liife themeHint dans main.js. */
.theme-switch { position: relative; display: inline-flex; }

.theme-hint {
  position: absolute;
  top: calc(100% + 0.6rem);
  right: 0;
  z-index: 1;
  width: max-content;
  max-width: min(16rem, calc(100vw - 2rem));
  padding: 1rem 1.1rem 0.95rem;
  border-radius: 1rem;
  background: rgba(250, 250, 252, 0.72);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(11, 5, 47, 0.10);
  box-shadow: 0 12px 32px -12px rgba(11, 5, 47, 0.22);
  color: var(--ink);
  text-align: center;
  display: none;
}
/* Bec pointant vers le switch. Cale sur la moitie de la largeur du
   bouton (meme clamp que .theme-toggle) puisque le popover est aligne
   sur son bord droit. */
/* Bec agrandi (0.6 -> 0.85rem) et bulle remontee (0.75 -> 0.6rem) pour
   quil pointe franchement vers le bouton.
   Geometrie : un carre de cote c tourne a 45 degres depasse de
   c * racine(2) / 2 au-dessus de son centre. Avec top = -c/2, le centre
   tombe pile sur le bord haut de la bulle, donc la pointe remonte de
   0.85 * 1.414 / 2 = 0.601rem. Lecart bulle/bouton etant regle a 0.6rem,
   la pointe arrive exactement au bord bas du bouton : au plus pres sans
   le chevaucher.
   Le decalage droit suit la meme logique quavant (moitie de la largeur
   du bouton, moins la moitie de la largeur du bec pour le centrer), la
   valeur soustraite passe donc de 0.3 a 0.425rem. */
.theme-hint::before {
  content: "";
  position: absolute;
  top: -0.425rem;
  right: calc(clamp(2.5rem, 2.2rem + 0.8vw, 2.75rem) / 2 - 0.425rem);
  width: 0.85rem;
  height: 0.85rem;
  background: inherit;
  border-left: 1px solid rgba(11, 5, 47, 0.10);
  border-top: 1px solid rgba(11, 5, 47, 0.10);
  border-radius: 0.15rem 0 0 0;
  transform: rotate(45deg);
}
html[data-theme="dark"] .theme-hint {
  background: rgba(11, 5, 47, 0.72);
  border-color: rgba(252, 252, 252, 0.14);
  box-shadow: 0 12px 32px -12px rgba(0, 0, 0, 0.55);
}
html[data-theme="dark"] .theme-hint::before {
  border-left-color: rgba(252, 252, 252, 0.14);
  border-top-color: rgba(252, 252, 252, 0.14);
}

.theme-hint__text {
  margin: 0.7rem 0 0;
  font-family: "Inter", sans-serif;
  font-size: var(--fs-small);
  line-height: 1.45;
}

.theme-hint__close {
  position: absolute;
  top: 0.3rem;
  right: 0.45rem;
  width: 1.3rem;
  height: 1.3rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: none;
  border: none;
  border-radius: 50%;
  font-family: "Inter", sans-serif;
  font-size: 1rem;
  line-height: 1;
  color: inherit;
  opacity: 0.45;
  cursor: pointer;
  transition: opacity 0.25s ease;
}
@media (hover: hover) and (pointer: fine) {
  .theme-hint__close:hover { opacity: 1; }
}

/* Oeil : traits fins, tout en currentColor pour suivre --ink et donc
   basculer navy / blanc casse avec le theme sans regle dediee. */
.theme-hint__eye { display: block; width: 4.25rem; height: auto; margin: 0 auto; }
.theme-hint__lid {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
}
/* Pli de la paupiere : ce seul trait fait basculer le dessin de
   pictogramme a oeil. stroke-opacity (et non opacity) parce que le
   clignement anime opacity sur ce meme element : les deux se
   multiplient au lieu de se remplacer, le pli garde donc sa
   discretion tout en disparaissant pendant la fermeture. */
.theme-hint__crease {
  fill: none;
  stroke: currentColor;
  stroke-width: 1;
  stroke-linecap: round;
  stroke-opacity: 0.3;
}
/* Iris : anneau limbique net, cercle interne plus doux, et huit fibres
   radiales entre les deux. Cest cette triple couche qui donne la
   profondeur, pas un cercle unique. */
.theme-hint__iris { fill: none; stroke: currentColor; stroke-width: 1.3; }
.theme-hint__iris-inner { fill: none; stroke: currentColor; stroke-width: 0.8; stroke-opacity: 0.4; }
.theme-hint__striations path {
  fill: none;
  stroke: currentColor;
  stroke-width: 0.8;
  stroke-linecap: round;
  stroke-opacity: 0.38;
}
.theme-hint__pupil { fill: currentColor; stroke: none; }
/* Reflet en var(--off-white) et non en blanc fixe : ce token bascule
   tout seul en navy sous data-theme=dark, or la pupille suit --ink et
   devient claire au meme moment. Le reflet reste donc contrasté sur la
   pupille dans les deux themes, sans une seule regle dediee. Les deux
   reflets sont poses A LINTERIEUR du rayon de la pupille, sinon ils se
   perdraient sur liris qui est vide. */
.theme-hint__glint { fill: var(--off-white); stroke: none; }
.theme-hint__glint--small { opacity: 0.65; }

/* transform-box: fill-box fait porter transform-origin sur la boite du
   trace lui-meme et non sur le viewBox entier : la paupiere haute se
   rabat alors exactement sur la ligne des coins de loeil (y=24), qui est
   aussi le point de depart de la paupiere basse. Sans ca, lorigine se
   calculerait sur tout le SVG et le trace glisserait hors de loeil. */
.theme-hint__lid--upper { transform-box: fill-box; transform-origin: bottom; }
.theme-hint__lid--lower { transform-box: fill-box; transform-origin: top; }

@keyframes theme-hint-in {
  from { opacity: 0; transform: translateY(-0.4rem); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes theme-hint-out {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-0.3rem); }
}
/* Clin doeil : la paupiere haute secrase sur la ligne des coins, la
   basse remonte un peu, liris disparait en meme temps. Letat 100% est
   loeil ouvert, donc loeil RESTE ouvert une fois lanimation finie. */
@keyframes theme-hint-blink-upper {
  0%   { transform: scaleY(1); }
  42%  { transform: scaleY(0.04); }
  58%  { transform: scaleY(0.04); }
  100% { transform: scaleY(1); }
}
@keyframes theme-hint-blink-lower {
  0%   { transform: scaleY(1); }
  42%  { transform: scaleY(0.25); }
  58%  { transform: scaleY(0.25); }
  100% { transform: scaleY(1); }
}
@keyframes theme-hint-blink-iris {
  0%   { opacity: 1; }
  42%  { opacity: 0; }
  58%  { opacity: 0; }
  100% { opacity: 1; }
}

/* display:none -> display:block via la classe : cest ce changement qui
   demarre les animations au bon moment. Avec un simple opacity, le clin
   doeil se serait joue au chargement de la page, invisible. */
.theme-hint.is-visible,
.theme-hint.is-leaving { display: block; }
.theme-hint.is-visible { animation: theme-hint-in 0.42s var(--ease-out-expo) both; }
.theme-hint.is-leaving { animation: theme-hint-out 0.42s ease both; }
.theme-hint.is-visible .theme-hint__lid--upper {
  animation: theme-hint-blink-upper 0.38s ease-in-out 0.52s both;
}
.theme-hint.is-visible .theme-hint__lid--lower {
  animation: theme-hint-blink-lower 0.38s ease-in-out 0.52s both;
}
.theme-hint.is-visible .theme-hint__iris-group,
.theme-hint.is-visible .theme-hint__crease {
  animation: theme-hint-blink-iris 0.38s ease-in-out 0.52s both;
}

@media (prefers-reduced-motion: reduce) {
  .theme-hint.is-visible,
  .theme-hint.is-leaving { animation-duration: 0.01ms; }
  .theme-hint.is-visible .theme-hint__lid--upper,
  .theme-hint.is-visible .theme-hint__lid--lower,
  .theme-hint.is-visible .theme-hint__crease,
  .theme-hint.is-visible .theme-hint__iris-group { animation: none; }
}

/* --- [ETAPE 1] Scrollytelling : ecriture de Beajify -> camion VUL ---
   z-index 4 : la section vient par-dessus .conviction (z-index 3), meme
   mecanique dempilement que le reste du site.
   La hauteur du pin-wrap EST la duree de lanimation : cest le seul
   endroit ou regler combien de scroll dure la sequence. 250vh pour
   letape 1 seule ; letape 2 lallongera pour loger les 5 scenarios. */
.story {
  position: relative;
  z-index: 4;
  background: var(--off-white);
}
/* 400vh et non 450 : le JS fait desormais demarrer la sequence un demi
   ecran AVANT lepinglage (voir storyScroll), ce qui rallonge la course
   totale dautant. On retire donc ces 50vh ici pour que la duree absolue
   de lecriture reste identique a celle qui a ete validee : seul le point
   de DEPART avance, le rythme ne change pas. */
/* 600vh depuis que le camion traverse lecran et quune seconde copie
   entre par la gauche : le trajet demande beaucoup plus de defilement que
   la simple avancee precedente. Toutes les fenetres de phase ont ete
   multipliees par 350/550 en contrepartie, pour que la duree ABSOLUE de
   lecriture et de la metamorphose reste exactement celle qui a ete
   validee. Seul le roulement recupere le temps gagne. */
/* 740vh : la sequence gagne une phase darrivee apres la sortie du
   camion. Les fenetres precedentes ont ete multipliees par 550/690 en
   contrepartie, pour que la duree ABSOLUE de lecriture, de la
   metamorphose et de la sortie reste exactement celle qui a ete validee.
   Seule la phase darrivee est du temps ajoute. */
.story__pin-wrap { position: relative; height: 740vh; }
/* overflow:hidden depuis que le camion roule sur une vraie distance : il
   deborde du cadre de scene en fin de course, et sans bornage il creerait
   une barre de defilement horizontale sur toute la page. Le clipping est
   ici volontaire, cest ce qui donnera au vehicule sa sortie de champ vers
   la section suivante. */
.story__pin {
  position: sticky;
  top: 0;
  height: 100vh; height: 100svh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.story__stage { width: min(90vw, 62rem); }
/* Texte revele par le passage du camion. Le decoupage est pilote en JS
   sur la position reelle de larriere du vehicule : le texte nexiste que
   DERRIERE lui, donc aucun recouvrement nest possible, par construction.
   clip-path plutot quune opacite mot a mot : le bord de coupe suit le
   camion, ce qui donne bien une revelation par le passage et non une
   apparition qui se trouverait etre synchrone. */
.story__reveal {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  padding-right: var(--edge);
  /* padding-left pose en JS : il vaut la position de depart de larriere
     du camion, qui depend de la largeur decran. */
  pointer-events: none;
  clip-path: inset(0 100% 0 0);
}
.story__reveal-text {
  margin: 0;
  max-width: 22ch;
  font-family: Playfair Display, Georgia, serif;
  font-weight: 700;
  font-size: clamp(1.75rem, 1.1rem + 3vw, 3.75rem);
  line-height: 1.15;
  color: var(--ink);
}
/* Le texte revele est dore en theme sombre : il a rejoint le groupe des
   lignes manuscrites en tete de fichier. La regle blanche qui se trouvait
   ici a ete retiree, elle serait passee APRES le groupe et aurait annule
   son color: transparent. En theme clair, .story__reveal-text garde son
   color: var(--ink) declare juste au-dessus. */

/* SECOND PANNEAU -- le contenu de la page ou le camion nous emmene.
   Le bloc vit dans lespace libere par le cadrage du camion entrant (30%
   de sa longueur seulement), donc son bord gauche est MESURE en JS a
   partir de la position darrivee reelle du vehicule. Une valeur en dur
   serait fausse des que la marge laterale change, cest-a-dire a chaque
   largeur decran -- meme regle que pour tout le reste de la section. */
.story__next {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-right: var(--edge);
  pointer-events: none;
  opacity: 0;
}
/* Meme traitement que le filigrane .cards-rise__watermark de la section
   Equipe : Playfair 700 en tres grand, navy PLEIN en clair et blanc a 5%
   en sombre. Le contraste inverse entre les deux themes est voulu la-bas
   et repris tel quel ici.
   Deux ecarts assumes avec loriginal, imposes par le contexte. Pas de
   white-space:nowrap : le filigrane dorigine est seul dans un en-tete
   pleine largeur et peut donc etre rogne, alors quici il partage le cadre
   avec le camion et doit pouvoir passer a la ligne. Et une taille plus
   basse (5.5rem contre 12rem) : la place utile est celle que le cadrage a
   30% laisse libre, pas la largeur de la page. */
/* Sorti du flux et pose en HAUT du cadre, au-dessus du camion. Deux
   consequences voulues. Il nest plus colle au titre : le groupe
   titre + texte se recentre seul, sans lui. Et surtout il echappe au
   padding-left mesure du bloc -- un enfant en position absolue se cale
   sur le bord du CADRE, pas sur sa zone de texte -- donc il demarre au
   bord de page et recupere toute la largeur que le camion lui prenait.
   La zone est libre : le toit du camion commence vers 196px du haut du
   cadre a 720px de hauteur, et plus bas encore sur un ecran plus haut,
   alors que le filigrane sarrete autour de 130px. */
.story__next-eyebrow {
  position: absolute;
  /* Valeur de repli seulement : le JS repose ce top a partir du bas
     reel de la nav et du toit du camion, mesures a linit et au resize. */
  top: 8rem;
  left: var(--edge);
  right: var(--edge);
  margin: 0;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  /* Repli seulement : le JS relit la taille reelle du filigrane Equipe et
     la reporte ici, pour que les deux restent identiques par construction
     et non par recopie dune formule quil faudrait penser a synchroniser. */
  font-size: clamp(2.25rem, 1rem + 4.5vw, 5.5rem);
  line-height: 1;
  /* nowrap comme le filigrane Equipe, et necessaire ici : cest le
     debordement sur UNE ligne qui sert a calculer la reduction. */
  white-space: nowrap;
  color: rgba(11, 5, 47, 1);
}
html[data-theme="dark"] .story__next-eyebrow { color: rgba(252, 252, 252, 0.05); }
/* Ligne manuscrite de la section : meme role et meme composition que
   .hero__script ou .conviction__script, posee en bas a DROITE comme
   les autres. Absolue, elle se cale sur le bord du cadre et echappe
   donc au padding-left mesure sur le camion, qui ne la concerne pas.
   Elle remplace le couple titre + phrase retire (Image & Flotte),
   redondant avec le filigrane Studio Graphique juste au-dessus. */
.story__script {
  position: absolute;
  right: var(--edge);
  bottom: clamp(1.5rem, 4vh, 3.25rem);
  margin: 0;
  /* Assez large pour tenir sur UNE ligne sur ordinateur, comme toutes les
     autres lignes manuscrites du site. A 26rem elle se cassait en deux. */
  max-width: min(46rem, 92%);
  text-align: right;
  font-family: 'Caveat', cursive;
  font-weight: 600;
  font-size: clamp(1.375rem, 1.1rem + 1.1vw, 1.9rem);
  color: var(--ink);
}
/* Le groupe gold du theme sombre passe la boite en fit-content : sans
   marge auto, la boite retrecie se recalerait a gauche de son ancrage. */
html[data-theme="dark"] .story__script { margin-left: auto; }

/* Une seule colonne depuis le retrait de Image & Flotte : lADN occupe
   toute la largeur laissee libre par le camion. */
.story__next-grid {
  display: flex;
  align-items: center;
  gap: clamp(1.5rem, 3vw, 3.5rem);
  width: 100%;
}

/* ---------- L'ADN DE BEAJIFY : la planche de l'atelier -------------------
   Le camion depose le visiteur au Studio Graphique. Ce qu il y trouve n est
   pas une brochure mais une TABLE A DESSIN : le logo se construit devant lui
   sur ses vraies lignes de reference. C est le meme langage que la premiere
   moitie de la section, ou le mot Beajify s ecrit trait par trait, et c est
   ce qui prouve la methode au lieu de la raconter.
   Toutes les cotes affichees sont mesurees sur logo-main.svg (ligne de base
   50.57, hauteur de capitale 29.79, sommet du B 0.50, italique a 8.3 degres
   verifie sur les deux bords du I) : aucune n est decorative.
   Toute l animation est declenchee par .is-live, pose par le JS quand le
   panneau apparait. Ce sont des TRANSITIONS et non des keyframes : elles se
   rejouent donc a l endroit quand on remonte, sans code de reset. */
.adn {
  --trait: rgba(11, 5, 47, 0.14);
  /* Les lignes de reference ont leur propre token : a 0.14 (la valeur des
     bordures) elles etaient invisibles a l ecran, et les remonter aurait
     alourdi toutes les bordures du bloc au passage. */
  --guide: rgba(11, 5, 47, 0.28);
  --trait-fort: rgba(11, 5, 47, 0.42);
  flex: 1 1 34rem;
  min-width: 0;
  font-family: 'Inter', sans-serif;
}
html[data-theme="dark"] .adn {
  --trait: rgba(252, 252, 252, 0.16);
  --guide: rgba(252, 252, 252, 0.3);
  --trait-fort: rgba(252, 252, 252, 0.48);
}

/* Toutes les entrees partagent la meme signature : leger deplacement + fade,
   en ease-out-expo. Le decalage se fait au transition-delay, un seul endroit
   a relire pour comprendre l ordre de la sequence. */
.adn__head, .plate, .regle, .valeurs { transition: opacity 900ms var(--ease-out-expo), transform 900ms var(--ease-out-expo); }
.adn__head, .regle, .valeurs { opacity: 0; transform: translateY(14px); }
.plate { opacity: 0; transform: translateY(10px); }
.story__next.is-live .adn__head,
.story__next.is-live .plate,
.story__next.is-live .regle,
.story__next.is-live .valeurs { opacity: 1; transform: none; }

.adn__head { margin-bottom: clamp(0.8rem, 1.8vh, 1.4rem); transition-delay: 60ms; }
.adn__title {
  margin: 0 0 0.4rem;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(1.35rem, 0.9rem + 1.2vw, 2rem);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.adn__lead {
  margin: 0;
  max-width: 60ch;
  font-size: clamp(0.8rem, 0.75rem + 0.2vw, 0.92rem);
  line-height: 1.55;
  color: var(--ink-soft);
}

.adn__cols {
  display: flex;
  gap: clamp(1.5rem, 3vw, 3.25rem);
  align-items: center;
}

/* ---- La planche ---- */
/* La borne est sur la PLANCHE et non sur le dessin : avec un max-width
   pose sur le svg, la colonne continuait de s elargir en flex et laissait
   un vide de 147px mesure entre le dessin et la colonne de droite. */
.plate { flex: 1 1 28rem; max-width: 36rem; min-width: 0; margin: 0; transition-delay: 140ms; }
.plate__svg { display: block; width: 100%; max-width: 100%; height: auto; overflow: visible; }

/* Les lignes de reference s etirent depuis la gauche, dans le sens de
   lecture : la planche se pose avant que le trait n arrive dessus. */
.plate__rule {
  stroke: var(--guide);
  stroke-width: 0.45;
  stroke-dasharray: 1.6 2.2;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 850ms var(--ease-out-expo), opacity 400ms linear;
}
.plate__rule--base { stroke-dasharray: none; stroke: var(--trait-fort); stroke-width: 0.5; }
.story__next.is-live .plate__rule { transform: scaleX(1); }
.plate__grid line:nth-child(1) { transition-delay: 240ms; }
.plate__grid line:nth-child(2) { transition-delay: 320ms; }
.plate__grid line:nth-child(3) { transition-delay: 400ms; }

/* Axe italique : deux paralleles a 8.3 degres, posees sur le I et sur le A.
   Deux et non une seule : c est leur PARALLELISME qui dit que l inclinaison
   est constante, une oblique isolee ne dirait rien. */
.plate__slant {
  stroke: var(--guide);
  stroke-width: 0.45;
  stroke-dasharray: 1.2 2.4;
  opacity: 0;
  transition: opacity 700ms var(--ease-out-expo), stroke 400ms linear, stroke-width 400ms linear;
  transition-delay: 1250ms;
}
.story__next.is-live .plate__slant { opacity: 1; }

/* Le logo lui-meme. pathLength=1 sur chaque lettre : la progression se mappe
   directement sur stroke-dashoffset, sans getTotalLength au runtime. */
.plate__letter {
  stroke: var(--ink);
  stroke-width: 0.85;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1000ms var(--ease-smooth), opacity 350ms linear, stroke-width 350ms linear, stroke 400ms linear;
}
html[data-theme="dark"] .plate__letter { stroke: var(--gold-2); }
.story__next.is-live .plate__letter { stroke-dashoffset: 0; }
/* Cascade B, E, A, J, I, F, Y : l ordre du fichier source est droite vers
   gauche, les tracés ont donc ete reordonnes dans le HTML pour que le
   nth-child suive l ordre de lecture. */
.plate__glyph path:nth-child(1) { transition-delay: 420ms; }
.plate__glyph path:nth-child(2) { transition-delay: 560ms; }
.plate__glyph path:nth-child(3) { transition-delay: 650ms; }
.plate__glyph path:nth-child(4) { transition-delay: 740ms; }
.plate__glyph path:nth-child(5) { transition-delay: 830ms; }
.plate__glyph path:nth-child(6) { transition-delay: 920ms; }
.plate__glyph path:nth-child(7) { transition-delay: 1010ms; }

/* Cotes : la hauteur du B rapportee a celle des capitales, et l angle. */
.plate__dims { opacity: 0; transition: opacity 700ms var(--ease-out-expo); transition-delay: 1450ms; }
.story__next.is-live .plate__dims { opacity: 1; }
.plate__tick, .plate__tick-cap { stroke: var(--trait-fort); stroke-width: 0.4; }
.plate__dim {
  fill: var(--ink-soft);
  font-family: 'Inter', sans-serif;
  font-size: 4.4px;
  font-weight: 500;
  letter-spacing: 0.04em;
}
.plate__legend {
  margin-top: 0.85rem;
  font-size: 0.68rem;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
  opacity: 0;
  transition: opacity 800ms var(--ease-out-expo);
  transition-delay: 1600ms;
}
.story__next.is-live .plate__legend { opacity: 1; }

/* ---- Colonne de droite ---- */
.adn__side { flex: 1 1 21rem; min-width: 0; }

.regles { margin: 0 0 clamp(0.9rem, 2vh, 1.5rem); padding: 0; list-style: none; }
.regle {
  display: flex;
  gap: 0.7rem;
  padding: 0.5rem 0;
  border-top: 1px solid var(--trait);
}
.regle:last-child { border-bottom: 1px solid var(--trait); }
.regle:nth-child(1) { transition-delay: 700ms; }
.regle:nth-child(2) { transition-delay: 810ms; }
.regle:nth-child(3) { transition-delay: 920ms; }
.regle__n {
  flex: none;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  line-height: 1.7;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  transition: color 300ms linear;
}
.regle__txt { font-size: 0.72rem; line-height: 1.5; color: var(--ink-soft); }
.regle__txt b { display: block; font-size: 0.78rem; font-weight: 600; color: var(--ink); }

/* MICRO-INTERACTION, en :has() donc sans une ligne de JS. Survoler une regle
   met en avant CE QU ELLE DECRIT sur la planche : le monogramme seul, les
   deux obliques, ou l epaisseur du trait. Le texte et le dessin cessent
   d etre deux blocs juxtaposes, ils se repondent. */
.story__next.is-live .regle { pointer-events: auto; cursor: default; }
.adn:has(.regle:hover) .regle:not(:hover) { opacity: 0.45; }
.regle { transition: opacity 300ms linear, transform 900ms var(--ease-out-expo); }
.adn:has(.regle[data-regle="1"]:hover) .plate__letter:not([data-l="B"]) { opacity: 0.16; }
.adn:has(.regle[data-regle="2"]:hover) .plate__slant { stroke: var(--trait-fort); stroke-width: 0.55; }
.adn:has(.regle[data-regle="2"]:hover) .plate__letter { opacity: 0.35; }
.adn:has(.regle[data-regle="3"]:hover) .plate__letter { stroke-width: 1.35; }
.adn:has(.regle[data-regle="3"]:hover) .plate__rule,
.adn:has(.regle[data-regle="3"]:hover) .plate__slant { opacity: 0.15; }

/* ---- Les deux valeurs ----
   UN SEUL logo coupe net en son milieu, et non deux cartes cote a cote.
   L image large de 124% de chaque moitie, decalee de +38% a gauche et de
   -62% a droite, se raccorde exactement a la couture : on lit une seule
   identite qui tient sur les deux fonds, ce qui EST l argument. Deux
   vignettes separees auraient montre deux logos. */
.valeurs { transition-delay: 1150ms; }
.valeurs__intro {
  margin: 0 0 0.55rem;
  font-size: 0.68rem;
  line-height: 1.45;
  color: var(--ink-soft);
}
/* La LARGEUR de la bande est bornee, pas seulement sa hauteur. Laissee
   libre elle prenait toute la colonne (579px mesures pour 69 de haut,
   soit un rapport de 8:1) alors que le logo est en 2,4:1 : contraint par
   la hauteur, il n occupait plus qu un huitieme de la bande et se lisait
   comme une vignette perdue. En bornant a 24rem le rapport tombe a 4,5:1
   et le logo retrouve un tiers de la largeur. */
.valeurs__split {
  position: relative;
  display: flex;
  max-width: 24rem;
  height: clamp(4.25rem, 9.5vh, 5.75rem);
  border: 1px solid var(--trait);
  border-radius: 0.5rem;
  overflow: hidden;
}
.valeurs__half { position: relative; flex: 1; overflow: hidden; }
/* Le logo est dimensionne par la HAUTEUR de la bande et centre sur la
   COUTURE : celle-ci est le bord DROIT de la moitie claire et le bord
   GAUCHE de la moitie sombre, donc left:100% d un cote et left:0 de
   l autre, avec la meme translation de -50%. Les deux moities posent
   ainsi la meme image au meme point et le raccord est exact par
   construction, a n importe quelle largeur.
   Une premiere version calait la largeur (124% de la moitie, decalee de
   +38% et -62%) : le raccord horizontal etait juste, mais le logo garde
   a son rapport 592/243 sortait alors deux fois plus haut que la bande
   et s y retrouvait tranche en haut et en bas. C est la hauteur qui
   contraint ici, pas la largeur. */
.valeurs__half img {
  position: absolute;
  top: 50%;
  height: 62%;
  width: auto;
  max-width: none;
  transform: translate(-50%, -50%);
}
.valeurs__half--clair { background: #FAFAFC; }
.valeurs__half--clair img { left: 100%; }
.valeurs__half--sombre { background: #0B052F; }
.valeurs__half--sombre img { left: 0; }
/* La moitie sombre se devoile par balayage, dans le sens de marche du
   camion. Le clip se combine a l overflow du cadrage sans le perturber. */
.valeurs__half--sombre { clip-path: inset(0 0 0 100%); transition: clip-path 1000ms var(--ease-out-expo); transition-delay: 1350ms; }
.story__next.is-live .valeurs__half--sombre { clip-path: inset(0 0 0 0); }
.valeurs__seam {
  position: absolute;
  top: 0; bottom: 0; left: 50%;
  width: 1px;
  background: var(--trait);
  transform: scaleY(0);
  transition: transform 700ms var(--ease-out-expo);
  transition-delay: 1500ms;
}
.story__next.is-live .valeurs__seam { transform: scaleY(1); }
.valeurs__hex {
  display: flex;
  justify-content: space-between;
  max-width: 24rem;
  margin-top: 0.35rem;
  font-size: 0.56rem;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}
.valeurs__hex i { font-style: normal; margin-left: 0.4em; opacity: 0.65; }

/* Fenetre basse : le cadre fait 100vh, et sous 800px de haut le filigrane
   et la ligne manuscrite laissent tres peu de place au bloc. On resserre
   sans jamais retirer de texte. */
@media (max-height: 800px) {
  .adn__head { margin-bottom: 0.6rem; }
  .adn__lead { font-size: 0.78rem; }
  .plate { max-width: 30rem; }
  .plate__legend { margin-top: 0.55rem; }
  .regle { padding: 0.38rem 0; }
  .valeurs__split { height: 3.9rem; }
}
@media (max-width: 78rem) {
  .adn__cols { flex-direction: column; align-items: stretch; gap: 1.2rem; }
  .plate { max-width: 30rem; }
}
@media (max-width: 62rem) {
  .story__next-grid { flex-direction: column; align-items: flex-start; gap: 1.1rem; }
  .adn { flex: 1 1 auto; width: 100%; max-width: 30rem; }
}
/* Sous 48rem seules des IMAGES decoratives disparaissent : le texte reste
   entier, donc rien n echappe a l indexation. */
@media (max-width: 48rem) {
  .valeurs__split, .valeurs__hex { display: none; }
}
/* Respect de la preference systeme : plus aucun mouvement ni trace
   progressif, tout est pose a l etat final. */
@media (prefers-reduced-motion: reduce) {
  .adn__head, .plate, .regle, .valeurs,
  .plate__rule, .plate__slant, .plate__letter, .plate__dims,
  .plate__legend, .valeurs__half--sombre, .valeurs__seam {
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
  }
}




/* ================= LES USAGES DU LOGO : LA CHAINE D IMPRESSION ===========
   Le prospect qui arrive ici doit avoir le sentiment de feuilleter le
   portfolio d une agence de branding, pas de regarder une demonstration
   technique. Trois choix en decoulent, et il ne faut pas les defaire :
     - un numero de planche en tres grand et tres pale DERRIERE le titre,
       plutot qu un chapitrage tabulaire ;
     - les caracteristiques reduites a UNE ligne discrete. La version
       precedente listait FORMAT / FOND PERDU / IMPRESSION en gras, ce qui
       se lisait comme une fiche produit ;
     - beaucoup d air et des mouvements lents. La precipitation fait
       toujours demo, jamais portfolio.

   MECANIQUE DE L IMPRESSION : chaque support arrive en papier VIERGE, une
   tete descend, et l encre apparait derriere elle. Le fond colore fait
   partie de l ENCRE et non du support : c est ce qui rend le passage
   spectaculaire, on voit le navy descendre sur la feuille au lieu de voir
   un texte se reveler sur un fond deja pose.
   Une seule variable pilote tout : --impr, de 0 a 100%, posee par le JS
   sur .tirage et heritee par l encre (clip) comme par la tete (position).
   Les supports restent construits en CSS aux vraies cotes d imprimeur :
   nets en Retina, sensibles au theme, et le logo affiche est le vrai
   fichier. Un mockup PNG genere par une API aurait interdit les trois. */
.usages {
  position: relative;
  z-index: 5;
  background: var(--off-white);
}
/* Ombre des objets POSES, declaree une fois pour les deux sections qui en
   posent : les supports imprimes de .usages, et la carte qui voyage vers
   .force. Recopier ces quatre couches dans la seconde section aurait suffi
   a les faire diverger a la premiere retouche. Meme principe que le groupe
   dore des lignes manuscrites en tete de fichier. */
.usages, .force {
  --ombre-objet:
    0 1px 1px rgba(11, 5, 47, 0.05),
    0 3px 6px rgba(11, 5, 47, 0.06),
    0 10px 20px rgba(11, 5, 47, 0.08),
    0 22px 44px rgba(11, 5, 47, 0.07);
}
/* CONTOUR CLAIR EN THEME SOMBRE, signale le 07/08 : une ombre TEINTEE NAVY
   a faible opacite, posee sur un fond deja navy (.usages herite de
   --off-white qui vaut --navy en sombre), ne recule pas -- elle se lit
   comme un halo grisatre plutot que comme une ombre, quel que soit le
   support (carte, prospectus, cadres mono partagent tous ce token). Le noir
   pur recule toujours sur du navy, quelle que soit l opacite, la ou le navy
   a faible opacite ne le fait pas necessairement. Spread reduit d un cran
   par rapport a la version claire : le halo signale n etait pas seulement
   mal teinte, il etait aussi trop etale. */
html[data-theme="dark"] .usages,
html[data-theme="dark"] .force {
  --ombre-objet:
    0 1px 1px rgba(0, 0, 0, 0.35),
    0 4px 10px rgba(0, 0, 0, 0.35),
    0 14px 28px rgba(0, 0, 0, 0.3),
    0 26px 48px rgba(0, 0, 0, 0.22);
}
/* 560vh = 420 * 4/3 : quatre planches au lieu de trois, la meme part de
   scroll pour chacune. Chaque planche a le temps d arriver, de s imprimer,
   puis d etre simplement REGARDEE avant de partir -- le temps de pose est
   ce qui separe un portfolio d un diaporama. Le decoupage JS (t = p * N)
   s adapte deja tout seul a N : seule cette hauteur doit suivre. */
/* 660vh = 560 utiles + UN ECRAN DE POSE a la fin. Cette pose n allonge pas
   la chaine d impression : le JS ramene la progression sur les 560vh
   d origine, chaque planche garde donc exactement le meme budget de
   scroll. L ecran gagne sert a la reprise par .force, qui le recouvre. */
.usages__pin-wrap { position: relative; height: 560vh; }
.usages__pin {
  position: sticky;
  top: 0;
  height: 100vh; height: 100svh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(1.25rem, 4vh, 3rem);
}

.usages__viewport { flex: 0 1 auto; min-height: 0; overflow: hidden; }
.usages__rail { display: flex; will-change: transform; }

.tirage {
  flex: 0 0 100%;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: clamp(1.5rem, 5vw, 5.5rem);
  padding: 0 var(--edge);
}
.tirage__scene { flex: 1 1 52%; min-width: 0; display: flex; justify-content: center; perspective: 1800px; }
/* La tete se cale sur l OBJET et non sur la scene : elle doit descendre le
   long du support, pas de la colonne qui le contient. */
.tirage__objet { position: relative; display: inline-block; }
.tirage__tete {
  position: absolute;
  left: -4%;
  right: -4%;
  top: var(--impr, 0%);
  height: 1px;
  background: linear-gradient(90deg, transparent 0%, var(--gold-2) 16%, var(--gold-1) 50%, var(--gold-2) 84%, transparent 100%);
  box-shadow: 0 0 14px 1px rgba(196, 184, 118, 0.5);
  opacity: var(--tete, 0);
  pointer-events: none;
  z-index: 4;
}

/* Le numero est DANS LE FLUX, il nest plus positionne en absolu.
   La bande reservee par un padding-top ne pouvait pas suffire : la hauteur
   du numero suit un clamp exprime en vw (3.5rem a 6.5rem) alors que le
   padding suivait un clamp exprime en vh. Deux clamps sur deux axes
   differents ne coincident qua certaines tailles de fenetre ; partout
   ailleurs le chiffre redescendait sur le titre. Mesure le 08/08 a 1280
   de large : numero de 104px pour une bande de 38px, soit 37px de
   chevauchement sur le titre.
   En flux, le numero reserve exactement sa propre hauteur quelle que soit
   la largeur et quel que soit le breakpoint : le titre commence forcement
   dessous, sans valeur a tenir synchronisee. .tirage etant en
   align-items: center, le bloc devenu plus haut se recentre tout seul.
   Le -0.05em de gauche est conserve en marge : cest la correction optique
   du flanc des chiffres Playfair, pour que le numero et le titre soient
   alignes a loeil et pas seulement a la boite. */
.tirage__dire { position: relative; flex: 1 1 38%; min-width: 0; max-width: 31rem; }
.tirage__num {
  margin: 0 0 0.1em -0.05em;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(3.5rem, 8vw, 6.5rem);
  line-height: 1;
  color: var(--ink);
  opacity: 0.07;
  pointer-events: none;
  user-select: none;
}
.tirage__titre {
  position: relative;
  margin: 0 0 0.65rem;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(1.5rem, 1rem + 1.5vw, 2.4rem);
  line-height: 1.08;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.tirage__txt {
  position: relative;
  margin: 0 0 1.4rem;
  max-width: 36ch;
  font-size: clamp(0.85rem, 0.78rem + 0.25vw, 1rem);
  line-height: 1.65;
  color: var(--ink-soft);
}
.tirage__spec {
  position: relative;
  margin: 0;
  padding-top: 0.85rem;
  border-top: 1px solid var(--ink-faint);
  font-size: 0.65rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* ---- LA COUCHE PAPIER : le mecanisme d impression -------------------------
   INVERSION faite le 07/08 apres trois correctifs infructueux sur le meme
   symptome (un lisere clair sur le pourtour de chaque support en theme
   sombre). Diagnostic final, mesure en direct : ecart geometrique de 0px
   sur les quatre cotes, clip-path valide et rigoureusement egal au
   border-radius du cadre, encre navy strictement egale au fond de page.
   Le seul element clair de la pile etait le PAPIER pose en fond du cadre,
   qui transparaissait par ANTIALIASING -- deux clippings arrondis
   superposes (border-radius + overflow du parent d un cote, clip-path de
   l enfant de l autre) ne peuvent pas s aligner au sub-pixel. Aucun
   reglage de rayon ni de couleur ne pouvait donc le corriger.

   D ou l inversion : le CADRE porte directement la couleur FINALE, et
   c est le PAPIER qui se retire par-dessus. A 100% d impression le papier
   est entierement clippe, donc il n existe plus aucune couche claire sous
   quoi que ce soit -- le defaut est supprime par construction et non
   masque. Le contenu, lui, n a plus besoin d etre clippe : le papier le
   recouvre tant qu il n est pas imprime. Un seul element anime par cadre. */
.tirage__papier {
  position: absolute;
  inset: 0;
  background: #FCFCFE;
  /* Se retire vers le HAUT : le bord de coupe descend avec la tete. Bord
     droit et non arrondi, donc aucun antialiasing d arrondi en jeu. */
  clip-path: inset(var(--impr, 0%) 0 0 0);
  pointer-events: none;
  z-index: 5;
}

/* ---- Planche 01 : la carte de visite ------------------------------------
   Redessinee d apres les cinq maquettes fournies par l utilisateur
   (cv-recto-1..3, cv-verso-clair, cv-verso-navy). Elles emploient tres
   exactement les couleurs de la charte, releve fait sur les fichiers :
   #0B052F a 97%, #C4B876 pour le trait, #FAFAFC pour le fond clair.
   Le format des fichiers est 3520x2320, soit 88 x 58 mm : c est du 85 x 55
   avec ses 3 mm de fond perdu, donc de vrais fichiers d impression. */
.carte {
  position: relative;
  width: clamp(16rem, 33vw, 26rem);
  aspect-ratio: 85 / 55;
  transform-style: preserve-3d;
  transform: rotateX(4deg) rotateY(var(--flip, 0deg));
}
/* L ombre vit SOUS la carte et non sur ses faces : posee sur une face elle
   tournerait avec elle et passerait au-dessus a mi-rotation.
   inset:0 et NON un inset asymetrique : en debordant de 8% vers le bas, la
   boite creusait un rectangle clair sous la carte que l on lisait comme une
   seconde carte posee derriere (signale le 07/08). L ombre doit epouser la
   carte, ce sont les decalages verticaux du box-shadow qui la font flotter. */
.carte::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 6% / 9.27%;
  box-shadow: var(--ombre-objet);
  transform: translateZ(-1px);
}
/* RAYON DES COINS mesure sur la maquette : les coins y sont transparents,
   l opacite commence a 210px sur 3520 de large, soit 6% (5,25 mm reels).
   Deux valeurs et non une : sur un rectangle 85x55, un border-radius en %
   donne une ELLIPSE, car le pourcentage se lit sur chaque axe. 6% de la
   largeur et 9.27% de la hauteur valent le meme rayon absolu, donc un
   arrondi circulaire. */
.carte__face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  border-radius: 6% / 9.27%;
  overflow: hidden;
}

/* RECTO d apres cv-recto-2 : le medaillon dore centre, pose sur deux filets
   qui traversent la carte. Le papier reste nu tant que rien n est imprime. */
/* Les deux faces etaient toutes deux a z=0 : en 3D, deux plans coplanaires
   produisent du Z-FIGHTING, et le verso BLANC pouvait affleurer sur le
   pourtour du recto navy selon l arrondi du rendu. On les ecarte d un demi
   pixel chacune (le translateZ du verso s applique dans son repere deja
   retourne, les deux s eloignent donc l une de l autre). Imperceptible a
   l oeil, mais il n y a plus de plan partage. */
.carte__face--recto { background: var(--navy); transform: translateZ(0.5px); }
.carte__encre { position: absolute; inset: 0; }
/* Le recto est le VISUEL de la maquette (cv-recto-1), a la demande de
   l utilisateur : le B geant en debossage et le mot Entreprise en serif
   espace. Le debossage se reconstruirait mal en CSS, et l image reste nette
   puisqu elle est servie a 1000px pour un affichage de 416px au plus.
   L encre est navy DERRIERE l image : les coins arrondis du fichier sont
   transparents, et un fond blanc y aurait dessine un lisere clair. */
.cvr__visuel { width: 100%; height: 100%; object-fit: cover; display: block; }

/* VERSO d apres cv-verso-clair. */
.carte__face--verso {
  background: #FAFAFC;
  transform: rotateY(180deg) translateZ(0.5px);
  display: flex;
  flex-direction: column;
  padding: 8.5% 8%;
}
.cvv__nom {
  margin: 0;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(0.78rem, 2.05vw, 1.3rem);
  line-height: 1.05;
  letter-spacing: -0.01em;
  color: var(--navy);
}
.cvv__poste { margin: 0.55em 0 0; font-size: clamp(0.36rem, 0.82vw, 0.5rem); color: rgba(11, 5, 47, 0.78); }
.cvv__accroche { margin: 0.35em 0 0; font-size: clamp(0.36rem, 0.82vw, 0.5rem); color: rgba(11, 5, 47, 0.5); }
.cvv__bas { margin-top: auto; display: flex; align-items: center; gap: 5%; }
.cvv__qr { width: 26%; height: auto; flex: none; }
.cvv__separateur { align-self: stretch; width: 1px; background: rgba(11, 5, 47, 0.22); flex: none; }
.cvv__contacts { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 0.55em; min-width: 0; }
.cvv__contacts li {
  display: flex;
  align-items: center;
  gap: 0.6em;
  font-size: clamp(0.34rem, 0.78vw, 0.48rem);
  letter-spacing: 0.02em;
  color: var(--navy);
}
.cvv__ico {
  flex: none;
  display: grid;
  place-items: center;
  width: 1.9em;
  height: 1.9em;
  border-radius: 50%;
  background: var(--navy);
  color: #FAFAFC;
}
.cvv__ico svg { width: 58%; height: 58%; stroke-linecap: round; stroke-linejoin: round; }

/* ---- Planche 02 : le prospectus ------------------------------------------
   Design cree par l utilisateur dans Claude Design et importe via le MCP
   DesignSync (projet 0e6fde02, fichier "Beajify - Prospectus"). Les styles
   inline de la source sont passes en classes ; les valeurs, elles, sont
   reprises telles quelles.
   Le fichier d origine est compose en unites de CONTENEUR (cqw/cqh) : on
   garde ce systeme et on declare .tract comme conteneur de taille. Toute la
   mise en page devient donc proportionnelle a la miniature, sans avoir a
   recalculer une seule valeur -- c est aussi ce qui permet de l agrandir
   librement plus tard sans rien casser.
   Format A4 (210 x 297) et non A5 : c est celui du fichier source. */
.tract {
  position: relative;
  height: clamp(14rem, 60vh, 26rem);
  aspect-ratio: 210 / 297;
  border-radius: 0.3rem;
  background: var(--navy);
  box-shadow: var(--ombre-objet);
  overflow: hidden;
  container-type: size;
}
.tract__encre {
  position: absolute;
  inset: 0;
  padding: 5.4cqh 7cqw 4.6cqh 9.5cqw;
  box-sizing: border-box;
  font-family: 'IBM Plex Sans', 'Inter', sans-serif;
  color: #EDE8DC;
}
/* Mention verticale dans la marge gauche, comme sur la source. */
.tract__marge {
  position: absolute;
  left: 2.6cqw;
  top: 50%;
  transform: translateY(-50%) rotate(180deg);
  writing-mode: vertical-rl;
  white-space: nowrap;
  margin: 0;
  font-size: 1.28cqh;
  letter-spacing: 0.16em;
  color: rgba(237, 232, 220, 0.5);
  z-index: 2;
}
/* Monogramme decoratif : le MEDAILLON ARGENTE, pas le monogramme dore.
   L asset de la source (assets/new-logo-source.png) s est revele IDENTIQUE
   au pixel pres a medallion-b.png deja present sur le VPS (meme MD5), on
   reutilise donc celui-ci. Une premiere version prenait Logo-doc.png repeint
   en dore : mauvais fichier et mauvaise couleur.
   Position reprise de la source (top -15px, left 381px, 233x183 sur un corps
   de 663x1011), convertie en pourcentages DU CORPS -- c est bien sur lui que
   se lit la position absolue, le monogramme etant son dernier enfant. */
.tract__monogramme {
  position: absolute;
  top: -1.5%;
  left: 57.5%;
  width: 35.1%;
  height: 18.1%;
  object-fit: contain;
  z-index: 1;
}
.tract__corps { position: relative; z-index: 2; display: flex; flex-direction: column; height: 100%; }
/* Le wrapper de la source (max-width: 42cqw) est indispensable : sans lui,
   dans un flex column, align-items:stretch etire l image sur toute la
   largeur et width:auto devient 100% -- le mot sortait ecrase. */
.tract__tete { max-width: 42cqw; }
.tract__mot { height: 5.6cqh; width: auto; display: block; }
.tract__baseline {
  margin: 0.9cqh 0 0;
  font-size: 1.35cqh;
  line-height: 1.5;
  color: rgba(237, 232, 220, 0.62);
  max-width: 44cqw;
}
.tract__accroche { margin-top: 5.2cqh; }
.tract__titre {
  margin: 0;
  font-family: 'Big Shoulders Display', 'Playfair Display', sans-serif;
  font-weight: 900;
  font-size: 7.2cqh;
  line-height: 0.94;
  letter-spacing: -0.01em;
  color: #F7F4EC;
  text-wrap: balance;
}
.tract__intro {
  margin: 2cqh 0 0;
  max-width: 82cqw;
  font-size: 1.8cqh;
  line-height: 1.55;
  color: rgba(237, 232, 220, 0.72);
  text-wrap: pretty;
}
.tract__offres {
  margin: 4.2cqh 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 1.8cqh;
}
.tract__offres li { display: flex; align-items: baseline; gap: 2.4cqw; }
.tract__n {
  flex-shrink: 0;
  width: 9cqw;
  font-family: 'Big Shoulders Display', 'Playfair Display', sans-serif;
  font-weight: 200;
  font-size: 5.2cqh;
  line-height: 1;
  color: rgba(247, 244, 236, 0.24);
}
.tract__bloc { min-width: 0; }
.tract__bloc b {
  display: block;
  font-family: 'Big Shoulders Display', 'Playfair Display', sans-serif;
  font-weight: 700;
  font-size: 2.5cqh;
  letter-spacing: 0.02em;
  color: #F5F1E8;
}
.tract__bloc i {
  display: block;
  margin-top: 0.3cqh;
  font-style: normal;
  font-size: 1.4cqh;
  color: rgba(237, 232, 220, 0.62);
  max-width: 68cqw;
}
/* margin-top:auto remplace le <div style="flex:1"> de la source : meme
   effet, un element de moins. */
.tract__pied { margin-top: auto; }
.tract__cta {
  margin: 0;
  font-family: 'Big Shoulders Display', 'Playfair Display', sans-serif;
  font-weight: 700;
  font-size: 3.4cqh;
  letter-spacing: 0.01em;
  color: #F7F4EC;
}
.tract__contacts {
  margin-top: 1.8cqh;
  display: flex;
  flex-wrap: wrap;
  column-gap: 4.2cqw;
  row-gap: 1cqh;
  font-size: 1.65cqh;
  color: rgba(237, 232, 220, 0.85);
}
.tract__web { font-weight: 700; color: var(--gold-2); letter-spacing: 0.02em; }

/* ---- Planche 03 : le marquage. Le support vierge est la tole nue, et
        c est l adhesif qui se pose au passage de la tete. ---- */
.mono { display: flex; align-items: flex-end; gap: clamp(0.9rem, 2.8vw, 2.25rem); }
.mono__cas { margin: 0; text-align: center; }
.mono__cas figcaption { margin-top: 0.6rem; font-size: 0.62rem; letter-spacing: 0.04em; color: var(--ink-soft); }
.mono__cadre { position: relative; background: var(--navy); box-shadow: var(--ombre-objet); overflow: hidden; }
.mono__encre { position: absolute; inset: 0; display: grid; place-items: center; }
/* VEHICULE : le dessin fourni par l utilisateur (Design-fourgon.svg), qui
   remplace la portiere suggeree en CSS (tole, vitre, poignee) -- celle-ci
   n avait plus lieu d etre et ses regles ont ete retirees.
   FOND CLAIR, contrairement aux deux autres cas : le dessin est un trace
   navy (#0B052F) sur carrosserie blanche, verifie en le posant sur trois
   fonds. Sur le navy des autres cadres il etait purement INVISIBLE -- meme
   piege que Logo-doc.png. Le poser sur clair est aussi le plus juste : un
   fourgon est blanc, et c est ce contraste qui fait lire le marquage.
   C est ce qui fait FONCTIONNER l impression ici : le fond du cadre et le
   papier sont tous deux clairs, donc rien ne se revele par la couleur --
   c est le DESSIN qui apparait a mesure que le papier se retire.
   Rapport 147/227 repris du fichier, largeur reduite en consequence pour
   que la hauteur reste alignee sur les deux autres cas (a rapport 3/4 et
   12rem la boite montait a 256px ; ici 10rem donne 247px). */
/* Le vehicule n a PLUS de cadre : ni fond, ni ombre, ni arrondi. C est un
   objet pose a meme la page, pas un ecran comme les deux autres cas.
   Rendu possible par l inline du SVG : ses 17 couleurs (14 navy + 3 noires)
   sont passees en currentColor, le dessin suit donc la couleur du texte.
   Sans cet inline, retirer le fond clair aurait rendu le fourgon INVISIBLE
   en theme sombre -- son trace est en #0B052F, soit la couleur meme du
   fond de page dans ce theme.
   box-shadow: none est necessaire : .mono__cadre porte --ombre-objet, qui
   aurait dessine un rectangle d ombre autour d un cadre devenu invisible. */
.mono__cas--vehicule .mono__cadre {
  width: clamp(6rem, 13vw, 10rem);
  aspect-ratio: 147 / 227;
  background: none;
  box-shadow: none;
  border-radius: 0;
  color: var(--navy);
}
html[data-theme="dark"] .mono__cas--vehicule .mono__cadre { color: rgba(252, 252, 252, 0.92); }
.mono__cas--vehicule .mono__encre { background: none; }
.mono__fourgon { width: 100%; height: 100%; display: block; overflow: visible; }

.mono__cas--rond .mono__cadre { width: clamp(4.5rem, 10vw, 7rem); aspect-ratio: 1; border-radius: 50%; }
/* favicon.svg porte deja son disque navy et son lisere dore : il remplit
   donc toute la pastille, exactement comme sur un vrai profil de reseau
   social. Le cadre n a plus a fournir de fond. */
.mono__avatar { position: relative; z-index: 1; width: 100%; height: 100%; display: block; }
/* PIEGE signale le 07/08 : le cercle de favicon.svg (r=14 dans un viewBox
   30x30) ne couvre que 14/15 = 93.3% de son propre canevas carre. Le reste
   du carre affiche par la balise <img> (les 6.7% restants, en couronne)
   est transparent -- sans fond navy derriere, c est le papier blanc
   #FCFCFE du cadre "vierge" qui perce en anneau net. La couleur de remplissage
   du cercle SVG (#0B052F) est deja EXACTEMENT --navy : garder le fond navy
   de l encre rend la couture invisible au lieu de la masquer par un cache. */


.mono__cas--onglet .mono__cadre { width: clamp(6rem, 13vw, 9rem); aspect-ratio: 16 / 9; border-radius: 0.35rem; }
.mono__cas--onglet .mono__cadre { background: linear-gradient(180deg, #1A1140 0%, var(--navy) 100%); }
.mono__barre { display: flex; align-items: center; gap: 0.3rem; width: 74%; padding: 0.3rem 0.4rem; border-radius: 0.25rem; background: rgba(252, 252, 252, 0.1); }
/* Le cas favicon utilise litteralement favicon.svg, qui porte deja son
   disque et son lisere : c est ce fichier exact que sert le navigateur. */
.mono__favicon { width: 0.85rem; height: 0.85rem; flex: none; display: block; }
.mono__barre i { display: block; height: 0.3rem; flex: 1; border-radius: 999px; background: rgba(252, 252, 252, 0.28); }

/* ---- Planche 04 : les documents legaux -----------------------------------
   Reference technique lue en lecture seule dans BeajFlow (demande
   explicite) : ses vrais PDF client (certificat de signature, contrats)
   sont deja composes en Playfair Display SemiBold + navy #0B052F -- la
   charte de ce site existe donc deja dans les documents administratifs
   reels. Ce que la planche reutilise, c est cette mise en page ; le
   contenu affiche est entierement fictif.
   Deux feuilles au format A4 (ratio 210/297, quasi identique a celui de
   l A5 du prospectus car toute la serie A partage le meme ratio racine de
   2) : le CONTRAT au repos derriere, deja pose et immobile, la FACTURE au
   premier plan qui suit le meme mecanisme d encre --impr que les trois
   planches precedentes. Un seul objet anime par planche, comme ailleurs :
   animer les deux feuilles independamment aurait charge la scene sans
   ajouter au propos. */
/* UN SEUL objet (la facture), comme les trois planches precedentes. Une
   seconde feuille (contrat) posee en retrait derriere a ete essayee puis
   retiree sur demande explicite : meme decalee, elle depassait encore du
   cadre de la facture -- "on ne doit pas voir ca". */
.doc {
  position: relative;
  width: clamp(10.5rem, 24vw, 15.5rem);
  aspect-ratio: 210 / 297;
  border-radius: 0.2rem;
  overflow: hidden;
  box-shadow: var(--ombre-objet);
  background: #FFFFFF;
}
.doc__encre {
  position: absolute;
  inset: 0;
  padding: 9% 9% 7%;
  display: flex;
  flex-direction: column;
}
.doc__tete { display: flex; align-items: center; gap: 0.6em; padding-bottom: 6%; border-bottom: 1.5px solid var(--navy); }
/* Le VRAI fichier des factures BeajFlow, pose tel quel : Logo-doc.png est
   un trace filaire (aucun aplat, uniquement des contours -- la regle 3 du
   panneau ADN plus haut dans cette meme section), donc directement lisible
   sur le papier blanc sans aucun montage. Une premiere version tentait de
   reconstruire un badge (disque gold + masque navy) : a cette taille,
   masquer un trace aussi fin donnait un rendu illisible, et ce n etait de
   toute facon pas le bon parti -- le fichier existant EST deja l asset a
   utiliser. */
.doc__badge { flex: none; width: 2.6em; height: auto; }
.doc__tete-txt { min-width: 0; }
.doc__eyebrow { margin: 0; font-family: 'Playfair Display', Georgia, serif; font-weight: 600; font-size: clamp(0.52rem, 1.25vw, 0.72rem); color: var(--navy); }
.doc__ref { margin: 0.15em 0 0; font-size: clamp(0.28rem, 0.68vw, 0.38rem); letter-spacing: 0.02em; color: rgba(11, 5, 47, 0.5); }
.doc__destinataire { margin: 7% 0; }
.doc__destinataire p { margin: 0; font-size: clamp(0.32rem, 0.78vw, 0.44rem); line-height: 1.5; color: rgba(11, 5, 47, 0.68); }
.doc__destinataire p:first-child { font-weight: 600; color: var(--navy); }
.doc__table { width: 100%; border-collapse: collapse; margin-bottom: auto; }
.doc__table td { padding: 0.55em 0; font-size: clamp(0.3rem, 0.72vw, 0.4rem); color: rgba(11, 5, 47, 0.65); border-bottom: 1px solid rgba(11, 5, 47, 0.1); }
.doc__table td:last-child { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--navy); }
/* Sous-totaux HT et TVA au-dessus du total : c est la structure d une vraie
   facture, et c est ce qui la distingue d un simple recapitulatif. */
.doc__sous-totaux { margin-top: 5%; }
.doc__sous-totaux p {
  display: flex;
  justify-content: space-between;
  margin: 0 0 0.35em;
  font-size: clamp(0.3rem, 0.72vw, 0.4rem);
  color: rgba(11, 5, 47, 0.6);
}
.doc__sous-totaux p span:last-child { font-variant-numeric: tabular-nums; color: rgba(11, 5, 47, 0.8); }
.doc__total {
  display: flex;
  justify-content: space-between;
  margin-top: 2%;
  padding-top: 4%;
  border-top: 1.5px solid var(--navy);
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 600;
  font-size: clamp(0.4rem, 0.95vw, 0.54rem);
  color: var(--navy);
}
.doc__pied { margin: 5% 0 0; font-size: clamp(0.24rem, 0.58vw, 0.32rem); line-height: 1.6; letter-spacing: 0.02em; color: rgba(11, 5, 47, 0.4); }

@media (max-width: 62rem) {
  .doc { width: min(15rem, 62vw); margin: 0 auto; }
}

/* ---- Pied de section : la signature a GAUCHE (celle du panneau
        precedent est a droite), la progression a droite. ---- */
.usages__pied {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 0 var(--edge);
}
.usages__script {
  margin: 0;
  font-family: 'Caveat', cursive;
  font-weight: 600;
  font-size: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  color: var(--ink);
}
html[data-theme="dark"] .usages__script {
  background: linear-gradient(135deg, var(--gold-1) 0%, var(--gold-2) 50%, var(--gold-3) 100%);
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  width: fit-content;
  padding-right: 0.35em;
}
.usages__steps { position: relative; display: flex; gap: clamp(0.9rem, 2.5vw, 2rem); padding-bottom: 0.7rem; font-size: 0.68rem; color: var(--ink-soft); }
.usages__step { display: flex; align-items: baseline; gap: 0.4rem; opacity: 0.35; transition: opacity 500ms var(--ease-out-expo), color 500ms linear; }
.usages__step i { font-style: normal; font-size: 0.58rem; font-weight: 600; letter-spacing: 0.08em; font-variant-numeric: tabular-nums; }
.usages__step.is-on { opacity: 1; color: var(--ink); }
.usages__steps-bar { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: rgba(11, 5, 47, 0.12); border-radius: 999px; overflow: hidden; }
html[data-theme="dark"] .usages__steps-bar { background: rgba(252, 252, 252, 0.16); }
.usages__steps-bar::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--avance, 33%);
  background: var(--ink);
  border-radius: inherit;
  transition: width 600ms var(--ease-out-expo);
}

@media (max-width: 62rem) {
  .tirage { flex-direction: column; justify-content: center; gap: 1.4rem; }
  .tirage__scene, .tirage__dire { flex: 0 0 auto; width: 100%; }
  .tirage__dire { max-width: none; }
  .tirage__num { font-size: 3.5rem; }
  .carte { width: min(20rem, 78vw); }
  .tract { height: clamp(10rem, 34vh, 15rem); }
  .usages__pied { flex-direction: column; align-items: flex-start; gap: 0.8rem; }
}
@media (max-height: 800px) {
  .tract { height: clamp(10rem, 44vh, 16rem); }
  .usages__pin { gap: 1rem; }
  .tirage__txt { margin-bottom: 1rem; }
}
/* Sans mouvement : tout est imprime d office, rien ne balaye. */
@media (prefers-reduced-motion: reduce) {
  .tirage__papier { display: none !important; }
  .tirage__tete { display: none; }
  .usages__step, .usages__steps-bar::after { transition-duration: 1ms !important; }
}

/* Voile de transition : couvre tout le cadre epingle, pas seulement le
   dessin. Cest lui qui donne le changement de page ; la scene, elle, ne
   doit jamais changer dopacite, sinon on ne fait questomper le vehicule. */
.story__veil {
  position: absolute;
  inset: 0;
  background: var(--off-white);
  opacity: 0;
  pointer-events: none;
}
.story__svg { display: block; width: 100%; height: auto; overflow: visible; }

/* REGLE DE COULEUR : le gold nexiste que sous data-theme=dark. En clair,
   navy plein pour le trait Beajify et --ink-faint pour le trait client.
   Aucun dore ne peut donc atteindre un fond clair, cest structurel et
   pas une question de discipline a chaque ajout. */
/* Epaisseur portee de 2.1 a 5 : le trait paraissait maigre a lecran.
   vector-effect:non-scaling-stroke rend cette valeur independante du
   viewBox, cest donc bien une epaisseur en pixels ecran, et les 27px
   declares dans Figma nont aucun effet ici. */
.story__ink {
  stroke: var(--ink);
  stroke-width: 7;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}
.story__road {
  stroke: var(--ink-faint);
  stroke-width: 1.6;
  stroke-linecap: round;
  fill: none;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}
/* Points du i et du j : traces fournis par le vectoriseur, donc des
   PATH a contour et non des cercles remplis. Legerement plus epais que
   le trait des lettres pour se lire comme des points et non comme deux
   tirets minuscules. */
/* Points du i et du j : cercles pleins, positionnes au centre des deux
   petits traces du fichier fourni. Un trace a contour rendait deux
   minuscules batonnets la ou il faut des points ronds. Rayon en unites
   du viewBox, donc proportionnel au mot. */
.story__dots { opacity: 0; }
.story__dots circle { fill: var(--ink); stroke: none; }
/* Camion dessine par lutilisateur : trait fin de dessin technique, en
   contraste avec le trait epais de lecriture. Il apparait une fois la
   metamorphose finie et prend le relais des six traces dencre, qui
   seffacent : on termine donc sur SON dessin exact, pas sur ma version
   reechantillonnee. */
.story__van { opacity: 0; }
/* Caisse et roues partagent exactement le meme style : les roues ne sont
   plus un dessin importe pose par-dessus, ce sont LES TRACES DORIGINE du
   camion, simplement isoles dans leur propre groupe.
   Ce changement dapproche supprime dun coup trois problemes : plus
   dancienne roue a effacer (rien nest retire), plus decart de taille ni
   de position (elles nont pas bouge dun pixel), plus daplat a reteinter.
   Le groupe .story__spin est vide de transform : il attend la rotation du
   roulement. Le centre exact de chaque roue est porte par data-cx/data-cy
   sur .story__wheel, mesure sur la boite reelle du groupe. */
.story__body path,
.story__wheel path {
  fill: none;
  stroke: var(--ink);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
html[data-theme="dark"] .story__body path,
html[data-theme="dark"] .story__wheel path { stroke: url(#storyGoldVan); }
/* Doré en losange plutot quen aplat. Les traits de cette section
   partagent desormais le meme degrade diagonal 135 degres que les lignes
   manuscrites et les badges, au lieu dun gold-2 uni qui tirait sur le
   jaune. Un trace SVG ne peut pas recevoir un linear-gradient CSS : il
   faut un <linearGradient> reference par stroke=url(#...), do les defs
   dans home.html.
   Deux identifiants distincts : lencre vit dans le repere de la scene,
   le camion dans son repere local a cause de son transform. */
.story-g1 { stop-color: var(--gold-1); }
.story-g2 { stop-color: var(--gold-2); }
.story-g3 { stop-color: var(--gold-3); }
/* DECOLORATION PENDANT LA METAMORPHOSE, theme sombre uniquement.
   Le mot Beajify secrit en dore, puis son trace se decolore vers lencre
   claire a mesure quil devient un camion : --blanchi va de 0 a 1 avec la
   progression de la metamorphose, posee par storyScroll sur le <svg>.
   Les deux gradients partagent ces trois classes de stops : lencre du mot
   ET les deux camions (celui qui sort de cette page, celui dont lavant
   entre sur la suivante) blanchissent donc ensemble, sans seconde
   variable a tenir synchronisee.
   Le blanchiment vise var(--ink), qui vaut deja #FCFCFC sous
   data-theme=dark : la cible nest pas un blanc invente, cest la couleur
   dencre du theme. En theme clair ces regles ne sappliquent pas et le
   trace reste en --ink plein, conformement a la regle structurelle posee
   plus haut (aucun dore ne peut atteindre un fond clair). */
html[data-theme="dark"] .story-g1 { stop-color: color-mix(in srgb, var(--gold-1), var(--ink) calc(var(--blanchi, 0) * 100%)); }
html[data-theme="dark"] .story-g2 { stop-color: color-mix(in srgb, var(--gold-2), var(--ink) calc(var(--blanchi, 0) * 100%)); }
html[data-theme="dark"] .story-g3 { stop-color: color-mix(in srgb, var(--gold-3), var(--ink) calc(var(--blanchi, 0) * 100%)); }
html[data-theme="dark"] .story__ink { stroke: url(#storyGoldScene); }
html[data-theme="dark"] .story__dots circle { fill: url(#storyGoldScene); }


/* Repli prefers-reduced-motion : PAS une version degradee. Le pin est
   supprime et les traces sont servis entierement dessines (dashoffset 0),
   en une image fixe lisible. Le JS detecte le meme media, remplace le d
   par letat final (le camion) et ne demarre jamais sa boucle : le partage
   des roles est donc CSS pour la mise en page et le dessin, JS pour la
   geometrie finale. */
@media (prefers-reduced-motion: reduce) {
  .story__pin-wrap { height: auto; padding-block: clamp(4rem, 3rem + 5vw, 8rem); }
  .story__pin { position: static; height: auto; }
  .story__ink,
  .story__road { stroke-dashoffset: 0; }
  .story__ink,
  .story__dots { opacity: 0; }
  .story__van { opacity: 1; }
}


/* ============ FORCE COMMERCIALE =========================================
   La section ne montre plus qu UNE chose : le prospectus qui grossit sur
   place, recule, puis s efface pour laisser venir le titre. Le triptyque et
   les criteres ont ete retires le 08/08 -- afficher une grille de
   qualification revenait a annoncer qu on prend la mission en main, alors
   que Beajify MET EN RELATION avec des enseignes et n est pas
   commissionnaire. Le geste du mot rompu par les coupes tombe avec eux.

   RECOUVREMENT : la section demarre un ecran avant la fin de .usages, qui
   tient sa planche 04 immobile pendant ce temps (temps de pose). La feuille
   est POSEE sur le rectangle mesure du vrai prospectus, puis s en detache.
   L original s efface en miroir de la copie : la somme des deux opacites
   vaut 1, on ne voit donc ni doublon ni trou. */
.force { position: relative; z-index: 6; margin-top: -50vh; }
.force__pin-wrap { position: relative; height: 260vh; }
/* Le fond ne commence qu APRES le recouvrement : pendant celui-ci il
   masquerait .usages, encore epinglee dessous. Sans lui, les sections
   empilees plus haut reapparaissaient sous .force. Meme token que le fond de
   .usages : les deux se raccordent sans couture. */
.force__pin-wrap::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50vh;
  bottom: 0;
  background: var(--off-white);
  z-index: 0;
}
.force__pin { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; pointer-events: none; z-index: 1; }
.force__fond { position: absolute; inset: 0; background: var(--off-white); opacity: var(--fond, 0); z-index: 0; }
/* Filigrane pose EXACTEMENT comme Studio Graphique : Playfair 700, navy
   PLEIN en clair et blanc a 5 % en sombre -- le contraste inverse entre les
   deux themes est voulu la-bas et repris tel quel. La taille est RELUE par le
   JS sur le filigrane de la section Equipe, jamais recopiee : les trois
   restent identiques par construction. Les valeurs ci-dessous sont un repli. */
.force__eyebrow {
  position: absolute;
  top: 8rem;
  left: var(--edge);
  right: var(--edge);
  z-index: 2;
  margin: 0;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(2.25rem, 1rem + 4.5vw, 5.5rem);
  line-height: 1;
  white-space: nowrap;
  color: rgba(11, 5, 47, 1);
  opacity: var(--tit, 0);
  transform: translateY(calc((1 - var(--tit, 0)) * 26px));
  pointer-events: none;
  user-select: none;
}
html[data-theme="dark"] .force__eyebrow { color: rgba(252, 252, 252, 0.05); }

/* En-tete redigee DANS le panneau epingle, sous le filigrane. C est elle qui
   occupe l ecran laisse vide par le prospectus efface -- le trou constate le
   08/08. Position absolue comme le filigrane, `top` pose par le JS (bas du
   filigrane + respiration) : la taille du filigrane etant relue sur celui de
   Studio Graphique, aucune valeur en dur ne pourrait la suivre.
   Le panneau est en overflow:hidden : la largeur est bridee et la taille du
   texte plafonnee pour qu un ecran bas ne rogne pas la fin du paragraphe. */
.force__intro {
  position: absolute;
  left: var(--edge);
  right: var(--edge);
  top: var(--introTop, 60%);
  z-index: 2;
  max-width: 72rem;
  opacity: var(--intro, 0);
  transform: translateY(calc((1 - var(--intro, 0)) * 22px));
  pointer-events: none;
}
.force__titre {
  margin: 0;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(1.875rem, 1.55rem + 1.6vw, 2.75rem);   /* niveau 1 = .rise h2 */
  line-height: 1.14;
  letter-spacing: -0.01em;
}
/* Les deux moities de la phrase sur deux lignes distinctes : tout le sens
   est dans le pivot entre "vous" et "nous", une seule ligne l ecraserait. */
.force__titre-part { display: block; }
/* Echelle de texte courant du site = celle de .conviction (meme clamp, meme
   graisse, meme interligne, meme couleur pleine). Multipliee par --echelle,
   que le JS reduit UNIQUEMENT si l en-tete ne tient pas dans le panneau :
   celui-ci est en overflow:hidden, un ecran bas rognerait la fin du
   paragraphe sans rien signaler. */
.force__lead {
  margin: clamp(1.5rem, 1.1rem + 1.4vw, 2.75rem) 0 0;
  max-width: 56ch;
  /* Ce paragraphe est SEUL sur son ecran : il peut respirer et se permettre
     d etre plus grand que du texte courant ordinaire, tout en restant tres
     en dessous du titre a 44 px -- c est cet ecart qui fait la hierarchie,
     pas la petitesse. --echelle reste le garde-fou du panneau en
     overflow:hidden pour les fenetres tres basses. */
  font-size: calc(clamp(1.125rem, 1rem + 0.55vw, 1.5rem) * var(--echelle, 1));
  line-height: 1.8;
  color: var(--ink-soft);
  opacity: var(--lead, 0);
  transform: translateY(calc((1 - var(--lead, 0)) * 16px));
}
/* Ligne manuscrite en bas a DROITE du panneau, comme celle du panneau ADN.
   Meme police, meme poids, meme fourchette de taille que les quatre autres
   Caveat du site -- regle fixe deja etablie, seul le texte change. */
.force__script,
.bureau__script {
  position: absolute;
  right: var(--edge);
  bottom: clamp(1.5rem, 4vh, 3.25rem);
  z-index: 2;
  margin: 0;
  text-align: right;
  font-family: 'Caveat', cursive;
  font-weight: 600;
  font-size: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  color: var(--ink);
  opacity: var(--mot, 0);
}
.force__scene { position: absolute; inset: 0; z-index: 1; perspective: 1600px; pointer-events: none; }
/* Position et taille en PIXELS ECRAN, posees image par image : c est ce qui
   permet de caler la feuille sur le rectangle mesure du vrai prospectus, puis
   de l emmener vers ses cibles. Un centrage flex ne saurait pas se poser sur
   un objet qui vit dans une autre section.
   Aucune ombre ici : c est le prospectus lui-meme qui porte la sienne, sinon
   une ombre rectangulaire resterait dessinee autour du vide quand il s efface. */
.force__feuille {
  position: absolute;
  left: var(--fl, 0px);
  top: var(--ft, 0px);
  width: var(--fw, 0px);
  height: var(--fh, 0px);
  opacity: var(--vue, 0);
  transform: rotateX(var(--fx, 0deg)) rotateZ(var(--fz, 0deg));
  will-change: transform, width, height, left, top;
}
/* --impr: 100% est INDISPENSABLE. La copie emporte son .tirage__papier, qui
   vit A L INTERIEUR de .tract depuis l inversion papier/encre du 07/08 : le
   cadre porte la couleur finale et le papier se retire par-dessus. Sans
   --impr il vaut 0 %, le papier recouvre donc l encre et la feuille reste
   BLANCHE -- elle n est jamais imprimee. La planche 04 recoit sa valeur du JS
   de la chaine d impression ; la copie, elle, arrive deja imprimee. */
.force__tract { position: absolute; inset: 0; opacity: var(--encre, 1); pointer-events: none; --impr: 100%; }
.force__tract .tract { width: 100%; height: 100%; aspect-ratio: auto; }

@media (prefers-reduced-motion: reduce) {
  .force { margin-top: 0; }
  .force__pin-wrap { height: auto; }
  .force__pin-wrap::before { display: none; }
  .force__pin { position: static; height: auto; padding: clamp(4rem, 3rem + 5vw, 8rem) var(--edge); }
  .force__fond { opacity: 1; }
  .force__scene { display: none; }
  .force__eyebrow { position: static; }
  .force__intro { position: static; max-width: none; margin-top: 2rem; opacity: 1; transform: none; --echelle: 1; }
  .force__script { position: static; margin-top: 1.5rem; text-align: left; opacity: 1; }
}

/* ============ FORCE COMMERCIALE / SUITE ==========================
   Ce qui suit le panneau epingle. .force__pin est en pointer-events:none,
   overflow:hidden et height:100vh : rien de cliquable ni de plus haut qu un
   ecran ne peut y vivre, d ou ce bloc dans le flux normal, avec son propre
   fond (le ::before du pin-wrap s arrete a la fin de la course epinglee).
   La course epinglee n est PAS touchee : .force__pin-wrap garde ses 260vh,
   dont depend le calage du zoom sur le temps de pose de .usages.

   Systeme typographique DU SITE (Playfair, Inter, degrade gold, feutre),
   jamais celui du prospectus : le prospectus est un EXEMPLE de ce qu on
   fabrique pour un transporteur, pas la charte de Beajify. */
.force__suite,
.bureau__suite {
  position: relative;
  z-index: 2;
  background: var(--off-white);
  /* Le bas est volontairement court : tout ce qu on donne d air au titre et
     au lien plus haut serait sinon AJOUTE a l attente avant l arrivee de
     Bureau Logistique. On le reprend ici, la hauteur totale ne bouge pas. */
  padding: clamp(2rem, 1.5rem + 2.5vw, 4rem) 0 clamp(2rem, 0.5rem + 7vw, 6rem);
}
.force__suite-inner,
.bureau__suite-inner {
  /* 1600px et non --container-max : c est la mesure de .conviction__inner,
     celle pour laquelle son echelle de texte a ete dessinee. Copier la taille
     sans copier la largeur donnait 33 signes par ligne au lieu de 46. */
  max-width: 1600px;
  margin-inline: auto;
  padding-inline: var(--edge);
}

/* --- Scene epinglee : le texte se BLOQUE en face de son titre -----
   Premiere version : colonne gauche collee (sticky) et paragraphes qui
   defilent a droite. ERREUR DE CONCEPTION -- deux objets dont un seul est
   immobile ne sont alignes qu a UN instant de la course ; le reste du temps
   le paragraphe est au-dessus ou en dessous de son titre. C est exactement
   ce qu a constate l utilisateur.
   Corrige en epinglant LES DEUX : la scene entiere tient un ecran, les trois
   etats du titre et les trois paragraphes sont empiles chacun sur une seule
   cellule de grille, et les deux colonnes sont centrees verticalement. Ils
   sont donc EN FACE par construction, a tout instant et a toute hauteur de
   fenetre, sans aucun seuil a caler. Seule leur opacite change.
   Trois BANDES successives et non trois colonnes cote a cote : trois fiches
   alignees redessineraient le triptyque retire le 08/08. */
.force__bandes,
.bureau__bandes {
  position: relative;
  height: 400vh;   /* course : ~1 ecran par bande. Etendue de 320 a 400vh
                      pour que le temps ou le titre est SEUL a l ecran dure
                      assez longtemps pour se voir (~10vh de scroll). */
  margin-top: clamp(2rem, 1.5rem + 2.5vw, 4rem);
}
.force__bandes-pin,
.bureau__bandes-pin {
  position: sticky;
  /* Hauteur AUTO et non 100vh : a 100vh le bloc etait centre dans un ecran
     entier, donc il commencait trop bas ET tout le bas de cet ecran restait
     structurellement vide -- vide qui se voyait d un coup au relachement de
     l epinglage. En hauteur auto, l element epouse son contenu : plus de bas
     a remplir, et sa position se regle par `top`, pose par le JS. */
  top: 18vh;
  height: auto;
  /* Disposition RECOPIEE de .conviction__inner : flex, titre a gauche cale
     en haut, texte a droite sur 55 %. "En face" ne voulait pas dire centre
     verticalement -- c etait ma mauvaise lecture, corrigee le 08/08.
     Les deux colonnes partent du MEME haut, comme dans .conviction. */
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-start;   /* les deux COLONNES partent du meme haut... */
}
/* Les trois etats occupent LA MEME cellule de grille : la boite prend la
   hauteur du plus grand, sans hauteur en dur a maintenir. */
.force__pilier,
.bureau__pilier { flex: 0 0 auto; max-width: 38%; }
.force__pilier-cadre,
.bureau__pilier-cadre { display: grid; }
.force__colonne,
.bureau__colonne { flex: 0 0 auto; width: 55%; display: grid; list-style: none; margin: 0; padding: 0; }
.force__etat,
.bureau__etat { grid-area: 1 / 1; }
.force__para,
.bureau__para { grid-area: 1 / 1; overflow: hidden; }
/* Le numero et le titre existent aussi AU-DESSUS de chaque paragraphe : le
   pilier est en aria-hidden (c est de la mise en scene), c est cette copie
   qui porte le titre pour un lecteur d ecran. Masquee a l oeil sans etre
   retiree de l arbre d accessibilite, et rendue visible sur mobile, ou la
   scene epinglee n a plus lieu d etre. */
.force__para-tete,
.bureau__para-tete {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
/* Valeurs de .conviction__label, sans son white-space:nowrap : ces titres-ci
   font plusieurs mots et doivent pouvoir passer a la ligne. */
.force__bande-titre,
.bureau__bande-titre {
  margin: 0;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(2.25rem, 1.8rem + 2vw, 3.25rem);
  line-height: 1.15;
  color: var(--ink);
}
/* Valeurs de .conviction__text. Multipliees par --echelleP, que le JS reduit
   UNIQUEMENT si le plus haut paragraphe ne tient pas dans la scene d un
   ecran : elle est epinglee et haute de 100vh, un texte trop long en
   sortirait sans rien signaler. Meme principe que --echelle sur l en-tete. */
.force__bande-texte,
.bureau__bande-texte {
  margin: 0;
  font-family: 'Inter', sans-serif;
  font-weight: 600;
  font-size: calc(clamp(1.625rem, 1.3rem + 1.4vw, 2.25rem) * var(--echelleP, 1));
  line-height: 1.5;
  color: var(--ink);
}

.force__final,
.bureau__final {
  margin-top: clamp(2rem, 1.5rem + 2.5vw, 4rem);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.force__final-titre,
.bureau__final-titre {
  margin: 0;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(1.875rem, 1.55rem + 1.6vw, 2.75rem);   /* = .force__titre */
  line-height: 1.14;
  letter-spacing: -0.01em;
}
.force__final-texte,
.bureau__final-texte {
  margin: clamp(1.5rem, 1.1rem + 1.4vw, 2.75rem) 0 0;   /* = .force__lead */
  max-width: 56ch;
  font-size: clamp(1.125rem, 1rem + 0.55vw, 1.5rem);   /* = .force__lead */
  line-height: 1.8;
  color: var(--ink-soft);
}
/* Meme forme que .rise__link (le seul lien de ce type sur le site) plutot
   qu un bouton plein : aucun bouton plein n existe ailleurs dans la page. */
.force__lien {
  display: inline-flex;
  align-items: center;
  align-self: flex-end;   /* comme .rise__link : le lien se detache de la
                             colonne de texte et ferme la section a droite. */
  gap: 0.45rem;
  margin-top: clamp(3rem, 2.5rem + 1.6vw, 4.5rem);
  font-family: 'Playfair Display', Georgia, serif;
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.1875rem);
  font-weight: 600;
}
.force__lien span {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.28em;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--ink-faint);
}
@media (hover: hover) and (pointer: fine) {
  .force__lien:hover span { text-decoration-color: var(--gold-2); }
}
.force__lien-arrow { color: var(--gold-2); transition: transform 0.35s var(--ease-out-expo); }
@media (hover: hover) and (pointer: fine) {
  .force__lien:hover .force__lien-arrow { transform: translateX(0.3rem); }
}

/* Montee des paragraphes et du bloc final. L etat de repos (opacity 0) est
   scope sous un drapeau que le JS pose LUI-MEME : si le module ne tourne pas
   (erreur JS en amont, script non charge), la section reste entierement
   lisible, simplement sans montee. Sans ce garde-fou, un incident ailleurs
   dans main.js rendrait tout le texte invisible. */
/* Le titre a sa propre valeur --et, en avance sur le --e de son texte : les
   deux arrivent ensemble mais pas d un bloc, le titre se pose puis le texte
   suit. Les deux partagent en revanche exactement la meme fenetre de sortie,
   pour qu une bande s efface d un seul tenant. */
.force__suite--anim .force__etat,
.force__suite--anim .bureau__etat {
  opacity: var(--et, 0);
  transform: translateY(calc((1 - var(--et, 0)) * 14px));
}
.force__suite--anim .force__bande-texte,
.force__suite--anim .bureau__points {
  transform: translateY(calc((1 - var(--e, 0)) * 118% - var(--s, 0) * 118%));
  will-change: transform;
}
.force__suite--anim .force__monte {
  opacity: 0;
  transform: translateY(48px);
  transition: opacity 1s var(--ease-out-expo), transform 1s var(--ease-out-expo);
}
.force__suite--anim .force__monte.is-in { opacity: 1; transform: none; }

/* Sur mobile le pilier n a plus de sens (rien a coller en face) : il
   disparait et chaque paragraphe reprend son propre numero et son titre. */
@media (max-width: 860px) {
  .force__bandes, .bureau__bandes { height: auto; }
  .force__bandes-pin, .bureau__bandes-pin { position: static; height: auto; display: block; }
  .force__pilier, .bureau__pilier { display: none; }
  .force__colonne, .bureau__colonne { display: block; width: 100%; }
  .force__suite--anim .force__bande-texte,
  .force__suite--anim .bureau__points { transform: none; }
  .force__suite--anim .force__para,
  .force__para,
  .bureau__para {
    grid-area: auto;
    overflow: visible;
    opacity: 1;
    transform: none;
    padding: clamp(2rem, 1.6rem + 2vw, 3.5rem) 0;
    border-top: 1px solid var(--ink-faint);
  }
  .force__colonne li:last-child { border-bottom: 1px solid var(--ink-faint); }
  .force__para-tete,
  .bureau__para-tete {
    position: static;
    width: auto;
    height: auto;
    margin: 0 0 clamp(0.75rem, 0.6rem + 0.6vw, 1.25rem);
    overflow: visible;
    clip-path: none;
    white-space: normal;
  }
}
@media (prefers-reduced-motion: reduce) {
  .force__bandes, .bureau__bandes { height: auto; }
  .force__bandes-pin, .bureau__bandes-pin { position: static; height: auto; display: block; }
  .force__pilier, .bureau__pilier { display: none; }
  .force__colonne, .bureau__colonne { display: block; width: 100%; }
  .force__suite--anim .force__bande-texte,
  .force__suite--anim .bureau__points { transform: none; }
  .force__para,
  .bureau__para {
    grid-area: auto;
    overflow: visible;
    opacity: 1;
    transform: none;
    transition: none;
    padding: clamp(2rem, 1.6rem + 2vw, 3.5rem) 0;
    border-top: 1px solid var(--ink-faint);
  }
  .force__colonne li:last-child { border-bottom: 1px solid var(--ink-faint); }
  .force__para-tete,
  .bureau__para-tete {
    position: static;
    width: auto;
    height: auto;
    margin: 0 0 clamp(0.75rem, 0.6rem + 0.6vw, 1.25rem);
    overflow: visible;
    clip-path: none;
    white-space: normal;
  }
  .force__monte { opacity: 1; transform: none; transition: none; }
}

/* ============ BUREAU LOGISTIQUE =================================
   Le trait de .story revient. Deux niveaux, exactement comme la-bas :
     .bureau__route = la route CLIENT -- elle preexiste, en --ink-faint
     .bureau__trait = le trait BEAJIFY -- celui qui redessine
   L animation EXECUTE le service au lieu de l illustrer : la route reelle
   se dessine avec ses detours, le camion la parcourt, puis le trait Beajify
   redresse LES MEMES points de depart et d arrivee. Les kilometres a vide
   disparaissent de l ecran.
   PAS de recouvrement par marge negative ici, contrairement a .force sur
   .usages : .force se termine sur son appel a l action, le recouvrir le
   masquerait. La continuite passe par l OBJET (le trait qui revient), pas
   par un chevauchement geometrique. */
.bureau { position: relative; z-index: 7; }
.bureau__pin-wrap { position: relative; height: 260vh; background: var(--off-white); }
.bureau__pin { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; pointer-events: none; }
.bureau__fond { position: absolute; inset: 0; background: var(--off-white); z-index: 0; }
/* Filigrane : meme traitement que Studio Graphique et Force Commerciale, et
   plafonne sur eux par le JS. Les valeurs ci-dessous sont un repli. */
.bureau__eyebrow {
  position: absolute;
  top: 8rem;
  left: var(--edge);
  right: var(--edge);
  z-index: 2;
  margin: 0;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(2.25rem, 1rem + 4.5vw, 5.5rem);
  line-height: 1;
  white-space: nowrap;
  color: rgba(11, 5, 47, 1);
  opacity: var(--tit, 0);
  transform: translateY(calc((1 - var(--tit, 0)) * 26px));
  user-select: none;
}
html[data-theme="dark"] .bureau__eyebrow { color: rgba(252, 252, 252, 0.05); }
.bureau__scene {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  /* Retrait haut pose par le JS : depuis que le trace occupe toute la largeur
     il est aussi plus haut, et le sommet du detour remontait DANS le
     filigrane -- le camion roulait au milieu du mot. Le retrait le maintient
     sous lui, quelle que soit la taille du titre. */
  padding-top: var(--sceneTop, 0px);
  opacity: var(--scene, 0);
  /* La scene remonte en fin de course pour que la route optimisee vienne
     SOULIGNER le filigrane. Sans ca l animation se terminait sur une ligne
     droite plantee au milieu de l ecran, sans destination.
     Elle se RESSERRE en meme temps (--kx, --dx) : le trace est centre dans
     son cadre alors que le filigrane est cale a gauche et ne remplit pas
     toute la largeur -- sans ce recalage le trait deborde du mot a droite.
     Origine a gauche : c est le repere dans lequel le JS calcule --dx. */
  transform-origin: left center;
  transform: translate(var(--dx, 0px), var(--monte, 0px)) scaleX(var(--kx, 1));
}
/* Largeur calee sur celle du filigrane (meme marge laterale) : plafonne en
   rem, le soulignement se retrouvait bien plus court que le mot des que
   l ecran depassait ~1400px. */
.bureau__svg { width: calc(100% - 2 * var(--edge)); height: auto; overflow: hidden; }
/* La route du client : un trait fin, presque efface -- elle n appartient pas
   a Beajify, elle etait deja la. */
.bureau__route {
  fill: none;
  stroke: var(--ink-faint);
  stroke-width: 2;
  stroke-linecap: round;
  opacity: var(--vue-route, 1);
}
/* Le trait Beajify : plein, et gold au theme sombre comme .story__ink. */
.bureau__trait {
  fill: none;
  stroke: var(--ink);
  stroke-width: 3;
  stroke-linecap: round;
  opacity: var(--vue-trait, 0);
}
/* Le trait suit --ink : navy en clair, BLANC en sombre. Pas d override gold
   ici, contrairement aux lignes manuscrites -- c est un trace, pas un accent.
   La route du client monte a 28 % de blanc : a --ink-faint (10 %) elle etait
   simplement invisible sur le navy.
   Le camion est une <image> SVG, sa couleur ne se pilote pas en CSS :
   brightness(0) l aplatit en noir, invert(1) le rend blanc. */
html[data-theme="dark"] .bureau__route { stroke: rgba(252, 252, 252, 0.28); }
html[data-theme="dark"] .bureau__camion { filter: brightness(0) invert(1); }
.bureau__camion { opacity: var(--vue-camion, 0); }
/* Bloc redige : memes valeurs que le debut et la fin de .force, pour que les
   sections se repondent. Toute retouche de l une se reporte sur les autres.
   Pose en absolu dans le panneau, `top` calcule par le JS a partir du
   soulignement : la taille du filigrane depend de la fenetre, donc la hauteur
   du trait aussi, donc aucune valeur en dur ne pourrait suivre. */
.bureau__intro {
  position: absolute;
  left: var(--edge);
  right: var(--edge);
  top: var(--introTop, 55%);
  z-index: 2;
  max-width: 72rem;
  opacity: var(--intro, 0);
  transform: translateY(calc((1 - var(--intro, 0)) * 22px));
  pointer-events: none;
}
.bureau__titre {
  margin: 0;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(1.875rem, 1.55rem + 1.6vw, 2.75rem);
  line-height: 1.14;
  letter-spacing: -0.01em;
}
.bureau__lead {
  margin: clamp(1.25rem, 0.9rem + 1.2vw, 2.25rem) 0 0;
  max-width: 56ch;
  font-size: calc(clamp(1.125rem, 1rem + 0.55vw, 1.5rem) * var(--echelle, 1));
  line-height: 1.8;
  color: var(--ink-soft);
  opacity: var(--lead, 0);
  transform: translateY(calc((1 - var(--lead, 0)) * 16px));
}

@media (prefers-reduced-motion: reduce) {
  .bureau__pin-wrap { height: auto; }
  .bureau__pin { position: static; height: auto; padding: clamp(4rem, 3rem + 5vw, 8rem) var(--edge); }
  .bureau__eyebrow { position: static; opacity: 1; transform: none; }
  /* La scene garde son etat FINAL : la route optimisee, tracee, sans camion.
     C est le resultat du service, la seule image qui se suffise a elle-meme. */
  .bureau__scene { position: static; margin-top: 2rem; }
  .bureau__route { opacity: 0; }
  .bureau__trait { opacity: 1; }
  .bureau__camion { opacity: 0; }
  .bureau__intro { position: static; max-width: none; margin-top: 2rem; opacity: 1; transform: none; --echelle: 1; }
  .bureau__script { position: static; margin-top: 1.5rem; text-align: left; opacity: 1; }
  .bureau__lead { opacity: 1; transform: none; }
}

/* Trois points separes par un filet plutot que par des puces : la liste se
   lit comme un sommaire et garde la sobriete du reste du site. Elle partage
   l echelle de texte des bandes de .force (selecteur groupe plus haut). */
/* Deux paragraphes dans la cloture : le second se detache du premier. */
.bureau__final-texte + .bureau__final-texte { margin-top: clamp(0.75rem, 0.6rem + 0.5vw, 1.15rem); }
.bureau__points {
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: 'Inter', sans-serif;
  font-weight: 600;
  font-size: calc(clamp(1.625rem, 1.3rem + 1.4vw, 2.25rem) * var(--echelleP, 1));
  line-height: 1.4;
  color: var(--ink);
}
/* Filets en --ink plein et non en --ink-faint : ils sont assumes comme un
   element de composition, pas comme une separation discrete. Suit le theme
   tout seul -- navy en clair, blanc en sombre. */
.bureau__points li {
  padding: clamp(0.9rem, 0.75rem + 0.6vw, 1.4rem) 0;
  border-top: 1px solid var(--ink);
}
.bureau__points li:last-child { border-bottom: 1px solid var(--ink); }
.bureau__titre-part { display: block; }


/* ============ PASSE RESPONSIVE (08/08) ==========================
   POINTS DE RUPTURE DE REFERENCE, en rem pour suivre la taille de police
   choisie par l utilisateur (un reglage d accessibilite courant) :
     36rem =  576px  grand telephone
     48rem =  768px  tablette portrait
     62rem =  992px  tablette paysage / petit portable
     75rem = 1200px  bureau
   Les sections anterieures gardent leurs valeurs historiques : les
   renumeroter toucherait des mises en page deja validees a l ecran, pour un
   gain purement cosmetique. Toute NOUVELLE regle se cale sur cette echelle.

   Rappel : la hauteur des panneaux epingles est passee en `svh` plus haut,
   sans quoi leur bas est coupe sur telephone tant que la barre d adresse est
   affichee. Ne pas revenir a 100vh seul. */

/* --- Navigation sur telephone -----------------------------------
   Les liens etaient simplement masques sous 900px, sans rien pour les
   remplacer : le site n avait AUCUNE navigation sur telephone. On les
   reaffiche en plus petit, et on retire les entrees inertes plutot que de
   montrer des libelles qui ne menent nulle part. */
@media (max-width: 62rem) {
  .nav__links {
    display: flex !important;
    gap: clamp(0.75rem, 0.5rem + 1.2vw, 1.5rem);
    font-size: var(--fs-small);
  }
  .nav__link-inert { display: none; }
}
@media (max-width: 36rem) {
  .nav__inner { gap: 0.5rem; }
  .nav__logo img { max-height: 2.1rem; width: auto; }
}

/* --- Cibles tactiles --------------------------------------------
   44px est le minimum recommande (WCAG 2.5.5, et la meme valeur cote Apple).
   Les liens texte du site faisaient 26px de haut. On elargit la zone
   cliquable SANS toucher au rendu : marge negative compensee par du padding,
   donc la ligne reste posee exactement au meme endroit.
   Scope aux pointeurs grossiers : a la souris, la precision suffit et un
   padding inutile decalerait des mises en page validees. */
@media (pointer: coarse) {
  /* Liens dans le flux : on elargit la zone tactile SANS deplacer la ligne --
     le padding est compense par une marge negative egale, la ligne reste
     exactement ou elle etait. */
  .rise__link,
  .force__lien {
    padding-block: 0.65rem;
    margin-block: -0.65rem;
  }
  /* Elements de la barre : ils sont deja centres dans une rangee flex, une
     hauteur minimale suffit et ne deplace rien. Mesure avant correctif :
     liens 40px, pastille d appel 24px de large, bascule de theme 40px. */
  .nav__links a,
  .nav__logo,
  .nav__cta,
  .theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
  }
}

/* --- Scenes a bandes : bascule a 62rem et non 860px --------------
   Une scene epinglee a deux colonnes n a plus de sens des la tablette
   paysage : la colonne de texte y tombe sous 40 signes par ligne. */
@media (min-width: 53.75rem) and (max-width: 62rem) {
  .force__bandes, .bureau__bandes { height: auto; }
  .force__bandes-pin, .bureau__bandes-pin { position: static; height: auto; display: block; }
  .force__pilier, .bureau__pilier { display: none; }
  .force__colonne, .bureau__colonne { display: block; width: 100%; }
  .force__suite--anim .force__bande-texte,
  .force__suite--anim .bureau__points { transform: none; }
  .force__para, .bureau__para {
    grid-area: auto;
    overflow: visible;
    opacity: 1;
    transform: none;
    padding: clamp(2rem, 1.6rem + 2vw, 3.5rem) 0;
    border-top: 1px solid var(--ink-faint);
  }
  .force__para-tete, .bureau__para-tete {
    position: static;
    width: auto;
    height: auto;
    margin: 0 0 clamp(0.75rem, 0.6rem + 0.6vw, 1.25rem);
    overflow: visible;
    clip-path: none;
    white-space: normal;
  }
}

/* --- Longueur de course sur telephone ---------------------------
   Une course pensee pour la souris devient interminable au pouce : le doigt
   parcourt bien moins de pixels par geste. Les scenes epinglees qui restent
   actives sur telephone voient donc leur course reduite. Le contenu et la
   choregraphie sont inchanges -- seule la distance a parcourir diminue,
   puisque tout est exprime en fraction de la course. */
@media (max-width: 48rem) {
  .force__pin-wrap { height: 190vh; }
  .bureau__pin-wrap { height: 190vh; }
}

/* --- Confort de lecture sur telephone ---------------------------
   Interligne allonge et marges laterales tenues : sur une colonne etroite,
   un interligne serre rend un paragraphe long nettement plus penible. */
@media (max-width: 48rem) {
  .force__bande-texte, .bureau__points { line-height: 1.45; }
  .bureau__points li { padding-block: clamp(0.8rem, 0.6rem + 1vw, 1.2rem); }
  .force__titre-part, .bureau__titre-part { display: inline; }
}

/* --- Orientation paysage sur telephone --------------------------
   Ecran tres bas : les panneaux epingles n ont pas la place d afficher un
   filigrane geant ET du texte. Le filigrane s efface au profit du texte,
   qui est ce qu on vient lire. */
@media (max-height: 30rem) and (orientation: landscape) and (max-width: 62rem) {
  .force__eyebrow, .bureau__eyebrow { opacity: 0.12 !important; }
  .force__script, .bureau__script { display: none; }
}

/* --- Ligne manuscrite du hero : CENTREE sur telephone ------------
   Elle est alignee a droite sur grand ecran, ou elle equilibre le bloc de
   titre cale a gauche. Sur une colonne etroite ce contrepoids n existe plus :
   le texte est deja centre au-dessus, et une ligne poussee a droite paraissait
   simplement mal calee.
   PIEGE DU THEME SOMBRE : la ligne y est peinte en degrade via
   background-clip:text, et un degrade de texte se peint sur la BOITE de
   l element, pas sur ses lettres. On centre donc la BOITE (width:fit-content
   + marges auto) au lieu d elargir la boite a 100 % : sinon le degrade
   s etalerait sur toute la largeur et les lettres n en montreraient que la
   portion centrale.
   Le padding qui compense le debordement des lettres de Caveat passe des deux
   cotes, sans quoi la compensation d un seul cote decalerait le centrage. */
@media (max-width: 48rem) {
  .hero__script {
    width: -moz-fit-content;
    width: fit-content;
    max-width: 100%;
    margin-inline: auto;
    text-align: center;
  }
  html[data-theme="dark"] .hero__script {
    margin-left: auto;
    margin-right: auto;
    padding-inline: 0.35em;
  }
}

/* --- Cartes Equipe sur telephone : contenu recentre ---------------
   Mesure avant correctif : 59 px au-dessus du contenu, 0 a 2 px en dessous.
   Le contenu n etait pas decentre, il etait A L ETROIT -- a 14rem la carte
   la plus chargee (Developpeur : texte + badge + note) touchait son bord bas.
   Centrer sans donner de place n aurait rien change : on ouvre d abord la
   hauteur, ensuite on centre.
   Hauteur FIXE et non auto : les cartes vivent dans un rail a defilement
   horizontal, des hauteurs variables donneraient un bas de rail en dents de
   scie. On cale donc tout le monde sur la plus chargee. */
@media (max-width: 48rem) {
  .cards-rise__card {
    height: 16rem;
    justify-content: center;
  }
}

/* --- Studio Graphique sur telephone -------------------------------
   CE QUI RESTE : l ecriture du mot, la metamorphose en camion, la phrase
   qu il devoile. Tout cela fonctionnait, il n y avait aucune raison d y
   toucher -- une premiere version avait depingle la scene entiere, c etait
   une erreur de perimetre.
   CE QUI CHANGE : le panneau Studio Graphique porte TOUTE la planche ADN en
   position absolue dans un cadre epingle d un ecran. A 390x700 le compte n y
   est pas et tout se recouvrait. Le JS le sort donc du cadre -- un enfant
   d un element `sticky` en overflow:hidden ne peut pas s en echapper par la
   mise en page seule -- et il se lit ici comme un bloc normal, sous la scene.
   Les reveils declenches par le passage du camion sont poses en dur : une
   fois le panneau sorti, plus rien ne les declenche.
   `!important` sur l opacite et la transformation : storyScroll les ecrit en
   style EN LIGNE, seule une declaration de feuille marquee important
   l emporte sur un style en ligne qui ne l est pas. */
@media (max-width: 48rem) {
  .story__next {
    position: static;
    padding-right: 0;
    opacity: 1 !important;
    transform: none !important;
    pointer-events: auto;
    padding-block: clamp(2.5rem, 2rem + 4vw, 4.5rem);
  }
  .story__next-eyebrow {
    position: static;
    white-space: normal;
    font-size: clamp(2rem, 1.2rem + 4vw, 3rem) !important;
    margin-bottom: clamp(1rem, 0.8rem + 1.5vw, 1.75rem);
    padding-inline: var(--edge);
  }
  .story__next-grid { display: block; }
  .story__script {
    position: static;
    max-width: none;
    text-align: left;
    margin-top: clamp(1.5rem, 1.2rem + 2vw, 2.5rem);
    padding-inline: var(--edge);
  }
  html[data-theme="dark"] .story__script { margin-left: 0; }
  /* Etats normalement declenches par le passage du camion. */
  .story__next .adn__head,
  .story__next .plate,
  .story__next .regle,
  .story__next .valeurs { opacity: 1 !important; transform: none !important; }
  .story__next .plate__rule { transform: scaleX(1); }
  .story__next .plate__slant { opacity: 1; }
  .story__next .plate__letter { stroke-dashoffset: 0; }
  .story__next .plate__dims,
  .story__next .plate__legend { opacity: 1; }
  .story__next .valeurs__half--sombre { clip-path: inset(0 0 0 0); }
  .story__next .valeurs__seam { transform: scaleY(1); }
}

/* --- Force Commerciale sur telephone -----------------------------
   La ligne manuscrite etait ancree au BAS du panneau. Sur une colonne
   etroite, l en-tete descend jusque-la et les deux se chevauchaient. Elle
   se pose desormais SOUS le paragraphe, a une hauteur calculee par le JS
   (--scriptTop) qui suit la taille reelle du bloc -- et cette hauteur entre
   dans le garde-fou d echelle, donc l en-tete se reduit d autant si besoin
   au lieu de venir mordre dessus.
   Le lien de cloture repasse a gauche : cale a droite il se retrouvait seul
   au bord d une colonne etroite, sans le bloc de texte qui lui repond sur
   grand ecran. On lui donne aussi de l air au-dessus, et on reprend ce
   qu on lui donne sur le bas de section, pour ne pas allonger l attente
   avant Bureau Logistique. */
@media (max-width: 48rem) {
  /* Les deux sections partagent cette structure -- en-tete posee en absolu
     dans un panneau epingle, ligne manuscrite ancree en bas. Elles doivent
     donc recevoir la meme correction : la ligne passe SOUS le paragraphe. */
  .force__script,
  .bureau__script {
    top: var(--scriptTop, auto);
    bottom: auto;
    left: var(--edge);
    text-align: left;
  }
  html[data-theme="dark"] .force__script,
  html[data-theme="dark"] .bureau__script { margin-left: 0; }
  .force__lien {
    align-self: flex-start;
    margin-top: clamp(2.25rem, 1.8rem + 2.5vw, 3.25rem);
  }
  .force__suite { padding-bottom: clamp(1rem, 0.5rem + 2vw, 2rem); }
}

/* --- Section 0% : le lien respire sur telephone -------------------
   Sur grand ecran le lien est cale a DROITE et la ligne manuscrite a gauche :
   ils ne se touchent jamais, l ecart lateral suffit a les separer. Sur une
   colonne unique ils se retrouvent l un sous l autre, et le retrait vertical
   d origine -- pense pour deux objets qui ne se font pas face -- devient
   trop court. On le double sous 48rem. */
@media (max-width: 48rem) {
  .rise__link { margin-top: clamp(3.5rem, 3rem + 3vw, 5rem); }
}
