/* ══════════════════════════════════════════════════════════════════════════
   La page de cas, version 2027 (Figma 940:7384)

   Ce qui change par rapport à 2026, en une phrase : la colonne de lecture ne
   bouge pas, mais les images débordent de 24 de chaque côté au lieu de 88.

   La maquette pose un bloc de 592 centré dans 1280 — donc 344 de marge de
   chaque côté — et écrit son texte à 24 du bord du bloc, soit 544. C'est
   exactement la largeur de texte de la version précédente, au même endroit :
   368 du bord de la page. Le lecteur ne verra pas la colonne changer. Ce sont
   les images qui gagnent 48, en tenant désormais toute la largeur du bloc.

   Les blocs se suivent à 8. Le blanc entre deux idées vient de leur retrait
   intérieur de 24, pas d'un écart écrit entre eux : deux blocs de texte qui se
   suivent donnent donc 8 + 24 + 24 = 56 de respiration, et une image collée à
   sa légende n'en a que 8. C'est ce qui fait tenir la page ensemble.
   ══════════════════════════════════════════════════════════════════════════ */

:root {
  /* Flora, 20 aout : « tous les blocs a l'interieur du projet body doivent
     avoir le meme radius (8px) ». Un seul jeton, et plus rien ne peut
     diverger — c'etait le cas : 6 sur les legendes, 16 sur les images. */
  --p27-radius: 8px;
  --p27-bloc: 592px;      /* la largeur d'un bloc, images comprises */
  --p27-texte: 544px;     /* la colonne de lecture */
  --p27-inset: 24px;      /* (592 - 544) / 2 */
  --p27-gap: 8px;         /* entre deux blocs */
  /* La barre, et le haut du corps sous elle. Les deux DERIVENT de la hauteur
     des cartes, jamais ecrits en dur : la maquette pose les cartes a 24 du
     haut et veut le meme 24 sous elles avant que la lecture commence.

     Serge, 21 aout : « la margin top du body project doit etre toujours egale
     a la hauteur du menu, on veut le meme ecart au-dessus des cartes et en
     dessous. » Ecrit en dur, ce 112 valait pour des cartes de 64 (24+64+24) ;
     Flora les a passees a 80 le 20 aout et l'ecart du bas est tombe a 8 sans
     que rien ne le signale. Derive, il suit.

     La barre garde SA hauteur de 80 : c'est elle qui centre le nom et le
     bouton du sommaire, la changer les deplacerait. Seul l'ecart du corps
     derive, et il derive de ce qui le decide vraiment — le bas des cartes,
     qui depassent la barre. */
  --p27-carte-h: 80px;    /* .nav-project--big, taille par defaut (1048:34853) */
  --p27-nav-h: 80px;      /* la bande qui centre le nom et le bouton */
  --p27-top: calc(var(--space-24) * 2 + var(--p27-carte-h));

  /* H1 : Book 28/34, interlettrage -0.28 — releve sur Project/Text/Section-Header
     (1025:32705), pas deduit. La page servait -1, soit trois fois trop serre. */
  --p27-h1-size: 28px;
  --p27-h1-line: 34px;
  --p27-h1-track: -0.28px;

  /* H2 : Book 24/30, interlettrage -0.24. La page servait 20/30 a -0.4 : un
     titre de bloc trop petit, qui ne se detachait pas de son paragraphe. */
  --p27-h2-size: 24px;
  --p27-h2-line: 30px;
  --p27-h2-track: -0.24px;

  /* H0, le nom du projet et sa baseline (940:7647) : Book 32/38, -0.64.
     La page servait 28/38 avec -1, donc un titre trop petit dans un
     interligne trop grand, et une coupe de lignes qui ne tombait pas
     comme la maquette. Releve sur le noeud, pas deduit. */
  /* Flora, 21 aout (999:32002) : H0 passe a 36 sur toutes les pages projet.
     Interligne 40 et -2% releves sur le meme node. */
  --p27-h0-size: 36px;
  --p27-h0-line: 40px;
  --p27-h0-track: -0.72px;
  --p27-body-size: 16px;  /* Body/Regular : 16/24 */
  --p27-body-line: 24px;

  /* Flora, 20 aout : « la largeur du menu du projet doit embrasser
     parfaitement la largeur de la totalite des boutons About/Approach/
     Contact ». Mesuree au navigateur, pas devinee : `.p27-nav-right` rend
     238.09px (les trois boutons plus les deux ecarts de 6 entre eux). Les
     deux sont deja cales sur le meme bord droit a 24 — seule la largeur les
     desaccordait. Si le texte des boutons change un jour, remesurer
     `.p27-nav-right` plutot que rajuster ce nombre a vue. */
  --p27-menu-w: 238.09px;
  --p27-menu-item-h: 32px;
}

/* ── Le corps ─────────────────────────────────────────────────────────────
   Une pile de blocs de 592, centrée. Rien d'autre ne décide de la largeur. */
.p27-body {
  display: flex;
  flex-direction: column;
  gap: var(--p27-gap);
  width: var(--p27-bloc);
  margin: 0 auto;
  padding: var(--p27-top) 0 0;
}

.p27-section {
  display: flex;
  flex-direction: column;
  gap: var(--p27-gap);
  scroll-margin-top: calc(var(--p27-nav-h) + var(--space-24));
}

/* L'apparition des blocs au defilement (reveal.js).

   Flora, 20 aout : « il n'y a pas du tout la meme animation ». Premiere
   mesure fausse — sur le mauvais element (le panneau #about, ouvert par le
   bouton Info, pas l'arrivee sur un projet). Reprise sur le vrai geste :
   cliquer un projet depuis leur accueil, puis mesurer le conteneur qui
   arrive. `getComputedStyle().transform` disait "none" partout — la piste
   qui manquait est `translate`, une propriete CSS distincte de `transform`
   que je n'avais pas verifiee. Le conteneur entrant glisse de `translate: 0
   660px` a `0 0` EN MEME TEMPS que son opacite passe de 0 a 1, une seule
   courbe pour les deux (mesure : progression quasi identique a chaque
   instant), sur ~870ms — pas de decalage entre enfants, le bloc bouge
   d'une seule piece, ce qui disperse c'est son contenu, pas son minutage.

   Ici a l'echelle d'un bloc de page plutot que d'un panneau plein ecran :
   meme duo translate+opacite, meme famille de courbe, distance et duree
   reduites pour rester lisible bloc apres bloc en descendant une page de
   29 000px. */
.p27-texte,
.p27-figure {
  opacity: 0;
  translate: 0 40px;
  transition: opacity 600ms cubic-bezier(0.65, 0, 0.35, 1),
              translate 600ms cubic-bezier(0.65, 0, 0.35, 1);
}
.p27-texte.p27-revele,
.p27-figure.p27-revele {
  opacity: 1;
  translate: 0 0;
}

/* ── Les blocs de texte ───────────────────────────────────────────────────

   La maquette n'a pas « des blocs de texte » : elle en a trois sortes, et
   confondre leurs reglages est ce qui faisait paraitre la page plus plate que
   le Figma.

   1. L'en-tete de section (Project/Text/Section-Header) : deux lignes du meme
      corps, collees — le nom de la section en gris, le titre en fonce
      dessous. Pas d'ecart entre elles : c'est un seul bloc de titre en deux
      couleurs, pas un surtitre suivi d'un titre.
   2. Le bloc courant (Meta-Label + Paragraph) : une etiquette grise, puis 48
      plus bas un titre et son texte separes de 12.
   3. La carte de recit (Narrative-Card) : du texte seul, plus fonce que celui
      des blocs courants, sans etiquette ni titre.

   Le retrait de 24 est porte par le bloc, pas par le texte : une image du meme
   bloc peut ainsi tenir toute la largeur sans se battre contre lui. */
.p27-texte {
  padding: var(--p27-inset);
  display: flex;
  flex-direction: column;
  /* Scale/48 : l'ecart entre l'etiquette et ce qu'elle annonce. */
  gap: 48px;
  /* La carte de verre : blanc a 30%, rayon 8 (radius/project-container). Elle
     laisse passer le fond floute, c'est ce qui pose le texte sur la page
     d'accueil au lieu de l'en couper. */
  background: rgba(255, 255, 255, 0.3);
  border-radius: var(--p27-radius);
}

/* L'ombre blanche de 34 sous le texte. C'est elle qui garde la lecture nette
   par-dessus un fond qui n'est jamais tout a fait uni. */
.p27-texte .p27-p,
.p27-texte .p27-h1,
.p27-texte .p27-h2,
.p27-texte .p27-eyebrow,
.p27-texte .p27-label,
.p27-texte .p27-liste {
  text-shadow: 0 0 34px #fff;
}

/* 1 · L'en-tete de section. */
.p27-entete { gap: 0; }

.p27-entete .p27-eyebrow,
.p27-entete .p27-h1 {
  margin: 0;
  font-family: var(--font-headings, var(--font-body));
  font-weight: var(--weight-book);
  font-size: var(--p27-h1-size);
  line-height: var(--p27-h1-line);
  letter-spacing: var(--p27-h1-track);
}
.p27-entete .p27-eyebrow { color: var(--text-project-title-grey); }
.p27-entete .p27-h1      { color: var(--text-project-title-dark); }

/* 2 · Le bloc courant. L'etiquette est du corps de texte, pas un petit
   caractere : 16/24 en Regular, la meme graisse que le paragraphe. */
.p27-eyebrow,
.p27-label {
  margin: 0;
  font-family: var(--font-body);
  font-weight: var(--weight-regular);
  font-size: var(--p27-body-size);
  line-height: var(--p27-body-line);
  color: var(--text-project-meta-label);
}

/* Le titre et son texte vont ensemble et se suivent a 12 (paragraph-m) : c'est
   le seul endroit de la page ou deux lignes sont aussi proches. */
