/* Identite Balbuzard — feuille partagee par les 5 pages. 2026-08-06.

   1-BIT : papier blanc pur, encre noire pure, zero rayon, zero ombre,
   zero materiau translucide. Les gris de surface n'existent plus : la
   profondeur se fait par le filet noir 1px, le vide, ou l'inversion
   (bloc encre). La marque est un balbuzard trame en cellules carrees
   dont la densite EST le score mesure (voir facade/#marque et .oiseau).

   DEUX VOIX, chacune avec un travail unique :
     --sans   SF / Inter   la marque, les titres, l'interface.
     --mono   SF Mono      UNIQUEMENT ce que la machine a mesure.

   Le mono ne sert plus a decorer une etiquette. S'il n'y a pas un nombre
   releve derriere, ce n'est pas la voix de la machine.

   Contrastes calcules, pas estimes (recalcules le 2026-08-08) :
     encre        sur papier  21.00:1
     gris         sur papier   5.07:1  texte ok
     gris-clair   sur encre    8.16:1  le gris change de valeur sur fond fonce
     rouge erreur sur papier   6.54:1  texte ok
     orange       sur papier   3.79:1  sous le seuil texte de 4.5:1 — assume, voir --orange
     orange       sur encre    5.54:1  texte ok */

:root{
  --fond:#FFFFFF;
  --blanc:#FFFFFF;
  --encre:#000000;
  --gris:#6E6E73;
  --gris-sur-fonce:#A1A1A6;
  /* UN SEUL orange, le vif, partout — decision de Joseph le 2026-08-09.
     Un --orange-texte assombri (#C54C09) a existe du 2026-08-08 au
     2026-08-09 pour tenir 4.5:1 sur papier ; a l'oeil il tirait sur le
     brun, et Joseph a tranche pour la teinte de marque. Cout connu et
     assume : 3.79:1 sur blanc, sous le seuil texte (SC 1.4.3) mais
     au-dessus du seuil graphique (3:1) — axe le signalera sur .fleche,
     .lien et .pilule, c'est un choix d'identite, pas un oubli. Pour
     revenir en arriere : retablir #C54C09 sur .fleche, .lien, .pilule et
     .rangee--vous b, plus un override .tuile--fonce{color:var(--orange)}
     sur .fleche et .lien, car l'assombri echoue (4.41:1) sur l'encre. */
  --orange:#E0570B;
  --piste:rgba(0,0,0,.16);
  --piste-fonce:rgba(255,255,255,.24);
  --filet:#000000;

  --sans:-apple-system,BlinkMacSystemFont,"Inter","Segoe UI",system-ui,sans-serif;
  --mono:ui-monospace,"SF Mono",SFMono-Regular,Menlo,Consolas,monospace;

  --erreur:#B3261E;

  /* Echelle d'espacement, sous-grille de 2pt assumee. Elle existait deja
     dans les faits (2, 6, 10, 14, 18px) mais n'etait nommee nulle part :
     les valeurs etaient subies, pas choisies. J'avais meme affirme a
     l'audit du 2026-08-08 que tout etait sur 4pt — c'etait faux, ma propre
     sortie de controle listait ces valeurs. Nommer l'echelle en fait une
     decision, et empeche la prochaine valeur inventee. */
  --e-1:.125rem;   /*  2px  liseres, decalages optiques */
  --e-2:.25rem;    /*  4px  */
  --e-3:.375rem;   /*  6px  */
  --e-4:.5rem;     /*  8px  */
  --e-5:.625rem;   /* 10px  */
  --e-6:.75rem;    /* 12px  */
  --e-7:.875rem;   /* 14px  */
  --e-8:1rem;      /* 16px  */
  --e-9:1.125rem;  /* 18px  */
  --e-10:1.25rem;  /* 20px  */
  --e-11:1.5rem;   /* 24px  */
  --e-12:1.75rem;  /* 28px  */
  --e-13:2rem;     /* 32px  */

  --r-s:0;
  --r-m:0;
  --r-l:0;
  --pilule:0;

  --marge:clamp(1.25rem,5vw,2.75rem);
  --souffle:clamp(4.5rem,11vh,8rem);

  /* TROIS courbes, une par registre de mouvement. Il n'y en avait qu'une,
     --ressort, appliquee aussi bien a une entree qu'a un chevron qui glisse
     de 3px au survol : la courbe iOS est juste pour la premiere, trop
     appuyee pour le second.
       --ressort  entrees et sorties, ce qui arrive ou s'en va
       --sortie   ease-out fort, pour ce qui se pose a l'ecran
       --doux     survol et changement de couleur, ou l'oeil ne suit rien */
  --ressort:cubic-bezier(.32,.72,0,1);
  --sortie:cubic-bezier(.23,1,.32,1);
  --doux:ease;
}

