/* ═══════════════════════════════════════════════════════════════
   Pages projet v2 (2026-10-02)
   Socle commun (direction.md B) puis une mise en page par projet :
   .p1 le portant, .p2 la salle s'éteint, .p3 les deux pages,
   .p4 la planche-contact, .p5 le titre qui traverse, .p7 le seuil, .p8 Relay, .p9 Hecto.
   (Le brouillon « Sans titre » est sorti du site : .portfolio/2026-10-05-coherence/retirees/projet-6/)
   Couleur du projet : --c sur <body>, encre lisible dessus : --c-ink.
   Le mouvement est dans project.js (un seul fichier, effets par attributs).
   La version précédente est gardée dans .portfolio/2026-10-02-pages-projet-v2/avant/
   ═══════════════════════════════════════════════════════════════ */

:root {
  --out: cubic-bezier(.16, 1, .3, 1);   /* entrées, sortie douce */
  --io: cubic-bezier(.7, 0, .2, 1);     /* ouvertures plein écran */
  --dep: cubic-bezier(.7, 0, .84, 0);   /* départs */
}

body.projet {
  --c: #000;
  --c-ink: #fff;
  --c-15: color-mix(in srgb, var(--c) 15%, var(--bg));
  --c-55: color-mix(in srgb, var(--c) 55%, var(--bg));
  --c-ui: var(--c);                     /* traits et filets : la couleur du projet (éclaircie en sombre, shared.css) */
  --next: #000;
  --next-ink: #fff;
  --m: 80px;                            /* marge */
  --g: 24px;                            /* gouttière */
  --col: calc((100vw - 2 * var(--m) - 11 * var(--g)) / 12);
  --filet: 0.5px solid rgba(var(--fg-rgb), 0.15);
  background: var(--bg);
  color: var(--fg);
  font-family: 'Source Sans 3', sans-serif;
  transition: background-color 1.2s var(--out);
}

body.projet.is-dark {
  background: var(--bg-salle);
}

main,
.fin {
  overflow-x: clip;
}

img,
video {
  display: block;
  max-width: 100%;
  height: auto;
}

/* Grille 12 colonnes alignée sur les marges */
.g12 {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--g);
  padding-left: var(--m);
  padding-right: var(--m);
}

/* Focus clavier : noir, blanc sur fond sombre, jamais en couleur du projet */
.projet a:focus-visible,
.projet button:focus-visible,
.projet [tabindex]:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 4px;
}

.is-dark a:focus-visible,
.is-dark button:focus-visible {
  outline-color: #fff;
}

/* ── Flèche retour (fixe en haut à gauche, inchangée) ── */
.back-nav {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 100;
  /* Sous la bascule de thème (zone de clic de 18 à 62px, trait à 48px du bord) : flèche
     alignée sur le même bord, sa propre zone de clic (14px autour) commence à 66px (arrow à 80px) */
  padding: 80px 48px 40px 48px;
}

.back-nav a {
  display: inline-flex;
  color: var(--fg);
  text-decoration: none;
}

.back-nav a:hover {
  transform: translateX(-10px);
}

.arrow-icon {
  display: block;
  width: 56px;
  height: auto;
  overflow: visible;
  transform: scaleX(-1);
}

/* ── Calque d'ouverture (ouverture.js puis project.js) ──
   Sous le header et la flèche, qui restent en place pendant le passage */
.ov {
  position: fixed;
  inset: 0;
  z-index: 95;
  overflow: hidden;
  pointer-events: none;
}

.ov img {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
}

/* ═══ Socle commun ═══ */

/* Titre : vrai nom, Archivo Black au cadrage (--fit posé par project.js) */
.titre {
  margin: 0;
  font-family: 'Archivo Black', sans-serif;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: -0.025em;
  line-height: 0.8;
  white-space: nowrap;
  color: var(--fg);
}

.fit {
  display: block;
  font-size: var(--fit, 16vw);
  white-space: nowrap;
}

/* Masque de ligne : le titre monte de sous sa ligne (motion B.5) */
.l {
  display: block;
  clip-path: inset(-0.4em -0.2em 0 -0.2em);
}

.t {
  display: inline-block;
}

html.js .titre .l > .t {
  animation: monte 0.9s var(--out) 0.15s both;
}

html.js .titre .l + .l > .t {
  animation-delay: 0.24s;
}

html.ouv .titre .l > .t {
  animation-delay: 0.55s;
}

html.ouv .titre .l + .l > .t {
  animation-delay: 0.63s;
}

/* Le titre du bloc « Projet suivant » ne s'anime pas */
html.js .suivant .titre .l > .t {
  animation: none;
}

@keyframes monte {
  from { transform: translateY(105%); }
  to   { transform: none; }
}

/* Colophon : une phrase à la place de la fiche */
.colophon {
  font-size: 20px;
  line-height: 1.45;
  color: var(--ink);
  max-width: 30ch;
}

/* Signature du colophon : lien vers About, couleur du texte, souligné fin */
.colophon a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* Lien en ligne, masqué tant que href est vide */
.site-lien {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 18px;
  font-size: 17px;
  font-weight: 600;
  color: var(--fg);
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 4px;
}

.site-lien[hidden] {
  display: none;
}

.site-lien svg {
  width: 14px;
  height: 14px;
}

/* Récit : paragraphes à attaque, sans intertitre */
.recit {
  margin-top: 160px;
}

.recit-col {
  grid-column: 2 / 9;
}

/* Récit : 21px sur grand écran pour qu'il pèse face au décor (corrections passe 1) */
.recit p {
  font-size: 21px;
  line-height: 1.6;
  color: var(--ink-2);
  max-width: 34em;
  margin-bottom: 1.1em;
  transition: color 1.2s var(--out);
}

/* Paragraphe décalé : colonne plus étroite, rentrée de deux colonnes (Ethikwear) */
.recit p.decale {
  margin-left: calc(var(--col) * 2 + var(--g) * 2);
  max-width: 26em;
}

.lead {
  font-family: 'Archivo Black', sans-serif;
  font-weight: 400;
  font-size: 19px;
  letter-spacing: 0;
  color: var(--fg);
  transition: color 1.2s var(--out);
}

/* Ce que j'en retiens : une phrase, comme une citation de fin d'article */
.retiens {
  margin-top: 180px;
}

.retiens p {
  position: relative;
  grid-column: 2 / 10;
  font-family: 'Archivo Black', sans-serif;
  font-size: clamp(30px, 3.6vw, 54px);
  line-height: 1.06;
  letter-spacing: -0.015em;
  color: var(--fg);
  max-width: 17em;
  transition: color 1.2s var(--out);
}

/* Le trait de marqueur (cohérence 2026-10-05) : le seul dispositif commun des sept pages.
   Comme sur une planche-contact, on entoure la phrase retenue : un trait tracé à la main
   (même famille que le cadre de la planche de Dugos), dans la couleur du projet, une seule fois. */
.marque-fin {
  position: absolute;
  left: 0;
  bottom: -0.26em;
  width: min(100%, 11em);
  height: 0.3em;
  overflow: visible;
  pointer-events: none;
}

.marque-fin path {
  fill: none;
  stroke: var(--c-ui);
  stroke-width: 5px;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1600;          /* en pixels d'écran (non-scaling-stroke) : plus long que le trait */
  stroke-dashoffset: 0;
}

/* Il se dessine quand la phrase se révèle, 250 ms après le texte, puis ne bouge plus */
html.js .retiens p:not(.in) .marque-fin path {
  stroke-dashoffset: 1600;
}

html.js .retiens p.in .marque-fin path {
  transition: stroke-dashoffset 0.9s var(--out) 0.25s;
}

/* Le trait dépasse sous la dernière ligne : pas de découpe sur la phrase révélée */
html.js .retiens p[data-rv].in {
  clip-path: none;
}

html.rv-secours .marque-fin path {
  stroke-dashoffset: 0 !important;
}

