/* =========================================
   PROJECT — Page projet (Instable + futures)
   Palette globale du site conservée
   ========================================= */

.project-page {
  background: transparent;
  color: var(--ink);
  min-height: 100vh;
  padding-bottom: 8rem;
}

/* Bouton retour en haut, à droite du logo (pas dessus) */
.project-back {
  position: fixed;
  /* Centre vertical = centre de la ligne du header : padding haut de la
     nav (1.5rem) + moitie de la hauteur du logo (34px de large -> 29.6px). */
  top: calc(1.5rem + 14.8px);
  translate: 0 -50%;
  left: calc(var(--gutter) + 4rem);
  z-index: 150;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-size: .85rem;
  letter-spacing: .1em;
  color: var(--ink);
  padding: .5rem 1rem;
  background: rgba(255, 255, 255, 0.94); /* sans flou d'arriere-plan (couteux) */
  border-radius: 100px;
  transition: transform .4s var(--ease-out), color .3s ease;
}

.project-back:hover {
  transform: translateX(-4px);
  color: var(--accent);
}

.project-back svg {
  transition: transform .4s var(--ease-out);
}

.project-back:hover svg {
  transform: translateX(-3px);
}

/* ═══════════════════════════════════════════
   MISE EN PAGE A DEUX COLONNES
   A gauche la presentation du projet, qui reste
   a l'ecran ; a droite le defile des visuels.
   On peut ainsi lire le propos en regardant les
   images, sans faire d'aller-retour.
   ═══════════════════════════════════════════ */

.project-split {
  display: grid;
  /* minmax(0, …) sur les deux pistes : sans lui, une piste de grille prend
     pour largeur minimale celle de son contenu, et un visuel large pousserait
     la colonne de droite au-dela de l'ecran. */
  grid-template-columns: minmax(0, 30%) minmax(0, 1fr);
  /* Indispensable au collage : sans `start`, les pistes s'etirent sur toute
     la hauteur de la ligne et `position: sticky` n'a plus de course. */
  align-items: start;
}

/* HERO du projet — devient la colonne de gauche, collante */
/* La presentation reste collee sur TOUT ecran d'ordinateur, y compris dans
   une fenetre reduite. Pour que ce soit tenable, ses espacements et sa typo
   sont bornes par la hauteur de fenetre autant que par sa largeur : le
   `min(Xvw, Yvh)` fait retrecir le bloc quand la fenetre s'aplatit, ce qu'un
   clamp purement horizontal ne faisait pas. */
.project-hero {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(.55rem, 1.7vh, 1.25rem);
  /* Le degagement sous le header ne doit PAS suivre la hauteur de fenetre :
     le header, lui, mesure toujours 63px. Une marge en vh pure tombait a 1px
     d'ecart sur un 1280x720, et passait carrement sous le logo en 1152x648.
     D'ou une base fixe (4rem) a laquelle s'ajoute une croissance douce. */
  padding: clamp(6.75rem, calc(4rem + 4.5vh), 9rem) clamp(1.5rem, 3vw, 3.5rem)
           clamp(.5rem, 2vh, 2rem) var(--gutter);
  /* Filet de securite pour les fenetres vraiment basses : la presentation
     defile alors dans son propre cadre plutot que d'etre tronquee. La barre
     est fine mais VISIBLE — cachee, personne ne devinerait qu'il reste du
     texte en dessous. */
  max-height: 100vh;
  max-height: 100svh;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(10, 10, 10, .18) transparent;
}

.project-hero::-webkit-scrollbar { width: 4px; }
.project-hero::-webkit-scrollbar-thumb {
  background: rgba(10, 10, 10, .18);
  border-radius: 2px;
}

/* L'ordre du HTML est metadonnees puis titre : a l'ecran on veut l'inverse,
   le titre d'abord. `order` evite de toucher au balisage des six pages. */
.project-hero__title    { order: 1; }
.project-hero__subtitle { order: 2; }
.project-hero__summary  { order: 3; }
.project-hero__meta     { order: 4; }

/* Resume du projet. Il remplace les longs blocs de texte qui occupaient la
   colonne de droite : tout ce qui explique est desormais ici, et la colonne
   de droite ne montre plus que des visuels.
   Plus petit que la description pour garder la hierarchie, et borne en
   longueur de ligne pour rester lisible. */
.project-hero__summary {
  font-size: clamp(.72rem, min(.95vw, 1.35vh), .85rem);
  line-height: 1.6;
  font-weight: 300;
  color: var(--ink-soft);
  max-width: 46ch;
}

.project-hero__summary strong {
  font-weight: 500;
  color: var(--ink);
}