*,*::before,*::after{box-sizing:border-box}
/* color-scheme verrouille le chrome du navigateur (barres de defilement,
   controles de formulaire natifs) sur le clair : le papier blanc est un
   choix d'identite, pas un defaut qu'un theme systeme peut renverser. */
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;color-scheme:light}
body{
  margin:0;
  background:var(--fond);
  color:var(--encre);
  font-family:var(--sans);
  font-size:1.0625rem;
  line-height:1.5;
  -webkit-font-smoothing:antialiased;
  /* clip coupe le debordement sans faire du body un conteneur de defilement,
     ce qui casserait les position:sticky (nav et recit). hidden reste en
     secours pour les navigateurs sans clip. */
  overflow-x:hidden;
  overflow-x:clip;
}
img,svg{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
/* Anneau de focus : ENCRE, pas orange. L'orange vire au brun fonce en
   protanopie et devient indistinguable du noir ambiant ; le contour doit
   se voir par sa forme et son epaisseur, jamais par sa seule teinte.
   Pas de rayon : le systeme est a zero partout. */
:focus-visible{outline:2px solid var(--encre);outline-offset:3px}

/* Lien d'evitement : invisible jusqu'au premier Tab, puis par-dessus la nav. */
.saut{
  position:absolute;left:-9999px;top:0;z-index:60;
  background:var(--encre);color:var(--blanc);
  padding:var(--e-6) var(--e-10);font-size:.9375rem;
}
.saut:focus{left:0}

/* ---------- Barre de navigation : papier opaque, filet au defilement ----------
   Le materiau translucide flou de l'ancienne identite est incompatible
   avec le 1-bit : opaque, blanc, un filet noir quand le contenu passe. */
.nav{
  position:sticky;top:0;z-index:40;
  display:flex;align-items:center;justify-content:space-between;gap:var(--e-8);
  padding:var(--e-3) var(--marge);
  background:var(--blanc);
}
/* Filet en pseudo-element anime en opacite : box-shadow se peint hors GPU,
   et ce declencheur est lie au defilement. */
.nav::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:var(--filet);opacity:0;transition:opacity .25s ease;
}
.nav.pose::after{opacity:1}
/* Le remplissage vertical sert l'aire tactile, pas l'apparence. */
.nav-marque{display:flex;align-items:center;gap:var(--e-4);flex:0 0 auto;padding:var(--e-4) 0}
.nav-marque svg{width:26px;color:var(--encre)}
.nav-marque b{font-weight:500;font-size:1rem;letter-spacing:-.015em;line-height:1}
/* wrap : a 320px — la largeur de reference du SC 1.4.10 Reflow — les cinq
   liens totalisent 341px et le dernier (« Contact ») etait coupe par le
   overflow-x:clip du body, donc invisible ET inatteignable. Le retour a la
   ligne rend tout accessible sans descendre la police sous 12px. */
.nav-liens{
  display:flex;align-items:center;flex-wrap:wrap;justify-content:flex-end;
  gap:clamp(.85rem,2.4vw,1.7rem);
}
/* min-height plutot qu'un rembourrage calcule : la hauteur d'une ligne varie
   avec la fonte reelle du systeme, donc un padding ajuste a l'oeil donnait
   38px sur telephone (mesure) au lieu des 44 vises. 44px est le minimum
   d'iOS et le seuil du SC 2.5.5 ; le SC 2.5.8 de WCAG 2.2 n'en demande que
   24, mais un lien de barre se tape au pouce. */
.nav-liens a{
  font-size:.8125rem;color:var(--gris);
  transition:color .2s ease;white-space:nowrap;
  display:inline-flex;align-items:center;min-height:44px;
}
.nav-liens a[aria-current="page"]{color:var(--encre)}
/* A cinq liens, le mot-symbole et la nav ne tiennent plus cote a cote sous
   ~416px. On garde la marque graphique et on laisse tomber le mot, comme
   Apple le fait sur telephone. */