/* Images et emplacements vides : sans cadre, sans arrondi, sans ombre */
.empty {
  background: var(--c-15);
}

.empty.c55 {
  background: var(--c-55);
}

.empty.c100 {
  background: var(--c);
}

/* Écran clair (fond blanc) : le filet de la grille Works */
.ecran {
  outline: var(--filet);
  outline-offset: -0.5px;
}

.legende {
  margin-top: 10px;
  max-width: 40ch;
  font-size: 14px;
  line-height: 1.4;
  color: var(--gris);
}

/* ── Révélations au scroll (motion B, project.js ajoute .in) ── */
html.js [data-rv="txt"] {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.9s var(--out), transform 0.9s var(--out);
}

html.js [data-rv="img"] {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 1.1s var(--out);
}

html.js [data-rv="img"] > * {
  transform: scale(1.12);
  transition: transform 1.4s var(--out);
}

html.js [data-rv].in {
  opacity: 1;
  transform: none;
  clip-path: inset(0);
}

html.js [data-rv].in > * {
  transform: none;
}

html.rv-secours [data-rv],
html.rv-secours [data-rv] > * {
  opacity: 1 !important;
  transform: none !important;
  clip-path: none !important;
}

/* ═══ Fin de page, identique partout : le projet suivant ═══ */
/* Projet suivant : tout le bloc est le lien, la couleur suivante monte du bas */
.suivant {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: 70vh;
  margin-top: 120px;
  padding: 28px var(--m) 40px;
  color: var(--fg);
  text-decoration: none;
  overflow: hidden;
}

.suivant::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--next);
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform 0.45s var(--dep);
}

.suivant:hover::before,
.suivant:focus-visible::before {
  transform: scaleY(1);
  transition: transform 0.7s var(--out);
}

.suivant-label {
  font-size: 16px;
  color: var(--gris);
  transition: color 0.4s ease;
}

.suivant .titre {
  display: block;
  transition: color 0.4s ease;
}

.is-dark .suivant-label {
  color: #999;
}

.suivant:hover .suivant-label,
.suivant:hover .titre,
.suivant:focus-visible .suivant-label,
.suivant:focus-visible .titre {
  color: var(--next-ink);
}

.projet .suivant:focus-visible {
  outline-color: var(--next-ink);
  outline-offset: -8px;
}

/* ═══ Projet 1, Ethikwear : le portant ═══ */
.p1 .ouv {
  position: relative;
  height: 100vh;
  min-height: 620px;
  overflow: hidden;
}

/* Vitrine : colonnes 6 à 12 + marge droite, du haut au bas de l'écran */
.p1 .ouv-img {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: calc(var(--col) * 7 + var(--g) * 6 + var(--m));
}

.p1 .ouv-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 80% 50%;   /* cale la capture de Works sur les mannequins */
}

.p1 .ouv-texte {
  position: absolute;
  top: 150px;
  left: var(--m);
  width: calc(var(--col) * 5 + var(--g) * 4);
}

/* Le titre traverse tout l'écran en bas, par-dessus l'image */
.p1 .ouv .titre {
  position: absolute;
  left: var(--m);
  right: var(--m);
  bottom: 40px;
  z-index: 2;
}

/* Le portant : sticky, le défilement vertical fait glisser le rail.
   --h = hauteur commune des écrans : 62 % de l'écran, mais jamais plus que la
   place sous le header, ni trop haute pour la largeur (tablette en portrait).
   Chaque écran a sa vraie proportion --r (largeur / hauteur du fichier), donc
   sa largeur est connue avant le chargement de l'image : la course est juste. */
.p1 .portant {
  --h: min(62vh, 52vw, calc(100vh - 250px));
  --haut: max(170px, calc((100vh - var(--h)) / 2));
  position: relative;
  margin-top: 160px;
}

.p1 .portant-scene {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}

.p1 .portant-barre {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--haut) - 4px);
  height: 1px;
  background: var(--fg);
}

.p1 .rail {
  position: absolute;
  top: var(--haut);
  left: 0;
  display: flex;
  gap: 24px;
  width: max-content;
  padding: 0 var(--m);
}

.p1 .rail figure {
  position: relative;
  flex: none;
  height: var(--h);
  width: calc(var(--h) * var(--r));
  background: var(--c-15);          /* jamais un trou blanc, même image pas encore chargée */
  transition: transform 0.4s var(--out);
}

.p1 .rail figure:hover {
  transform: translateY(6px);
}

.p1 .rail figure > .empty,
.p1 .rail figure > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.p1 .rail .legende {
  position: absolute;
  top: 100%;
  left: 0;
  width: max-content;
  max-width: 100%;
}

/* ═══ Projet 2, Redstone : la salle s'éteint ═══ */
.p2 .ouv {
  padding-top: 190px;
  align-items: start;
}

.p2 .ouv-gauche {
  grid-column: 1 / 9;
}

/* Grand mais posé : pas au cadrage, plafonné et tenu dans les colonnes 1 à 8 */
.p2 .ouv .titre {
  font-size: min(var(--fit, 11vw), clamp(72px, 11vw, 168px));
}

.p2 .ouv .colophon {
  margin-top: 48px;
  max-width: min(30ch, calc(var(--col) * 4 + var(--g) * 3));
}

.p2 .ouv-img {
  grid-column: 9 / 13;
  width: calc(100% + var(--m));
  max-width: none;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  object-position: 50% 45%;
}

/* Textes déjà à l'écran quand la salle s'éteint */
.is-dark .recit p {
  color: #aaa;
}

.is-dark .lead,
.is-dark .retiens p {
  color: #fff;
}

.p2 .salle-pin {
  position: relative;
  height: 320vh;
  margin-top: 120px;
}

.p2 .salle-scene {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  display: grid;
  place-items: center;
  perspective: 1400px;
}

/* L'affiche : 78vh de haut, au ratio des fichiers (1144 × 1626). Elle s'incline
   un peu selon --k pendant que les calques se posent par fondus (project.js) */
.p2 .affiche {
  position: relative;
  height: 78vh;
  aspect-ratio: 1144 / 1626;
  background: #000;
  transform-style: preserve-3d;
  transform: rotateX(calc(var(--k, 0) * 24deg)) rotateZ(calc(var(--k, 0) * -8deg));
}

.p2 .calque,
.p2 .affiche-finale {
  position: absolute;
  inset: 0;
  transform: translate3d(0, 0, calc(var(--k, 0) * var(--dz, 0px)));
}

.p2 .calque > img,
.p2 .affiche-finale > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Le titre flotte devant l'image quand l'affiche s'incline */
.p2 .calque-titre { --dz: 140px; }

/* Avant le script : seul le personnage est visible, les autres calques arrivent par fondu */
html.js .p2 .calque-fond,
html.js .p2 .calque-avant,
html.js .p2 .calque-titre,
html.js .p2 .affiche-finale {
  opacity: 0;
}

/* Nom du calque en cours, à gauche de l'affiche, aligné sur son bas */
.p2 .calque-nom {
  position: absolute;
  right: calc(50% + 78vh * 0.352 + 32px);
  bottom: 11vh;
  font-size: 16px;
  color: var(--soft);
  white-space: nowrap;
  transition: opacity 0.3s ease;
}

/* Le générique, comme le billing block d'une affiche de cinéma */
.p2 .generique {
  max-width: 520px;
  margin: 80px auto 0;
  padding: 0 var(--m);
  box-sizing: content-box;
  text-align: center;
  font-family: 'Archivo Black', sans-serif;
  font-size: 14px;
  line-height: 1.6;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fg);
  transition: color 1.2s var(--out);
}

.is-dark .generique {
  color: #fff;
}

.p2 .generique span {
  display: block;
}

/* ═══ Projet 3, Unik : les deux pages qui défilent ensemble ═══ */
.p3 .ouv {
  position: relative;
  height: 100vh;
  min-height: 600px;
  background: var(--c);
  overflow: hidden;
}