/* Deux colonnes plutot qu'une pile : cinq champs empiles ajoutaient pres de
   250px a la colonne, qui ne tenait alors plus dans un ecran de portable. */
.project-hero__meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(.5rem, 1.2vh, .85rem) 1.25rem;
  font-size: clamp(.62rem, min(.8vw, 1.1vh), .72rem);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding-top: clamp(.5rem, 1.2vh, .85rem);
  border-top: 1px solid var(--line);
}

/* Les champs longs (logiciels, discipline) reprennent toute la largeur. */
.project-hero__meta-item:nth-child(4),
.project-hero__meta-item:nth-child(5) {
  grid-column: 1 / -1;
}

.project-hero__meta-item {
  display: flex;
  flex-direction: column;
  gap: .3rem;
}

.project-hero__meta-label {
  font-size: .65rem;
  opacity: .6;
}

.project-hero__meta-value {
  font-weight: 500;
  color: var(--ink);
}

/* Le titre vit dans une colonne etroite ET collante : sa taille est bornee
   par la hauteur de fenetre autant que par sa largeur. */
.project-hero__title {
  font-size: clamp(1.7rem, min(3vw, 4.4vh), 3.2rem);
  font-weight: 700;
  letter-spacing: -0.065em;
  line-height: .95;
  color: var(--ink);
}

.project-hero__subtitle {
  font-family: var(--font-display);
  font-style: normal;
  font-weight: 400;
  font-size: clamp(.85rem, min(1.25vw, 1.75vh), 1.15rem);
  line-height: 1.45;
  letter-spacing: -0.01em;
  color: var(--ink);
  max-width: 42ch;
}

/* GRILLE — colonne de droite. Aucune marge laterale : les visuels touchent
   le filet a gauche et le bord de l'ecran a droite, comme demande. Les
   variantes de largeur (--full, --centered, --half-left…) continuent de
   fonctionner, la grille de 12 colonnes etant simplement plus etroite. */
.project-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(1rem, 2vw, 2rem);
  padding: clamp(7rem, 16vh, 11rem) 0 4rem;
  max-width: none;
  margin: 0;
  /* Filet de separation avec la colonne de gauche */
  border-left: 1px solid var(--line);
  /* Les images apparaissent legerement agrandies (x1,15) : sans ceci elles
     depassaient de l'ecran et la page glissait de cote sur iPhone. `clip`
     coupe sans creer de zone de defilement (le sticky continue de marcher). */
  overflow-x: hidden;
  overflow-x: clip;
}

/* VISUEL — par défaut : fond transparent, pas de crop possible */
.project-visual {
  position: relative;
  overflow: hidden;
  background: transparent;
  border-radius: 4px;
}

.project-visual__img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  padding: clamp(1rem, 2vw, 2rem);
  transition: transform 1.4s var(--ease-out);
}

/* Variante vidéo — pareil que --bleed mais pour les balises <video> */
.project-visual__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  background: var(--ink);
}

/* Container Lottie — animations vectorielles */
.project-visual__lottie {
  width: 100%;
  height: 100%;
  display: block;
  padding: clamp(2rem, 4vw, 4rem);
  box-sizing: border-box;
}

.project-visual__lottie canvas,
.project-visual__lottie svg {
  width: 100% !important;
  height: 100% !important;
  display: block;
}

/* Variante "dark band" — pour animations sur fond clair qui ont besoin
   d'un fond sombre derrière pour être lisibles (cf. buisson Cactime) */
.project-visual--dark {
  background: #160d0f;
  overflow: hidden;
}

.project-visual--dark .project-visual__lottie,
.project-visual--dark .project-visual__img {
  padding: 0;
}

/* Variante avec fond crème — pour les visuels qui ont besoin de ressortir */
.project-visual--cream {
  background: var(--instable-bg);
}

/* Variante pour les photos réelles */
.project-visual--photo {
  background: var(--bg-2);
}

.project-visual--photo .project-visual__img {
  object-fit: cover;
  padding: 0;
}

.project-visual--photo:hover .project-visual__img {
  transform: scale(1.03);
}

/* Variante "edge-to-edge" pour mockups */
.project-visual--bleed .project-visual__img {
  padding: 0;
  object-fit: cover;
}

/* Variante "screen" — pour photos sur fond noir qui doivent se fondre dans le fond clair.
   Le mode 'screen' rend les zones noires transparentes, le sujet clair reste visible. */
.project-visual--screen {
  background: transparent;
}
.project-visual--screen .project-visual__img {
  mix-blend-mode: screen;
  padding: 0;
  object-fit: cover;
}