@media (max-width:26rem){
  .nav-marque b{display:none}
  .nav-liens{gap:var(--e-4)}
  /* 12px est le plancher pour la police : on ne descend pas plus bas, on
     laisse la barre wrapper. La cible tactile, elle, reste a 44px. */
  .nav-liens a{font-size:.75rem}
}
@media (hover:hover) and (pointer:fine){
  .nav-liens a:hover{color:var(--encre)}
}

/* ---------- Tuiles ---------- */
.tuile{padding:var(--souffle) var(--marge);text-align:center}
/* Les surfaces empilees delimitaient les sections ; en 1-bit tout est
   papier, c'est le filet qui reprend ce travail. */
main>section+section{border-top:1px solid var(--encre)}
.tuile--fonce{background:var(--encre);color:var(--blanc)}
.tuile--blanche{background:var(--blanc)}
.dedans{max-width:56rem;margin:0 auto}
.dedans--large{max-width:70rem;margin:0 auto}

/* ---------- Voile de chargement : l'oiseau, puis la page blanchit ----------
   Le voile est entierement construit en JS (voir script.js). Il n'existe donc
   pas dans le HTML : sans JS, en mouvement reduit, ou si le script echoue, le
   visiteur ne voit jamais un ecran noir qui ne part pas. C'est la seule
   facon sure de poser un voile par-dessus une page — le contenu, lui, est
   deja la, dans le DOM, lisible par les robots et les lecteurs d'ecran.

   La toile est a la resolution de la grille et etiree ici : pixelated garde
   chaque cellule carree et nette. Pas de transition de sortie : la
   dissolution pixel par pixel EST la sortie, et elle se termine sur un ecran
   entierement blanc, identique au papier de la page en dessous. */
.voile{
  position:fixed;inset:0;z-index:100;background:var(--blanc);
  transition:opacity .26s var(--ressort);
}
.voile canvas{
  display:block;width:100%;height:100%;
  image-rendering:pixelated;image-rendering:crisp-edges;
}
/* La sequence finit sur un ecran noir plein ; le fondu evite le saut vers
   le papier de la page. Duree calee sur SORTIE dans script.js. */
.voile[data-parti]{opacity:0;pointer-events:none}

/* Signature de marque du heros : le visiteur doit savoir qui parle avant
   de lire le probleme. */
.lockup{display:flex;align-items:center;justify-content:center;gap:var(--e-5);margin-bottom:var(--e-10)}
.lockup svg{width:48px;height:auto;color:var(--encre)}
.lockup b{font-size:1.5rem;font-weight:500;letter-spacing:-.02em;line-height:1}

/* ---------- Voix 1 : la marque et l'interface.
   Le crenage suit la taille : serre en grand, neutre en corps de texte. */
.geant{
  font-size:clamp(2.75rem,7.2vw,4.75rem);
  font-weight:500;line-height:1.05;letter-spacing:-.035em;
  margin:0;text-wrap:balance;
}
.grand{
  font-size:clamp(2.05rem,4.8vw,3.1rem);
  font-weight:500;line-height:1.08;letter-spacing:-.028em;
  margin:0;text-wrap:balance;
}
.sous{
  font-size:clamp(1.0625rem,1.5vw,1.3125rem);
  font-weight:400;line-height:1.42;letter-spacing:-.008em;
  color:var(--gris);max-width:34ch;margin:var(--e-8) auto 0;
  text-wrap:balance;
}
.tuile--fonce .sous{color:var(--gris-sur-fonce)}
.micro{
  font-size:.8125rem;letter-spacing:.01em;
  color:var(--gris);margin:0 0 var(--e-7);
}
.tuile--fonce .micro{color:var(--gris-sur-fonce)}
.mention{
  font-size:.8125rem;line-height:1.5;color:var(--gris);margin:var(--e-8) 0 0;
}
.tuile--fonce .mention{color:var(--gris-sur-fonce)}

/* ---------- Voix 3 : la machine. Uniquement des valeurs relevees. ---------- */
.lecture{
  font-family:var(--mono);font-weight:400;
  font-size:clamp(2.4rem,6vw,3.6rem);letter-spacing:-.02em;line-height:1;
  margin:var(--e-7) 0 0;color:var(--orange);
}
.lecture--nulle{color:var(--piste)}
.tuile--fonce .lecture--nulle{color:var(--piste-fonce)}
.unite{font-family:var(--mono);font-size:.75rem;letter-spacing:.05em;color:var(--gris);margin:var(--e-4) 0 0}
.tuile--fonce .unite{color:var(--gris-sur-fonce)}