/* Le titre passe derrière la vitrine : le portable couvre le milieu du mot */
.p3 .ouv .titre {
  position: absolute;
  left: var(--m);
  right: var(--m);
  bottom: 40px;
  z-index: 1;
}

.p3 .ouv-img {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 2;
  width: min(64vw, 960px);
  transform: translate(-50%, -50%);
}

/* La vitrine est un mockup sur fond gris : on la détoure au contour du portable
   (relevé sur web/unik-vitrine.webp) pour qu'il soit posé seul sur le rose.
   Avec une vitrine sur fond transparent, retirer ce clip-path. */
.p3 .ouv-img.detoure {
  clip-path: polygon(22.9% 26%, 23.75% 25%, 25% 24.8%, 75% 24.8%, 76.25% 25%, 76.6% 26%,
    76.6% 74.25%, 80.7% 74.25%, 80.7% 75.8%, 80.1% 76.5%, 77.6% 77%, 74.4% 77.2%,
    25.9% 77.2%, 22.6% 77%, 19.5% 76.5%, 18.6% 75.8%, 18.6% 74.25%, 22.9% 74.25%);
}

.p3 .apres {
  margin-top: 72px;
}

.p3 .apres > div {
  grid-column: 1 / 6;
}

.p3 .duo {
  position: relative;
  margin-top: 160px;
}

.p3 .duo-scene {
  position: sticky;
  top: 0;
  height: 100vh;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 120px minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  padding: 170px var(--m) 40px;
}

.p3 .duo-legende {
  grid-row: 1;
  padding-bottom: 14px;
  font-size: 14px;
  color: var(--gris);
}

.p3 .duo-legende + .duo-legende {
  grid-column: 3;
}

.p3 .fenetre {
  position: relative;
  grid-row: 2;
  overflow: hidden;
}

.p3 .page {
  width: 100%;
}

/* Wireframe vide dessiné en CSS : la même structure, nue puis habillée */
.p3 .page.vide {
  display: grid;
  grid-template-rows: 9fr 22fr 30fr 18fr 14fr 7fr;
  gap: 12px;
  aspect-ratio: 1 / 3;
}

.p3 .page.nue > i {
  background: var(--bg);
  outline: 0.5px solid rgba(var(--fg-rgb), 0.25);
  outline-offset: -0.5px;
}

.p3 .page.habillee > i:nth-child(1) { background: var(--c-15); }
.p3 .page.habillee > i:nth-child(2) { background: var(--c-55); }
.p3 .page.habillee > i:nth-child(3) { background: var(--c); }
.p3 .page.habillee > i:nth-child(4) { background: #222; }
.p3 .page.habillee > i:nth-child(5) { background: var(--c-55); }
.p3 .page.habillee > i:nth-child(6) { background: var(--c-15); }

/* Notes au centre : elles suivent les pages, face aux sections qu'elles commentent */
.p3 .notes {
  position: relative;
}

.p3 .note {
  position: absolute;
  left: 0;
  right: 0;
  max-width: 120px;
  margin: 0 auto;
  font-size: 15px;
  line-height: 1.35;
  color: var(--ink);
  text-align: center;
}

/* Les détails : trois recadrages collés, d'un bord à l'autre */
.p3 .details {
  display: flex;
  height: 48vh;
  margin-top: 160px;
}

.p3 .details > * {
  flex: var(--r) 1 0;
  min-width: 0;
  height: 100%;
  aspect-ratio: var(--r);
  object-fit: cover;
  background: var(--c-15);          /* emplacement réservé tant que l'image n'est pas là */
}

/* ═══ Projet 4, Dugos Photographie : la planche-contact ═══ */
.p4 .heros {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}

.p4 .heros-media {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Le voile : la page blanche passe sur la vidéo, qui reste en place */
.p4 .feuille {
  position: relative;
  z-index: 1;
  background: var(--bg);
  padding-top: 48px;
}

.p4 .ouv-titre {
  padding: 0 var(--m);
}

.p4 .ouv-titre .l + .l {
  margin-top: 0.06em;
}

.p4 .ouv-texte {
  margin-top: 40px;
}

.p4 .ouv-texte > div {
  grid-column: 1 / 7;
}

/* Le site est en ligne : le lien passe au premier plan, sous le colophon.
   Même dessin pour le prototype Figma d'Ethikwear (p1). */
.p1 .site-lien,
.p4 .site-lien {
  margin-top: 24px;
  font-size: 22px;
  gap: 8px;
}

.p1 .site-lien svg,
.p4 .site-lien svg {
  width: 18px;
  height: 18px;
}

.p4 .planche-zone {
  display: flex;
  flex-direction: column;
  margin-top: 160px;
  padding: 0 var(--m);
}

/* Filets partagés, le même trait que la grille Works */
.p4 .planche {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));   /* 9 vues : 3 × 3 */
  border-top: var(--filet);
  border-left: var(--filet);
}

.p4 .vue {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 2000 / 1182;           /* le format des captures du site */
  padding: 16px;
  border: 0;
  border-right: var(--filet);
  border-bottom: var(--filet);
  background: none;
}

.p4 .vue > .empty,
.p4 .vue > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--c-15);          /* emplacement réservé tant que l'image n'est pas là */
}

.p4 .vue:focus-visible {
  outline-offset: -4px;
}

/* Le cadre tracé au marqueur : un trait SVG, pas une bordure */
.p4 .marqueur {
  position: absolute;
  inset: 10px;
  width: calc(100% - 20px);
  height: calc(100% - 20px);
  overflow: visible;
  pointer-events: none;
}

.p4 .marqueur path {
  fill: none;
  stroke: var(--c-ui);
  stroke-width: 3px;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: var(--trait, 2000px);
  stroke-dashoffset: var(--trait, 2000px);
  transition: stroke-dashoffset 0.35s var(--dep);
}

.p4 .vue:hover .marqueur path,
.p4 .vue:focus-visible .marqueur path,
.p4 .vue.choisie .marqueur path {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 0.6s var(--out);
}

.p4 .grande {
  margin-top: 48px;
}

.p4 .grande-vue {
  aspect-ratio: 2000 / 1182;
  background: var(--c-15);
  transition: opacity 0.4s ease;
}

.p4 .grande-vue > * {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.p4 .grande-vue.change {
  opacity: 0;
  transition-duration: 0.2s;
}

/* Le parcours en vidéo, à la largeur de la planche */
.p4 .parcours {
  margin-top: 140px;
  padding: 0 var(--m);
}

.p4 .parcours-vue {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: var(--surface);
}

.p4 .parcours-vue video {
  width: 100%;
  aspect-ratio: 1280 / 756;
  object-fit: cover;
}

/* ═══ Projet 5, Queen : le titre qui traverse ═══ */
.p5 .traverse {
  position: relative;
  height: 200vh;
  background: var(--c);
}

.p5 .traverse-scene {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}

/* Au cadrage au repos (le mot se lit en entier), puis il glisse vers la gauche
   et sort de l'écran au défilement */
.p5 .traverse .titre {
  position: absolute;
  top: 50%;
  left: var(--m);
  right: var(--m);
  z-index: 2;
  transform: translateY(-50%);
}

/* Les cartons : deux devant le titre, un derrière. top = position de repos */
.p5 .carton {
  position: absolute;
  z-index: 3;
}

.p5 .carton > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
}

/* Recadrage précis d'une grande page (carton C, haut de la fiche album) :
   l'image est plus large que le carton et décalée ; les marges en % suivent sa largeur */
.p5 .carton > img.recadre {
  width: var(--w);
  max-width: none;
  height: auto;
  margin-left: var(--l);
  margin-top: var(--h);
}