/* Variante "composition entiere" — la boite epouse la comp After Effects,
   sans marge interne. A reserver aux Lottie dont le dessin ne remplit pas
   la comp : le cadrage voulu est deja dans le fichier, un padding en plus
   ne ferait que rapetisser l'animation. Le rapport de la boite doit suivre
   celui de la comp (ici 16/9) pour qu'il ne reste aucune bande vide. */
.project-visual--comp .project-visual__lottie {
  padding: 0;
}

/* Variante "logo seul" — padding plus généreux pour respirer */
.project-visual--logo .project-visual__img {
  padding: clamp(2rem, 5vw, 5rem);
}

/* Object-position pour cadrage photo */
.project-visual--center .project-visual__img { object-position: center; }
.project-visual--top .project-visual__img { object-position: top; }
.project-visual--bottom .project-visual__img { object-position: bottom; }

/* Variante "sans recadrage" — la boite epouse les proportions du fichier au
   lieu de lui imposer un rapport. Les autres variantes (--full, --panoramic,
   --centered…) fixent un aspect-ratio et, combinees a object-fit:cover,
   rognent l'image : c'est voulu pour un rythme de grille, mais destructeur
   quand le visuel est une composition qu'on doit voir en entier. */
.project-visual--asis {
  grid-column: 1 / -1;
  aspect-ratio: auto;
  overflow: visible;
}

.project-visual--asis .project-visual__img {
  width: 100%;
  height: auto;
  object-fit: fill;   /* sans effet : la boite suit deja l'image */
  padding: 0;
}

/* Lottie posee pile sur l'image, au meme cadre (comp et capture en 16:9).
   Fond noir tant que l'animation n'est pas chargee : l'image ne doit pas
   apparaitre avant le loader. */
.project-visual--reveal { overflow: hidden; }

.project-visual__reveal {
  position: absolute;
  inset: 0;
  background: #000;
  pointer-events: none;
}

.project-visual__reveal.is-ready { background: transparent; }

.project-visual__reveal svg {
  width: 100% !important;
  height: 100% !important;
  display: block;
}

/* Meme principe, en plus petit : pour un visuel qui n'a pas besoin de toute
   la largeur (une maquette d'interface, par exemple). Centre, pour ne pas
   laisser un vide asymetrique d'un seul cote. */
.project-visual--asis-sm .project-visual__img {
  max-width: 58%;
  margin-inline: auto;
}

/* Paire cote a cote, proportions conservees. Chaque visuel occupe une
   demi-colonne ; a largeur egale, leurs hauteurs suivent leurs rapports
   respectifs — ils ne sont donc pas forces au meme cadre. */
.project-visual--asis-half {
  grid-column: span 6;
  aspect-ratio: auto;
  overflow: visible;
}

/* Plafond en pixels et non en pourcentage : ces deux fichiers ne font que
   600px de large en natif. Etires sur une demi-colonne (510px sur un ecran
   de 1500), ils etaient affiches a 85% de leur definition — donc flous des
   qu'on les regarde sur un ecran a forte densite. A 320px ils sont servis a
   1,9x, ce qui les rend nets.
   Centres dans leur demi-colonne, ce qui cree du meme coup l'ecart entre
   eux sans avoir a toucher a la gouttiere de la grille. */
.project-visual--asis-half .project-visual__img {
  width: 100%;
  max-width: min(100%, 320px);
  margin-inline: auto;
  height: auto;
  object-fit: fill;
  padding: 0;
}

/* ========== ETAPES 3D SUPERPOSEES (balayage automatique) ==========
   Trois rendus du meme volant empiles — topologie, clay, rendu final — que
   revele un bandeau balayant l'image de gauche a droite, en boucle.
   Pas de JS : chaque calque est decoupe par un clip-path anime sur un cycle
   commun de 12s, soit trois etapes de 4s (1,2s de balayage + 2,8s de pause).
   Le 4e calque reprend l'image du 1er, si bien qu'au rebouclage l'image
   affichee est deja celle du depart : la reprise est invisible. */
.wipe {
  grid-column: 1 / -1;
  /* Les trois rendus ont deja de larges marges autour du volant : a pleine
     largeur de colonne le bloc ecrasait tout le reste de la page. */
  max-width: 58%;
  margin-inline: auto;
}

/* Le 1er calque est dans le flux : c'est lui qui donne sa hauteur a la
   boite. Les suivants sont cales par-dessus, au pixel pres. */
.wipe__layer {
  display: block;
  width: 100%;
  height: auto;
}

.wipe__layer--2,
.wipe__layer--3,
.wipe__layer--4 {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  clip-path: inset(0 100% 0 0);
  animation: wipe-reveal 12s linear infinite;
}

/* Meme specificite que la regle ci-dessus, declarees apres : ce sont donc
   ces noms d'animation qui l'emportent. */