/* ---------- Liens et boutons ---------- */
.actions{display:flex;flex-wrap:wrap;gap:var(--e-11);justify-content:center;margin-top:var(--e-12)}
.fleche{
  font-size:1.0625rem;color:var(--orange);letter-spacing:-.006em;
  display:inline-flex;align-items:center;gap:var(--e-2);padding:var(--e-3) 0;
}
.fleche::after{content:"\203A";font-size:1.2em;line-height:1;transition:transform .18s var(--doux)}
@media (hover:hover) and (pointer:fine){
  .fleche:hover::after{transform:translateX(3px)}
}
/* Lien dans le fil d'une phrase : souligne, jamais une fleche ni un flex,
   qui casseraient la ligne de texte. */
.lien{color:var(--orange);text-decoration:underline;text-underline-offset:.18em}

.pilule{
  display:inline-block;padding:var(--e-6) var(--e-11);border-radius:var(--pilule);
  background:var(--orange);color:var(--blanc);font-size:1rem;font-weight:500;
  letter-spacing:-.006em;border:0;cursor:pointer;font-family:var(--sans);
  /* transform pour la pression, background pour le survol : deux proprietes
     nommees, jamais `all`. La pression est plus courte que le survol —
     le systeme repond vite, l'oeil suit lentement. */
  transition:transform .1s var(--sortie),background-color .2s var(--doux),opacity .2s var(--doux);
}
.pilule:active{transform:scale(.97)}
/* Survol par INVERSION, pas par eclaircissement. brightness(1.08) etait un
   reste de l'ancienne identite : tout le systeme 1-bit signale le survol en
   inversant ou en cernant, jamais en changeant la luminosite d'un aplat. */
@media (hover:hover) and (pointer:fine){
  .pilule:hover{background-color:var(--encre)}
}

/* ---------- L'instrument ---------- */
.instrument{width:min(300px,66vw);margin:clamp(2.4rem,6vh,3.8rem) auto 0}
.instrument svg{width:100%;height:auto}

/* ---------- Le recit au defilement : la conversation d'IA ----------
   Section haute, panneau colle au centre. Le defilement revele les repliques
   une a une, dans les deux sens (frotte, donc interruptible par nature).
   Sans JS ou en mouvement reduit : tout est visible, hauteur normale. */
.recit{position:relative;background:var(--blanc)}
/* svh : stable quand la barre d'adresse mobile se retracte, sinon les seuils
   du recit glissent pendant la lecture. vh en secours. */
.js .recit{height:340vh;height:340svh}
.recit-colle{padding:var(--souffle) var(--marge);text-align:center}
.js .recit-colle{
  position:sticky;top:0;min-height:100vh;min-height:100svh;padding-top:0;padding-bottom:0;
  display:flex;align-items:center;justify-content:center;
}
.convo{max-width:32rem;margin:0 auto;display:flex;flex-direction:column;gap:var(--e-7);text-align:left}
/* Qui parle dans la scene. La bulle seule ne suffisait pas : il faut lire
   « c'est une IA qui repond » sans aucun contexte prealable. */
.convo-qui{
  font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;
  /* Marge NEGATIVE volontaire : l'etiquette « qui parle » doit se coller a
     sa bulle, pas flotter au-dessus. Seule valeur negative de la feuille. */
  color:var(--gris);margin:0 0 calc(-1 * var(--e-4));align-self:flex-start;
  display:flex;align-items:center;gap:var(--e-4);
}
.convo-qui--client{align-self:flex-end}
/* Trois pulsations, pas l'infini. La puce dit « l'IA repond » : trois
   battements suffisent a le dire, alors qu'une boucle sans fin tourne
   pendant toute la lecture du recit et vole l'attention aux repliques.
   forwards fige l'etat final, sinon elle ressauterait a plein. */
.puce-ia{
  width:.5rem;height:.5rem;border-radius:50%;background:var(--orange);
  animation:puise 2.4s ease-in-out 3 forwards;
}
@keyframes puise{50%{opacity:.35}}
/* L'animation demarre au chargement de la page, mais la bulle n'apparait
   qu'apres plusieurs ecrans de defilement : sans ce garde, les trois
   pulsations sont finies avant d'etre vues. On la met en pause tant que la
   replique n'est pas revelee ; play-state (et non un redemarrage) fait que
   remonter/redescendre ne rejoue pas les trois cycles. */