.p27-paragraphe {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.p27-h1 {
  margin: 0;
  font-family: var(--font-headings, var(--font-body));
  font-weight: var(--weight-book);
  font-size: var(--p27-h1-size);
  line-height: var(--p27-h1-line);
  letter-spacing: var(--p27-h1-track);
  color: var(--text-project-title-dark);
}

/* Le titre d'un bloc à l'intérieur d'une section : même famille, plus petit. */
.p27-h2 {
  margin: 0;
  font-family: var(--font-headings, var(--font-body));
  font-weight: var(--weight-book);
  font-size: var(--p27-h2-size);
  line-height: var(--p27-h2-line);
  letter-spacing: var(--p27-h2-track);
  color: var(--text-project-title-dark);
}


/* Le texte courant. #4d4d4d, releve sur chaque bloc du Figma
   (text/project/dark-titles-secondary). La page le servait en #8b8b8b, la
   couleur des etiquettes : tout le corps du texte etait donc de la teinte
   reservee a ce qui doit s'effacer. */
.p27-p {
  margin: 0;
  font-family: var(--font-body);
  font-weight: var(--weight-regular);
  font-size: var(--p27-body-size);
  line-height: var(--p27-body-line);
  color: var(--text-secondary-dark);
}

/* La carte de recit (Project/Text/Narrative-Card) : du texte seul, sans
   etiquette ni titre, et plus fonce que le reste — c'est la voix de Flora,
   pas la description d'un ecran.

   Ses lignes se suivent A LA LIGNE, pas a 48 : dans la maquette c'est un seul
   bloc de texte avec des retours, pas une pile de paragraphes. La ou Flora a
   laisse une ligne blanche, `p27-p--saut` la rend — une seule, de la hauteur
   d'une ligne. */
.p27-recit { gap: 0; }
.p27-recit .p27-p { color: var(--primary-800); }
.p27-recit .p27-p--saut { margin-top: var(--p27-body-line); }

/* 4 · La note (Project/Text/Paragraph-secondary, 1025:32870).

   Une remarque de Flora en marge du recit : une premiere ligne fonce qui
   annonce, puis le propos juste dessous — 2 seulement les separent, ils se
   lisent d'un trait — dans un gris plus clair que le texte courant. */
.p27-note .p27-paragraphe { gap: 2px; }
.p27-note .p27-note-tete {
  margin: 0;
  font-family: var(--font-body);
  font-weight: var(--weight-regular);
  font-size: var(--p27-body-size);
  line-height: var(--p27-body-line);
  color: var(--primary-800);
}
.p27-note .p27-p { color: var(--text-project-paragraph-secondary); }

/* Ces blocs-la sont des NOTES (Project/Text/Paragraph-secondary, 1025:32870)
   et non des encarts. Flora, 20 aout : « ce format de texte que tu as
   developpe n'est pas bon, c'est le format du highlighted text ».

   La difference tient a deux choses : pas de carte blanche a l'interieur du
   bloc, et l'ordre des encres inverse — la ligne qui annonce est la FONCEE,
   le propos qui suit est plus clair. Un encart met en avant ; une note
   commente. */
.p27-duo {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Project/Text/Highlighted-text (1025:32746). RARE : un seul dans tout
   Iteration X. Il vit DANS un bloc de note, sous elle, et ne fait que 544 —
   la colonne de lecture, pas la largeur du bloc. C'est la seule exception au
   fond commun de la page. */
.p27-encart {
  width: var(--p27-texte);
  max-width: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-16);
  background: var(--glassy-white-400);
  border-radius: var(--radius-6);
}
.p27-encart .p27-label { color: var(--greyscale-500); font-weight: var(--weight-regular); }
.p27-encart .p27-p { color: var(--greyscale-700); }
.p27-duo .p27-label {
  font-weight: var(--weight-regular);
  color: var(--primary-800);
}
.p27-duo .p27-p,
.p27-duo .p27-liste li { color: var(--text-project-paragraph-secondary); }

.p27-liste { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: var(--space-8); }
.p27-liste li {
  font-family: var(--font-body);
  font-weight: var(--weight-regular);
  font-size: var(--p27-body-size);
  line-height: var(--p27-body-line);
  color: var(--text-secondary-dark);
}

/* Project/Text/Links-Paragraph-secondary (1055:35190) : une liste d'articles
   de presse, titre souligne + source entre parentheses. Pas de href fournis
   par le Figma — texte stylise, pas des vrais liens. */
.p27-liens {
  display: flex;
  flex-direction: column;
  gap: 2px;
  color: var(--text-project-paragraph-secondary);
  font-size: var(--p27-body-size);
  line-height: var(--p27-body-line);
}
.p27-lien {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-6);
}
.p27-lien-titre {
  font-family: var(--font-body);
  font-weight: var(--weight-book);
  text-decoration: underline;
  text-underline-offset: 2px;
}
/* Quand le nom mene quelque part, il se comporte comme un lien : il prend la
   main au survol et fonce legerement. Le soulignement, lui, etait deja la —
   c'est la maquette qui le veut, avec ou sans destination. */