.wipe__layer--3 { animation-name: wipe-reveal-2; }
.wipe__layer--4 { animation-name: wipe-reveal-3; }

@keyframes wipe-reveal {
  0%            { clip-path: inset(0 100% 0 0); }
  10%, 100%     { clip-path: inset(0 0 0 0); }
}

@keyframes wipe-reveal-2 {
  0%, 33.33%    { clip-path: inset(0 100% 0 0); }
  43.33%, 100%  { clip-path: inset(0 0 0 0); }
}

@keyframes wipe-reveal-3 {
  0%, 66.66%    { clip-path: inset(0 100% 0 0); }
  76.66%, 100%  { clip-path: inset(0 0 0 0); }
}

/* Le trait de coupe. Un simple filet d'un pixel, a peine visible : c'est le
   changement d'image qui doit se remarquer, pas lui. Son cycle fait 4s — un
   tiers de celui des calques — donc il passe une fois par etape sans qu'on
   ait a le synchroniser autrement. translateX(-100%) le cale juste a gauche
   de la ligne de coupe. */
.wipe__band {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  transform: translateX(-100%);
  background: rgba(10, 10, 10, .22);
  opacity: 0;
  pointer-events: none;
  animation: wipe-band 4s linear infinite;
}

@keyframes wipe-band {
  0%    { left: 0;    opacity: 0; }
  2%    { opacity: 1; }
  28%   { opacity: 1; }
  30%   { left: 100%; opacity: 0; }
  100%  { left: 100%; opacity: 0; }
}

/* Petite mention de l'etape en cours, dans le coin de l'image. Meme
   traitement que les legendes : discrete, elle nomme sans s'imposer. */
.wipe__step {
  position: absolute;
  left: clamp(1rem, 2vw, 2rem);
  bottom: clamp(1rem, 2vw, 2rem);
  font-size: .6rem;
  font-weight: 300;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(10, 10, 10, .40);
  pointer-events: none;
  animation: wipe-step-topo 12s linear infinite;
}

.wipe__step--clay   { animation-name: wipe-step-clay; }
.wipe__step--render { animation-name: wipe-step-render; }

@keyframes wipe-step-topo {
  0%, 4%      { opacity: 1; }
  9%, 76%     { opacity: 0; }
  81%, 100%   { opacity: 1; }
}

@keyframes wipe-step-clay {
  0%, 5%      { opacity: 0; }
  10%, 33%    { opacity: 1; }
  38%, 100%   { opacity: 0; }
}

@keyframes wipe-step-render {
  0%, 38%     { opacity: 0; }
  43%, 66%    { opacity: 1; }
  71%, 100%   { opacity: 0; }
}

/* Mouvement reduit : on fige sur le rendu final, sans bandeau. */
@media (prefers-reduced-motion: reduce) {
  .wipe__layer--2,
  .wipe__layer--3,
  .wipe__layer--4,
  .wipe__step {
    animation: none;
  }
  .wipe__layer--3 { clip-path: inset(0 0 0 0); }
  .wipe__band { display: none; }
  .wipe__step { opacity: 0; }
  .wipe__step--render { opacity: 1; }
}

/* ========== LAYOUTS DE GRILLE ========== */

.project-visual--full {
  grid-column: 1 / -1;
  aspect-ratio: 16 / 9;
}

.project-visual--panoramic {
  grid-column: 1 / -1;
  aspect-ratio: 21 / 8;
}

/* Variante hero pour mettre vraiment en valeur un visuel (sketches, key shot) */
.project-visual--hero {
  grid-column: 1 / -1;
  aspect-ratio: 4 / 3;
}

.project-visual--hero .project-visual__img {
  padding: clamp(2rem, 5vw, 5rem);
  object-fit: contain;
}

.project-visual--centered {
  grid-column: 2 / 12;
  aspect-ratio: 16 / 9;
}

.project-visual--centered-narrow {
  grid-column: 3 / 11;
  aspect-ratio: 16 / 10;
}

.project-visual--half-left {
  grid-column: 1 / 7;
  aspect-ratio: 4 / 5;
}

.project-visual--half-right {
  grid-column: 7 / -1;
  aspect-ratio: 4 / 5;
}

.project-visual--two-third {
  grid-column: 1 / 9;
  aspect-ratio: 16 / 10;
}

.project-visual--one-third {
  grid-column: 9 / -1;
  aspect-ratio: 4 / 5;
}

.project-visual--portrait-center {
  grid-column: 4 / 10;
  aspect-ratio: 3 / 4;
}

/* Portrait 2/3 — photos verticales, garde son ratio jusqu'en mobile */
.project-visual--tall {
  grid-column: 4 / 10;
  aspect-ratio: 2 / 3;
}

