@import url('./hero-mobile.css');

/* ===========================================================================
   Recette Farès — cahier de tests rempli le 21/09/2026.
   Ce fichier ne contient que les écarts relevés en recette. Il se charge après
   styles/v3-niveau.css pour surcharger sans rien y réécrire, afin que chaque
   correction reste lisible et réversible.
   =========================================================================== */

/* --- Dépliants supprimés (items 23, 39, 41, 43, 45, 47, 53, 55, 57, 59, 67,
       69, 73, 79, 85, 93) -----------------------------------------------------
   Les 76 <details class="v3-details"> sont devenus des <div class="v3-details
   v3-static">. Les règles de .v3-details continuent de s'appliquer ; seules les
   règles [open] tombent, et elles ne portaient que la rotation du « + ». */
.v3-static {
  display: block;
}

/* Le corps était révélé par le dépliage ; il est désormais toujours lisible. */
.v3-static > div {
  padding-top: 10px;
}

/* --- Nom de la page (items 37, 51, 65, 77, 89) ----------------------------
   « Le titre est très petit ; on ne comprend pas que c'est le nom de la page. »
   Le libellé passe de 12 px à une échelle fluide, gagne du poids et perd le
   voile d'opacité qui l'effaçait. L'interlettrage est resserré à mesure que le
   corps grandit, sinon le mot se disloque. */
.v3-label-page {
  font-size: clamp(17px, 1.45vw, 22px);
  letter-spacing: .1em;
  font-weight: 600;
  opacity: 1;
  margin-bottom: 22px;
}

/* --- Titres des quatre familles d'offres (item 43.1) ----------------------
   « Le titre des 4 offres Marque, campagne, contenus, vidéos sont très petits. »
   Ne concerne que le rail des familles de Visual IA (#c2), pas les autres
   surtitres du site, qui eux ont été validés. */
#c2 .v3-kicker {
  font-size: clamp(15px, 1.15vw, 18px);
  letter-spacing: .06em;
  font-weight: 600;
  opacity: 1;
}

/* --- Accroche de la page Références (item 89.2) ---------------------------
   « Réduire la taille du texte : Des entreprises aux enjeux différents. »
   Elle rivalisait avec le titre de la page ; elle redevient une accroche. */
#h2conf {
  font-size: clamp(28px, 2.9vw, 44px);
  line-height: 1.12;
  max-width: 24ch;
}

/* --- Confort de lecture ---------------------------------------------------
   Avec tous les contenus dépliés, certaines cartes gagnent en hauteur. On
   retire le calage bas hérité du dépliant, qui creusait un vide entre le titre
   et un corps désormais toujours présent. */
.v3-static {
  margin-top: 14px;
}

@media (max-width: 720px) {
  .v3-label-page {
    font-size: 16px;
    margin-bottom: 16px;
  }
  #c2 .v3-kicker {
    font-size: 15px;
  }
}

/* --- Redondance des tailles client (Références) ---------------------------
   « VISUAL IA · GRAND GROUPE » répétait la taille sur la même ligne
   typographique que l'offre : sur six cas, « GRAND GROUPE » sortait trois
   fois en capitales, et la taille pesait autant que l'offre elle-même.
   Le cahier des charges impose de mentionner la taille (point 93) : elle est
   donc conservée, mais redescendue au rang de métadonnée, dans la pastille
   déjà utilisée par « Cas illustratif ». L'offre redevient l'information
   principale ; la répétition ne crie plus. */
.v3-cas-kicker {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.v3-taille {
  font-size: 11px;
  letter-spacing: .04em;
  text-transform: none;
  font-weight: 500;
  padding: 4px 10px;
  border: 1px solid currentColor;
  border-radius: 999px;
  opacity: .68;
}

/* ===========================================================================
   Accessibilité — écarts RGAA AA relevés au rendu (Chromium, 390 / 768 / 1440).
   Tous préexistaient à la recette : le build intact présente exactement les
   mêmes. Le README pose RGAA AA comme non négociable, et le point 11 du cahier
   porte sur les contrastes et les zones cliquables : ils sont donc corrigés.
   =========================================================================== */

/* --- Contraste du texte (WCAG 1.4.3, seuil 4.5:1 sous 24 px) --------------
   Valeurs mesurées sur le fond réellement calculé, pas estimées. */
#agents .ai-process-steps li {
  color: #68747b;                 /* était #728087 — 3,86:1 sur #fff8ea */
}                                 /* désormais 4,54:1. La règle d'origine est
                                     portée par #agents : la surcharge doit
                                     reprendre la même spécificité. */

#agents .ai-desk dt {
  color: #5b7179;                 /* était #5C727A — 4,44:1 sur #edf1eb */
}                                 /* désormais 4,50:1 */

/* --- Zones cliquables (WCAG 2.5.8, minimum 24 x 24 px) --------------------
   Les liens en pleine phrase restent exemptés ; seules les commandes
   autonomes sont reprises. Le champ anti-spam .honey est déjà neutralisé
   (aria-hidden + tabindex="-1") : il n'est pas concerné. */
.v3-card > h3 > a,
.locations-grid article button.text-link,
address a,
.map-consent-note a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}

.consent-label input[type="checkbox"],
#agents .ai-check input[type="checkbox"] {   /* la règle d'origine est portée
                                                par #agents : même spécificité */
  width: 24px;
  height: 24px;
  flex: 0 0 24px;
}

/* ===========================================================================
   Défilement et hauteurs — retour d'Adam sur Pixel 10 Pro et sur ordinateur,
   21/09 : « tout buggé niveau scroll » et « plein d'espace vide ».

   La conception d'origine est assumée et documentée dans v3-niveau.css : chaque
   chapitre occupe un écran, et le suivant glisse par-dessus le précédent. Sur
   un navigateur piloté, cela ne se voit pas. Sur un appareil réel, deux choses
   se produisent.

   L'accroche au défilement reprend la main sur le geste : la page décide où
   s'arrêter à la place du lecteur. C'est ce qui donne la sensation de bug, et
   c'est aussi ce que vise le point 13 du cahier, « réduction des animations
   sans gêner la lecture ».

   La hauteur plancher d'un écran par chapitre produit, elle, de 22 % à 37 % de
   vide selon les pages : une section de 900 px pour 320 px de contenu laisse
   580 px de rien. Mesuré sur les quatre pages, en 412 x 915 et en 1440 x 900.

   Les chapitres qui ont besoin de la pleine hauteur la gardent : le film
   d'ouverture, la démonstration Agents IA, et le premier écran de chaque page.
   C'est une décision de présentation : Isabelle et Farès peuvent la revoir,
   et il suffit de retirer ce bloc pour revenir à l'état d'avant.
   =========================================================================== */