.p5 .carton { overflow: hidden; }
/* A à droite du colophon (lisibilité, intégration 2026-10-03) ; B et C inchangés */
.p5 .carton-a { top: 54vh; left: 29vw; width: 21vw; aspect-ratio: 4 / 5; }
.p5 .carton-b { top: 70vh; left: 44vw; width: 34vw; aspect-ratio: 3 / 2; z-index: 1; }
.p5 .carton-c { top: 86vh; left: 72vw; width: 20vw; aspect-ratio: 1; }

.p5 .traverse .colophon {
  position: absolute;
  left: var(--m);
  bottom: 40px;
  z-index: 4;
  color: #000;
}

/* Le calque : wireframe et maquette l'un sur l'autre, un trait jaune balaie
   de gauche à droite (direction 2026-10-03-queen D). Rendu de base = lecture
   empilée, figée à moitié (sans JS, mouvement réduit). html.calque-ok = épinglé. */
.p5 .calque {
  --ratio: 1512 / 890;
  --trait: 6px;
  margin-top: 160px;
  padding: 0 var(--m);
}

.p5 .calque-cadre {
  display: grid;
  gap: 88px;
  justify-items: center;
}

/* Une paire = un cadre au ratio des fichiers, l'écran clair au filet de Works */
.p5 .paire {
  position: relative;
  width: min(100%, calc(74vh * 1512 / 890));
  aspect-ratio: var(--ratio);
  margin: 0;
  outline: var(--filet);
  outline-offset: -0.5px;
  --p: 50%;
}

.p5 .paire img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: top;
}

.p5 .paire .mq {
  clip-path: inset(0 calc(100% - var(--p)) 0 0);
}

/* Le trait : jaune bordé de noir, lisible sur le gris comme sur le noir.
   Sans JS il est posé au milieu (left), épinglé il suit le bord par transform */
.p5 .trait {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--p);
  z-index: 2;
  width: var(--trait);
  margin-left: calc(var(--trait) / -2);
  box-sizing: border-box;
  background: var(--c);
  border-left: 1px solid #000;
  border-right: 1px solid #000;
  transition: opacity 0.2s ease;
}

.p5 .paire-nom {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 12px;
  font-size: 16px;
  font-weight: 600;
  color: var(--fg);
}

.p5 .calque-legende {
  display: none;
}

/* Épinglé : un seul cadre au centre de l'écran, les paires empilées dedans */
html.calque-ok .p5 .calque {
  position: relative;
  height: calc(100vh + var(--n, 4) * 90vh);
  padding: 0;
}