.js .recit .puce-ia{animation-play-state:paused}
.js .recit .pas.vu .puce-ia{animation-play-state:running}
.bulle{padding:var(--e-8) var(--e-10);border-radius:var(--r-m);font-size:1.0625rem;line-height:1.5}
.bulle--client{
  background:var(--encre);color:var(--blanc);
  align-self:flex-end;max-width:88%;
}
.bulle--ia{
  background:var(--blanc);border:1px solid var(--encre);align-self:flex-start;
  max-width:94%;
}
.bulle--ia p{margin:0}
.reponses{list-style:none;margin:var(--e-6) 0 0;padding:0}
.reponses li{display:flex;align-items:center;gap:var(--e-6);padding:var(--e-4) 0}
.reponses li + li{border-top:1px solid var(--filet)}
.reponses i{font-style:normal;color:var(--gris);font-size:.875rem;min-width:1.1rem}
.masque-nom{display:inline-block;height:.8em;width:11ch;border-radius:var(--pilule);background:var(--piste)}
.absent{
  border:1.5px dashed var(--orange);border-radius:var(--r-m);
  padding:var(--e-7) var(--e-9);font-weight:500;text-align:center;
}
.recit-punch{
  font-size:clamp(1.0625rem,1.5vw,1.3125rem);line-height:1.42;
  max-width:34ch;margin:var(--e-12) auto 0;color:var(--encre);font-weight:500;
  text-wrap:balance;
}
/* Meme courbe et meme duree que .surgit : les deux sont la meme revelation
   au defilement, elles ne doivent pas diverger. */
.js .recit .pas{opacity:0;transform:translateY(14px);transition:opacity .45s var(--sortie),transform .45s var(--sortie)}
.recit .pas.vu{opacity:1;transform:none}

/* Punch du pont : meme registre que le recit */
.pont-punch{
  font-size:clamp(1.0625rem,1.5vw,1.3125rem);line-height:1.42;font-weight:500;
  max-width:34ch;margin:var(--e-11) auto 0;text-wrap:balance;
}

/* ---------- Cartes ---------- */
.cartes{
  display:grid;gap:clamp(.9rem,2vw,1.4rem);
  grid-template-columns:repeat(auto-fit,minmax(17rem,1fr));
  margin-top:clamp(2.4rem,5vh,3.4rem);text-align:left;
}
.carte{
  background:var(--blanc);border:1px solid var(--encre);
  padding:clamp(1.6rem,3vw,2.2rem);
  display:flex;flex-direction:column;gap:var(--e-4);
}
.tuile--blanche .carte{background:var(--fond)}
.carte h3{margin:0;font-size:1.3125rem;font-weight:500;letter-spacing:-.016em}
/* Numero d'etape : sequence reelle du processus, pas une decoration.
   Assez grand pour que l'orange reste du registre graphique (3:1 suffit).
   Deux classes, sinon `.carte p` gagne sur la couleur et la taille. */
.carte .etape-no{font-size:1.75rem;font-weight:500;color:var(--orange);line-height:1;margin:0 0 var(--e-2)}
.carte p{margin:0;color:var(--gris);font-size:.9375rem;line-height:1.5}
.carte .fleche{margin-top:.4rem;font-size:.9375rem}
/* En 1-bit rien ne se deplace au survol : le cadre s'epaissit, c'est tout. */
@media (hover:hover) and (pointer:fine){
  a.carte:hover{outline:2px solid var(--encre);outline-offset:-1px}
}