a.p27-lien-titre { color: inherit; cursor: pointer; transition: color 140ms ease; }
a.p27-lien-titre:hover { color: var(--text-primary, #2b2b2b); }
.p27-lien-source { font-family: var(--font-body); font-weight: var(--weight-regular); }

/* ── Les images ───────────────────────────────────────────────────────────

   Project-image+Caption (1025:33446) : l'image ET sa legende sont un seul
   bloc de verre, pas une image suivie d'un texte libre. La legende porte le
   meme blanc a 30% que le reste et son propre retrait (24 sur les cotes, 16
   en haut et en bas) — c'est ce fond-la qui manquait.

   Le cadre de l'image tient le degrade rose du composant : on ne le voit que
   sous une image qui ne remplit pas sa boite, et c'est exactement a cela
   qu'il sert. */
.p27-figure {
  margin: 0;
  display: flex;
  flex-direction: column;
  background: rgba(255, 255, 255, 0.3);
  /* Flora, 21 aout : les containers d'image portent toujours radius/6 (6px),
     pas radius/project-container (8px, --p27-radius) — ce dernier reste
     pour les blocs de texte uniquement. */
  border-radius: var(--radius-6);
  overflow: clip;
}

.p27-media {
  position: relative;
  width: 100%;
  overflow: clip;
  background: linear-gradient(180deg, #e4ddf7 0%, #f7ddf1 100%);
}

.p27-media > img,
.p27-media > video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Variante « Desktop mockup » (Image-Full-width, 1025:33453) : une capture
   d'application ne se pose pas sur le degrade rose mais sur un GRIS, avec son
   propre rayon et son ombre portee. C'est ce fond gris qui manquait.

   Flora, 20 aout : « j'ai enleve les margins » sur cette variante — releve
   sur 1025:33448, le composant maitre pour les 4 formats reutilises sur
   toute page projet (Default Image, Desktop mockup, Mobile slider, Mobile
   Fixed). Plus de retrait de 16 : la capture touche les quatre bords. */
.p27-media--cadre {
  background: var(--glassy-light-200);
}
/* AXA (1091:40697 et les autres cadres du projet) : presque tous ses fonds
   de cadre sont noirs, pas le gris clair partage par le reste du site
   (Flora, 23 aout, releve sur plusieurs blocs d'affilee). */
[data-projet="axa-live"] .p27-media--cadre { background: #010101; }
.p27-media--cadre > img,
.p27-media--cadre > video {
  border-radius: var(--radius-6);
  box-shadow: 0 4px 17px 8px rgba(0, 0, 0, 0.06);
}

/* Flora, 21 aout (1061:36991) : plusieurs images dans le meme "Image
   container" sont toujours collees, gap 0 — jamais l'espacement par
   defaut entre blocs de la page. Un seul cadre (rayon + ombre) pour toute
   la pile, pas un par image — sinon les ombres se chevauchent aux jointures. */
.p27-media--pile { display: flex; flex-direction: column; gap: 0; }
.p27-media--pile > img {
  display: block; width: 100%; height: auto; border-radius: 0; box-shadow: none;
}
.p27-media--pile.p27-media--cadre {
  border-radius: var(--radius-6);
  box-shadow: 0 4px 17px 8px rgba(0, 0, 0, 0.06);
  overflow: clip;
}

/* AXA, General structure : la maquette dessinee entiere (telephone, ombre)
   est un PNG, et la video se pose PILE sur le rectangle de l'ecran — la
   geometrie en pourcentages vient de l'ancienne page (p26-ecran), relevee
   sur le Figma. Le span recoit position/taille en style inline par figure. */
.p27-ecran { position: absolute; overflow: hidden; box-sizing: border-box; }
.p27-ecran .video-slot { width: 100%; height: 100%; object-fit: cover; display: block; }

/* AXA, les paires prototype Figma / Claude Code (1087:40007, 1091:40218) :
   deux telephones cote a cote dans le meme cadre gris, centres. */
/* Flora, 23 aout (1087:40007, 1091:40218) : fond quasi-noir, un contour
   d'iPhone (SVG du node) pose sur chaque video, un logo dessous (Figma a
   gauche, Claude a droite). */
.p27-media--duo {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-24);
  background: #010101;
}
.p27-duo-colonne {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-24);
}
.p27-duo-tel { position: relative; display: block; width: 100%; }
.p27-duo-tel > .video-slot {
  position: absolute;
  display: block;
  object-fit: cover;
}
.p27-duo-outline {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.p27-duo-logo { display: block; }

/* Une figure dont le média ne remplit pas le cadre : il se pose au centre de
   son aplat, à sa taille propre. */
.p27-media--pose { display: flex; align-items: center; justify-content: center; }
.p27-media--pose > img,
.p27-media--pose > video {
  width: auto; height: auto;
  max-width: 100%; max-height: 100%;
  object-fit: contain;
  /* Mockup-shadow, releve sur 1032:33865. Une maquette posee sur un aplat a
     son rayon et son ombre propres — sinon elle est collee au fond. */
  border-radius: var(--radius-16);
  box-shadow: 0 4px 24px 8px rgba(0, 0, 0, 0.04);
}

/* Project/Text/Caption-Image, type « Paragraph » (1025:33462) : deux vrais
   champs distincts dans le Figma (titre fonce + description grise), pas
   juste une ligne italique coupee en deux — a ne confondre avec le type
   « Caption » simple (1025:33442), une seule ligne italique, toujours
   grise, jamais de titre distinct meme quand le texte contient un ":".
   PropertyGRID n'a que des Caption simples ; Iteration X a de vrais
   Paragraph (« The issue split view », etc.) — c'est la que ce type-la
   s'applique. */
.p27-caption--para {
  display: flex;
  flex-direction: column;
  gap: 0;
  font-family: var(--font-body);
  font-style: normal;
  font-weight: var(--weight-regular);
}
.p27-caption--para b { font-weight: var(--weight-regular); color: var(--primary-800); }
.p27-caption--para span { color: var(--text-project-paragraph-secondary); }

/* Project/Text/Caption-Image, type « Caption » (1025:33442). Flora, 20 aout :
   « j'ai enleve le background blanc 30% de tous les containers image avec
   captions » — releve sur le composant, plus de fond ici non plus. */
.p27-caption {
  margin: 0;
  padding: var(--space-16) var(--p27-inset);
  text-shadow: 0 0 34px #fff;
  font-family: var(--font-headings, var(--font-body));
  font-weight: 450;
  font-style: italic;
  font-size: var(--p27-body-size);
  line-height: var(--p27-body-line);
  color: var(--text-project-meta-label, #8b8b8b);
}

/* La rangee de maquettes mobiles (1032:33837) : le cadre ne grandit pas, c'est
   son contenu qui glisse a l'interieur. Vaut pour toute rangee de telephones,
   sur ce projet comme sur les suivants. */
.p27-tel-rang {
  display: flex;
  /* 1087:39931 : 16 entre les maquettes, pas 8 — le dernier telephone visible
     doit rester legerement coupe au bord pour se lire comme scrollable
     (Flora, 23 aout). */
  gap: var(--space-16);
  align-items: center;
  justify-content: safe center;
  overflow-x: auto;
  touch-action: pan-x;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  padding: var(--space-24);
  /* Flora, 20 aout : sans arret defini, un flick au doigt relache la rangee a
     n'importe quel pixel — un telephone coupe a mi-largeur contre le bord de
     l'ecran, sans le retrait de 24 que portent les texte containers. L'arret
     s'aligne desormais sur ce meme retrait des deux cotes, un telephone a la
     fois. */
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--space-24);
}
.p27-tel-rang::-webkit-scrollbar { display: none; }
.p27-tel-rang > * {
  flex: none;
  width: 171px;  /* 1114:44709 : 170.8, arrondi — 181 debordait les rangees courtes de 3-6 maquettes et cassait leur centrage (safe center bascule a gauche des qu'il y a overflow). */
  height: auto;
  border-radius: var(--radius-16);
  scroll-snap-align: start;
  /* 1087:39911 : chaque maquette porte un contour 1px #1e386e. */
  border: 1px solid #1e386e;
  box-sizing: border-box;
}
/* Le cadre ne grandit pas avec la rangee : il tient sa hauteur et c'est le
   contenu qui defile dedans (1032:33837). Vaut pour toute rangee de maquettes
   mobiles, sur ce projet comme sur les suivants. */
.p27-media--rang { height: auto; }
/* La main ouverte n'apparait que sur un rail qui deborde vraiment — la classe
   est posee par `rails.js` apres mesure. Le glisser marchait deja sur ces
   pages, mais RIEN ne le disait : le curseur restait une fleche, donc avec
   une souris ordinaire (pas de molette horizontale) la moitie de la rangee
   etait hors d'atteinte sans qu'on sache qu'elle existait (Serge, 24 aout).
   Meme regle que les rangees 2026 (project-2026.css), a l'identique. */
/* Pendant qu'on tire — et pendant que la rangee se pose apres le lacher —
   l'aimantation est suspendue : `snap mandatory` re-aimante chaque
   affectation de scrollLeft sur une carte, et le drag devenait un saut
   binaire debut/fin (Flora, 24 aout : « tres abrupt »). rails.js pose et
   retire ces classes, et fait lui-meme la pose en douceur. */
.p27-tel-rang.est-tire,
.p27-tel-rang.se-pose { scroll-snap-type: none; }
.p27-tel-rang.peut-defiler { cursor: grab; }
.p27-tel-rang.est-tire { cursor: grabbing; }
/* Sur une rangee ouvrable, la MAQUETTE prime sur le rail : c'est elle qu'on
   agrandit, et Flora, 24 aout : « on ne voit que l'icone drag and drop sur
   les mobiles, il faut en priorite sur les maquettes qu'on voit l'icone zoom
   in ». La main reste sur les marges de la rangee, la ou il n'y a rien a
   ouvrir et ou l'on tire. */
.zi-oui .p27-tel-rang img { cursor: zoom-in; }
.zi-oui .p27-tel-rang.est-tire img { cursor: grabbing; }

/* Pendant qu'on tire, le navigateur ne doit ni selectionner du texte ni partir
   sur son glisser-deposer d'image. */
.p27-tel-rang.peut-defiler img {
  -webkit-user-drag: none;
  user-select: none;
}

/* Au clavier, une zone defilante doit pouvoir recevoir le focus. */
.p27-tel-rang:focus-visible {
  outline: 2px solid var(--border-action);
  outline-offset: 2px;
}

/* Les contours ne sont pas uniformes d'une rangee a l'autre dans les mockups :
   le bleu ci-dessus est celui des rangees « My AXA », mais l'editorial
   d'AXA en porte des rouges (1091:40417), et plusieurs rangees n'en ont
   aucun — les deux editoriales, les archives (1095:40764) et celle de
   PropertyGRID. Une classe par variante, jamais un style en ligne. */
.p27-tel-rang--nu > * { border: none; }
.p27-tel-rang--rouge > * { border-color: #402822; }
.p27-tel-rang--rouge > :first-child { border-color: #792510; }

.p27-media--rang .p27-tel-rang { height: 100%; align-items: center; box-sizing: border-box; }

/* ── L'en-tête du projet ──────────────────────────────────────────────────
   La couverture d'abord, le titre ensuite : la maquette pose l'image en haut
   du bloc et le titre dessous (940:7447 puis 940:7644). */
/* Flora, 20 aout (1032:33943) : la cover est 4/3 dans la maquette (592x444,
   pile 4/3), pas la proportion du fichier. Sans `aspect-ratio`, `height:
   auto` suivait le fichier (1184x710, ~5/3) — plus large que prevu. Le
   cadre impose maintenant 4/3, `object-fit: cover` recadre l'image dedans
   comme le fait le node Figma (une image pleine boite, pas etiree). */
.p27-cover { width: 100%; aspect-ratio: 4 / 3; border-radius: var(--p27-radius); overflow: clip; }
.p27-cover img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Project/Text/Hero-Header (1022:32695) : c'est un bloc de verre comme les
   autres, ce que la page avait oublie — le titre flottait sur le fond. */
.p27-titre {
  padding: var(--p27-inset);
  display: flex;
  flex-direction: column;
  gap: 0;
  background: rgba(255, 255, 255, 0.3);
  border-radius: var(--p27-radius);
}
.p27-titre .p27-projet,
.p27-titre .p27-baseline { text-shadow: 0 0 34px #fff; }
.p27-projet {
  margin: 0;
  font-family: var(--font-headings, var(--font-body));
  font-weight: 450;
  font-size: var(--p27-h0-size);
  line-height: var(--p27-h0-line);
  letter-spacing: var(--p27-h0-track);
  color: var(--text-project-meta-label, #8b8b8b);
}
.p27-baseline {
  margin: 0;
  font-family: var(--font-headings, var(--font-body));
  font-weight: 450;
  font-size: var(--p27-h0-size);
  line-height: var(--p27-h0-line);
  letter-spacing: var(--p27-h0-track);
  color: var(--text-primary, #2b2b2b);
}

/* Les métadonnées du projet : rôle, métriques, équipe. */
/* Les infobulles de l'equipe depassent de 34px sous leur rangee, dans
   l'emprise du conteneur de texte SUIVANT. Chaque .p27-texte porte un
   `translate` (l'animation d'apparition), donc son propre contexte
   d'empilement : a z-index egal, c'est l'ordre du document qui tranche,
   et le bloc d'apres peint par-dessus. Flora, 22 aout : la priorite de
   visibilite va aux PREMIERS elements dans l'ordre — le bloc qui porte
   les avatars passe donc devant ceux qui arrivent apres lui. */
.p27-texte:has(.p27-equipe) { position: relative; z-index: 2; }
.p27-metas { display: flex; flex-direction: column; gap: var(--space-32); }
.p27-meta { display: flex; gap: var(--space-8); }
.p27-meta-label { flex: none; width: 140px; }
/* Flora, 22 aout (1114:45270) : les valeurs se suivent SANS ecart — le
   node les pose a y=0/24/48, un pas de 24 qui est leur hauteur de ligne
   meme. Le gap de 4 qui vivait ici les desserrait partout, bureau comme
   telephone. */
.p27-meta-valeurs { display: flex; flex-direction: column; gap: 0; }

/* L'equipe (1025:33292) : jamais stylee, ce qui la faisait tomber au flux
   par defaut — les portraits en pile, un par ligne, a la largeur pleine du
   bloc (`img { display: block; max-width: 100% }` de base.css n'a rien pour
   les en empecher). La rangee attend un flex row, 4 d'ecart. */
/* Flora, 21 aout (1025:33268 + atome 163:22696) : les memes proprietes que
   le bloc testimonials de la home (`.testimonial-avatars` / `.testimonial`,
   hero.css) — le gap passe a 16 (etait 4), et chaque avatar « Inactive »
   porte desormais un anneau noir tres leger (glassy-black-500, 0.2). Les
   deux composants partagent les memes jetons expres : retoucher l'un doit
   retoucher l'autre. */
.p27-equipe { display: flex; flex-wrap: wrap; gap: var(--space-16); align-items: flex-start; }
/* Flora, 20 aout : « Team » doit etre centre verticalement sur la rangee de
   portraits, pas cale en haut — la rangee fait 64 de haut, l'etiquette une
   seule ligne. */
.p27-meta--equipe { align-items: center; }
/* Chaque pastille : 64 avec le disque de 54 dedans, centre. Le rayon vient
   d'ici, pas du fichier — team-1.jpg est un JPEG, il n'a pas de coins
   transparents a offrir comme les PNG qui l'entourent (voir le commentaire
   d'`equipe()` dans le generateur). */
.p27-equipe-pastille,
.p27-equipe--flora {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 64px;
  height: 64px;
  padding: var(--space-4);
  border-radius: var(--radius-full, 999px);
  box-sizing: border-box;
  border: 1px solid var(--glassy-black-500);
}
.p27-equipe--flora { border: 1px solid var(--border-action); }
/* Une pastille peut etre un lien (LinkedIn, nouvel onglet) : meme habit. */
a.p27-equipe-pastille { text-decoration: none; color: inherit; }
/* Le nom au survol (Tooltip du composant Avatars, 41:820) — copie conforme
   de `.testimonial-name` (hero.css) : les deux composants partagent les
   memes jetons expres, retoucher l'un doit retoucher l'autre. */
.p27-equipe-pastille,
.p27-equipe--flora { position: relative; }
.p27-equipe-nom {
  position: absolute;
  left: 50%;
  bottom: -34px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4) var(--space-6);
  border-radius: var(--space-4);
  background: var(--surface-tooltip);
  backdrop-filter: blur(var(--blur-8));
  -webkit-backdrop-filter: blur(var(--blur-8));
  color: var(--primary-white);
  font-weight: var(--weight-regular);
  font-size: 14px;
  line-height: 18px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 260ms cubic-bezier(0.16, 1, 0.3, 1);
  z-index: 6;
}
.p27-equipe-pastille:hover .p27-equipe-nom,
.p27-equipe-pastille:focus-visible .p27-equipe-nom,
.p27-equipe--flora:hover .p27-equipe-nom,
.p27-equipe--flora:focus-visible .p27-equipe-nom { opacity: 1; }
/* La pastille survolee passe devant, sinon la voisine peint sur le nom. */
.p27-equipe-pastille:hover,
.p27-equipe--flora:hover { z-index: 5; }
@media (prefers-reduced-motion: reduce) {
  .p27-equipe-nom { transition-duration: 0.01ms; }
}
.p27-equipe-pastille img,
.p27-equipe--flora img {
  width: 54px;
  height: 54px;
  border-radius: 100px;
  object-fit: cover;
}

/* ── La barre du haut ─────────────────────────────────────────────────────
   Le nom à gauche, les cartes de projets au centre, le bouton du sommaire à
   droite (940:8012 / 940:8019 / 940:8696). Les boutons About/Approach/Contact
   sont masqués dans la maquette : sur une page de cas, c'est le sommaire qui
   prend leur place. */
.p27-nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 20;
  height: var(--p27-nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-24);
}
/* AUCUNE nav du site ne porte de fond — meme sur AXA (Flora, 23 aout,
   correction ferme) : le bg-[#1d1d1d] repere sur 1072:37603 appartenait a
   un AUTRE element du calque, pas a la barre. Ne pas y revenir. */
/* Les cartes ne sont pas centrees sur la barre : la maquette les pose a 24 du
   haut (940:8019), comme le nom et la croix, et les laisse depasser de 8 en
   bas puisqu'elles font 64 dans une barre de 80. Sans `top`, une boite absolue
   se cale sur le milieu de la bande de contenu et remonte a 8 — c'est ce qui
   les faisait mordre le bord de l'ecran. */
.p27-nav-centre {
  position: absolute;
  top: var(--space-24);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--space-8);
  /* La reapparition (etat de repos, ci-dessous) est volontairement plus
     lente et plus douce que la disparition (regle suivante) : Flora, 20
     aout, « rends le mouvement plus smooth et fluide quand ça remonte au
     scroll ». Transform et opacity sur la meme duree, sinon l'un finit
     avant l'autre et la carte semble se figer une fraction de seconde. */
  transition: transform 620ms cubic-bezier(0.16, 1, 0.3, 1), opacity 620ms cubic-bezier(0.16, 1, 0.3, 1);
}
/* Flora, 20 aout : les cartes disparaissent vers le haut en scrollant vers
   le bas, et reapparaissent en glissant depuis le haut de la page en
   remontant — meme repos qu'au chargement (24 du bord), rien de plus a
   leur donner. `menu-2027.js` bascule cette classe selon la direction du
   geste, pas la position. */
.p27-nav-centre--cachee {
  transform: translate(-50%, -100%);
  opacity: 0;
  pointer-events: none;
  /* Partir est plus rapide qu'arriver : la carte n'a pas besoin d'etre
     regardee sur le chemin de la sortie, seulement sur celui du retour. */
  transition: transform 320ms cubic-bezier(0.4, 0, 1, 1), opacity 280ms ease-in;
}

/* About / Approach / Contact (1048:34853, Nav-right).

   Flora, 20 aout : « on n'a plus de close button, on garde les items de
   base ». La croix (940:8696) tenait ce coin depuis le premier portage 2027 ;
   le Figma l'a retiree, et avec elle l'idee qu'une page de cas ne menait
   nulle part. Fermer reste possible sans bouton dedie : clic a cote de la
   feuille, ou Echap (menu-2027.js, inchange — les deux ne dependaient pas de
   la croix). Meme composant que sur l'accueil, `nav.css` porte tout. */
.p27-nav-right {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  justify-content: flex-end;
}

/* ── Le menu du projet ────────────────────────────────────────────────────
   Project-Nav-Iteration-X (1005:32633), releve noeud par noeud.

   Ce n'est pas un deroulant : il est la en permanence, a droite, a 24 du bord
   comme la croix qui le surplombe. Huit pilules de 204, 4 entre elles, sans
   panneau derriere — chaque pilule porte son propre blanc a 60% et laisse voir
   l'accueil au travers, exactement comme les blocs de texte du corps.

   Il est cale EN BAS, a 24 du bord inferieur et a 24 du bord droit — les
   memes retraits que la barre du haut. C'est ce que dit la maquette une fois
   lue dans le bon sens : elle le pose a 534, et 534 + 284 + 24 = 842, la
   hauteur de sa fenetre. Ce n'est donc pas une distance depuis le haut, c'est
   une distance depuis le bas — et c'est la seule des deux qui tienne quand la
   fenetre change de taille.

   La geometrie des pilules est celle de la barre — 32 de haut, rayon 6,
   retrait 6/12, texte 14/20 — donc `nav-item` porte tout, et seules les deux
   couleurs de la jauge changent. C'est ce que Flora demandait : exactement les
   boutons de la barre. */
.p27-menu {
  position: fixed;
  bottom: var(--space-24);
  right: var(--space-24);
  z-index: 19;
  width: var(--p27-menu-w);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-height: calc(100vh - var(--p27-nav-h) - var(--space-24) * 2);
  transform: translateY(0);
  overflow-y: auto;
  scrollbar-width: none;
}
.p27-menu::-webkit-scrollbar { display: none; }

/* La pilule. `nav-item` donne la boite, la typo et la jauge ; ici seulement le
   fond au repos (surface/project/nav-item-default) et l'encre (#8b8b8b), qui
   sont les deux seules choses que la maquette change. Le texte est cale a
   gauche, la barre centre le sien. */
.p27-menu .nav-item {
  --gauge-off: var(--surface-project-nav-item);
  --gauge-on: var(--surface-project-nav-item-hover);
  justify-content: flex-start;
  width: 100%;
  color: var(--text-project-nav-item);
  text-align: left;
}
/* Flora, 24 aout, capture a l'appui : « My AXA » restait plus clair que les
   autres apres qu'on l'ait quitte. Le coupable n'etait pas l'etat actif mais
   `:focus-within` — un clic SOURIS laisse le focus sur la tete du tiroir, donc
   la pilule gardait le blanc du survol indefiniment. `:has(:focus-visible)` ne
   repond qu'au focus clavier, celui qui a besoin d'etre montre : au clavier
   l'anneau reste, a la souris l'item redevient default des qu'on s'en va.

   `nav.css` pose un fond gris au survol de tout `.nav-item`. Dans le menu du
   projet c'est faux : le systeme veut un blanc qui gagne en opacite, pas un
   gris. Deux classes contre une, donc plus fort — et `background` en toutes
   lettres, sinon la jauge de la barre repasse devant. */
.p27-menu .nav-item:not([data-courant="1"]):hover,
.p27-menu .nav-item:not([data-courant="1"]):has(:focus-visible) {
  background: var(--surface-project-nav-item-hover);
  background-image: none;
  color: var(--text-project-nav-item-hover);
  border-radius: var(--radius-6);
}
.p27-menu .nav-item[data-courant="1"] {
  background: var(--surface-project-nav-item-active);
  background-image: none;
}
/* Flora, 21 aout : le +/- doit lui aussi reagir au survol, meme noir que le
   texte hovered — jusqu'ici seule la couleur heritee du texte changeait,
   pas assez visible sur un trait aussi fin. Pas sur un tiroir deja ouvert :
   sa tete est desactivee (ci-dessus), rien a signaler au survol. */
.p27-menu .nav-item:not([data-courant="1"]):not([data-ouvert="1"]):hover .p27-plus,
.p27-menu .nav-item:not([data-courant="1"]):not([data-ouvert="1"]):has(:focus-visible) .p27-plus {
  color: var(--text-project-nav-item-hover);
}

/* La rubrique ou l'on se trouve. Elle ne peut pas emprunter `aria-current` de
   la barre — la barre s'en sert pour la page courante, et cette regle-la
   coupe le survol. Ici on veut l'inverse : la rubrique lue reste marquee ET
   repond au pointeur. */
/* La rubrique ou l'on se trouve prend le blanc PLEIN : Flora, 20 aout — « le
   menu du projet a des items blancs dans les composants de ma maquette ». Le
   systeme nomme trois etats et la page n'en servait qu'un : defaut 60%,
   survol 80%, actif 100%. C'est l'opacite qui monte, pas un gris qui
   s'assombrit — la page passait au gris de la barre, qui n'a rien a faire
   ici. */
.p27-menu .nav-item[data-courant="1"],
.p27-menu .p27-groupe:has(> .p27-groupe-tete[data-courant="1"]) {
  --gauge-off: var(--surface-project-nav-item-active);
  --gauge-on: var(--surface-project-nav-item-active);
  color: var(--text-project-nav-item-active);
}
/* Le repli, pour les navigateurs qui ignorent `:has`. */
.p27-menu .p27-groupe-tete[data-courant="1"] { color: var(--text-project-nav-item-active); }

/* Une tete de tiroir OUVERT passe en desactive (1005:32398). Elle n'est plus
   une destination : elle est devenue le contenant de ses sous-rubriques, et
   c'est parmi elles qu'on choisit. */
.p27-groupe[data-ouvert="1"] > .p27-groupe-tete,
.p27-groupe[data-ouvert="1"] > .p27-groupe-tete[data-courant="1"] {
  color: var(--text-project-nav-item-disabled);
  cursor: default;
}

/* Un groupe est la pilule elle-meme : le tiroir s'ouvre A L'INTERIEUR, la
   pilule grandit. C'est ce que fait le composant (Accordion-body est un enfant
   de Project-nav-item), et c'est pour cela que le groupe porte `nav-item` et
   non sa tete. */
.p27-groupe {
  flex-direction: column;
  align-items: stretch;
  height: auto;
  gap: 0;
}
/* La pilule ouverte est la variante "Active" du composant (1005:32417) : fond
   blanc plein, pas les 60% du repos — c'est le tiroir qui se distingue du
   reste du menu, pas un survol. Et elle ne se remplit plus AU survol : sur une
   pilule devenue haute, la jauge de la barre couvrirait un panneau entier. */
.p27-groupe[data-ouvert="1"] {
  --gauge-off: var(--surface-project-nav-item-active);
  --gauge-on: var(--surface-project-nav-item-active);
}

/* La tete : un bouton transparent, pas un lien. Elle ouvre le tiroir ET mene a
   sa section — les deux, parce que Flora demande qu'un item du menu amene a sa
   section, et que le « + » demande qu'il se deplie. */
.p27-groupe-tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-8);
  width: 100%;
  height: 20px;
  padding: 0;
  margin: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
/* Icon/Add et Icon/Less (1005:32352 / 1005:32351) : le meme trait de 12x1,
   celui du plus disparaissant quand le tiroir s'ouvre. Dessine plutot
   qu'ecrit — un caractere ne sait pas faire disparaitre une seule de ses deux
   barres. */
.p27-plus {
  flex: none;
  width: 20px;
  height: 20px;
  position: relative;
  color: currentColor;
}
.p27-plus::before,
.p27-plus::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 12px;
  height: 1px;
  margin: -0.5px 0 0 -6px;
  background: currentColor;
  transition: transform .26s var(--hover-ease), opacity .26s var(--hover-ease);
}
.p27-plus::after { transform: rotate(90deg); }
[aria-expanded="true"] .p27-plus::after { transform: rotate(90deg) scaleX(0); opacity: 0; }

/* Le tiroir (Accordion-body 1005:32372) : 180 de large, a 24 sous le titre,
   des lignes de 20 espacees de 6. Ferme il n'existe pas.

   `grid-template-rows` de 0fr a 1fr est la seule facon d'animer vers une
   hauteur qu'on ne connait pas d'avance — et on ne la connait pas, elle depend
   du nombre de sous-rubriques. */
.p27-tiroir {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .28s var(--hover-ease);
}
.p27-tiroir > div { overflow: hidden; min-height: 0; }
.p27-groupe[data-ouvert="1"] .p27-tiroir { grid-template-rows: 1fr; }
.p27-tiroir-liste {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  padding-top: var(--space-24);
}
.p27-tiroir a {
  display: block;
  width: 100%;
  height: 20px;
  font-family: var(--font-body);
  font-weight: var(--weight-book);
  font-size: var(--body-14-size);
  line-height: var(--body-14-line);
  color: var(--text-project-nav-subitem);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color 200ms ease;
}
.p27-tiroir a:hover,
.p27-tiroir a:focus-visible { color: var(--text-project-nav-item-hover); }
.p27-tiroir a[data-courant="1"] { color: var(--text-project-nav-subitem-active); }

/* Le tiroir ferme est hors du parcours du clavier : sans cela on tabule dans
   des liens qu'on ne voit pas. */
.p27-groupe:not([data-ouvert="1"]) .p27-tiroir a { visibility: hidden; }

@media (prefers-reduced-motion: reduce) {
  .p27-tiroir, .p27-plus::before, .p27-plus::after { transition: none; }
}

/* ── Le projet suivant ────────────────────────────────────────────────────
   La même carte que sur la page d'accueil, à la largeur du bloc. */
/* Flora, 21 aout (1055:34903) : 128px entre la fin du corps du projet et la
   carte "Next project", pour tous les projets. --space-48 n'a jamais existe
   comme token (padding-top invalide -> tout le raccourci tombait a 0) ; ecart
   corrige en tenant compte du gap de 8px deja pose par .p27-body entre blocs. */
/* L'ecart avec la carte absorbe la montee du survol. La carte se souleve de
   14px quand le pointeur passe (projects.css) : avec 8px d'ecart elle venait
   couvrir « Next project » (Flora, 25 aout, capture a l'appui). 24px laissent
   les 14px passer et 10 de respiration — et du meme coup l'etiquette remonte,
   ce qu'elle demandait aussi. */
.p27-next { padding: 120px 0 var(--space-64); display: flex; flex-direction: column; gap: var(--space-24); }
/* « Next project » s'aligne sur l'image et sur le titre qui la suit — tous
   trois au bord du bloc. Il portait le retrait de 24 des colonnes de texte,
   qui n'a pas lieu d'etre ici : la carte, elle, va bord a bord (Flora,
   25 aout : « le titre doit etre aligne avec l'image, la ca fait crade »). */
.p27-next .p27-eyebrow { padding: 0; }

/* ── Sur un écran étroit ──────────────────────────────────────────────────
   Le bloc n'a plus de marge à donner : il prend la largeur moins 32 de
   chaque côté, et le texte garde son retrait de 24 — donc la colonne suit
   sans jamais toucher le bord. */
@media (max-width: 1140px) {
  /* La barre fait 172 avec les cartes (16 marge + 36 rangee du haut + 16
     ecart + 104 cartes), puis 16 de plus avant le corps — meme regle que
     1114:43628, la rangee du haut passant de 32 a 36 pour s'accorder aux
     boutons du reste du site. */
  .p27-body { padding-top: 188px; }
  .p27-section { scroll-margin-top: 128px; }
}

@media (max-width: 680px) {
  .p27-body { width: auto; margin: 0 var(--space-16); }
  /* Les variantes mobiles des blocs de texte (1114:45619 pour le Hero-Header,
     1114:45625 pour le Section-Header) : le H0 du titre de projet redescend au
     corps du H2, comme le H1 des sections. */
  :root {
    --p27-inset: 16px;
    --p27-h1-size: 24px; --p27-h1-line: 30px;
    --p27-h0-size: 24px; --p27-h0-line: 30px; --p27-h0-track: -0.24px;
  }
  /* Next project (1114:44875) : 16 entre l'eyebrow et la carte, pas les 8
     du bureau — Flora, 22 aout : « il n'y a aucun espace entre next project
     et la card project ». */
  .p27-next { gap: var(--space-24); }

  /* Le bloc des metas de l'aperçu, variante mobile (1114:45255) : chaque
     libelle (Context, Role, Metrics, Team) passe AU-DESSUS de ses valeurs
     — plus la colonne de 140 a gauche du bureau, l'ecran est trop etroit
     pour deux colonnes. Releve sur le node : 8 entre libelle et valeurs,
     32 entre sections (le gap de .p27-metas, deja bon), avatars de
     l'equipe a 8 d'ecart qui passent a la ligne (x 0/72/144/216, 2e rangee
     a y=72). */
  .p27-meta { flex-direction: column; gap: var(--space-8); }
  .p27-meta-label { width: auto; }
  .p27-meta--equipe { align-items: stretch; }
  .p27-equipe { gap: var(--space-8); }

  /* Flora, 22 aout, corrige le meme jour : « je t'ai indique 16px comme a
     droite et a gauche du body container, tu as mis 24px ». L'ecart entre
     deux blocs de texte suit donc bien `--p27-inset` (16 sur telephone),
     et non le 24 du bureau. */
  .p27-body, .p27-section { gap: var(--space-16); }

  /* La rangee de telephones (1114:44720) : sur telephone elle part du meme
     retrait de 24 que le reste et ne deborde qu'A DROITE, un telephone
     entier visible puis le suivant qui se devoile au scroll. Centree
     (`safe center`, la regle du bureau), elle rognait un peu des deux
     cotes des le chargement — pas un aperçu volontaire, juste un
     cadrage force au milieu d'un contenu plus large que l'ecran. */
  .p27-tel-rang { justify-content: safe flex-start; }

  /* Flora, 22 aout : « les maquettes mobile sont coupees !!!!!! » — et la
     coupe etait VERTICALE, pas horizontale. Le cadre porte le ratio du
     bureau (592/441, en style inline) : a 361 de large il ne fait plus que
     269 de haut, et des telephones de 393 y perdent leur tiers inferieur.
     Sur la maquette mobile (1114:44720, Image-Full-width 361x441) le cadre
     GARDE sa hauteur — les telephones restent entiers, seule la largeur
     visible retrecit. `!important` est necessaire : le ratio est un style
     inline pose par le generateur, une regle de feuille ne le bat pas
     autrement. La hauteur revient alors du contenu lui-meme
     (24 + telephone + 24), a n'importe quelle taille de telephone. */
  .p27-media--rang { aspect-ratio: auto !important; }
  .p27-media--rang .p27-tel-rang { height: auto; }
  /* 1091:40423 : le contour des maquettes change de couleur en mobile,
     #402822 au lieu du #1e386e du bureau (Flora, 23 aout). */
  .p27-tel-rang > * { border-color: #402822; }
}

/* ── Sous 1140 : le sommaire n'a plus la place ────────────────────────────
   Meme raison qu'en 2026 (project-2026.css) : la colonne de 592 est centree
   dans la fenetre, donc le menu de 204 colle a 24 du bord droit mord dessus
   en dessous d'une certaine largeur — mesure au navigateur, vers 1048px.
   Sans hamburger ni etat replie par defaut (aucun script ne pilote un tel
   toggle sur cette page), le menu restait affiche en permanence, opaque,
   par-dessus le texte : c'est le bug remonte par Serge le 20 aout, capture a
   l'appui, le sommaire flottant sur « The issue split view ». Il s'efface
   avant ce point plutot que de chevaucher la lecture, au meme seuil que la
   page 2026. */
@media (max-width: 1140px) {
  .p27-menu { display: none; }
}

/* ── Le sommaire sur telephone (1114:45555, 174:27693, 1114:46066) ────────

   Flora, 21 aout : « lorsqu'on atterrit sur le menu, les cards project sont
   visibles, comme sur le desktop disparaissent lorsqu'on scroll vers le bas,
   pour laisser apparaitre l'item "Project index" a la place des project
   cards qui reste sticky tant qu'on scroll vers le bas ». Puis « qui se
   devoile quand l'utilisateur tape sur "Project index" ».

   Le bandeau et les cartes occupent donc la MEME bande sous la barre :
   quand `menu-2027.js` cache les cartes (deja son role sur desktop), il
   montre le bandeau, et l'inverse en remontant. */
.p27-index { display: none; }
.p27-burger { display: none; }

@media (max-width: 1140px) {
  /* La barre passe sur deux rangees : le nom et les boutons en haut, la
     bande des projets en dessous. Les mesures viennent des deux etats du
     Figma — 393x184 avec les cartes (1114:45555) et 393x112 avec le
     bandeau (174:27693) : 16 de marge, 32 de haut par rangee, 16 d'ecart,
     et 104 pour les cartes. */
  .p27-nav {
    height: auto;
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    row-gap: var(--space-16);
    padding: var(--space-16);
    /* Flora, 22 aout, trois fois de suite : « le menu n'est pas cense avoir
       un background, il faut le supprimer » — la barre est transparente,
       TOUJOURS, au repos comme au scroll (1114:43628 et ses captures
       IMG_7835/7836 : la bande grise au scroll etait le probleme, pas la
       solution). Comme sur le bureau : seuls les boutons portent leur
       propre verre, jamais la bande qui les contient. Deux mauvaises
       lectures successives ont mis un verre permanent puis un verre au
       defilement — les deux etaient faux. */
    background: transparent;
  }
  /* 16 d'ecart entre les rangees avec les cartes (1114:45555), 12 avec le
     bandeau "Project index" (174:27693) — releve sur les deux etats. */
  .p27-nav:has(.p27-index--vu) { row-gap: var(--space-12); }
  .p27-nav > [data-nav="name"] { grid-column: 1; grid-row: 1; justify-self: start; }
  .p27-nav-right { grid-column: 2; grid-row: 1; }

  /* Cartes et bandeau partagent la meme case : l'un s'efface, l'autre
     apparait, et la barre se retracte d'elle-meme puisque la rangee ne fait
     plus que la hauteur du bandeau. */
  .p27-nav-centre,
  .p27-index { grid-column: 1 / -1; grid-row: 2; }

  .p27-nav-centre {
    position: static;
    transform: none;
    width: auto;
    /* `overflow: hidden` sur les deux axes coupait net la 3e carte (139x3 +
       gaps = 432, contre 361 de large) : Flora, 22 aout — « elle doit comme
       le dernier avatar de la ligne testimonial continuer pour etre coupee
       par le screen et montrer qu'on peut scroller ». L'axe Y reste cache
       (c'est lui qui porte le repli vertical), l'axe X devient scrollable.

       Meme second bug que la rangee de testimonials, trouve en verifiant
       en direct plutot qu'en le supposant corrige : `overflow-x:auto` seul
       ne suffit pas, `.p27-nav` porte 16 de padding sur ses quatre cotes et
       le scroll s'arretait 16px avant le vrai bord de l'ecran, jamais
       flush. `margin-right` negatif annule ce padding pour cette rangee
       seule, sans lui ajouter son propre padding-right — sinon le meme
       ecart revient, juste deplace en bout de course. */
    margin-right: calc(-1 * var(--space-16));
    /* Le pendant gauche (Flora, 22 aout) : meme mecanique — coupe au vrai
       bord de l'ecran en scrollant, depart a 16 au repos. */
    margin-left: calc(-1 * var(--space-16));
    padding-left: var(--space-16);
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* Meme protection que la rangee de testimonials (Flora, 22 aout : les
       avatars « bougent vers le haut/bas selon ce qu'on fait avec le
       doigt ») — un `<img>` est nativement draggable, et sans
       `touch-action` un geste horizontal peut se melanger au defilement
       vertical de la page. */
    touch-action: pan-x;
    overscroll-behavior-x: contain;
    max-height: 104px;
    transition: max-height 320ms cubic-bezier(0.4, 0, 1, 1), opacity 280ms ease-in;
  }
  .p27-nav-centre::-webkit-scrollbar { display: none; }
  .p27-nav-centre--cachee {
    transform: none;
    max-height: 0;
    opacity: 0;
  }

  .p27-index {
    display: block;
    align-self: center;
    /* Flora, 22 aout (1152:5908 mis a jour) : la pilule est A DROITE et
       petite (145 dans la maquette — ici la largeur du contenu, memes
       paddings), plus une barre pleine largeur. */
    justify-self: end;
    opacity: 0;
    pointer-events: none;
    transition: opacity 280ms ease-in;
  }
  .p27-index--vu {
    opacity: 1;
    pointer-events: auto;
    transition: opacity 620ms cubic-bezier(0.16, 1, 0.3, 1);
  }
  /* La pilule "Project index" (1152:5908 mis a jour) : blanche a 80% +
     flou, largeur de son contenu (145 dans la maquette), texte #3a3a3a
     (primary/700) des le repos, 16 entre le texte et l'icone. Ouverte,
     elle ne change PAS : son + devient − et le panneau tombe dessous
     (1164:39944), elle ne s'etire plus en tete de carte. */
  .p27-index-tete {
    display: flex;
    align-items: center;
    gap: var(--space-16);
    width: auto;
    margin: 0;
    /* Flora, 22 aout : memes proportions que les boutons de la nav mobile
       (8/12 de padding, texte 16/20, donc 36 de haut) — a cote de boutons
       de 36, la pilule de 32 au corps de 14 paraissait minuscule. */
    padding: 8px var(--space-12);
    border: 0;
    border-radius: var(--radius-6);
    background: var(--surface-project-nav-item-hover);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    font-family: var(--font-body);
    font-weight: var(--weight-book);
    font-size: 16px;
    line-height: 20px;
    color: #3a3a3a;
    text-align: left;
    cursor: pointer;
  }
  /* Ouverte, elle devient la tete du panneau deroule (1152:6957) : blanc a
     80% et flou, pour ancrer visuellement le sommaire au-dessus des
     pilules translucides qu'il contient — Flora, 22 aout : « pas de
     background derriere le menu, c'est tres laid » sans cet etat. */

  /* Ouvert (1164:39944) : la pilule reste telle quelle et le panneau —
     une carte blanche a 80% floutee de 241 de large, padding 12, coins 6 —
     tombe a 8 dessous, aligne a droite. Hauteur au contenu (le node est
     "hug"), jamais l'ecran entier. `top` = bord bas de la pilule + 8 :
     16 de marge + 36 de rangee haute + 12 d'ecart + 32 de pilule + 8. */
  .p27-menu {
    display: none;
    position: fixed;
    /* 16 de marge + 36 de rangee haute + 12 d'ecart + 36 de pilule + 8. */
    top: 108px;
    /* `bottom: auto` est indispensable : la regle du bureau (plus haut dans
       ce fichier) pose `bottom: 24px`, et une boite fixed avec top ET
       bottom fixes est ETIREE entre les deux — 724px de carte pour 322px
       de contenu, le vide en blanc dessous (IMG_7841). La hauteur doit
       venir du contenu seul, comme le node "hug" 1164:39944. */
    bottom: auto;
    left: auto;
    right: var(--space-16);
    width: 241px;
    min-width: 0;
    max-height: calc(100vh - 124px);
    overflow-y: auto;
    z-index: 18;
    gap: var(--space-6);
    padding: var(--space-12);
    /* Flora, 22 aout (1152:6957 mis a jour) : fond BLANC PLEIN et bordure
       primary/50, « afin qu'on le voit partout » — le blanc a 80% laissait
       la page trop transparaitre sur certains fonds. */
    border: 1px solid var(--primary-50, #f4f4f4);
    border-radius: var(--radius-6);
    background: var(--primary-white, #fff);
  }
  /* Les etats des pilules sur telephone (1152:5908, atomes 1154:7198,
     variante device=Mobile uniquement). Le fond s'ecrit ICI en toutes
     lettres, pas via les variables de jauge : les regles du bureau posent
     leurs blancs (60/80/100%) directement sur `background`, et des
     variables ne les battent pas — c'est ce qui peignait des pilules
     blanches sur panneau blanc en ligne (IMG_7840). Ces regles-ci arrivent
     plus tard dans le fichier a selecteur egal, donc elles gagnent.

     - repos (et survol : sur un ecran tactile un :hover reste colle apres
       le tap, donc meme fond) : gris 20%, texte #8b8b8b ;
     - section simple active : gris 60%, texte #2b2b2b ;
     - accordeon ouvert ou contenant la section lue : TOUT l'accordeon en
       gris 60%, sa tete en #b9b9b9 (desactivee, regle bureau conservee),
       sous-item lu en #2b2b2b (regle bureau conservee). */
  .p27-menu .nav-item,
  .p27-menu .nav-item:not([data-courant="1"]):hover,
  .p27-menu .nav-item:not([data-courant="1"]):focus-within {
    background: var(--glassy-light-500);
    background-image: none;
    border-radius: var(--radius-6);
    color: var(--text-project-nav-item);
    /* Flora, 22 aout : « tous les items doivent tous etre de la meme
       taille, taille de police incluse » — les memes 8/12 et 16/20 que les
       boutons de la nav et la pilule Project index, donc 36 de haut. */
    padding: 8px var(--space-12);
    font-size: 16px;
    line-height: 20px;
  }
  /* Les sous-items des accordeons suivent la meme police. */
  .p27-menu .p27-tiroir a { font-size: 16px; line-height: 20px; height: 20px; }
  .p27-menu .nav-item[data-courant="1"] {
    background: var(--glassy-light-300);
    background-image: none;
    color: var(--text-project-nav-item-active);
  }
  .p27-menu .p27-groupe[data-ouvert="1"],
  .p27-menu .p27-groupe:has(> .p27-groupe-tete[data-courant="1"]) {
    background: var(--glassy-light-300);
    background-image: none;
  }
  /* L'accordeon ouvert descend a 12 de padding bas (1154:7216 : pt-6
     pb-12), la ou une pilule fermee reste a 6/6. */
  .p27-menu .p27-groupe[data-ouvert="1"] { padding-bottom: var(--space-12); }
  :root.p27-index-ouvert .p27-menu { display: flex; }

  /* Les boutons a la taille de la nav du reste du site sur telephone
     (mobile.css, Menu-Mobile 1:2017 : padding 8, texte 16/20, soit 36 de
     haut) — mobile.css n'est pas charge sur les pages projet, elles
     restaient donc aux 32/14 du bureau : Flora, 22 aout, « les boutons
     sont bien plus petits » que sur les autres pages. La pilule "Project
     index" et les items du sommaire gardent leur corps de 14 : ce sont
     des composants du menu (1152:6906), pas des boutons de nav. */
  .p27-nav .nav-item {
    padding: 8px var(--space-12);
    font-size: 16px;
    line-height: 20px;
  }

  /* La barre passe a « Contact » + le bouton du sommaire (1114:45555). */
  .p27-nav-right [data-nav="about"],
  .p27-nav-right [data-nav="approach"] { display: none; }
  /* Carre, a la meme taille que le burger de la home (36x36, mobile.css) —
     le 32 du composant suivait les anciens boutons de 32 ; les boutons
     passant a 36 pour s'accorder au reste du site, il suit. */
  .p27-burger {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 0;
    cursor: pointer;
  }
  /* L'icone est le fichier Icon/menu (24:564) de la maquette — le meme
     que le burger de la home — plus les trois traits dessines en CSS,
     qui n'etaient pas la bonne icone (Flora, 22 aout). */
  .p27-burger img { width: 12px; height: 11px; display: block; }

  .p27-nav-centre img { -webkit-user-drag: none; user-drag: none; pointer-events: none; }
}

/* ── Les cartes de projets dans la barre ──────────────────────────────────
   Flora, 20 aout (1048:34853) : les cartes passent a 80 de haut. C'est
   exactement la taille par defaut de `.nav-project--big` dans
   `project-nav.css` (106.67×80) — plus besoin de la retailler ici, elle
   porte deja la bonne valeur telle quelle. Les regles de survol et
   l'animation d'arrivee viennent du meme fichier, inchangees. */
.p27-nav .nav-projects-group { display: flex; gap: var(--space-8); }

/* `project-nav.css` pose `.project-nav` en barre fixe pleine largeur : c'est
   son role sur l'ancienne page, pas ici. Dans la barre 2027 elle n'est plus
   qu'un groupe de vignettes au centre, donc on la remet en flux. Les regles de
   survol et l'animation d'arrivee des cartes, elles, restent intactes. */
.p27-nav .project-nav {
  position: static;
  padding: 0;
  max-width: none;
  height: auto;
  min-height: 0;
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  display: flex;
  justify-content: center;
}

/* ── Le fond : l'accueil, et le verre par-dessus ───────────────────────────
   Figma 940:7385 (l'accueil, 1280x5133) sous 940:7443 (le panneau du projet,
   1280x28911). Le panneau porte `rgba(231,231,231,.6)` et `blur(65)`, relevés
   sur le nœud et non déduits : c'est parce qu'il est déjà laiteux que les
   cartes de texte peuvent se contenter de 30% de blanc.

   L'accueil est FIXE. Il ne défile pas avec le cas : la feuille glisse
   par-dessus lui, il reste où il est. */

.p27 { background: transparent; }

.p27-fond {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

/* L'accueil derriere est une IMAGE, plus un site entier charge dans un cadre.

   Ce cadre tirait toute la page d'accueil — sa feuille de style, son script,
   ses polices et sa video de portrait qui tournait en boucle — pour n'en
   montrer qu'une bouillie floue. Et comme cette video bougeait, le
   `backdrop-filter` du voile devait reflouter tout l'ecran a chaque image.

   Une image de 320 de large suffit : a 65 de flou, aucun detail ne survit. Elle
   pese 7 Ko la ou le cadre coutait une page complete, et le flou est cuit
   dedans — donc plus aucun filtre a la volee. */
.p27-fond {
  background-image: url("../home-flou.jpg?v=462");
  background-size: cover;
  background-position: top center;
}

.p27-voile {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: rgba(231, 231, 231, 0.6);
}

/* Le corps passe au-dessus des deux couches. La barre et le sommaire portent
   deja `position: fixed` et leurs z-index (20 et 19) plus haut dans cette
   feuille : ne rien redeclarer ici, une regle `position: relative` les
   remettrait dans le flux et pousserait la page de 380 vers le bas. */
.p27-body { position: relative; z-index: 2; }

/* Le navigateur qui ne sait pas flouter un arriere-plan recevrait l'accueil
   en clair sous le texte. Dans ce cas le voile devient opaque. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .p27-voile { background: var(--primary-50); }
}

/* ── Le voile se fond, seul le corps se deplace ───────────────────────────

   Flora, 20 aout : « il ne faut pas que le background du projet vienne par le
   bas, il doit apparaitre en fade in et disparaitre en fade out. C'est
   seulement le body project qui apparait ».

   Un nom de transition propre suffit a l'obtenir : nomme, le voile sort du
   groupe de la page et n'en suit plus le glissement — il se fond, ce que fait
   par defaut un element present d'un seul cote. Le corps, lui, reste dans le
   groupe racine et garde son mouvement. */
.p27-fond  { view-transition-name: p27-fond; }
.p27-voile { view-transition-name: p27-voile; }

/* Flora, 20 aout, capture a l'appui contre aparelho.studio : le fond ne doit
   pas jouer SA propre traversee en meme temps que les cartes.

   Premiere correction (180ms, sans le delai de la page) : mesuree correcte
   sur l'opacite, fausse a l'ecran. Capture apres coup : le fond, devenu
   opaque en 180ms, restait SEUL a l'ecran — un visage flou plein cadre, rien
   d'autre — pendant que la page (`page-rise`, 640ms) mettait pres de 600ms
   de plus a arriver. Le fond n'a jamais ete le probleme d'origine ; c'etait
   le fait qu'il partageait la courbe des CARTES avant leur propre correction
   plus haut. Les cartes ont maintenant leur rythme a elles ; le fond n'a
   plus besoin d'etre decouple de rien — il retrouve la meme traversee que la
   page qui le porte, `--transition-travel` / `--transition-ease`, et les
   deux arrivent ensemble comme avant que les cartes n'aient leur regle
   separee. */
/* Flora, 21 aout : le gris ne fait plus que se DISSOUDRE, jamais glisser ni
   balayer — meme duree et meme courbe que le corps qui arrive (la courbe des
   containers de reveal.js), sans delai : les couches montent ensemble. */
::view-transition-group(p27-fond),
::view-transition-group(p27-voile) {
  animation-duration: var(--page-dissolve);
  animation-timing-function: var(--page-dissolve-ease);
}

/* ── Le corps du projet, couche a part entiere ────────────────────────────

   Flora, 21 aout, gif aparelho a l'appui : « du gris perturbe la fluidite de
   la transition, et les projets n'arrivent pas proprement ».

   La vraie cause, retrouvee en relisant l'arbre de transition : fond et
   voile, nommes, peignent AU-DESSUS du cliche de la racine — qui contenait
   le corps. Dans la page reelle c'est l'inverse (fond z0, voile z1, corps
   z2). Pendant chaque traversee, le gris se posait donc PAR-DESSUS le
   contenu en train d'arriver, d'ou le voile grisatre sur tout.

   Le corps est desormais nomme lui aussi, et l'arbre de transition rejoue
   l'empilement exact de la page : fond 0, voile 1, corps 2, sommaire 3, et
   les cartes/boutons de la barre a 5 (transition.css). Le gris ne peut plus
   passer devant le contenu, par construction. */
.p27-body { view-transition-name: project-body; }

::view-transition-group(p27-fond)     { z-index: 0; }
::view-transition-group(p27-voile)    { z-index: 1; }
::view-transition-group(project-body) { z-index: 2; }
::view-transition-group(project-menu) { z-index: 3; }

/* L'entree du corps : la meme arrivee que ses propres containers (reveal.js,
   40px de montee avec le fondu, courbe 0.65/0/0.35/1) — la page arrive comme
   son contenu arrive, un seul vocabulaire. */
:root.vt-to-project::view-transition-new(project-body) {
  animation: p27-corps-entre var(--page-dissolve) var(--page-dissolve-ease) 60ms both;
}
:root.vt-from-project::view-transition-old(project-body) {
  animation: p27-corps-sort 450ms var(--page-dissolve-ease) both;
}
:root.vt-to-project::view-transition-group(project-body),
:root.vt-from-project::view-transition-group(project-body) {
  animation-duration: var(--page-dissolve);
  animation-timing-function: var(--page-dissolve-ease);
}
/* Entre DEUX projets, le groupe ne doit pas bouger du tout — et c'etait la
   diagonale que Flora signale le 25 aout : « un mouvement de diagonale qui
   remonte en haut, c'est degueulasse ».

   Un groupe de transition interpole tout seul la POSITION et la TAILLE entre
   l'ancien element et le nouveau. Quand on quitte un projet en etant au
   milieu de la page, l'ancien `.p27-body` est capture haut et long, le
   nouveau court et en haut : le groupe descend donc en biais et se
   redimensionne pendant que les deux feuilles glissent lateralement. Le
   mouvement lu a l'ecran est la somme des deux — une diagonale.

   Fige, le groupe ne fait plus rien : il ne reste que la poussee horizontale
   des deux feuilles (`across-from-right` / `across-to-left`), c'est-a-dire
   exactement le glissement d'aparelho. */
:root.vt-across::view-transition-group(project-body) {
  animation: none;
}

@keyframes p27-corps-entre { from { opacity: 0; transform: translateY(40px); } }
@keyframes p27-corps-sort  { to   { opacity: 0; transform: translateY(40px); } }

/* ── Le sommaire pendant les traversees ───────────────────────────────────

   Flora, 21 aout : « le menu projet doit disparaitre et apparaitre quand le
   projet change dans une animation qui rappelle celle utilisee dans
   l'apparition des containers du body project ». Nomme, il quitte la feuille
   qui se pousse et joue sa propre partition : il s'efface en descendant,
   puis le sommaire du nouveau projet monte de 40px avec un fondu — les
   memes 40px et la meme courbe que les containers. Sur la poussee entre
   deux projets, il part vite et revient une fois la poussee bien engagee. */
.p27-menu { view-transition-name: project-menu; }

:root.vt-to-project::view-transition-new(project-menu) {
  animation: p27-corps-entre 500ms var(--page-dissolve-ease) 250ms both;
}
:root.vt-from-project::view-transition-old(project-menu) {
  animation: p27-corps-sort 350ms var(--page-dissolve-ease) both;
}
:root.vt-across::view-transition-old(project-menu) {
  animation: p27-corps-sort 300ms var(--page-dissolve-ease) both;
}
:root.vt-across::view-transition-new(project-menu) {
  animation: p27-corps-entre 500ms var(--page-dissolve-ease) 300ms both;
}
:root.vt-across::view-transition-image-pair(project-menu) { isolation: none; }
/* `height: auto` : les deux sommaires n'ont pas le meme nombre de lignes,
   et la boite du groupe passe de l'un a l'autre — sans cela les cliches
   s'etirent pour la remplir pendant le morphing. */
:root.vt-across::view-transition-old(project-menu),
:root.vt-across::view-transition-new(project-menu) {
  mix-blend-mode: normal;
  height: auto;
}

/* ── Ne peindre que ce qui est a l'ecran ──────────────────────────────────

   La page fait 29 000 de haut et nine sections. Sans cela le navigateur
   calcule et peint les neuf a chaque image, y compris les 28 000 qu'on ne
   regarde pas. `contain-intrinsic-size` lui donne une hauteur presumee pour
   que la barre de defilement ne saute pas. */
.p27-section {
  content-visibility: auto;
  contain-intrinsic-size: auto 2400px; /* remplace par section */
}

/* La priorite de visibilite va aux PREMIERS elements dans l'ordre du
   document (Flora, 22 aout) : les infobulles de l'equipe depassent sous
   leur section, et `content-visibility: auto` fait de chaque section son
   propre contexte d'empilement — a z-index egal, la section SUIVANTE
   peindrait par-dessus. L'echelle descend donc avec l'ordre. */
.p27-body > * { position: relative; }
/* Et il ne suffit pas de peindre AU-DESSUS : `content-visibility: auto`
   impose un confinement de peinture qui ROGNE tout ce qui depasse de la
   section — l'infobulle perdait ses 10 derniers pixels (mesure : la bande
   sombre s'arrete net au bas de la section, y=354). La section qui porte
   l'equipe renonce donc a cette optimisation ; c'est l'overview, la
   premiere de la page, celle qui est de toute facon toujours visible. */
.p27-section:has(.p27-equipe) { content-visibility: visible; }
.p27-body > :nth-child(1) { z-index: 39; }
.p27-body > :nth-child(2) { z-index: 38; }
.p27-body > :nth-child(3) { z-index: 37; }
.p27-body > :nth-child(4) { z-index: 36; }
.p27-body > :nth-child(5) { z-index: 35; }
.p27-body > :nth-child(6) { z-index: 34; }
.p27-body > :nth-child(7) { z-index: 33; }
.p27-body > :nth-child(8) { z-index: 32; }
.p27-body > :nth-child(9) { z-index: 31; }
.p27-body > :nth-child(10) { z-index: 30; }
.p27-body > :nth-child(11) { z-index: 29; }
.p27-body > :nth-child(12) { z-index: 28; }
.p27-body > :nth-child(13) { z-index: 27; }
.p27-body > :nth-child(14) { z-index: 26; }
.p27-body > :nth-child(15) { z-index: 25; }
.p27-body > :nth-child(16) { z-index: 24; }
.p27-body > :nth-child(17) { z-index: 23; }
.p27-body > :nth-child(18) { z-index: 22; }
.p27-body > :nth-child(19) { z-index: 21; }
.p27-body > :nth-child(20) { z-index: 20; }
.p27-body > :nth-child(21) { z-index: 19; }
.p27-body > :nth-child(22) { z-index: 18; }
.p27-body > :nth-child(23) { z-index: 17; }
.p27-body > :nth-child(24) { z-index: 16; }


/* ── La loupe : regarder une capture de pres ───────────────────────────────

   Flora, 24 aout : « j'aimerais que sur certains containers image on puisse
   zoomer ». Le besoin est mesurable, pas decoratif — les captures d'interface
   sont posees dans une colonne de 666px alors que le fichier en fait 2688
   (Iteration X, la vue scindee) ou 3952 (PropertyGRID, la marketplace) : le
   texte de l'UI y est simplement illisible. Un simple agrandissement « plein
   ecran » ne reglerait rien, il ferait gagner 40% ; ce qu'il faut c'est
   atteindre les pixels du fichier, donc un zoom AVEC deplacement.

   Le voile est CELUI DES AUTRES OVERLAYS (Flora, 24 aout : « pourrais-tu
   utiliser le meme fond que pour les testimonials et la page contact ? ») :
   le verre clair de I1118:46828 — glassy-light/600 a 0.1 et un flou de 85,
   pose sur le voile lui-meme comme dans testimonials.css. Un site n'a pas
   trois manieres d'effacer sa page. Le verrou de defilement est le meme
   aussi (html.tm-fige) : un seul mecanisme pour tous les overlays.

   Quelles images : celles dont le fichier a de la definition en reserve.
   zoom-image.js le mesure a l'ouverture (naturalWidth vs largeur affichee) et
   ne pose le curseur-loupe que la ou le zoom apporte vraiment quelque chose —
   jamais une liste tenue a la main, qui serait fausse au premier export. */

.zi-loupe { cursor: zoom-in; }
.zi-loupe:has(.p27-tel-rang) { cursor: default; }

.zi-voile {
  position: fixed;
  inset: 0;
  z-index: 70;              /* au-dessus des temoignages et du Contact (60) */
  display: none;
  background: var(--glassy-light-600, rgba(203, 203, 203, 0.1));
  backdrop-filter: blur(85px);
  -webkit-backdrop-filter: blur(85px);
  opacity: 0;
  transition: opacity 200ms ease;
}
.zi-voile.zi-ouvert { display: block; }
.zi-voile.zi-visible { opacity: 1; }

/* La scene occupe tout, l'image y est posee au centre et transformee a la
   main (JS) : une transition sur `transform` seule reste sur le compositeur,
   donc le deplacement suit le doigt sans repeindre l'image. */
.zi-scene {
  position: absolute;
  inset: 0;
  overflow: hidden;
  touch-action: none;       /* le pincement est a nous, pas au navigateur */
}
.zi-image {
  position: absolute;
  top: 0;
  left: 0;
  /* base.css borne toute image a la largeur de son conteneur — utile partout
     ailleurs, faux ici : la visionneuse pose l'image A SA TAILLE DE FICHIER et
     c'est la transformation qui l'ajuste. Sans cette levee, une capture de
     2688 px etait ramenee a la largeur de l'ecran puis re-agrandie : le zoom
     « 1:1 » interpolait au lieu de montrer les pixels d'origine. */
  max-width: none;
  max-height: none;
  transform-origin: 0 0;
  will-change: transform;
  user-select: none;
  -webkit-user-drag: none;
}
.zi-image.zi-anime { transition: transform 320ms cubic-bezier(0.22, 0.61, 0.36, 1); }
/* La video de la visionneuse partage tout avec l'image — position, echelle,
   deplacement — et n'en differe que par la balise. */
.zi-video { object-fit: contain; background: rgba(0, 0, 0, 0.04); }
.zi-scene.zi-peut-zoomer .zi-image { cursor: zoom-in; }
.zi-scene.zi-zoome .zi-image { cursor: grab; }
.zi-scene.zi-tire .zi-image { cursor: grabbing; }

/* La legende de la figure suit son image : c'est elle qui dit ce qu'on
   regarde, la perdre en ouvrant serait perdre la moitie du propos. */
/* La legende dit ce qu'on regarde — indispensable a l'ouverture, genante des
   qu'on est au 1:1 : l'image couvre alors tout l'ecran et le texte se pose
   au milieu d'elle. Elle s'efface donc pendant le zoom et revient avec
   l'image ajustee. */
.zi-scene.zi-zoome + .zi-legende { opacity: 0; }
.zi-legende {
  position: absolute;
  z-index: 2;
  opacity: 1;
  transition: opacity 160ms ease;
  left: 0;
  right: 0;
  bottom: 0;
  /* Une legende qui traverse un ecran de 2560 se lit mal : l'oeil perd la
     ligne suivante. Flora, 24 aout : « garde 720px en largeur max ».
     C'est la mesure de confort habituelle — a peu pres 90 signes par ligne. */
  max-width: 720px;
  margin: 0 auto;
  padding: var(--space-16) var(--space-24) var(--space-24);
  text-align: center;
  color: var(--text-secondary, #6b6b6b);
  font-size: 14px;
  line-height: 20px;
  font-style: italic;
  white-space: pre-line;   /* la legende garde ses deux lignes */
  pointer-events: none;
  /* Plus de degrade sombre : sur le verre clair, la legende se lit seule. */
  background: none;
}

/* Les memes boutons que dans les temoignages (Flora, 24 aout : « ils sont
   censes adopter les memes codes ») : 32 de cote, rayon 6, verre gris et
   encre #4d4d4d — pas de rond noir. La croix reprend `--surface-nav-bg` avec
   son flou de 8, les fleches le verre plus discret `--glassy-dark-500`,
   exactement comme .tm-fermer et .tm-fleche. */
.zi-bouton {
  position: absolute;
  z-index: 3;              /* au-dessus de l'image, qui peut couvrir l'ecran */
  top: var(--space-24);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-6);
  color: var(--nav-default);
  cursor: pointer;
}
/* Meme socle que les boutons des temoignages, et pour la meme raison : le
   voile porte deja un `backdrop-filter`, donc celui des boutons ne rend pas
   sur iOS (piege B2). Un fond dense qui tient tout seul, le flou par-dessus
   pour les navigateurs qui le rendent. */
.zi-bouton {
  background: rgba(232, 232, 232, 0.94);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.06);
}
.zi-fermer { right: var(--space-24); }
.zi-prec, .zi-suiv { top: 50%; margin-top: -16px; }
.zi-prec { left: var(--space-24); }
.zi-suiv { right: var(--space-24); }
/* Le voile prend le focus a l'ouverture (role de dialogue) : il ne doit rien
   peindre. L'anneau reste sur les boutons, au clavier seulement. */
.zi-voile:focus { outline: none; }
.zi-bouton:focus { outline: none; }
.zi-bouton:focus-visible { outline: 2px solid var(--nav-default); outline-offset: 2px; }
.zi-bouton[hidden] { display: none; }

/* Sur un ecran tactile les fleches gênent plus qu'elles n'aident : le pouce
   est deja sur l'image, et la place manque. */
@media (hover: none) {
  .zi-prec, .zi-suiv { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .zi-voile { transition: none; }
  .zi-image.zi-anime { transition: none; }
}