/* Vertical 9/16 — vidéos au format social (Meta / Google Ads) */
.project-visual--vertical {
  grid-column: 5 / 9;
  aspect-ratio: 9 / 16;
}

/* Visuel cale contre le bord droit de la page (la coupe de la photo y
   disparait), sur la moitie droite de la colonne */
.project-visual--edge-right {
  grid-column: 3 / -1;
  border-radius: 0;
}

@media (max-width: 900px) {
  .project-visual--edge-right { grid-column: 1 / -1; }
}

/* ── Vegas : Arcade & Casino sur fond flou ──
   Fond photo flou, et par-dessus deux colonnes (picto au-dessus du mot).
   Chaque element empile sa version rose et sa version jaune : arcade
   commence en rose, casino en jaune, et ils s'echangent toutes les
   --vz-swap secondes (bascule nette). Chaque element oscille aussi sur
   lui-meme, avec une duree et un decalage propres. Positions relevees sur
   la maquette (en % du cadre). */
.project-visual.vz {
  --vz-swap: 1.6s;
  aspect-ratio: 2000 / 908;
  background-size: cover;
  background-position: center;
  border-radius: 0;
}

.vz__item {
  position: absolute;
  transform: translate(-50%, -50%);
}

.vz__item img {
  display: block;
  width: 100%;
  height: auto;
}

.vz__item .vz__yellow {
  position: absolute;
  inset: 0;
}

/* Arcade : rose visible d'abord ; casino : jaune visible d'abord */
.vz__item--arcade-picto .vz__yellow,
.vz__item--arcade-word .vz__yellow { animation: vz-show calc(var(--vz-swap) * 2) steps(1) infinite; }
.vz__item--casino-picto .vz__yellow,
.vz__item--casino-word .vz__yellow { animation: vz-hide calc(var(--vz-swap) * 2) steps(1) infinite; }

@keyframes vz-show { 0% { opacity: 0; } 50% { opacity: 1; } }
@keyframes vz-hide { 0% { opacity: 1; } 50% { opacity: 0; } }

.vz__item--arcade-picto { left: 31.5%; top: 35%; width: 14.5%; }
.vz__item--arcade-word  { left: 31.5%; top: 75%; width: 27.5%; }
.vz__item--casino-picto { left: 67.5%; top: 34%; width: 17.5%; }
.vz__item--casino-word  { left: 67.5%; top: 74.5%; width: 26%; }

/* Gigotement facon animation papier / lettres decoupees : l'angle saute
   d'une position a l'autre sans transition (steps), environ 4 poses par
   seconde. Chaque element a sa propre suite d'angles et son decalage,
   pour qu'ils ne bougent jamais en meme temps. */
.vz__item               { animation: vz-jig-a 1s steps(1) infinite; }
.vz__item--arcade-word  { animation-name: vz-jig-b; animation-delay: -.37s; }
.vz__item--casino-picto { animation-name: vz-jig-c; animation-delay: -.61s; }
.vz__item--casino-word  { animation-name: vz-jig-a; animation-delay: -.13s; }

@keyframes vz-jig-a {
  0%   { transform: translate(-50%, -50%) rotate(-3deg); }
  25%  { transform: translate(-50%, -50%) rotate(2deg); }
  50%  { transform: translate(-50%, -50%) rotate(-1deg); }
  75%  { transform: translate(-50%, -50%) rotate(3.5deg); }
}

@keyframes vz-jig-b {
  0%   { transform: translate(-50%, -50%) rotate(2.5deg); }
  25%  { transform: translate(-50%, -50%) rotate(-2deg); }
  50%  { transform: translate(-50%, -50%) rotate(1deg); }
  75%  { transform: translate(-50%, -50%) rotate(-3deg); }
}

@keyframes vz-jig-c {
  0%   { transform: translate(-50%, -50%) rotate(-1.5deg); }
  25%  { transform: translate(-50%, -50%) rotate(3deg); }
  50%  { transform: translate(-50%, -50%) rotate(-3.5deg); }
  75%  { transform: translate(-50%, -50%) rotate(1deg); }
}

/* Telephone : cadre vertical, Arcade en haut et Casino en bas, chacun
   centre, en grand. Le fond flou est recadre au centre (cover). */
@media (max-width: 720px) {
  .project-visual.vz { aspect-ratio: 3 / 4; }
  .vz__item--arcade-picto { left: 50%; top: 20%;   width: 27%; }
  .vz__item--arcade-word  { left: 50%; top: 38%;   width: 56%; }
  .vz__item--casino-picto { left: 50%; top: 61%;   width: 33%; }
  .vz__item--casino-word  { left: 50%; top: 79%;   width: 53%; }
}