/* ---------- Les deux colonnes qui separent le mesure du conseille ---------- */
.voix{
  display:grid;gap:clamp(.9rem,2vw,1.4rem);
  grid-template-columns:repeat(auto-fit,minmax(17rem,1fr));
  margin-top:clamp(2.4rem,5vh,3.4rem);text-align:left;
}
.voix section{background:var(--blanc);border:1px solid var(--encre);padding:clamp(1.6rem,3vw,2.2rem)}
.tuile--blanche .voix section{background:var(--fond)}
.voix h3{margin:0 0 var(--e-9);font-size:.8125rem;font-weight:500;color:var(--gris)}
.voix ul{list-style:none;margin:0;padding:0}
/* Les deux colonnes sont du contenu de meme rang : ce que la machine mesure
   et ce que je fais sont les deux moities d'une meme offre. Elles portent
   donc le meme traitement.
   Correction du 2026-08-08 : la colonne machine etait en encre grasse et
   l'autre en gris, ce qui faisait lire la seconde comme desactivee alors
   qu'elle enumere justement le travail facture. La distinction entre les
   deux voix est deja portee par les deux titres — elle n'a pas besoin
   d'etre repetee par la couleur, et surtout pas au prix d'une hierarchie
   involontaire. */
.voix li{padding:var(--e-4) 0;font-size:.9375rem;line-height:1.5;color:var(--encre)}
.voix li + li{border-top:1px solid var(--filet)}

/* ---------- Releve : que des valeurs relevees, donc tout en mono ---------- */
.releve{
  background:var(--blanc);border:1px solid var(--encre);
  padding:clamp(1.4rem,3vw,2rem);margin-top:clamp(2.4rem,5vh,3.4rem);
  font-family:var(--mono);font-size:.8125rem;text-align:left;
}
.tuile--blanche .releve{background:var(--fond)}
.rangee{display:flex;align-items:center;gap:var(--e-7);padding:var(--e-5) 0}
.rangee + .rangee{border-top:1px solid var(--filet)}
.rangee i{font-style:normal;color:var(--gris);min-width:1.5rem}
/* Les barres sont des mesures : elles doivent s'etablir, pas exister deja.
   scaleX depuis la gauche — transform et opacite seulement, donc compose
   sur le GPU. La cascade est portee par --rang, pose sur chaque rangee. */
.barre{
  flex:1;height:.75rem;border-radius:var(--pilule);background:var(--piste);
  transform-origin:left center;
}
.js .releve .barre{transform:scaleX(0)}
.js .releve.vu .barre{
  transform:none;
  transition:transform .4s var(--ressort);
  transition-delay:calc(var(--rang,0) * 60ms);
}
.rangee--vous .barre{background:none;border:1.5px dashed var(--orange)}
.rangee b{font-weight:400;color:var(--gris);min-width:4.4rem;text-align:right;font-variant-numeric:tabular-nums}
.rangee--vous b{color:var(--orange)}

/* ---------- Vignettes d'exemples ---------- */
.vignette{
  aspect-ratio:16/10;border:1px solid var(--encre);background:var(--blanc);
  display:flex;align-items:center;justify-content:center;
  font-size:.8125rem;color:var(--gris);margin-bottom:var(--e-9);
}
.tuile--blanche .vignette{background:var(--blanc)}
/* Le deroule des captures : la page du site glisse du haut au pied dans le
   cadre, puis remonte, en continu — decision de Joseph du 2026-08-09,
   assumee contre la regle maison sur les boucles infinies. Garde-fous : le
   survol fige la boucle (ce qui sert aussi de pause, SC 2.2.2), et le bloc
   mouvement reduit coupe l'animation d'office (iteration 1, duree quasi
   nulle, repos sur le haut du site, statique).
   linear : un defilement constant n'est pas un geste, il n'a pas de courbe.
   100cqh = la hauteur du cadre 16/10 (la vignette est son propre conteneur) ;
   sans soutien des unites conteneur, le calc est invalide et la capture
   reste simplement statique. --defile-duree est posee inline sur chaque
   image : la vitesse de lecture depend de la hauteur de la page capturee,
   une seule duree pour toutes donnerait un site qui file et un qui rampe. */
.vignette--defile{container-type:size;display:block;overflow:hidden;padding:0}
.vignette--defile img{width:100%;height:auto;animation:deroule var(--defile-duree,26s) linear infinite}
@keyframes deroule{
  0%,6%{transform:translateY(0)}
  47%,53%{transform:translateY(calc(-100% + 100cqh))}
  94%,100%{transform:translateY(0)}
}
@media (hover:hover) and (pointer:fine){
  .vignette--defile:hover img{animation-play-state:paused}
}

/* Cadre honnete pour la photo absente. On ne met jamais d'image inventee. */
.portrait{
  width:min(17rem,58vw);aspect-ratio:4/5;border:1px solid var(--encre);
  margin:clamp(2.4rem,6vh,3.6rem) auto 0;background:var(--blanc);
  display:flex;align-items:center;justify-content:center;
  font-size:.8125rem;color:var(--gris);
}
.tuile--fonce .portrait{background:rgba(255,255,255,.07);color:var(--gris-sur-fonce)}