/* --- L'accroche rend la main ---------------------------------------------- */
html:has(.v3-page):not(#_) {
  scroll-snap-type: none;
}

.v3-chapter:not(#_),
.v3-rail:not(#_),
.v3-rail-stage:not(#_) {
  scroll-snap-align: none;
  scroll-snap-stop: normal;
}

/* --- Les hauteurs pleine page sont conservées ------------------------------
   Premier réflexe, le 21/09 : j'avais aplati les chapitres pour supprimer le
   vide. C'était une erreur. Ce vide n'en est pas un : c'est la course dont la
   chorégraphie a besoin pour que chaque chapitre glisse par-dessus le
   précédent. Adam veut cet effet, et il a raison — il fait le caractère du
   site. Seule l'accroche au défilement, ci-dessus, est retirée : elle prenait
   la main sur le geste sans rien apporter à l'effet.
   -------------------------------------------------------------------------- */

/* --- Le vide en haut d'un chapitre : la répartition, pas la hauteur --------
   Adam, 21/09 : « sans scroll, par exemple Agent IA, le 1er des deux, trop de
   zone vide en haut ». Il a raison, et la cause n'est pas la hauteur d'écran.

   v3-niveau.css mesure la part d'écran qu'un chapitre remplit. En dessous de
   52 %, il le marque « ampleur grande » et étire son contenu du haut vers le
   bas, avec justify-content:space-between. Le commentaire d'origine dit à quoi
   cette règle est destinée : « réservé aux chapitres qui portent un en-tête à
   deux colonnes ». Le sélecteur, lui, ne vérifie jamais la présence de cet
   en-tête. Sur un chapitre qui n'en a pas, l'étirement ne place plus deux
   blocs : il écarte les paragraphes un par un.

   Mesuré au rendu, à 412 x 915, écart maximal entre deux éléments voisins :

     Agents IA, premier écran      107 / 115 / 106 / 91 px
     Références, « Des entreprises aux enjeux différents »      566 px
     Marque blanche, la promesse                                614 px
     À propos, « Notre approche »                               304 px

   Sur l'écran d'Agents IA, le libellé AGENTS IA se détache du titre qu'il
   annonce : 210 px séparent l'en-tête du titre. C'est exactement le vide dont
   parle Adam, et il est là sans avoir défilé d'un pixel.

   La correction ne touche ni à la hauteur des chapitres, ni au glissement,
   ni à la typographie agrandie par l'ampleur — tout cela reste. Elle rend
   simplement à la règle le périmètre que son auteur avait écrit : un chapitre
   se déploie s'il a un en-tête à deux colonnes pour tenir le bas ; sinon, son
   contenu reste un bloc, centré dans son écran comme partout ailleurs sur le
   site. L'espace libre redevient une marge autour d'un bloc lisible, au lieu
   d'une déchirure entre ses lignes.
   -------------------------------------------------------------------------- */
.v3-chapter[data-ampleur=grande]:not(.v3-cta):not(.v3-chiffres)
  > .v3-inner:not(:has(> .v3-head)):not(#_) {
  justify-content: center;
}


/* ===========================================================================
   Le premier écran — Adam, 21/09 : « si ennuyeux, si plat, si boring et peu
   crédible », capture du Pixel 10 Pro à l'appui.

   Le jugement est juste et il dépasse le vide. Recentrer le bloc supprime la
   déchirure, mais un titre au tiers de sa place, une énumération grise en
   pleine ligne et rien qui dise que la page continue : cela reste un écran
   qui n'affirme rien. Ce qui suit lui rend de la tenue, sans sortir de la
   direction artistique — encre, crème, cyan, menthe, rose, et la typographie
   déjà en place. Rien n'est inventé côté palette ni côté fonte.
   =========================================================================== */

/* --- Le titre tient son écran sur téléphone -------------------------------
   v3-niveau.css plafonne le titre d'un chapitre ample à 36 px sous 860 px de
   large, pour éviter qu'un très grand corps ne déborde au milieu d'une page.
   Le premier écran n'a pas ce risque : il ne porte qu'un titre, et il a tout
   l'écran. Mesuré sur Pixel (412 px) : 36 px occupaient deux lignes sur onze
   possibles. Le corps devient fluide, borné par la largeur ET par la hauteur,
   donc il ne peut pas déborder, même sur un écran court. */
@media (max-width: 860px) {
  main > :first-child.v3-chapter[data-ampleur] .v3-display:not(#_),
  main > :first-child.v3-chapter[data-ampleur=moyenne] .v3-display:not(#_) {
    font-size: min(11.6vw, 6.2svh, 58px);
    line-height: .98;
    letter-spacing: -.035em;
  }
}

/* --- Le nom de la page devient un repère ----------------------------------
   « AGENTS IA » flottait seul, sans rien qui le rattache au titre. Un filet
   cyan le précède : on lit un repère de chapitre, plus un mot égaré. Le point
   respire lentement — c'est le seul mouvement de l'écran, et il suffit à ce
   qu'il ne paraisse pas figé. */
main > :first-child.v3-chapter .v3-label-page:not(#_) {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: clamp(18px, 2.4svh, 28px);
}

main > :first-child.v3-chapter .v3-label-page::before {
  content: '';
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--n-cyan);
  box-shadow: 0 0 0 0 rgba(72, 185, 206, .55);
  animation: r-souffle 3.2s var(--n-ease) infinite;
}

main > :first-child.v3-chapter .v3-label-page::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  max-width: clamp(56px, 12vw, 160px);
  background: linear-gradient(to right, var(--n-cyan), transparent);
  opacity: .8;
}

@keyframes r-souffle {
  0%, 70%, 100% { box-shadow: 0 0 0 0 rgba(72, 185, 206, .5); }
  35%           { box-shadow: 0 0 0 7px rgba(72, 185, 206, 0); }
}

/* --- Les six capacités deviennent un objet, pas une phrase ----------------
   « ÉCRIRE · RECHERCHER · ANALYSER · SYNTHÉTISER · CRÉER · ÉCOUTER » était
   posé en note grise, à 72 % d'opacité, replié sur deux lignes molles. C'est
   pourtant la seule preuve de substance de l'écran : ce que les agents font.
   Il devient une grille numérotée, chaque capacité sur son filet. Le balisage
   est produit par scripts/recette-20260921.js ; sans JavaScript, la phrase
   d'origine reste en place et reste lisible. */
.r-capacites {
  list-style: none;
  margin: clamp(18px, 2.6svh, 30px) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: rgba(255, 248, 234, .14);   /* les filets sont le fond qui perce */
  border-top: 1px solid rgba(255, 248, 234, .14);
  max-width: 46ch;
}

.r-capacites li {
  background: var(--n-ink);
  display: flex;
  align-items: baseline;
  padding: 12px 12px 13px 0;
}

.r-capacites li span {
  font-size: clamp(13px, 1.55svh, 15px);
  letter-spacing: .07em;
  text-transform: uppercase;
  line-height: 1.2;
}

@media (min-width: 861px) {
  .r-capacites { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .r-capacites li { padding-right: 20px; }
}

/* --- Dire que la page continue -------------------------------------------
   Rien, en bas du premier écran, n'annonçait la suite : le lecteur pouvait
   croire la page terminée. Un filet descend lentement dans la marge droite,
   là où l'écran est libre. Il est décoratif et ne prend ni le clavier ni le
   lecteur d'écran. Réservé aux écrans larges : sur téléphone, la marge droite
   est occupée par le bouton d'appel. */
@media (min-width: 861px) {
  main > :first-child.v3-chapter::before {
    content: '';
    position: absolute;
    right: calc(var(--n-gutter) - 1px);
    bottom: clamp(40px, 7svh, 88px);
    width: 1px;
    height: clamp(56px, 9svh, 92px);
    background: linear-gradient(to bottom, transparent, currentColor 45%, transparent);
    opacity: .3;
    z-index: 1;
    pointer-events: none;
    mask-image: linear-gradient(to bottom, #000 0 100%);
    animation: r-descente 2.6s var(--n-ease) infinite;
  }
}

@keyframes r-descente {
  0%        { transform: translateY(-38%); opacity: 0; }
  30%, 62%  { opacity: .42; }
  100%      { transform: translateY(38%); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  main > :first-child.v3-chapter .v3-label-page::before,
  main > :first-child.v3-chapter::before { animation: none; }
}

/* --- Reprises après rendu -------------------------------------------------
   Trois écarts relevés à la capture, pas devinés. */

/* La grille des capacités touchait le bouton : zéro pixel entre les deux,
   mesuré à 412 et à 1440. Et elle n'avait de filet qu'en haut, ce qui la
   laissait ouverte par le bas. */
.r-capacites {
  border-bottom: 1px solid rgba(255, 248, 234, .14);
}

.r-capacites + .v3-button:not(#_) {
  margin-top: clamp(22px, 3.2svh, 34px);
}

/* Le premier écran portait, sur téléphone, 100 px de marge haute contre 46 en
   bas : le bloc centré retombait 58 px trop bas. Les deux marges se rejoignent,
   la hauteur d'écran du chapitre ne bouge pas. */
@media (max-width: 860px) {
  main > :first-child.v3-chapter:not(#_) {
    padding-top: clamp(44px, 6svh, 76px);
  }
}

/* --- Le système travaille -------------------------------------------------
   Un écran qui présente des agents et ne bouge pas d'un pixel se dément
   lui-même. Un trait cyan balaie le filet haut de la grille, une fois toutes
   les six secondes, puis s'efface. C'est le seul mouvement de la page avec la
   respiration du repère : assez pour qu'elle soit vivante, assez peu pour
   qu'on puisse lire. Arrêté net en mouvement réduit. */
.r-capacites {
  position: relative;
}

.r-capacites::before {
  content: '';
  position: absolute;
  inset: -1px auto auto 0;
  height: 1px;
  width: 34%;
  background: linear-gradient(to right, transparent, var(--n-cyan), transparent);
  animation: r-balayage 6s linear infinite;
  pointer-events: none;
}

@keyframes r-balayage {
  0%          { transform: translateX(-100%); opacity: 0; }
  8%          { opacity: .9; }
  34%         { opacity: .9; }
  42%, 100%   { transform: translateX(294%); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .r-capacites::before { animation: none; opacity: 0; }
}

/* La deuxième colonne collait au filet vertical : son numéro le touchait.
   Les cellules reçoivent une gouttière interne, sauf celles de la première
   colonne, qui doivent rester alignées sur le titre. */
.r-capacites li { padding-left: 14px; }
.r-capacites li:nth-child(odd) { padding-left: 0; }

@media (min-width: 861px) {
  .r-capacites li:nth-child(odd) { padding-left: 14px; }
  .r-capacites li:nth-child(3n+1) { padding-left: 0; }
}

/* Colonnes égales en fractions : « RECHERCHER » débordait sous le filet de la
   colonne suivante, à 1440 comme à 1366. Chaque colonne part désormais de la
   largeur de son mot le plus long ; aucune ne peut plus rogner. */
.r-capacites:not(#_) {
  grid-template-columns: repeat(2, minmax(max-content, 1fr));
  width: fit-content;
  max-width: 100%;
}

@media (min-width: 861px) {
  .r-capacites:not(#_) {
    grid-template-columns: repeat(3, minmax(max-content, 1fr));
  }
}

/* --- Le repère devient un système ------------------------------------------
   Un seul écran tenu ne fait pas un site tenu. Le même repère — pastille cyan,
   filet qui s'efface — passe sur l'intitulé de chaque chapitre : « NOTRE
   APPROCHE », « NOS IMPLANTATIONS », « CE QUE NOUS FAISONS ». Ces mots étaient
   des mentions grises de 12 px posées au-dessus d'un titre ; ils deviennent le
   repère de lecture d'un chapitre, identique d'une page à l'autre.

   La respiration, elle, reste au seul premier écran : six pastilles qui
   palpitent dans une même page, ce n'est plus un signal, c'est un clignotant.
   Les intitulés de la clôture rose, centrés par nature, gardent leur axe. */
.v3-chapter > .v3-inner > .v3-label:not(.v3-label-page):not(#_),
.v3-chapter .v3-head .v3-label:not(#_),
.v3-rail-head .v3-label:not(#_) {
  display: flex;
  align-items: center;
  gap: 12px;
}

.v3-chapter > .v3-inner > .v3-label:not(.v3-label-page)::before,
.v3-chapter .v3-head .v3-label::before,
.v3-rail-head .v3-label::before {
  content: '';
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--n-cyan);
}

.v3-chapter > .v3-inner > .v3-label:not(.v3-label-page)::after,
.v3-chapter .v3-head .v3-label::after,
.v3-rail-head .v3-label::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  max-width: clamp(44px, 9vw, 120px);
  background: linear-gradient(to right, var(--n-cyan), transparent);
  opacity: .75;
}

/* Le cyan de marque n'est lisible que sur l'encre. Sur les quatre fonds clairs
   du site — cyan, menthe, crème, rose — il disparaît, littéralement : sur le
   parcours « Ce que nous produisons » de Visual IA, la pastille cyan posée sur
   un fond cyan ne se voyait pas du tout. Le repère y passe en encre, comme le
   reste du texte de ces chapitres. */
.v3-chapter:not([data-theme=ink]) .v3-label::before,
.v3-rail:not([data-theme=ink]) .v3-label::before {
  background: var(--n-ink);
  opacity: .55;
}

.v3-chapter:not([data-theme=ink]) .v3-label::after,
.v3-rail:not([data-theme=ink]) .v3-label::after {
  background: linear-gradient(to right, var(--n-ink), transparent);
  opacity: .32;
}

/* La clôture est centrée : le filet la décentrerait. */
.v3-cta > .v3-inner > .v3-label:not(#_) {
  justify-content: center;
}

.v3-cta > .v3-inner > .v3-label::after {
  display: none;
}

/* ===========================================================================
   Trois corrections qui ne s'appliquaient pas — contrôle du 21/09 au soir.

   J'ai relu chaque déclaration de ce fichier en demandant au navigateur, page
   par page, si elle gagnait réellement la cascade. Trois ne la gagnaient pas.
   Elles étaient écrites, elles étaient commentées, elles ne changeaient rien à
   l'écran. Les voici réparées, et la cause de chacune est notée : c'est la même
   erreur qui pourrait se reproduire.

   La cause commune : v3-niveau.css écrit ses règles avec « :not(#_) ». Ce
   sélecteur ne sélectionne rien de plus, mais il compte comme un identifiant
   dans le calcul de priorité. Une règle de classe ordinaire ne peut donc pas
   le surcharger, quel que soit l'ordre des fichiers.
   =========================================================================== */

/* --- Points 37, 51, 65, 77, 89 : le nom de la page ------------------------
   « Le titre est très petit ; on ne comprend pas que c'est le nom de la page. »
   Ma règle « .v3-label-page » perdait contre « .v3-label:not(#_) », qui fixe
   12 px. Mesuré : 12 px affichés sur les cinq pages, à 1440 comme à 412. */
.v3-label-page:not(#_):not(#_) {
  font-size: clamp(17px, 1.45vw, 22px);
  letter-spacing: .1em;
  font-weight: 600;
  opacity: 1;
}

@media (max-width: 720px) {
  .v3-label-page:not(#_):not(#_) {
    font-size: 16px;
  }
}

/* --- Point 43.1 : le titre des quatre familles ----------------------------
   « Le titre des 4 offres Marque, campagne, contenus, vidéos sont très
   petits. » Ma règle visait « #c2 .v3-kicker ». Or c2 n'est pas le parcours :
   c'est l'identifiant du titre h2 à l'intérieur. Le sélecteur ne désignait
   donc aucun élément de la page. On vise le parcours par ce qu'il annonce. */
[aria-labelledby="c2"] .v3-rail-item .v3-kicker:not(#_) {
  font-size: clamp(20px, 1.7vw, 25px);
  line-height: 1.15;
  letter-spacing: -.012em;
  font-weight: 600;
  opacity: 1;
  margin-bottom: clamp(8px, 1.3svh, 14px);
}

/* Premier essai, à 18,7 px : la famille et la promesse tombaient au même corps,
   à un cran de graisse près — 600 contre 700. Deux lignes grasses côte à côte
   ne font pas une hiérarchie, elles font une bouillie. Farès appelle « Marque,
   Campagnes, Contenus, Vidéo » le titre des quatre offres : c'est donc la
   famille qui porte le titre, et la promesse qui l'explique. La graisse de la
   promesse redescend, et seulement dans ce parcours-là. */
[aria-labelledby="c2"] .v3-rail-item h3:not(#_) {
  font-weight: 500;
}

/* --- Point 89.2 : l'accroche de Références --------------------------------
   « Réduire la taille du texte : Des entreprises aux enjeux différents. »
   Ma règle « #h2conf » perdait contre « .v3-chapter[data-ampleur] .v3-display
   :not(#_) », plus prioritaire malgré l'identifiant. Mesuré : 108 px affichés
   à 1440, là où la correction en demandait 44 au plus. */
#h2conf:not(#_):not(#_) {
  font-size: clamp(30px, 4.2vw, 60px);
  line-height: 1.08;
  letter-spacing: -.028em;
  max-width: 22ch;
}

/* Le palier retenu n'est pas arbitraire. Le titre de la page, sur cette même
   page, fait 95 px à 1440 : à 108 px, l'accroche passait devant lui, et c'est
   très exactement ce que dit le point 89.2 — elle rivalisait avec le nom de la
   page. À 60 px elle lui est clairement subordonnée, sans devenir une légende
   perdue au milieu d'un écran plein. Rapport mesuré : 0,63. */

/* La mention de bas de bloc traversait les 1313 px de la page, d'un bord à
   l'autre, en 13 px. Une ligne de texte ne se lit plus au-delà d'environ
   90 signes ; celle-ci en fait 137. */
.v3-chapter > .v3-inner > .v3-note:not(#_) {
  max-width: 64ch;
}

/* ===========================================================================
   Garde-fou anti-zone vide — Adam, 21/09 : « je veux un garde-fou ».

   Trois étages, décrits en tête de scripts/recette-20260921.js. Ce bloc est le
   premier : quand un chapitre publie un remplissage sous le budget, il reçoit
   data-vide et sa typographie respire d'un cran. Les bornes sont en svh autant
   qu'en vw, donc le corps ne peut jamais dépasser la hauteur de son écran —
   un garde-fou qui ferait déborder ne serait qu'un autre défaut.

   Ce qui vient de la recette de Farès reste au-dessus : les règles portées par
   un identifiant renforcé — le nom de la page, l'accroche de Références — sont
   plus prioritaires que celles-ci et ne bougent pas d'un pixel. Le garde-fou
   n'a le droit de remplir que ce que personne n'a demandé.
   =========================================================================== */
.v3-chapter[data-vide=fort] .v3-display:not(#_):not(#_) {
  font-size: min(9.6vw, 13.4svh, 156px);
}

.v3-chapter[data-vide=fort] .v3-cover:not(#_):not(#_) {
  font-size: min(8.2vw, 11.4svh, 136px);
}

.v3-chapter[data-vide=fort] .v3-lead:not(#_):not(#_) {
  font-size: clamp(18px, 2.7svh, 24px);
  max-width: 40ch;
}

.v3-chapter[data-vide=fort] > .v3-inner:not(#_) {
  gap: clamp(4px, 1svh, 12px);
}

/* --- Les scènes des pages intérieures -------------------------------------
   La toile se glisse en premier enfant du chapitre, derrière le texte. Le
   chapitre isole sa pile pour que la toile d'un écran ne passe jamais devant
   le texte du suivant pendant le glissement. Même traitement que la clôture de
   l'accueil, qui porte déjà ces deux règles dans v3-niveau.css. */
.v3-chapter[data-scene3d=actif] {
  isolation: isolate;
}

.v3-chapter[data-scene3d=actif] > .v3-inner:not(#_) {
  position: relative;
  z-index: 1;
}

/* ===========================================================================
   Les cartes de cas — Adam, 21/09 : « beaucoup trop de texte, ça doit être
   beaucoup plus imagé, largement plus, et plus design ».

   Rien n'est retiré du texte de Farès. C'est la hiérarchie qui manquait : un
   titre, deux surtitres et deux blocs de prose au même corps et à la même
   couleur, empilés sur une seule colonne. L'œil n'avait aucun point d'entrée,
   et trois cartes côte à côte faisaient un mur.
   =========================================================================== */

/* Le titre de la carte perd le « Cas 1 · » que le numéro dit désormais, et
   descend d'un cran : c'est le numéro qui accroche, pas lui. */
.v3-slide .v3-card > h3:not(#_) {
  font-size: clamp(18px, 1.5vw, 22px);
  line-height: 1.2;
  font-weight: 600;
  margin-bottom: 4px;
  max-width: 26ch;
}

/* Défi et réponse en vis-à-vis. Sur un écran large, deux colonnes : la carte
   perd la moitié de sa hauteur de texte, et la comparaison se lit d'un regard
   au lieu de se lire à la file. */
.r-duo {
  display: grid;
  gap: clamp(14px, 2vw, 26px);
  margin-top: clamp(12px, 1.8svh, 18px);
}

@media (min-width: 861px) {
  .r-duo { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.r-duo-part > p:not(.v3-kicker) {
  font-size: clamp(13.5px, .92vw, 14.5px);
  line-height: 1.5;
  max-width: 42ch;
  opacity: .88;
}

/* Le surtitre devient une étiquette sur filet : on voit le rôle avant de lire
   le texte. Le défi reste en retrait, la réponse prend la couleur de marque —
   la carte raconte alors un passage, pas deux paragraphes. */
.r-duo-part > .v3-kicker:not(#_) {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 11px;
  letter-spacing: .16em;
  margin-bottom: 8px;
  opacity: .72;
}

.r-duo-part > .v3-kicker::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: currentColor;
  opacity: .28;
}

.r-duo-part[data-role=reponse] > .v3-kicker:not(#_) {
  color: var(--n-cyan);
  opacity: 1;
}

.v3-chapter:not([data-theme=ink]) .r-duo-part[data-role=reponse] > .v3-kicker:not(#_) {
  color: var(--n-ink);
  opacity: .9;
}

.r-duo-part[data-role=reponse] > p:not(.v3-kicker) {
  opacity: 1;
}

/* Les étapes redeviennent une légende : plus petites, moins contrastées, en bas
   de carte. Elles disaient le déroulé avec le poids d'un titre. */
.v3-card .v3-chips:not(#_) {
  margin-top: clamp(14px, 2svh, 20px);
  gap: 6px;
}

.v3-card .v3-chips li:not(#_) {
  font-size: 10px;
  letter-spacing: .08em;
  padding: 5px 9px;
  opacity: .6;
}

/* La matière 3D en tête de carte, quand scenes-20260921.js l'a posée. La
   hauteur vient de .v3-scene3d, déjà définie dans v3-niveau.css pour les
   cartes de l'accueil : même objet, même mesure. */
.v3-card > .v3-scene3d:not(#_) {
  margin-bottom: clamp(8px, 1.4svh, 16px);
}

/* --- La matière en bande, à hauteur du numéro -----------------------------
   Empilée au-dessus du texte, la scène ajoutait 225 px à une carte qui n'avait
   pas 100 px de marge : le chapitre passait de 806 à 1 334 px, soit une fois et
   demie son écran, et la moitié de la carte tombait sous le pli. En bande, à
   côté du chiffre, elle occupe une hauteur que la carte avait déjà. */
.r-cas-tete {
  display: flex;
  align-items: flex-end;
  gap: clamp(10px, 1.4vw, 18px);
  margin-bottom: 6px;
}

.r-cas-tete > .v3-scene3d:not(#_) {
  /* La matière se cale à gauche, sur le même axe que le titre et le texte.
     Étalée sur toute la largeur de la carte, elle flottait au milieu de rien. */
  flex: 0 0 auto;
  width: min(52%, 220px);
  height: clamp(64px, 8.4svh, 94px);
  margin: 0;
}


/* --- Les chiffres clés respirent aussi ------------------------------------
   Le garde-fou a relevé l'écran « Quelques chiffres » de l'accueil à 39 % de
   remplissage sur téléphone, 44 % sur ordinateur : quatre nombres compacts au
   milieu d'un écran de cyan. C'est le seul chapitre du site que le garde-fou
   refusait, et il avait raison. Les nombres sont ce que cet écran a à montrer :
   c'est donc à eux de prendre la place, pas à un remplissage quelconque. */
.v3-chapter[data-vide=fort] .v3-stat-valeur:not(#_) {
  font-size: min(16.5vw, 15svh, 152px);
  line-height: .92;
}

/* Desserrer l'interlettrage des titres a reduit leur hauteur, et l'ecran des
   chiffres cles est repasse sous le budget de remplissage. Le garde-fou l'a
   arrete avant la publication. Les chiffres prennent un cran de plus. */
.v3-chapter.v3-chiffres:not(#_) .v3-stats {
  gap: clamp(22px, 4svh, 54px);
}

.v3-chapter[data-vide=fort] .v3-stat-label:not(#_) {
  font-size: clamp(11px, 1.5svh, 14px);
}

.v3-chapter[data-vide=fort] .v3-stats:not(#_) {
  gap: clamp(18px, 3.4svh, 46px);
}

/* --- La clôture ne dépend pas de WebGL pour tenir son écran ----------------
   Le garde-fou a bloqué la publication du 21/09 sur les clôtures d'À propos et
   de Contact : 23 % à 44 % de remplissage. La scène de clôture les occupe bien,
   mais un écran qui n'est plein que si le rendu 3D démarre est un écran vide
   avec de la chance. Le titre de clôture prend donc la place par lui-même, et
   la matière vient par-dessus. */
.v3-cta[data-vide=fort] .v3-display:not(#_):not(#_) {
  /* Le facteur en vw était trop bas pour un téléphone : 11 vw plafonnaient le
     titre à 45 px sur 412 de large, et la clôture restait à un quart de son
     écran. Une clôture ne porte que trois mots : elle peut les prendre en
     grand. La borne en svh, elle, garantit qu'ils tiennent en hauteur. */
  font-size: min(19.5vw, 17svh, 176px);
  line-height: .94;
  max-width: 12ch;
}

.v3-cta[data-vide=fort] .v3-label:not(#_) {
  font-size: clamp(13px, 1.8svh, 16px);
  margin-bottom: clamp(14px, 2.4svh, 26px);
}

.v3-cta[data-vide=fort] .v3-button:not(#_) {
  margin-top: clamp(36px, 6.6svh, 74px);
}

/* ===========================================================================
   Fluidité — audit du 22/09, Pixel 7 avec processeur ralenti.

   Deux propriétés coûtent cher et étaient posées sur tous les chapitres en
   permanence : will-change, qui demande au navigateur de garder un calque
   séparé prêt à l'emploi, et filter: blur(), qui l'oblige à recomposer ce
   calque hors écran à chaque image. Sur un téléphone, chaque calque plein
   écran pèse environ 2,3 millions de pixels ; six chapitres en réservaient
   six, en permanence, qu'ils soient visibles ou non.

   v3-niveau.js marque désormais d'un attribut les seuls chapitres réellement
   animés, ceux qui sont à portée de l'écran. Les deux propriétés ne coûtent
   plus que là. Le glissement, lui, ne change pas d'un pixel : la transformation
   reste posée sur tous les chapitres, c'est elle qui fait l'effet.
   =========================================================================== */
.v3-chapter > .v3-inner:not(#_) {
  will-change: auto;
  filter: none;
}

.v3-chapter[data-anime=oui] > .v3-inner:not(#_) {
  will-change: transform;
  filter: blur(var(--n-blur, 0px));
}

/* ===========================================================================
   Alignement sur les standards des meilleurs sites produit.
   Référence mesurée : le système d'Apple, relevé sur refero.design le 22/09.

   Trois écarts, chiffrés. Ce ne sont pas des impressions.
   =========================================================================== */

/* --- 1. L'interlettrage des titres était trois fois trop serré -------------
   Apple pose son titre de 80 px à -1,2 px, soit -0,015 em, et documente la
   raison : « rend le plus grand corps compact plutôt que promotionnel ».
   Echoes posait -0,05 em, soit -4,25 px à 85 px. Trois fois plus serré que la
   référence. Un titre trop chassé se lit comme un logo, pas comme une phrase,
   et c'est une des signatures d'un site qui en fait trop.

   On desserre sans aller jusqu'à la valeur d'Apple : le caractère du site
   tient en partie à cette densité. -0,025 em est le milieu, et il reste
   nettement plus serré qu'un réglage par défaut. */
.v3-display:not(#_):not(#_),
.v3-cover:not(#_):not(#_) {
  letter-spacing: -.025em;
}

/* --- 2. Le corps de texte était sous le plancher ---------------------------
   Apple ne descend jamais sous 17 px pour un paragraphe, et pose 1,47
   d'interligne sur son corps de 20 px. Echoes était à 16 px sur ordinateur et
   15 px dans les cartes. Un point de corps ne se remarque pas ; dix minutes de
   lecture, si. */
.v3-slide p:not(#_),
.v3-card p:not(.v3-kicker):not(#_),
.r-duo-part > p:not(.v3-kicker):not(#_) {
  font-size: clamp(15.5px, 1.05vw, 17px);
  line-height: 1.5;
}

/* --- 3. Trente signes par ligne --------------------------------------------
   Mesuré sur les cartes de cas : trente signes par ligne. La fourchette
   admise, d'Apple à n'importe quel manuel de typographie, est de 45 à 75, avec
   un optimum autour de 66. À trente, l'œil change de ligne toutes les quatre
   ou cinq mots et la lecture devient hachée.

   La cause est ma mise en vis-à-vis du défi et de la réponse : elle divise par
   deux la largeur disponible dans une carte qui ne fait déjà que 490 px. Le
   vis-à-vis ne se déclenche donc plus que si la carte est assez large pour le
   porter, mesurée par une requête de conteneur plutôt que par la largeur de la
   fenêtre — c'est la carte qui compte, pas l'écran. */
.v3-card {
  container-type: inline-size;
}

@media (min-width: 861px) {
  .r-duo:not(#_) { grid-template-columns: minmax(0, 1fr); }
}

@container (min-width: 620px) {
  .r-duo:not(#_) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --- Les chiffres clés, sans dépendre d'un attribut ------------------------
   Cet écran ne porte que quatre nombres. Les faire dépendre du garde-fou, qui
   se déclenche après mesure, les laissait à 48 px dans un écran de 900 : 45,6 %
   de remplissage, juste sous le budget, et un écran qui ne montre pas ce qu'il
   a à montrer. Ils prennent la place directement.

   La borne en svh garantit que les quatre tiennent en hauteur quel que soit
   l'écran, et le garde-fou de publication le vérifie sur trois largeurs. */
.v3-chiffres .v3-stat-valeur:not(#_):not(#_) {
  font-size: min(9vw, 12svh, 104px);
  line-height: .94;
}

.v3-chiffres .v3-stat-label:not(#_) {
  font-size: clamp(11px, 1.4svh, 13px);
}

/* Quatre nombres alignés sur une seule rangée occupaient 161 px de haut, quelle
   que soit leur taille : un bandeau mince au milieu d'un écran de 900. En deux
   rangées de deux, chaque nombre a la place de se lire, et l'écran montre enfin
   ce qu'il a à montrer. Sur téléphone la colonne unique reste la seule lisible. */
@media (min-width: 861px) {
  .v3-chiffres .v3-stats:not(#_) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(26px, 5svh, 64px) clamp(32px, 4vw, 80px);
  }
}

@media (max-width: 860px) {
  .v3-chiffres .v3-stats:not(#_) {
    gap: clamp(20px, 3.4svh, 40px);
  }
  .v3-chiffres .v3-stat-valeur:not(#_):not(#_) {
    font-size: min(17vw, 9.5svh, 84px);
  }
}

/* ===========================================================================
   Le premier écran : un sujet, et de la profondeur.

   Adam, 22/09 : « l'écran est tellement faible, tout à gauche, sans relief ».
   Deux défauts distincts, et deux corrections distinctes.

   Le sujet manque : c'est scenes-20260921.js qui le pose, la matière de la
   page dans la moitié que le texte laisse libre.

   Le relief manque : un aplat n'a pas de relief, par définition. Une source de
   lumière est posée derrière le sujet, dans les couleurs de la marque, et le
   bas de l'écran s'assombrit légèrement. Rien d'autre : ni ombre portée, ni
   dégradé décoratif. Apple documente d'ailleurs l'inverse comme une faute —
   « ne pas ajouter de dégradés, l'image produit fournit la couleur et la
   profondeur de la page ». Ici la matière joue le rôle de l'image produit, et
   la lumière ne fait que l'asseoir.
   =========================================================================== */
main > .v3-chapter:first-child[data-theme=ink] {
  position: sticky;                       /* deja pose par v3-niveau.css */
  isolation: isolate;
}

main > .v3-chapter:first-child[data-theme=ink]::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(58% 52% at 74% 40%, rgba(72, 185, 206, .16), transparent 70%),
    radial-gradient(42% 40% at 88% 66%, rgba(239, 184, 196, .10), transparent 72%),
    linear-gradient(to bottom, transparent 55%, rgba(13, 27, 38, .34));
}

main > .v3-chapter:first-child[data-theme=ink] > .v3-inner {
  position: relative;
  z-index: 2;
}

/* Sur un écran large, le texte cesse de s'étaler : il tient sa colonne, et la
   moitié droite appartient à la matière. Une accroche qui court sur toute la
   largeur ne laisse aucune place à un sujet. */
/* Sur un ecran large, le texte tient une colonne et la moitie droite appartient
   a la matiere. C'est le bloc entier qui est borne, pas chaque paragraphe :
   borner les titres un par un les faisait casser en quatre lignes, et le
   conteneur restait pleine largeur, si bien que la scene se retrouvait
   coincee dans une bande de 86 px au bord droit. Mesure a l'appui, 22/09. */
@media (min-width: 861px) {
  main > .v3-chapter:first-child:has(.r-heros-matiere) > .v3-inner:not(#_) {
    max-width: min(56%, 720px);
  }
}

/* L'emplacement de la matière du premier écran.

   Il brille de lui-même : sans carte graphique, la moitié droite garde une
   source de lumière et un cercle de matière sourde, donc une composition. Avec
   la carte, l'objet vient s'asseoir dedans et la lumière devient son halo.
   C'est la règle du fichier CLAUDE.md : tout vide est revendiqué, et ce qui le
   revendique ne doit pas dépendre de WebGL. */
main > .v3-chapter:first-child .r-heros-matiere:not(#_):not(#_) {
  position: absolute;
  z-index: 1;
  pointer-events: none;
  aspect-ratio: auto;
  /* Sur téléphone, la matière prend la bande libre du haut. Posée en bas, elle
     passait derrière le bouton d'appel, coupée en deux : mesuré et vu le
     22/09. La bande haute ne porte rien, elle est là pour le centrage, et un
     sujet y est chez lui. */
  left: 22vw; right: -8vw; top: 5svh;
  height: 22svh;
  background:
    radial-gradient(50% 48% at 46% 50%, rgba(72, 185, 206, .42), transparent 68%),
    radial-gradient(32% 30% at 68% 62%, rgba(239, 184, 196, .30), transparent 70%);
  filter: blur(10px);
}

@media (min-width: 861px) {
  main > .v3-chapter:first-child .r-heros-matiere:not(#_):not(#_) {
    left: auto; right: 2vw; top: 10%; bottom: 10%;
    width: min(40%, 620px); height: auto;
    background:
      radial-gradient(44% 40% at 52% 48%, rgba(72, 185, 206, .28), transparent 66%),
      radial-gradient(28% 26% at 66% 64%, rgba(239, 184, 196, .20), transparent 70%);
  }
}

/* Quand la matière tourne, le halo s'efface derrière elle : il était le
   remplaçant, pas un décor à superposer. */
main > .v3-chapter:first-child[data-scene3d=actif] .r-heros-matiere:not(#_):not(#_) {
  background: none;
  filter: none;
}

/* ===========================================================================
   PLANCHER DE CORPS
   ---------------------------------------------------------------------------
   Mesuré, pas supposé : la vérification de tenue relève chaque texte dont le
   corps passe sous le plancher, et voici les familles qu'elle a nommées le
   22/09. Quinze pixels pour ce qui se lit en continu, douze et demi pour ce
   qui se repère. En dessous, le texte n'est pas discret, il est illisible sur
   un portable tenu à bout de bras, et Farès l'avait déjà relevé cinq fois dans
   son cahier sur d'autres éléments.

   L'opacité des pastilles remonte à un, dans le même mouvement : un texte de
   douze pixels à quatre-vingt-cinq pour cent d'opacité perd le contraste que
   sa taille lui rendait déjà difficile à tenir.
   =========================================================================== */
.v3-chips li:not(#_):not(#_) { font-size: 12.5px; opacity: 1; }
.v3-note:not(#_):not(#_),
.ai-evidence-note:not(#_):not(#_),
.ai-human-note:not(#_):not(#_),
.map-consent-note:not(#_):not(#_) { font-size: 15px; line-height: 1.6; }
.ai-data-table:not(#_):not(#_) { font-size: 15px; }
.ai-demo-about p:not(#_):not(#_),
.ai-check span:not(#_):not(#_),
.consent-label span:not(#_):not(#_) { font-size: 15px; }
.r-duo-part > .v3-kicker:not(#_):not(#_),
.eyebrow:not(#_):not(#_),
.optional:not(#_):not(#_),
.ai-demo-marker > span:not(#_):not(#_) { font-size: 12.5px; }

/* La cible du consentement cartographique mesurait vingt-trois pixels de haut.
   Le critère 2.5.8 des règles d'accessibilité en demande vingt-quatre. */
.map-consent button:not(#_):not(#_),
[class*=consent] button:not(#_):not(#_) { min-height: 26px; }

/* Deux cibles mesuraient vingt-trois pixels au rendu, pour vingt-quatre
   demandés : la règle existait, la valeur arrivait arrondie sous le seuil.
   On ne joue pas à un pixel près avec un critère d'accessibilité. */
.locations-grid article button.text-link:not(#_):not(#_) { min-height: 26px; }
.consent-label input[type=checkbox]:not(#_):not(#_),
#agents .ai-check input[type=checkbox]:not(#_):not(#_) {
  width: 26px; height: 26px; flex: 0 0 26px;
}

/* ===========================================================================
   PLANCHER DE CORPS, SUITE : CE QUE MON PROPRE SURSIS AVAIT TU
   ---------------------------------------------------------------------------
   Le 22/09 au matin, j'ai mis toute la famille des textes trop petits en
   sursis, d'un seul geste, pour débloquer la publication. La relecture de la
   démonstration Agents IA a ensuite trouvé des titres composés à 8,7 px sur
   téléphone. Le garde-fou les avait bien vus : c'est mon fourre-tout qui les
   taisait.

   Le sursis ne couvre plus que la zone grise, de douze à quinze pixels. En
   dessous de douze, il n'y a pas de zone grise, et voici les familles que le
   garde-fou refuse désormais de laisser passer.
   =========================================================================== */

/* Titres des feuilles de cas. La règle d'origine se cale sur la largeur et la
   hauteur de l'écran sans plancher : à 412 px, min(2.1vw, 3.4svh, 32px) vaut
   8,65 px. Un titre de huit pixels et demi n'est pas un titre. Le plancher
   entre dans le calcul, la souplesse reste. */
.v3-cas .ai-desk h3:not(#_):not(#_) {
  font-size: max(15px, min(2.1vw, 3.4svh, 32px));
  line-height: 1.14;
}

/* Intitulés et mentions du théâtre d'agent, composés entre 10,5 et 11 px. */
.v3-agent .ea-agent-caption:not(#_):not(#_),
.v3-agent .ea-sheet-label:not(#_):not(#_),
.v3-agent .ea-foot > p:not(#_):not(#_) { font-size: 12.5px; }
.v3-agent .ea-support:not(#_):not(#_) { font-size: 15px; }

/* Intitulés des chiffres clés, mention du formulaire, marqueurs de la
   démonstration. Même plancher, même raison. */
.v3-stat-label:not(#_):not(#_),
#contact-form .eyebrow:not(#_):not(#_),
.field .optional:not(#_):not(#_),
.ai-chapter-marker > span:not(#_):not(#_),
.ai-demo-marker > span:not(#_):not(#_),
.ai-eyebrow:not(#_):not(#_),
#agents .ai-small-status:not(#_):not(#_),
#agents .ai-editor-label:not(#_):not(#_),
#agents .ai-panel-feedback:not(#_):not(#_),
#agents .ai-source-links a:not(#_):not(#_) { font-size: 12.5px; }
.ai-demo-note:not(#_):not(#_) { font-size: 12.5px; line-height: 1.6; }

/* Références : le titre et son appui forment un seul bloc, sans tête étirée
   qui repousse la campagne sous un demi-écran vide sur téléphone. */
.v3-etude .v3-inner:not(#_):not(#_) { justify-content:center; gap:28px; }
.v3-etude .v3-head:not(#_):not(#_) { flex:0 0 auto; margin:0; }
.v3-etude .v3-media:not(#_):not(#_) { flex:0 0 auto; width:100%; margin:0; }
.v3-etude .v3-media a { display:block; }
.v3-etude .v3-media img:not(#_):not(#_) { width:100%; height:clamp(260px,43svh,520px); object-fit:cover; }
.v3-etude .v3-note:not(#_):not(#_) { margin:0; }
@media(max-width:860px) {
 .v3-etude .v3-head:not(#_):not(#_) { gap:24px; }
 .v3-etude .v3-media img:not(#_):not(#_) { height:clamp(240px,40svh,390px); object-position:48% center; }
}