html.calque-ok .p5 .calque-scene {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

html.calque-ok .p5 .calque-cadre {
  display: block;
  position: relative;
  height: min(74vh, calc((100vw - 2 * var(--m)) * 890 / 1512));
  aspect-ratio: var(--ratio);
  overflow: hidden;
  outline: var(--filet);
  outline-offset: -0.5px;
}

html.calque-ok .p5 .paire {
  position: absolute;
  inset: 0;
  width: auto;
  aspect-ratio: auto;
  outline: none;
  clip-path: inset(var(--e, 0%) 0 0 0);
}

/* Épinglé, le trait suit le bord par transform (posé par project.js) */
html.calque-ok .p5 .paire .trait {
  left: 0;
  will-change: transform, opacity;
}

html.calque-ok .p5 .paire .mq {
  will-change: clip-path;
}

/* Le nom de chaque paire reste pour les lecteurs d'écran ; à l'œil, la légende commune */
html.calque-ok .p5 .paire-nom {
  top: auto;
  margin: 0;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

html.calque-ok .p5 .calque-legende {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  width: calc(min(74vh, calc((100vw - 2 * var(--m)) * 890 / 1512)) * 1512 / 890);
  margin-top: 16px;
}

.p5 .calque-nom,
.p5 .calque-etat {
  transition: opacity 0.3s ease;
}

.p5 .calque-nom {
  font-size: 16px;
  font-weight: 600;
  color: var(--fg);
}

.p5 .calque-etat {
  font-size: 14px;
  color: var(--muted);
  transition-duration: 0.2s;
}

/* Le prototype : un seul grand lien, souligné en jaune au survol, comme le trait du calque */
.proto {
  margin-top: 160px;
}

.proto-lien {
  grid-column: 1 / -1;
  justify-self: start;
  font-family: 'Archivo Black', sans-serif;
  font-size: clamp(40px, 6.4vw, 104px);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--fg);
  text-decoration: none;
}

.proto-texte {
  background-image: linear-gradient(var(--c-ui), var(--c-ui));
  background-repeat: no-repeat;
  background-position: 0 92%;
  background-size: 0 0.12em;
  transition: background-size 0.7s var(--out);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

.proto-fin {
  white-space: nowrap;
}

.proto-fin svg {
  display: inline-block;
  width: 0.6em;
  height: 0.6em;
  margin-left: 0.12em;
  vertical-align: 0.02em;
  transition: transform 0.7s var(--out);
}

.proto-fin svg path {
  stroke-width: 2.4;
}

.proto-lien:hover .proto-texte,
.proto-lien:focus-visible .proto-texte {
  background-size: 100% 0.12em;
}

.proto-lien:hover svg,
.proto-lien:focus-visible svg {
  transform: translate(6px, -6px);
}

/* Parallaxe douce : l'image est 12 % plus haute que son cadre */
.px {
  position: absolute;
  left: 0;
  right: 0;
  top: -6%;
  height: 112%;
}

.px > * {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ═══ Tablette (768 à 1099) ═══ */
@media (max-width: 1099px) {
  body.projet {
    --m: 48px;
  }

  .recit-col {
    grid-column: 1 / 9;
  }

  .recit p {
    font-size: 19px;
  }

  .lead {
    font-size: 17px;
  }

  /* Ethikwear : la colonne de droite est trop étroite pour le portable (audit-ux 13).
     Jusqu'à 1099px, l'ouverture passe en pile : vitrine 4:3 bord à bord, titre
     qui chevauche son bas, colophon dessous (comme en mobile). */
  .p1 .ouv {
    height: auto;
    min-height: 0;
    padding-top: 190px;
    display: flex;
    flex-direction: column;
  }

  .p1 .ouv-img {
    position: relative;
    width: 100%;
    aspect-ratio: 4 / 3;
    max-height: 72vh;          /* tablette à l'horizontale : le titre reste dans l'écran */
  }

  .p1 .ouv .titre {
    position: relative;
    left: auto;
    right: auto;
    bottom: auto;
    margin: -0.42em var(--m) 0;
  }

  .p1 .ouv-texte {
    order: 3;
    position: static;
    width: auto;
    margin-top: 32px;
    padding: 0 var(--m);
  }

  .retiens p {
    grid-column: 1 / -1;
  }

  .p2 .ouv-gauche {
    grid-column: 1 / 8;
  }

  .p2 .ouv-img {
    grid-column: 8 / 13;
  }
}

/* ═══ Mobile (< 768) ═══ */
@media (max-width: 767px) {
  body.projet {
    --m: 20px;
    --g: 12px;
  }

  /* Header et flèche défilent avec la page */
  body.projet header,
  body.projet .theme-nav,
  body.projet .back-nav {
    position: absolute;
  }

  .back-nav {
    padding: 80px 20px 20px 48px;
  }

  .arrow-icon {
    width: 40px;
  }

  .colophon {
    font-size: 17px;
  }

  .recit {
    margin-top: 96px;
  }

  .recit-col,
  .retiens p {
    grid-column: 1 / -1;
  }

  .recit p {
    font-size: 17px;
  }

  .recit p.decale {
    margin-left: 0;
  }

  .lead {
    font-size: 15px;
  }

  .retiens {
    margin-top: 110px;
  }

  .retiens p {
    font-size: 28px;
  }

  .marque-fin {
    width: min(100%, 9em);
  }

  .marque-fin path {
    stroke-width: 4px;
  }

  .suivant {
    min-height: 52vh;
    padding-bottom: 24px;
  }

  .suivant:active::before {
    transform: scaleY(1);
    transition: transform 0.7s var(--out);
  }

  .suivant:active .suivant-label,
  .suivant:active .titre {
    color: var(--next-ink);
  }

  /* Projet 1 : ouverture, voir la règle tablette (jusqu'à 1099px).
     Sous 768px le titre démarre sous la vitrine : le bas de la capture portrait porte
     un bouton noir où les lettres noires se perdaient (cohérence 2026-10-05, point 17). */
  .p1 .ouv .titre {
    margin: 12px var(--m) 0;
  }

  .p1 .portant {
    height: auto !important;
    margin-top: 96px;
  }

  .p1 .portant-scene {
    position: relative;
    height: auto;
    overflow: visible;
  }

  .p1 .portant-barre {
    top: 0;
  }

  .p1 .rail {
    position: relative;
    top: 0;
    width: 100%;
    padding-top: 4px;
    padding-bottom: 32px;
    transform: none !important;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding: 0 20px;
    scrollbar-width: none;
  }

  .p1 .portant {
    --h: min(56svh, 80vw);
  }

  .p1 .rail figure {
    scroll-snap-align: start;
  }

  .p1 .rail figure:hover {
    transform: none;
  }

  /* Projet 2 */
  .p2 .ouv {
    padding-top: 190px;
  }

  .p2 .ouv-gauche,
  .p2 .ouv-img {
    grid-column: 1 / -1;
  }

  .p2 .ouv .titre {
    font-size: var(--fit, 20vw);
  }

  .p2 .ouv .colophon {
    margin-top: 32px;
    max-width: 30ch;
  }

  .p2 .ouv-img {
    width: 100%;
    margin-top: 40px;
  }

  /* Projet 3 */
  .p3 .ouv {
    height: 100svh;
    min-height: 560px;
    display: flex;
    flex-direction: column;
    padding-top: 190px;
  }

  .p3 .ouv .titre {
    position: relative;
    left: auto;
    right: auto;
    bottom: auto;
    margin: 0 var(--m);
  }

  /* Détourée, la vitrine peut déborder : le portable prend presque toute la largeur */
  .p3 .ouv-img {
    position: relative;
    left: auto;
    top: auto;
    width: 140%;
    max-width: none;
    margin: auto 0 auto -20%;
    transform: none;
  }

  .p3 .apres {
    margin-top: 48px;
  }

  .p3 .apres > div {
    grid-column: 1 / -1;
  }

  .p3 .duo {
    margin-top: 96px;
  }

  .p3 .duo-scene {
    height: 100svh;
    grid-template-columns: minmax(0, 1fr) 0 minmax(0, 1fr);
    column-gap: 6px;
    padding-top: 24px;
    padding-bottom: 24px;
  }

  .p3 .notes {
    visibility: hidden;
  }

  .p3 .details {
    height: 48svh;
    margin-top: 96px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
  }

  .p3 .details > * {
    flex: none;
    width: auto;
    aspect-ratio: var(--r);
    scroll-snap-align: start;
  }

  /* Projet 4 */
  /* La vitrine entière, pleine largeur, sous le header */
  .p4 .heros {
    height: 100vh;
    height: 100svh;
    margin-top: 0;
  }

  .p4 .ouv-texte > div {
    grid-column: 1 / -1;
  }

  .p4 .planche-zone {
    margin-top: 96px;
  }

  /* 3 colonnes gardées : la planche reste un carré de 9, petites vues comme sur une vraie planche */
  .p4 .vue {
    padding: 6px;
  }

  .p4 .marqueur {
    inset: 3px;
    width: calc(100% - 6px);
    height: calc(100% - 6px);
  }

  .p4 .grande {
    order: -1;
    margin: 0 0 32px;
  }

  .p4 .parcours {
    margin-top: 88px;
  }

  /* Projet 5 */
  .p5 .traverse {
    height: auto;
    padding: 190px 0 56px;
  }

  /* Le titre d'abord, dans le premier écran, puis les cartons */
  .p5 .traverse-scene {
    position: relative;
    height: auto;
    display: flex;
    flex-direction: column;
  }

  .p5 .traverse .titre {
    order: -1;
    position: relative;
    top: auto;
    left: auto;
    right: auto;
    margin: 0 var(--m);
    font-size: var(--fit, 20vw);   /* le mot entier, au cadrage, comme les six autres pages */
    transform: none;
  }

  .p5 .carton {
    position: relative;
    top: auto;
    left: auto;
    width: calc(100% - 2 * var(--m) - 20px);
    margin: 40px var(--m) 0;
    transform: none !important;
  }

  .p5 .carton-b {
    margin-left: calc(var(--m) + 20px);
  }

  .p5 .traverse .colophon {
    position: static;
    margin: 40px var(--m) 0;
  }

  .p5 .calque {
    --trait: 4px;
    margin-top: 96px;
  }

  .p5 .calque-cadre {
    gap: 64px;
  }

  .p5 .paire {
    width: 100%;
  }

  .p5 .paire-nom,
  .p5 .calque-nom {
    font-size: 14px;
  }

  .p5 .calque-etat {
    font-size: 13px;
  }

  /* Épinglé en mobile : cadre pleine largeur utile, centré à 45 % de l'écran */
  html.calque-ok .p5 .calque {
    height: calc(100svh + var(--n, 4) * 80svh);
  }

  html.calque-ok .p5 .calque-scene {
    height: 100svh;
    justify-content: flex-start;
    padding-top: calc(45svh - (100vw - 2 * var(--m)) * 890 / 1512 / 2);
  }

  html.calque-ok .p5 .calque-cadre {
    width: calc(100vw - 2 * var(--m));
    height: auto;
  }

  html.calque-ok .p5 .calque-legende {
    width: calc(100vw - 2 * var(--m));
  }

  .proto {
    margin-top: 96px;
  }

  .proto-texte {
    background-size: 100% 0.12em;
  }
}

/* Mobile et mouvement réduit : la salle se déplie en lecture verticale */
@media (max-width: 767px), (prefers-reduced-motion: reduce) {
  .p2 .salle-pin {
    height: auto;
    margin-top: 120px;
  }

  .p2 .salle-scene {
    position: relative;
    height: auto;
    display: block;
    perspective: none;
    overflow: visible;
    padding: 0 var(--m);
  }

  .p2 .affiche {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 72px;
    width: 100%;
    max-width: 520px;
    height: auto;
    aspect-ratio: auto;
    margin: 0 auto;
    transform: none;
  }

  .p2 .calque,
  .p2 .affiche-finale,
  html.js .p2 .calque,
  html.js .p2 .affiche-finale {
    position: relative;
    inset: auto;
    display: block;
    aspect-ratio: 1144 / 1626;
    opacity: 1;
    transform: none;
  }

  /* Le nom de chaque calque au-dessus de lui */
  .p2 .calque::before,
  .p2 .affiche-finale::before {
    content: attr(data-nom);
    position: absolute;
    bottom: 100%;
    left: 0;
    padding-bottom: 10px;
    font-size: 14px;
    color: #999;
  }

  .p2 .affiche {
    background: none;
  }

  .p2 .calque,
  .p2 .affiche-finale {
    background: #000;
  }

  .p2 .calque-nom {
    display: none;
  }

  .p2 .generique {
    margin-top: 72px;
  }
}

@media (max-width: 767px) {
  .p2 .generique {
    font-size: 15px;
  }
}

/* ═══ Mouvement réduit : aucun déplacement, découpe ni épinglage ═══ */
@media (prefers-reduced-motion: reduce) {
  html.js [data-rv],
  html.js [data-rv] > * {
    transform: none !important;
    clip-path: none !important;
    transition: opacity 0.25s linear;
  }

  html.js [data-rv] {
    opacity: 0;
  }

  html.js [data-rv].in {
    opacity: 1;
  }

  html.js .titre .l > .t {
    animation: fondu 0.25s linear both;
  }

  /* Le trait de marqueur est déjà tracé, il apparaît en fondu avec la phrase */
  html.js .retiens p .marque-fin {
    opacity: 0;
    transition: opacity 0.2s linear;
  }

  html.js .retiens p.in .marque-fin {
    opacity: 1;
  }

  html.js .retiens p .marque-fin path,
  html.js .retiens p.in .marque-fin path {
    stroke-dashoffset: 0;
    transition: none;
  }

  body.projet,
  .suivant::before,
  .p1 .rail figure,
  .p4 .grande-vue {
    transition-duration: 0.01s;
  }

  .p1 .portant {
    height: auto !important;
  }

  .p1 .portant-scene {
    position: relative;
    height: auto;
    padding-bottom: 32px;
  }

  .p1 .portant-barre {
    top: 0;
  }

  .p1 .rail {
    position: relative;
    top: 0;
    width: 100%;
    padding-top: 4px;
    overflow-x: auto;
    transform: none !important;
  }

  .p3 .duo {
    height: auto !important;
  }

  .p3 .duo-scene {
    position: relative;
    height: auto;
  }

  .p3 .page {
    transform: none !important;
  }

  .p3 .notes {
    visibility: hidden;
  }

  .p5 .traverse {
    height: 100vh;
  }

  .p5 .traverse-scene {
    position: relative;
  }

  .p5 .traverse .titre {
    animation: none;
  }

  .p5 .carton,
  .px {
    transform: none !important;
  }
}

@keyframes fondu {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ═══ Corrections passe 1 : header, cibles, titres de section ═══ */

/* Header et flèche lisibles sur tout fond (audit-ux 4 et 5) : blancs en
   « différence », donc noirs sur blanc, clairs sur une photo ou un titre noir.
   Sur un aplat de couleur (project.js pose .sur-couleur) ou dans la salle noire,
   on revient au noir ou au blanc francs. */
body.projet header,
body.projet .theme-nav,
body.projet .back-nav {
  mix-blend-mode: difference;
}

body.projet nav a,
body.projet .theme-toggle,
body.projet .back-nav a {
  color: #fff;
  transition: transform 0.2s ease;
}

body.projet header a:focus-visible,
body.projet .theme-toggle:focus-visible,
body.projet .back-nav a:focus-visible {
  outline-color: #fff;
}

body.projet.sur-couleur header,
body.projet.sur-couleur .theme-nav,
body.projet.sur-couleur .back-nav,
body.projet.is-dark header,
body.projet.is-dark .theme-nav,
body.projet.is-dark .back-nav {
  mix-blend-mode: normal;
}

body.projet.sur-couleur nav a,
body.projet.sur-couleur .theme-toggle,
body.projet.sur-couleur .back-nav a {
  color: #000;
}

body.projet.sur-couleur header a:focus-visible,
body.projet.sur-couleur .theme-toggle:focus-visible,
body.projet.sur-couleur .back-nav a:focus-visible {
  outline-color: #000;
}

/* Dugos : le hero est une grille de portraits, la « différence » rend le menu
   illisible (audit-ux 1). Sur la photo : blanc franc sur un voile sombre en haut
   du hero ; dès que la feuille blanche passe sous le header, retour à la règle. */
body.p4.sur-photo header,
body.p4.sur-photo .theme-nav,
body.p4.sur-photo .back-nav {
  mix-blend-mode: normal;
}

body.p4.sur-photo nav a,
body.p4.sur-photo .theme-toggle,
body.p4.sur-photo .back-nav a {
  color: #fff;
}

.p4 .heros::after {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 240px;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.62), rgba(0, 0, 0, 0.3) 55%, rgba(0, 0, 0, 0));
  pointer-events: none;
}

/* Cibles tactiles de 44px sans changer le dessin (audit-ux 9).
   Le header a sa propre zone dans shared.css. */
.back-nav a,
.site-lien {
  position: relative;
}

.back-nav a::after {
  content: "";
  position: absolute;
  inset: -14px -10px;          /* au moins 44 px de haut et de large, même à 40 × 20 en mobile */
}

.site-lien::after {
  content: "";
  position: absolute;
  inset: -12px -8px;
}

/* Titres de section pour les lecteurs d'écran, invisibles à l'œil (audit-ux 14) */
.lecteur {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ═══ Projet 6, Passage Secret : le seuil (2026-10-05) ═══
   Classe de page .p7.
   Une fente d'une colonne s'ouvre au centre, s'élargit jusqu'au plein cadre,
   puis les pages se relaient par lanières. project.js pose les découpes (--k).
   Sans JavaScript ou en mouvement réduit : les pages s'empilent avec leur légende. */

/* Ouverture : titre au cadrage, colophon, mention */
.p7 .ouv-ps {
  padding: 170px var(--m) 0;
}

.p7 .ouv-ps-texte {
  margin-top: 36px;
  max-width: 620px;
}

/* La mention de cadre : une note de colophon, en 600, au filet de la couleur de la page */
.p7 .mention {
  margin-top: 28px;
  max-width: 620px;
  padding-left: 16px;
  border-left: 3px solid var(--c-ui);
  font-size: 18px;
  font-weight: 600;
  line-height: 1.45;
  color: var(--fg);
}

/* Repli : pages empilées, chacune avec sa légende */
.p7 .seuil {
  margin-top: 140px;
}

.p7 .seuil-scene {
  padding: 0 var(--m);
}

.p7 .seuil-page {
  margin: 0 0 24px;
}

.p7 .seuil-page figcaption {
  margin-top: 10px;
  font-size: 16px;
  font-weight: 600;
  color: var(--fg);
}

.p7 .seuil-bande {
  display: none;
}

/* Épinglé : la scène remplit l'écran, la bande basse porte la légende */
html.seuil-ok .p7 .seuil {
  position: relative;
  height: 460vh;
  margin-top: 120px;
}

html.seuil-ok .p7 .seuil-scene {
  position: sticky;
  top: 0;
  height: 100vh;
  padding: 0;
  overflow: hidden;
}

html.seuil-ok .p7 .seuil-cadre {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: calc(100vh - 56px);
  /* La fente : project.js pose --t, --r, --l (en px) selon le défilement */
  clip-path: inset(var(--t, 0px) var(--r, 0px) 0 var(--l, 0px));
  will-change: clip-path;
}

html.seuil-ok .p7 .seuil-page {
  position: absolute;
  inset: 0;
  margin: 0;
}

html.seuil-ok .p7 .seuil-page img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

/* Le nom de chaque page reste pour les lecteurs d'écran ; à l'œil, la bande basse */
html.seuil-ok .p7 .seuil-page figcaption {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

html.seuil-ok .p7 .seuil-bande {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 56px;
  padding: 0 var(--m);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  background: var(--bg);
  font-size: 16px;
  line-height: 1.3;
}

.p7 .seuil-nom {
  font-weight: 600;
  color: var(--fg);
  transition: opacity 0.3s ease;
}

/* Le mobile : la plongée et la version téléphone, décalées en hauteur */
.p7 .mobile-ps {
  margin-top: 160px;
  align-items: start;
}

.p7 .mobile-ps figure {
  margin: 0;
}

.p7 .mobile-ps-a {
  grid-column: 1 / 9;
}

.p7 .mobile-ps-b {
  grid-column: 9 / 12;
  margin-top: 120px;
}

@media (max-width: 1099px) {
  .p7 .mobile-ps-a { grid-column: 1 / 8; }
  .p7 .mobile-ps-b { grid-column: 8 / 13; margin-top: 80px; }
}

@media (max-width: 767px) {
  .p7 .ouv-ps {
    padding-top: 190px;
  }

  .p7 .mention {
    font-size: 17px;
  }

  .p7 .seuil {
    margin-top: 88px;
  }

  html.seuil-ok .p7 .seuil {
    height: 380vh;
    margin-top: 88px;
  }

  .p7 .mobile-ps {
    margin-top: 88px;
  }

  .p7 .mobile-ps-a { grid-column: 1 / 13; }
  .p7 .mobile-ps-b { grid-column: 5 / 13; margin-top: 24px; }
}

/* Le parcours en vidéo : à la largeur des marges, sans cadre ni arrondi */
.p7 .parcours {
  margin-top: 140px;
  padding: 0 var(--m);
}

.p7 .parcours figure {
  margin: 0;
}

.p7 .parcours-vue {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: #172232;
}

.p7 .parcours-vue video {
  width: 100%;
  aspect-ratio: 1280 / 800;
  object-fit: cover;
}

@media (max-width: 767px) {
  .p7 .parcours { margin-top: 88px; }
}

@media (prefers-reduced-motion: reduce) {
  .p7 .seuil-nom { transition: none; }
}

/* ═══ Projet 8, Relay : le titre posé sur l'application ═══
   Classe de page .p8. Le titre au cadrage, puis la capture de l'application
   bord à bord (même fichier que la case de Works : le calque se recadre dessus).
   Le lien « Tester l'app » et la phrase de fin reprennent le dessin de Queen (.proto). */
.p8 .ouv-relay {
  padding-top: 150px;
}

.p8 .ouv-relay .titre {
  margin: 0 var(--m);
}

.p8 .ouv-relay-img {
  margin-top: 40px;
}

.p8 .ouv-relay-img img {
  width: 100%;
  height: auto;
  aspect-ratio: 1600 / 1000;
}

/* Téléphone en portrait : la source portrait (740 × 1600) garde son ratio, sans être écrasée dans 1600 / 1000 */
@media (max-aspect-ratio: 3/5) {
  .p8 .ouv-relay-img img {
    aspect-ratio: 740 / 1600;
  }
}

.p8 .ouv-relay-texte {
  margin-top: 40px;
}

.p8 .ouv-relay-texte > div {
  grid-column: 1 / 6;
}

/* Le feed sur ordinateur, bord à bord, sous les vues mobiles */
.p8 .bureau {
  margin-top: 160px;
}

.p8 .bureau img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1600 / 1000;
  background: var(--c-15);   /* emplacement réservé tant que l'image n'est pas là */
}

.p8 .bureau .legende {
  padding: 0 var(--m);
}

/* Cibles tactiles du lien du colophon (audit-ux 3) : le dessin ne bouge pas */
.p8 .site-lien {
  min-height: 44px;
  margin-top: 6px;
}

/* Les vues : captures mobiles collées, à la même hauteur, centrées, fond blanc de chaque côté */
.p8 .vues {
  --h: min(70vh, 69vw);      /* trois écrans collés tiennent toujours dans la largeur */
  display: flex;
  justify-content: center;
  padding-bottom: 64px;      /* la place des légendes, sous les écrans */
  margin-top: 160px;
}

.p8 .vues > figure {
  position: relative;
  flex: none;
  height: var(--h);
  width: calc(var(--h) * var(--r));
  background: var(--c-15);   /* emplacement réservé tant que l'image n'est pas là */
}

.p8 .vues > figure > img {
  width: 100%;
  height: 100%;
  max-width: none;
}

.p8 .vues .legende {
  position: absolute;
  top: 100%;
  left: 0;
  width: max-content;
  max-width: 100%;
}

@media (max-width: 767px) {
  .p8 .ouv-relay {
    padding-top: 190px;
  }

  .p8 .bureau {
    margin-top: 96px;
  }

  .p8 .proto-lien {
    min-height: 44px;
  }

  .p8 .ouv-relay-texte > div {
    grid-column: 1 / -1;
  }

  /* Rail horizontal natif, accroché au bord gauche, le dernier écran déborde */
  .p8 .vues {
    --h: 60svh;
    justify-content: flex-start;
    margin-top: 96px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
  }

  .p8 .vues > figure {
    scroll-snap-align: start;
  }
}


/* ═══ Projet 9, Hecto : le niveau qui monte ═══
   Classe de page .p9. Couleur du projet : orange #EE7B3F, encre indigo #1D1650
   (posées sur <body>). Le titre est posé sur un aplat orange, la capture de la
   vitrine se révèle par le bas comme une pinte qui se remplit. Puis la vitrine,
   l'admin sur téléphone (bande orange), l'admin sur bureau et le schéma tracé
   au marqueur. Même fichier que la case de Works : depuis la grille, le calque
   se recadre dessus et le niveau ne rejoue pas (html.ouv). */
.p9 {
  --mousse: #F5E6DC;                 /* la ligne de mousse, seulement pendant la montée */
}

/* L'aplat orange : le titre, la mention de cadre, la capture */
.p9 .ouv-hecto-haut {
  padding-top: 150px;
  background: var(--c);
}

.p9 .ouv-hecto .titre {
  margin: 0 var(--m);
  color: var(--c-ink);
  /* Taille de départ proche du cadrage final (project.js affine avec --fit) : le bloc ne saute pas
     quand le calque de Works se recadre dessus (audit-ux 2) */
  font-size: var(--fit, calc((100vw - 2 * var(--m)) * 0.264));
}

/* Arrivée depuis Works : le niveau ne rejoue pas, la mousse n'existe pas */
html.ouv .p9 .ouv-hecto-img::after {
  display: none;
}

/* La mention de cadre, dite une seule fois, sur l'orange, dès le premier écran */
.p9 .cadre {
  margin: 28px var(--m) 0;
  font-family: 'Archivo Black', sans-serif;
  font-size: 18px;
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--c-ink);
  padding-bottom: 28px;
}

.p9 .ouv-hecto-img {
  position: relative;
  overflow: hidden;
}

.p9 .ouv-hecto-img img {
  width: 100%;
  height: auto;
  aspect-ratio: 1600 / 1000;
}

/* Téléphone en portrait : la source portrait (740 × 1600) garde son ratio */
@media (max-aspect-ratio: 3/5) {
  .p9 .ouv-hecto-img img {
    aspect-ratio: 740 / 1600;
  }
}

/* Le niveau : la capture se révèle par le bas, un trait de mousse en accompagne le bord.
   Seulement à l'arrivée directe (pas de calque #ov, donc pas html.ouv). Fill backwards :
   une fois joué, plus aucune découpe sur l'image. */
html.js:not(.ouv) .p9 .ouv-hecto-img img {
  animation: hecto-niveau 1.1s var(--out) 0.3s backwards;
}

.p9 .ouv-hecto-img::after {
  content: "";
  position: absolute;
  inset: 0;
  border-top: 4px solid var(--mousse);
  pointer-events: none;
  opacity: 0;
}

html.js:not(.ouv) .p9 .ouv-hecto-img::after {
  animation: hecto-mousse 1.1s var(--out) 0.3s backwards,
             hecto-mousse-fin 1.1s linear 0.3s backwards;
}

@keyframes hecto-niveau {
  from { clip-path: inset(100% 0 0 0); }
  to   { clip-path: inset(0); }
}

@keyframes hecto-mousse {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}

/* Visible pendant la montée, disparaît sur les 200 dernières ms (18 % de 1,1 s) */
@keyframes hecto-mousse-fin {
  0%, 82% { opacity: 1; }
  100%    { opacity: 0; }
}

.p9 .ouv-hecto-texte {
  margin-top: 40px;
}

.p9 .ouv-hecto-texte > div {
  grid-column: 1 / 6;
}

/* Vitrine et admin sur bureau : une image 16/10 bord à bord */
.p9 .bureau {
  margin-top: 160px;
}

.p9 .bureau img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1600 / 1000;
  background: var(--c-15);   /* emplacement réservé tant que l'image n'est pas là */
}

.p9 .bureau .legende {
  padding: 0 var(--m);
}

/* Rails de téléphones : écrans à la même hauteur, sans cadre. --r = largeur / hauteur de l'image.
   La profondeur : au survol d'un rail, l'écran le plus proche du pointeur reste à 1,
   les autres passent à .55 (project.js, pointeur fin seulement). */
.p9 .vues > figure {
  position: relative;
  flex: none;
  height: var(--h);
  width: calc(var(--h) * var(--r));
  background: var(--c-15);
}

.p9 .vues > figure > img {
  width: 100%;
  height: 100%;
  max-width: none;
}

html.js .p9 [data-profondeur] figure.loin > img {
  opacity: 0.55;
  transition: opacity 0.3s ease, clip-path 1.1s var(--out);
}

/* La vitrine sur mobile : trois écrans collés, d'un bord à l'autre */
.p9 .vues-vitrine {
  --h: min(76vh, 70vw);
  display: flex;
  justify-content: center;
  padding-bottom: 64px;       /* la place des légendes, sous les écrans */
  margin-top: 160px;
}

.p9 .vues-vitrine .legende {
  position: absolute;
  top: 100%;
  left: 0;
  width: max-content;
  max-width: 100%;
}

/* L'admin sur téléphone : quatre écrans sur une bande orange bord à bord, légèrement décalés */
.p9 .admin-tel {
  /* Les quatre écrans + trois gouttières tiennent toujours entre les marges (ratio 0,462 × 4 = 1,848) */
  --h: min(52vh, calc((100vw - 2 * var(--m) - 3 * var(--g)) / 1.848));
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: var(--g);
  min-height: 70vh;
  padding: 6vh var(--m);
  margin-top: 160px;
  background: var(--c);
  color: var(--c-ink);
}

.p9 .admin-tel > figure:nth-child(even) {
  margin-top: 24px;
}

.p9 .admin-tel .legende {
  max-width: calc(var(--h) * var(--r));
  color: var(--c-ink);
}

.p9 .admin-tel:focus-visible {
  outline-color: var(--c-ink);
  outline-offset: -6px;
}

/* Le schéma : une ligne tracée au marqueur, quatre mots posés dessus, deux phrases dessous */
.p9 .schema {
  position: relative;
  margin-top: 160px;
  padding: 0 var(--m);
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: var(--g);
}

.p9 .schema .mot {
  grid-row: 1;
  font-family: 'Archivo Black', sans-serif;
  font-size: clamp(20px, 2.2vw, 28px);
  line-height: 1.1;
  color: var(--fg);
  padding-bottom: 12px;
}

.p9 .schema .mot:nth-of-type(1) { grid-column: 1; }
.p9 .schema .mot:nth-of-type(2) { grid-column: 2; }
.p9 .schema .mot:nth-of-type(3) { grid-column: 3; }
.p9 .schema .mot:nth-of-type(4) { grid-column: 4; }

.p9 .schema .trait {
  grid-row: 2;
  grid-column: 1 / -1;
  display: block;
  width: 100%;
  height: 22px;
  overflow: visible;
}

.p9 .schema .trait-v {
  display: none;
}

.p9 .schema .trait path {
  fill: none;
  stroke: var(--c-ui);
  stroke-width: 5px;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 2600;          /* pixels d'écran (non-scaling-stroke) : plus long que le trait */
  stroke-dashoffset: 0;
}

.p9 .schema .phrase {
  grid-row: 3;
  display: flex;
  gap: 10px;
  margin-top: 16px;
  font-size: 16px;
  line-height: 1.45;
  color: var(--ink-2);
}

.p9 .schema .phrase-1 { grid-column: 1; }
.p9 .schema .phrase-2 { grid-column: 2 / 5; max-width: 34ch; }

.p9 .schema .phrase svg {
  flex: none;
  width: 22px;
  height: 14px;
  margin-top: 5px;
  overflow: visible;
}

.p9 .schema .phrase svg path {
  fill: none;
  stroke: var(--fg);
  stroke-width: 1.8px;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Au passage à l'écran : le trait se dessine de gauche à droite, chaque mot apparaît quand le trait l'atteint */
html.js .p9 .schema:not(.in) .trait path {
  stroke-dashoffset: 2600;
}

html.js .p9 .schema.in .trait path {
  transition: stroke-dashoffset 1.2s var(--out);
}

html.js .p9 .schema:not(.in) .mot,
html.js .p9 .schema:not(.in) .phrase {
  opacity: 0;
  transform: translateY(12px);
}

html.js .p9 .schema.in .mot,
html.js .p9 .schema.in .phrase {
  transition: opacity 0.7s var(--out), transform 0.7s var(--out);
  transition-delay: calc(var(--i, 0) * 240ms + 0.1s);
}

@media (max-width: 767px) {
  .p9 .ouv-hecto-haut {
    padding-top: 190px;
  }

  .p9 .cadre {
    font-size: 16px;
    margin-top: 22px;
    padding-bottom: 22px;
  }

  .p9 .ouv-hecto-texte > div {
    grid-column: 1 / -1;
  }

  .p9 .bureau {
    margin-top: 96px;
  }

  /* Rails horizontaux natifs, sans barre : le visuel suivant dépasse, on peut glisser */
  .p9 .vues-vitrine,
  .p9 .admin-tel {
    justify-content: flex-start;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
  }

  .p9 .vues-vitrine {
    --h: 60svh;
    margin-top: 96px;
  }

  .p9 .admin-tel {
    --h: 52svh;
    min-height: 78vh;
    margin-top: 96px;
    padding: 6vh var(--m);
  }

  .p9 .vues > figure {
    scroll-snap-align: start;
  }

  .p9 .admin-tel {
    scroll-padding-left: var(--m);   /* le premier écran s'arrête sur la marge, pas au bord */
  }

  .p9 .admin-tel > figure:last-child {
    margin-right: 40px;
  }

  /* Le schéma à la verticale : même trait, quatre mots empilés */
  .p9 .schema {
    margin-top: 96px;
    grid-template-columns: 22px minmax(0, 1fr);
    column-gap: 18px;
  }

  .p9 .schema .trait-h {
    display: none;
  }

  /* Le trait vertical longe les quatre mots, sur toute la hauteur du schéma */
  .p9 .schema .trait-v {
    display: block;
    position: absolute;
    top: 0;
    bottom: 0;
    left: var(--m);
    width: 22px;
    height: 100%;
  }

  .p9 .schema .mot {
    grid-column: 2 !important;
    font-size: 24px;
    padding-bottom: 0;
  }

  .p9 .schema .mot:nth-of-type(1) { grid-row: 1; }
  .p9 .schema .phrase-1          { grid-row: 2; grid-column: 2; margin: 10px 0 34px; }
  .p9 .schema .mot:nth-of-type(2) { grid-row: 3; margin-bottom: 34px; }
  .p9 .schema .mot:nth-of-type(3) { grid-row: 4; }
  .p9 .schema .phrase-2          { grid-row: 5; grid-column: 2; margin: 10px 0 34px; }
  .p9 .schema .mot:nth-of-type(4) { grid-row: 6; }
}

/* Mouvement réduit : le niveau devient un fondu de 300 ms, le trait est déjà tracé, les mots sont là */
@media (prefers-reduced-motion: reduce) {
  html.js:not(.ouv) .p9 .ouv-hecto-img img {
    animation: fondu 0.3s linear backwards;
  }

  html.js:not(.ouv) .p9 .ouv-hecto-img::after {
    animation: none;
    display: none;
  }

  html.js .p9 .schema:not(.in) .trait path,
  html.js .p9 .schema.in .trait path {
    stroke-dashoffset: 0;
    transition: none;
  }

  html.js .p9 .schema:not(.in) .mot,
  html.js .p9 .schema:not(.in) .phrase {
    opacity: 1;
    transform: none;
  }

  html.js .p9 .schema.in .mot,
  html.js .p9 .schema.in .phrase {
    transition: none;
  }

  html.js .p9 [data-profondeur] figure.loin > img {
    opacity: 1;
    transition: none;
  }
}