/* ---------- Prix : un prix est une annonce, pas une mesure. Donc pas de mono. ---------- */
.prix{display:grid;gap:clamp(.9rem,2vw,1.4rem);grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin-top:clamp(2.4rem,5vh,3.4rem)}
.prix section{background:var(--blanc);border:1px solid var(--encre);padding:clamp(1.6rem,3vw,2.2rem);text-align:center}
.tuile--blanche .prix section{background:var(--fond)}
.prix .chiffre{font-size:clamp(2.1rem,4.4vw,2.9rem);font-weight:500;letter-spacing:-.028em;margin:0;line-height:1.1}
.prix .chiffre span{font-size:.42em;font-weight:400;color:var(--gris);letter-spacing:-.01em}
.prix p{margin:var(--e-4) 0 0;color:var(--gris);font-size:.9375rem;line-height:1.5}

/* ---------- Formulaire ---------- */
.champs{max-width:30rem;margin:clamp(2.2rem,5vh,3rem) auto 0;display:grid;gap:var(--e-6);text-align:left}
.champs label{font-size:.8125rem;color:var(--gris);display:block;margin-bottom:var(--e-3)}
.champs input,.champs textarea{
  width:100%;font-family:var(--sans);font-size:1rem;color:var(--encre);
  background:var(--blanc);border:1px solid var(--filet);border-radius:var(--r-s);
  padding:var(--e-6) var(--e-7);transition:border-color .2s ease;
}
.champs textarea{min-height:7rem;resize:vertical}
/* JAMAIS outline:none ici. La regle precedente supprimait l'anneau et ne
   laissait qu'un changement de couleur de bordure de 1px : trop mince pour
   le SC 2.4.11, et invisible en protanopie ou l'orange rejoint le noir.
   L'anneau d'encre porte le focus par sa forme, l'orange ne fait que
   souligner le champ actif. focus-visible : pas d'anneau a la souris. */
.champs input:focus-visible,.champs textarea:focus-visible{
  border-color:var(--orange);
  outline:2px solid var(--encre);outline-offset:2px;
}
.champs input:focus,.champs textarea:focus{border-color:var(--orange)}
.champs .pilule{
  margin-top:var(--e-4);justify-self:start;
  border:0;font-family:inherit;cursor:pointer;
}
.cache{position:absolute;left:-9999px}

/* Texte d'aide sous l'etiquette : il porte la regle du champ (« laissez vide
   si vous n'en avez pas »), donc il se lit avant la saisie, pas apres. */
.champs .aide{font-size:.8125rem;line-height:1.45;color:var(--gris);margin:0 0 var(--e-4)}
/* 12px est le plancher absolu pour du texte visible. Cette etiquette porte
   l'information qui ouvre la porte au prospect ideal — celui qui n'a pas de
   site — donc elle ne descend pas en dessous. */
.facultatif{
  font-size:.75rem;letter-spacing:.04em;text-transform:uppercase;
  color:var(--gris);border:1px solid var(--filet);border-radius:var(--pilule);
  padding:var(--e-1) var(--e-4);margin-left:.4rem;
}

/* Erreur de champ. Jamais la couleur seule : le message ecrit porte
   l'information, le rouge ne fait que la souligner.

   L'erreur pousse le bouton vers le bas en apparaissant. On ne peut pas
   supprimer ce deplacement sans reserver la place en permanence, ce qui
   deplacerait le bouton des le premier chargement — mais on peut le rendre
   lisible : 150ms d'entree au lieu d'un saut sec.

   TRANSITION + @starting-style, pas des keyframes. La validation se
   declenche au blur ET a chaque frappe : des keyframes repartent de zero a
   chaque relance, une transition se retarge depuis l'etat courant. */
.erreur-champ{
  font-size:.8125rem;line-height:1.45;color:var(--erreur);margin:var(--e-3) 0 0;
}
.js .erreur-champ:not([hidden]){
  opacity:1;transform:none;
  transition:opacity .15s var(--sortie),transform .15s var(--sortie);
  @starting-style{opacity:0;transform:translateY(-2px)}
}
.champs input[aria-invalid="true"]{border-color:var(--erreur);border-width:2px}