@media (prefers-reduced-motion: reduce) {
  .vz__item, .vz__item .vz__yellow { animation: none; }
  .vz__item--arcade-picto .vz__yellow,
  .vz__item--arcade-word .vz__yellow { opacity: 0; }
}

/* Illustrations (SVG, planches) : jamais contre les bords, contrairement
   aux photos et rendus qui vont bord a bord. */
.project-visual--inset .project-visual__img {
  padding-inline: clamp(2rem, 6vw, 7rem);
}

/* Visuel reduit et centre (ordinateur), a pleine largeur sur telephone */
.project-visual--narrow {
  width: 62%;
  justify-self: center;
}

@media (max-width: 900px) {
  .project-visual--narrow { width: 100%; }
}

/* Deux visuels cote a cote, a la meme hauteur. Colonnes dans le rapport
   des largeurs a hauteur egale : 4:3 (1,333) contre 9:16 (0,5625), soit
   2,37 pour 1. Chaque visuel garde sa legende juste dessous. */
.project-pair {
  grid-column: 1 / -1;
  display: grid;
  /* Le rendu (avec ses marges blanches) est plus petit que s'il avait la
     hauteur de la video, et centre verticalement a cote d'elle. */
  grid-template-columns: 1.7fr 1fr;
  gap: clamp(2rem, 4vw, 4rem);
  align-items: center;
}

.project-pair__item { min-width: 0; }

/* Breakdown des calques Vegas : bandeau bleu nuit de la marque, pleine
   largeur, avec un titre et trois "ecrans" numerotes (01 02 03) facon
   passes After Effects. Les videos a fond blanc s'y detachent comme des
   cartes ; empilees sur mobile. */
.bd {
  grid-column: 1 / -1;
  background: #0d1356;
  color: #ffcafd;
  padding: clamp(1.5rem, 3.5vw, 3.5rem) clamp(1rem, 3.5vw, 3.5rem);
}
.bd__head {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .12em;
  margin-bottom: clamp(1rem, 2vw, 1.75rem);
}
.bd__head span:last-child { color: #fff91d; }
.bd__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(.75rem, 1.5vw, 1.5rem);
}
.bd__item { margin: 0; min-width: 0; }
.bd__item video {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  border-radius: 6px;
  background: #fff;
}
.bd__item figcaption {
  margin-top: .7rem;
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .12em;
}
.bd__num { color: #fff91d; margin-right: .4em; }
@media (max-width: 720px) {
  .bd__grid { grid-template-columns: 1fr; }
}

.project-pair .wipe { max-width: none; margin: 0; }
/* Le duo est centre, avec la meme marge a gauche et a droite : la video ne
   colle plus au bord de l'ecran. Les legendes s'alignent sur leur visuel. */
.project-pair {
  padding-inline: clamp(2rem, 6vw, 7rem);
}

.project-pair .project-caption { margin-top: .9rem; padding-inline: 0; }

/* Paires de photos : meme hauteur (colonnes au rapport des formats, en
   style dans la page), alignees en haut et en bas. */
/* Bord a bord, comme les autres photos des projets : pas de marge laterale */
.project-pair--photos { align-items: stretch; padding-inline: 0; }
.project-pair--photos > .project-visual { grid-column: auto; min-width: 0; }

@media (max-width: 900px) {
  /* !important : les paires de photos fixent leurs colonnes en style */
  .project-pair { grid-template-columns: 1fr !important; padding-inline: 0; }
  .project-pair .project-caption { padding-inline: var(--gutter); }
}

.project-visual--photo-l {
  grid-column: 1 / 8;
  aspect-ratio: 4 / 3; /* matche les photos landscape */
}

.project-visual--photo-s {
  grid-column: 8 / -1;
  aspect-ratio: 3 / 4; /* matche les photos portrait */
}

.project-visual--photo-half {
  grid-column: span 6;
  aspect-ratio: 4 / 3;
}

/* Sans recadrage, mais sans toucher a la largeur. Meme principe que --asis
   (la boite epouse les proportions du fichier), sauf que --asis impose aussi
   `grid-column: 1 / -1`. Ici la colonne reste celle de la variante qui
   accompagne : --centered, --half-left, --half-right…
   Declare apres les variantes de grille et apres --bleed pour l'emporter sur
   leur aspect-ratio et leur object-fit, a specificite egale. */
.project-visual--nocrop {
  aspect-ratio: auto;
  overflow: visible;
}

.project-visual--nocrop .project-visual__img {
  width: 100%;
  height: auto;
  object-fit: fill;   /* sans effet : la boite suit deja l'image */
  padding: 0;
}

/* Sections texte */
/* La colonne de droite etant deja etroite, un retrait de 2 colonnes de plus
   etranglait le texte : il prend maintenant toute la largeur, borne par une
   longueur de ligne lisible. Le retrait lateral l'empeche de coller au filet
   et au bord de l'ecran, contrairement aux visuels. */
.project-text {
  grid-column: 1 / -1;
  max-width: 62ch;
  padding: 5rem clamp(1rem, 2vw, 2rem) 2rem;
  font-size: clamp(1rem, 1.15vw, 1.15rem);
  line-height: 1.6;
  font-weight: 300;
  color: var(--ink);
}

.project-text__label {
  display: block;
  font-size: .7rem;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 1.5rem;
  font-weight: 500;
}

.project-text strong {
  font-weight: 500;
  color: var(--ink);
}

/* Legendes — les petites mentions sous chaque visuel : mots-cles, logiciels.
   Alignees a gauche et non plus etalees d'un bord a l'autre : sur une colonne
   large, `space-between` renvoyait la seconde mention a l'autre bout de
   l'ecran, loin du visuel qu'elle decrit. */
.project-caption {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .3rem 1.25rem;
  font-size: .6rem;
  font-weight: 300;
  /* L'interlettrage large etait le vrai coupable : en capitales, un .12em
     etalait la mention sur pres d'un tiers de la largeur de colonne. */
  letter-spacing: .08em;
  text-transform: uppercase;
  /* Plus clair que --ink-soft (#6b6b6b) : la mention doit se lire quand on la
     cherche, pas entrer en concurrence avec le visuel. */
  color: rgba(10, 10, 10, .40);
  margin-top: .6rem;
  padding: 0 clamp(1rem, 2vw, 2rem) 2.5rem;
}

/* La seconde mention (outil, references colorimetriques) passe encore d'un
   cran en retrait : c'est une precision technique, pas le sujet. */
.project-caption span + span {
  color: rgba(10, 10, 10, .28);
}

/* Next project */
.project-next {
  --next-pad: clamp(2rem, 8vw, 10rem);
  padding: 8rem var(--next-pad) 0;
  text-align: center;
  border-top: 1px solid var(--line);
  margin-top: 4rem;
  /* Annule le padding-bottom de .project-page : la page s'arrete net sur
     la main, on ne peut pas defiler plus bas. */
  margin-bottom: -8rem;
  overflow: hidden;
}

/* La main tendue sous le nom du projet suivant, comme si elle le portait.
   Le bandeau prend toute la largeur (marges negatives = padding de la
   section) et coupe le bas de l'image : le bras sort par le bas de la page.
   Positions relevees sur la maquette : bout des doigts a ~65% de la
   largeur, juste sous la fin du nom. */
.project-next__hand {
  position: relative;
  /* Coupe au niveau du poignet, comme sur la maquette. */
  height: 15.5vw;
  margin: 2rem calc(-1 * var(--next-pad)) 0;
  pointer-events: none;
}

.project-next__hand img {
  position: absolute;
  top: 0;
  left: 5vw;
  width: 60vw;
  max-width: none;
  height: auto;
}

/* Sur mobile le nom occupe presque toute la largeur : la main grandit
   pour rester a son echelle, le bras sortant par la gauche. */
@media (max-width: 900px) {
  .project-next__hand { height: 24.5vw; }
  .project-next__hand img { left: -8vw; width: 95vw; }
}

.project-next__label {
  font-family: var(--font-display);
  font-style: normal;
  font-weight: 400;
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: var(--ink-soft);
  margin-bottom: 1.5rem;
}

.project-next__link {
  display: inline-block;
  font-size: clamp(3rem, 8vw, 7rem);
  font-weight: 500;
  letter-spacing: -0.065em;
  color: var(--ink);
  transition: color .4s ease;
}

.project-next__link:hover { color: var(--accent); }

/* Hover calque sur l'animation "let's talk" (lets-talk-text.json, 30 i/s) :
   deux groupes qui grossissent autour d'un meme point, le second en retard.
   - entree : nom 100 -> 106% en 4 images puis 105% a 6 ; fleche plus lente,
     106% a 7 images puis 105% a 9 ;
   - sortie : retour a 100% en 5 images, la fleche une image apres.
   Courbes lineaires, comme dans le JSON. Le point commun (centre du lien)
   est pose en transform-origin par project.js. */
.project-next__name,
.project-next__arrow {
  display: inline-block;
  transition: transform .167s linear;
}

.project-next__arrow { transition-delay: .033s; }

.project-next__link:hover .project-next__name,
.project-next__link:focus-visible .project-next__name {
  transform: scale(1.05);
  transition-delay: 0s;
  animation: next-pop-name .2s linear;
}

.project-next__link:hover .project-next__arrow,
.project-next__link:focus-visible .project-next__arrow {
  transform: scale(1.05);
  transition-delay: 0s;
  animation: next-pop-arrow .3s linear;
}

@keyframes next-pop-name {
  0%     { transform: scale(1); }
  66.67% { transform: scale(1.06); }
  100%   { transform: scale(1.05); }
}

@keyframes next-pop-arrow {
  0%     { transform: scale(1); }
  77.78% { transform: scale(1.06); }
  100%   { transform: scale(1.05); }
}

@media (prefers-reduced-motion: reduce) {
  .project-next__name,
  .project-next__arrow { transition: none; animation: none !important; transform: none !important; }
}

/* ========== RESPONSIVE ========== */
@media (max-width: 900px) {
  /* Une colonne etroite de texte a cote d'une colonne etroite d'images ne
     laisse de place ni a l'un ni a l'autre : on empile, et la presentation
     cesse de coller — elle defile normalement puis laisse la place aux
     visuels. */
  .project-split {
    grid-template-columns: 1fr;
  }

  .project-hero {
    position: static;
    max-height: none;
    overflow: visible;
    padding: 9rem var(--gutter) 2.5rem;
  }

  .project-grid {
    grid-template-columns: 1fr;
    padding: 2rem 0 2rem;
    border-left: 0;
  }

  .project-caption,
  .project-text {
    padding-left: var(--gutter);
    padding-right: var(--gutter);
  }

  .project-visual--full,
  .project-visual--panoramic,
  .project-visual--hero,
  .project-visual--centered,
  .project-visual--centered-narrow,
  .project-visual--half-left,
  .project-visual--half-right,
  .project-visual--two-third,
  .project-visual--one-third,
  .project-visual--portrait-center,
  .project-visual--photo-l,
  .project-visual--photo-s,
  .project-visual--photo-half {
    grid-column: 1 / -1;
    aspect-ratio: 4 / 3;
  }

  /* Planches vectorielles (SVG, souvent tres larges) : un cadre 4:3 les
     entourait de grands vides blancs. Sur telephone, le cadre suit le
     dessin : hauteur au plus juste, sans marge interieure verticale. */
  .project-visual:has(> .project-visual__img[src$=".svg"]) {
    aspect-ratio: auto;
  }

  .project-visual > .project-visual__img[src$=".svg"] {
    height: auto;
    padding-block: 0;
  }

  /* Animations Lottie : elles gardent leur format 16:9 (le 4:3 ajoutait
     des bandes vides au-dessus et en dessous). */
  .project-visual--full.project-visual--comp { aspect-ratio: 16 / 9; }

  /* Legendes : moins d'air dessous, les sections s'enchainent mieux */
  .project-caption { padding-bottom: 1.5rem; }

  /* Les formats verticaux gardent leur ratio — on ne les recadre pas en 4/3 */
  .project-visual--tall,
  .project-visual--vertical {
    grid-column: 1 / -1;
  }

  /* Retrait lateral conserve (defini plus haut dans ce meme bloc) : seules
     les marges verticales changent ici. */
  .project-text {
    grid-column: 1 / -1;
    padding-top: 3rem;
    padding-bottom: 2rem;
  }

  /* La grille n'a plus qu'une colonne : un `span 6` y creerait cinq colonnes
     implicites et ferait deborder la page. La paire s'empile. */
  .project-visual--asis-half { grid-column: 1 / -1; }

  /* Sur un telephone, 58% de la largeur rendrait la maquette illisible. */
  .project-visual--asis-sm .project-visual__img { max-width: 100%; }
  .wipe { max-width: 100%; }
}

/* Espacement regulier entre les sections (Vegas) : qu'une section finisse
   sur une legende ou sur un visuel, la suivante commence toujours a la meme
   distance (--section-space). La legende reste collee a son visuel. */
.project-grid--even { --section-space: clamp(3rem, 5vw, 4.5rem); }
.project-grid--even .project-caption { padding-bottom: 0; }
.project-grid--even > :is(.project-visual, .project-pair, .bd):not(:first-child) {
  margin-top: calc(var(--section-space) - clamp(1rem, 2vw, 2rem));
}

/* Telephone uniquement : les visuels ne touchent plus les bords de l'ecran,
   une fine marge a gauche et a droite. Les textes et legendes gardent leur
   alignement d'avant (la marge est retiree de leur propre retrait). */
@media (max-width: 900px) {
  .project-grid { --edge: 12px; padding-inline: var(--edge); }
  .project-grid .project-caption,
  .project-grid .project-text,
  .project-pair .project-caption {
    padding-left: calc(var(--gutter) - var(--edge));
    padding-right: calc(var(--gutter) - var(--edge));
  }
}