/* Les deux regions vivantes. Vides, elles ne doivent occuper aucune place :
   un bloc reserve en permanence deplacerait le bouton au premier message. */
.message:empty{display:none}
.message{
  margin-top:var(--e-7);padding:var(--e-7) var(--e-8);
  font-size:.9375rem;line-height:1.5;
}
.message ul{margin:var(--e-3) 0 0;padding-left:var(--e-9)}
.message--erreur{background:rgba(179,38,30,.08);color:var(--erreur)}
/* Meme geste, meme budget que .erreur-champ : le resume entre en 150 ms au
   lieu de claquer. @starting-style rejoue a chaque passage par display:none,
   ce qui est le comportement voulu pour un message qui va et vient. */
.js .message--erreur:not(:empty){
  opacity:1;transform:none;
  transition:opacity .15s var(--sortie),transform .15s var(--sortie);
  @starting-style{opacity:0;transform:translateY(-2px)}
}

/* LE moment de la fin du parcours. Regle Peak-End : les gens jugent une
   experience par son sommet et par son dernier ecran, et celui-ci est le
   dernier ecran de tout le site. Il merite le budget de delice que les
   elements vus cent fois par jour n'ont pas droit d'avoir.
   L'oiseau se pose : la puce orange arrive d'en haut avec le bloc. */
.message--succes{
  background:rgba(224,87,11,.10);color:var(--encre);
  border-left:2px solid var(--orange);
}
.js .message--succes:not(:empty){
  animation:atterrit .28s var(--ressort) both;
}
@keyframes atterrit{from{opacity:0;transform:translateY(6px)}}
.message--succes::before{
  content:"";display:inline-block;vertical-align:.05em;
  width:.5rem;height:.5rem;border-radius:50%;
  background:var(--orange);margin-right:var(--e-4);
}
.champs button[aria-disabled="true"]{opacity:.55;cursor:default}

/* ---------- Coordonnees ---------- */
.coord{display:flex;flex-direction:column;align-items:center;gap:var(--e-4);margin-top:var(--e-11);font-size:1rem}
.coord a{border-bottom:1px solid var(--filet);padding:var(--e-4) 0 var(--e-3)}
.aremplir{color:var(--gris);border-bottom-style:dashed}

/* ---------- Pied ---------- */
.pied{
  padding:var(--e-13) var(--marge);background:var(--fond);
  display:flex;flex-wrap:wrap;gap:var(--e-7);justify-content:space-between;align-items:center;
  font-size:.8125rem;color:var(--gris);
}
.pied div{display:flex;align-items:center;gap:var(--e-4)}
.pied svg{width:20px;color:var(--encre)}

/* ---------- Apparition : masquage conditionnel a html.js ---------- */
.js .surgit{opacity:0;transform:translateY(16px)}
/* 450ms, pas 600 : c'est la meme revelation au defilement que .recit .pas,
   qui est deja a 450. Un meme geste ne doit pas avoir deux budgets. */
.vu.surgit{opacity:1;transform:none;transition:opacity .45s var(--sortie),transform .45s var(--sortie)}
.d1{transition-delay:.05s}
.d2{transition-delay:.14s}
.d3{transition-delay:.24s}

/* ---------- Preferences systeme ---------- */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important}
  /* Mouvement reduit, pas zero : les changements de couleur aident la
     comprehension et ne declenchent rien de vestibulaire. */
  .nav-liens a,.champs input,.champs textarea,.nav::after,.pilule{
    transition-duration:.2s !important;
    transition-property:color,border-color,background-color,opacity;
  }
  .js .surgit{opacity:1;transform:none}
  .js .recit{height:auto}
  .js .recit-colle{position:static;min-height:0;padding:var(--souffle) var(--marge)}
  .js .recit .pas{opacity:1;transform:none}
  a.carte:hover{transform:none}
  /* Les barres du releve sont une mesure : elles s'affichent a leur valeur,
     sans course. Idem pour les messages, qui restent instantanes. */
  .js .releve .barre{transform:none}
}
/* prefers-reduced-transparency : plus rien a reduire, la barre est opaque. */
@media (prefers-contrast:more){
  .carte,.voix section,.prix section,.releve{border:1px solid var(--encre)}
  .sous,.carte p,.voix li,.prix p,.mention{color:var(--encre)}
}
