:root {
  --ink: #17171a;
  --muted: #6b6b68;
  --accent: #17171a;
}

/* Seul assets/fonts/minion-pro-italic.ttf existe réellement (ni woff2, ni
   woff, ni otf). Un navigateur qui échoue à CHARGER le format qu'il a
   choisi dans une liste src ne retente pas le suivant (il ne bascule que
   si le format n'est pas SUPPORTÉ) — woff2 étant listé en premier et 404,
   la police entière échouait silencieusement et retombait sur Georgia,
   d'où le rendu incohérent (gras, taille) observé jusqu'ici. Un seul src
   pointant vers le fichier qui existe vraiment règle ça. */
@font-face {
  font-family: "Minion Pro";
  src: url("../fonts/minion-pro-italic.ttf") format("truetype");
  font-style: italic;
  font-weight: 400;
  font-display: swap;
}

* { box-sizing: border-box; }

/* Même dégradé gris partout (accueil ET pages projets), calé sur le fond réel
   de rock.jpg. background-attachment: fixed le cale sur la fenêtre plutôt que
   sur la hauteur de la page, pour garder le même dégradé visuel même sur une
   page projet qui défile (comme About, plus longue qu'un écran). */
html, body {
  margin: 0;
  padding: 0;
  background: linear-gradient(to top, #b0a9b1 0%, #c1bbc5 20%, #d5d4dc 50%, #e4e1ec 80%, #f3f2f8 100%);
  background-attachment: fixed;
  color: var(--ink);
  font-family: "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

@media (max-width: 700px) {
  html, body {
    background: linear-gradient(to top, #c0b4c2 0%, #e0dae6 20%, #f2ecf6 40%, #f3f0f7 100%);
    background-attachment: fixed;
  }
}

/* Sur mobile, un léger scroll résiduel peut faire "rebondir" la page (effet
   élastique iOS) et laisser entrevoir un instant le blanc par défaut de
   <html> derrière le contenu. overscroll-behavior coupe ce rebond. */
html {
  overscroll-behavior: none;
}
html.home {
  height: 100%;
}

/* Curseur natif masqué uniquement sur pointeur fin (souris) ;
   sur mobile/tactile on garde le comportement par défaut. */
@media (hover: hover) and (pointer: fine) {
  body.has-custom-cursor,
  body.has-custom-cursor * {
    cursor: none;
  }
}

/* ---------- Page d'accueil : la roche, en pleine page ---------- */

/* Dégradé calé sur le fond réel de rock.jpg (mesuré directement sur le
   fichier, plusieurs points du haut vers le bas) : si un espace apparaît
   malgré tout (barre d'adresse mobile, marge sur petit écran…), il se fond
   dedans au lieu de trancher en blanc. Sous 700px, rock-mobile.jpg a son
   propre dégradé (voir plus bas) : les deux photos n'ont pas exactement le
   même fond. */
body.home {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  overscroll-behavior: none;
  background: linear-gradient(to bottom, #b0a9b1 0%, #c1bbc5 20%, #d5d4dc 50%, #e4e1ec 80%, #f3f2f8 100%);
}

.stage {
  position: relative;
  height: 100vh;
  height: 100dvh;
  width: 100vw;
  margin: 0;
  overflow: hidden;
}

/* Roche = 2600x1535px. .rock-frame est toujours mis à l'échelle pour
   couvrir tout l'écran EN CONSERVANT ce ratio (comme background-size:cover,
   mais en pur CSS, sans JS) : width/height de base = plein écran, et le
   min-width/min-height calculé à partir du ratio prend le relais dès que
   la base ne suffit plus à couvrir l'autre dimension. Le débordement est
   centré puis rogné par .stage (overflow: hidden). Important : .rock-frame
   DOIT garder exactement le ratio de la photo (pas object-fit:cover sur
   l'image toute seule) car les points chauds sont positionnés en % de ce
   conteneur — si sa forme ne correspond plus exactement à l'image, ils se
   décalent des symboles.
   100dvh (dynamic viewport height) au lieu de 100vh : sur mobile, vh se
   base sur la hauteur "barre d'adresse rétractée", donc quand elle est
   visible ça laissait un vrai espace en haut. dvh suit la hauteur réellement
   visible. Les deux valeurs sont déclarées : les navigateurs qui ne
   connaissent pas dvh gardent simplement la valeur vh juste au-dessus. */
.rock-frame {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100vw;
  height: 100vh;
  height: 100dvh;
  min-width: calc(100vh * 2600 / 1535);
  min-width: calc(100dvh * 2600 / 1535);
  min-height: calc(100vw * 1535 / 2600);
}

.rock-frame img {
  display: block;
  width: 100%;
  height: 100%;
  /* Tant que la photo n'est pas encore chargée (4G lente, cache froid), cette
     couleur remplace le blanc par défaut du navigateur pour une image vide. */
  background: #d5d4dc;
  user-select: none;
  -webkit-user-drag: none;
}

@media (max-width: 700px) {
  .rock-frame img {
    background: #f2ecf6;
  }
}

/* Sous 700px, <picture> charge rock-mobile.jpg (1356x2941, recadrage portrait
   dédié, avec sa propre marge grise sur les côtés) au lieu de rock.jpg : le
   ratio utilisé par la technique "cover" ci-dessus doit changer en même temps,
   sinon .rock-frame continue de calculer sa taille sur le ratio bureau et
   déforme/surcadre la photo mobile. */
@media (max-width: 700px) {
  .rock-frame {
    min-width: calc(100vh * 1356 / 2941);
    min-width: calc(100dvh * 1356 / 2941);
    min-height: calc(100vw * 2941 / 1356);
  }

  /* Dégradé propre à rock-mobile.jpg (mesuré directement dessus) : sa marge
     grise s'éclaircit plus vite que celle de rock.jpg. */
  body.home {
    background: linear-gradient(to bottom, #c0b4c2 0%, #e0dae6 20%, #f2ecf6 40%, #f3f0f7 100%);
  }
}

.hover-caption {
  position: fixed;
  top: 50%;
  margin: 0;
  max-width: 24vw;
  font-family: "Minion Pro", Georgia, "Times New Roman", serif;
  font-style: italic;
  font-size: clamp(1.6rem, 3.2vw, 2.8rem);
  line-height: 1.25;
  color: #a8a0ab;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s ease, transform 0.35s ease;
  z-index: 15;
}

.hover-caption-left {
  left: clamp(2rem, 6vw, 6rem);
  text-align: right;
  transform: translateY(-50%) translateX(-10px);
}

.hover-caption-right {
  right: clamp(2rem, 6vw, 6rem);
  text-align: left;
  transform: translateY(-50%) translateX(10px);
}

.hover-caption-left.visible,
.hover-caption-right.visible {
  transform: translateY(-50%) translateX(0);
}

.hover-caption.visible {
  opacity: 1;
}

@media (max-width: 700px) {
  .hover-caption {
    display: none;
  }
}

/* ---------- Points chauds ---------- */

.hotspot {
  position: absolute;
  transform: translate(-50%, -50%);
  width: 6%;
  height: 6%;
  border-radius: 50%;
  background: transparent;
  border: 0;
  padding: 0;
  display: block;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}

/* mode calibration (?calibrate) : seul endroit où le contour des points reste visible */
.calibrate .hotspot {
  outline: 1px solid rgba(200, 40, 40, 0.6);
  border-radius: 50%;
}
.calibrate-marker {
  position: absolute;
  width: 10px;
  height: 10px;
  margin-left: -5px;
  margin-top: -5px;
  border-radius: 50%;
  background: red;
  pointer-events: none;
}

/* ---------- Curseur pioche personnalisé ---------- */

#pickaxe-cursor {
  position: fixed;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 9999;
  /* La pointe du pic (coin haut-gauche de la photo) est calée sur le curseur ;
     le pivot du balancement est vers la poignée. Recalcule ces valeurs si tu
     changes d'image. */
  transform: translate(-17px, -8px) rotate(-10deg);
  transform-origin: 33px 59px;
  will-change: transform;
  transition: transform 0.08s ease-out;
  display: none;
}

body.has-custom-cursor #pickaxe-cursor {
  display: block;
}

#pickaxe-cursor img,
#pickaxe-cursor svg {
  display: block;
  height: 80px;
  width: auto;
  pointer-events: none;
  user-select: none;
}

#pickaxe-cursor.swing {
  animation: pickaxe-swing 0.32s ease-in-out;
}

@keyframes pickaxe-swing {
  0%   { transform: translate(-17px, -8px) rotate(-10deg); }
  40%  { transform: translate(-17px, -8px) rotate(30deg); }
  100% { transform: translate(-17px, -8px) rotate(-10deg); }
}

/* ---------- Page projet ---------- */

/* min-height (pas height) + justify-content:center : si le contenu tient sur
   un écran (cas courant : titre + texte court + une seule vidéo), tout se
   centre verticalement et il n'y a rien à scroller. Si le contenu dépasse
   (About, plusieurs vidéos...), le conteneur grandit normalement au-delà du
   min-height et ça défile comme avant : aucun cas n'est cassé par l'autre. */
.project-page {
  max-width: 1100px;
  margin: 0 auto;
  /* padding-top a un plancher fixe : sous ce seuil, la marge en vh seule
     ne suffit plus à dégager .back-link (position: fixed, top: 28px) et
     le titre vient chevaucher "BACK". */
  padding: max(4vh, 70px) 6vw 4vh;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* Détaché du flux centré : reste toujours en haut à gauche de l'écran, peu
   importe si le contenu en dessous est court (centré) ou long (défile). */
.back-link {
  position: fixed;
  top: 28px;
  left: 32px;
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  z-index: 20;
}
.back-link:hover {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

/* Le titre casse volontairement la colonne de 1100px de .project-page pour
   utiliser (presque) toute la largeur de la fenêtre : sinon, quelle que soit
   la taille de police visée ci-dessous, le script qui le force sur une seule
   ligne le rétrécissait pour tenir dans ces 1100px — la vraie police jamais
   atteinte. margin-left: calc(50% - 50vw) est l'astuce "full-bleed" standard
   pour un enfant d'un conteneur centré par margin:auto (contrairement à
   left:50%, qui se base sur la largeur du PARENT et ne marche pas ici). */
.project-title {
  font-family: "Minion Pro", Georgia, "Times New Roman", serif;
  font-style: italic;
  font-size: clamp(3.5rem, 9vw, 6.5rem);
  letter-spacing: -0.01em;
  box-sizing: border-box;
  width: 100vw;
  margin: 0 0 0.8rem calc(50% - 50vw);
  padding: 0 6vw;
}
.mobile-only-break {
  display: none;
}

.project-description {
  font-size: 0.92rem;
  line-height: 1.65;
  color: #333;
  margin: 0 0 2rem;
  white-space: pre-line;
  /* Même astuce full-bleed que .project-title : sans elle, une description
     seule (pas de crédits à côté) reste calée sur la colonne de 1100px de
     .project-page, décalée par rapport au titre qui démarre à 6vw du bord
     réel de l'écran. */
  width: 100vw;
  max-width: 50vw;
  margin-left: calc(50% - 50vw);
  padding: 0 6vw;
  box-sizing: border-box;
}
@media (max-width: 700px) {
  .project-description {
    max-width: 100vw;
  }
  /* Retour à la ligne ajouté uniquement pour éviter un mot seul en fin de
     ligne sur desktop (ex: UNITED24) : sur mobile, la largeur de ligne est
     différente et ce retour forcé n'a plus lieu d'être. */
  .desktop-only-break {
    display: none;
  }
  /* Inverse : un retour forcé uniquement utile sur mobile (ex: Plan
     International, dont le pageTitle est trop long pour tenir lisiblement
     sur une seule ligne à cette largeur) — invisible sur desktop où le
     titre tient très bien sur une ligne. */
  .mobile-only-break {
    display: inline;
  }
}

/* Layout standard de chaque page projet : description à gauche (jamais
   plus de la moitié de la largeur) et crédits à droite, en une ou deux
   colonnes selon ce que project.credits fournit. */
.project-header {
  display: flex;
  gap: 3rem;
  align-items: flex-start;
  margin-top: 0;
  margin-right: 0;
  margin-bottom: 2.25rem;
  /* Même astuce full-bleed que .project-title (padding 6vw identique) :
     sans ça, la ligne texte/crédits restait calée sur la colonne de
     1100px de .project-page, décalée par rapport au titre qui, lui,
     démarre à 6vw du bord réel de l'écran. */
  width: 100vw;
  margin-left: calc(50% - 50vw);
  padding: 0 6vw;
  box-sizing: border-box;
}
.project-header .project-description {
  flex: 0 1 50%;
  width: auto;
  max-width: 50%;
  margin: 0;
  padding: 0;
}
.project-credits {
  display: flex;
  gap: 2.5rem;
  flex: 1 1 50%;
}
.project-credits-col {
  flex: 1 1 0;
  font-size: 0.85rem;
  line-height: 1.6;
  color: #333;
}
.project-credits-col p {
  margin: 0 0 0.5rem;
}
.project-credits-col p:last-child {
  margin-bottom: 0;
}
.credit-role {
  display: block;
  font-size: 0.68rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
@media (max-width: 700px) {
  .project-header {
    flex-direction: column;
    gap: 1.5rem;
  }
  .project-header .project-description {
    max-width: 100%;
  }
  /* .project-header a align-items:flex-start (nécessaire en row sur
     desktop) : empilé en colonne sur mobile, ça fait que .project-credits
     se réduit à la largeur de son contenu au lieu de profiter de toute la
     largeur dispo, ce qui fait passer "Creative Director" (et les noms un
     peu longs) à la ligne pour rien. */
  .project-header .project-credits {
    width: 100%;
  }
}

.project-media {
  display: grid;
  gap: 1.25rem;
}

.media-placeholder {
  aspect-ratio: 16 / 9;
  background: #eceae6;
  border: 1px dashed #c9c7c2;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  font-size: 0.85rem;
  text-align: center;
  padding: 1rem;
}

/* Grille de captures presse/réseaux sociaux (screenshots portrait, ratios
   variables) : column-count s'adapte à des hauteurs différentes sans
   étirer les images, contrairement à une grille avec aspect-ratio fixe. */
.press-grid {
  column-count: 4;
  column-gap: 1rem;
  margin-top: 2rem;
}
@media (max-width: 900px) {
  .press-grid { column-count: 2; }
}
.press-shot {
  display: block;
  width: 100%;
  margin-bottom: 1rem;
  border-radius: 4px;
  break-inside: avoid;
}

/* Carrousel photo (ex: LVMH) : une bande horizontale scrollable plutôt
   qu'un empilement vertical, pour tenir sur un seul écran sans scroll de
   page même avec plusieurs photos. Hauteur bornée en vh (pas en largeur
   fixe) : chaque image garde son propre ratio, seule sa hauteur est
   contrainte. */
.photo-carousel {
  position: relative;
  margin-top: 1.5rem;
  /* Casse la colonne de 1100px de .project-page (même astuce full-bleed
     que .project-title) : les photos gagnent en largeur par rapport à la
     ligne texte/crédits au-dessus. */
  width: 100vw;
  margin-left: calc(50% - 50vw);
  padding: 0 3vw;
  box-sizing: border-box;
}
.photo-carousel-track {
  display: flex;
  gap: 1rem;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  cursor: grab;
}
.photo-carousel-track::-webkit-scrollbar { display: none; }
.photo-carousel-track.dragging {
  cursor: grabbing;
  scroll-snap-type: none;
}
/* Chaque média est enveloppé dans .carousel-slide (plutôt que d'être
   directement l'enfant flex de la piste) pour pouvoir loger sa légende
   juste en dessous de lui en version mobile (empilée). */
.carousel-slide {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 92vw;
  scroll-snap-align: center;
}
.photo-carousel-track img {
  height: min(54vh, 520px);
  width: auto;
  max-width: 92vw;
  object-fit: cover;
  border-radius: 4px;
}
/* Une vidéo n'a pas de taille intrinsèque comme une image : on fixe la
   hauteur (comme .photo-carousel-track img) et on en déduit la largeur
   via aspect-ratio, au lieu de compter sur width:auto. */
.carousel-video {
  position: relative;
  height: min(54vh, 520px);
  aspect-ratio: 16 / 9;
  max-width: 92vw;
  background: #000;
  border-radius: 4px;
  overflow: hidden;
}
/* Légende partagée sous le carrousel (desktop) : un seul texte qui change
   selon la photo actuellement centrée, mis à jour en JS via
   IntersectionObserver. */
.carousel-caption {
  margin: 1rem 0 0;
  text-align: center;
  font-size: 0.92rem;
  font-style: italic;
  color: #333;
  min-height: 1.4em;
  white-space: pre-line;
  max-width: 640px;
  margin-left: auto;
  margin-right: auto;
  transition: opacity 0.25s ease;
}
/* Légende par photo, utilisée seulement en version mobile empilée (voir
   media query ci-dessous) : pas de "photo active" en mode empilé, donc
   chaque légende reste collée à sa propre photo. */
.carousel-slide-caption {
  display: none;
}
.carousel-video iframe,
.carousel-video video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
/* Triangle épuré plutôt qu'un rond plein : le bouton garde une zone de clic
   de 40px (accessibilité tactile), mais n'affiche visuellement qu'un
   triangle via ::before (technique des bordures CSS). Le glyphe flèche
   d'origine (&larr;/&rarr;) reste dans le HTML pour les lecteurs d'écran,
   juste rendu invisible ici. */
.carousel-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 40px;
  height: 40px;
  border: none;
  background: transparent;
  color: transparent;
  font-size: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 5;
  padding: 0;
}
.carousel-arrow::before {
  content: "";
  width: 0;
  height: 0;
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
  opacity: 0.55;
  transition: opacity 0.2s ease;
}
.carousel-arrow.prev::before { border-right: 13px solid var(--ink); }
.carousel-arrow.next::before { border-left: 13px solid var(--ink); }
.carousel-arrow:hover::before { opacity: 0.9; }
.carousel-arrow.prev { left: -8px; }
.carousel-arrow.next { right: -8px; }
/* Mise en page dédiée à Créateur d'immortels (desktop uniquement) :
   deux colonnes - à gauche titre / texte / légende empilés, à droite
   le carrousel qui occupe toute la hauteur disponible. grid-template-areas
   permet de placer chaque élément indépendamment de son ordre dans le DOM. */
@media (min-width: 701px) {
  .project-page-createur-dimmortels {
    display: grid;
    /* Colonne carrousel plus large que la colonne texte : les photos
       paysage (largeur > hauteur) ont besoin de plus d'espace horizontal
       pour ne pas se retrouver minuscules une fois bridées par la hauteur. */
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    /* Le texte d'intro reste collé sous le titre (haut d'écran) ; seule la
       légende photo est poussée vers le bas par la ligne vide (1fr). */
    grid-template-rows: auto auto 1fr auto;
    grid-template-areas:
      "title    carousel"
      "desc     carousel"
      ".        carousel"
      "caption  carousel";
    column-gap: 5vw;
    max-width: none;
    width: 100vw;
    margin: 0 0 0 calc(50% - 50vw);
    /* Même plancher en haut et en bas (max(4vh, 70px)) : sinon le bas,
       resté à 4vh sans plancher, finissait plus proche du bord que le
       haut sur la plupart des hauteurs d'écran. */
    padding: max(4vh, 70px) 6vw max(4vh, 70px);
    /* height (pas juste min-height) : la ligne 1fr de la grille a besoin
       d'une hauteur définie à répartir pour que le carrousel (height:100%
       en cascade jusqu'à l'image) se calcule correctement, plutôt que de
       grandir à la taille naturelle de l'image et faire déborder la page. */
    height: 100vh;
    height: 100dvh;
    box-sizing: border-box;
  }
  .project-page-createur-dimmortels .project-title {
    grid-area: title;
    width: auto;
    margin: 0 0 1.5rem;
    padding: 0;
  }
  .project-page-createur-dimmortels .project-description {
    grid-area: desc;
    width: auto;
    max-width: none;
    margin: 0 0 2rem;
    padding: 0;
  }
  .project-page-createur-dimmortels .carousel-caption {
    grid-area: caption;
    text-align: left;
    max-width: none;
    margin: 0;
  }
  .project-page-createur-dimmortels .photo-carousel {
    grid-area: carousel;
    width: auto;
    max-width: none;
    height: 100%;
    margin: 0;
    padding: 0;
  }
  .project-page-createur-dimmortels .photo-carousel-track {
    height: 100%;
    align-items: center;
  }
  .project-page-createur-dimmortels .carousel-slide {
    max-width: none;
    height: 100%;
    justify-content: center;
  }
  /* height/width:auto + max-height/max-width plutôt qu'une hauteur forcée à
     100% : une photo paysage, une fois sa largeur bridée à celle de la
     colonne, dépasserait moins en hauteur que le carrousel et ne doit pas
     être recadrée pour combler l'espace - elle se centre verticalement à
     sa propre taille (comme les portraits, déjà correctement contraints
     par la hauteur). */
  .project-page-createur-dimmortels .photo-carousel-track img,
  .project-page-createur-dimmortels .carousel-video {
    height: auto;
    width: auto;
    max-height: 100%;
    /* Largeur réelle de la colonne carrousel : (100vw - 2*6vw de padding -
       5vw de column-gap) * 1.2/2fr = 49.8vw. Marge de sécurité à 49vw. */
    max-width: 49vw;
  }
  /* Sans le padding latéral qu'ont les autres pages autour de .photo-carousel,
     les flèches (positionnées par rapport à ce conteneur) touchaient presque
     les photos larges. On les repousse dans la marge de la grille plutôt que
     de rogner encore la largeur dispo pour les photos. */
  .project-page-createur-dimmortels .carousel-arrow.prev {
    left: -48px;
  }
  .project-page-createur-dimmortels .carousel-arrow.next {
    right: -48px;
  }
}
@media (max-width: 700px) {
  .carousel-arrow { display: none; }
  /* Pas de carrousel sur mobile : toutes les photos à la suite, en
     colonne pleine largeur, et on laisse la page défiler normalement. */
  .photo-carousel-track {
    flex-direction: column;
    overflow: visible;
    scroll-snap-type: none;
    cursor: default;
  }
  .carousel-slide {
    width: 100%;
    max-width: 100%;
  }
  .photo-carousel-track img {
    height: auto;
    width: 100%;
    max-width: 100%;
  }
  .carousel-video {
    height: auto;
    width: 100%;
    max-width: 100%;
  }
  /* En version empilée, la légende partagée n'a pas de sens (pas de
     "photo active") : on la cache et on affiche plutôt une légende sous
     chaque photo. */
  .carousel-caption {
    display: none;
  }
  .carousel-slide-caption {
    display: block;
    margin: 0.5rem 0 0;
    text-align: center;
    font-size: 0.85rem;
    font-style: italic;
    color: #333;
    white-space: pre-line;
  }
}

.video-embed {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #000;
}

.video-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.not-found {
  padding: 20vh 6vw;
  text-align: center;
}

/* ---------- Page About ---------- */

/* Bannière "hero" : photo de fond avec titre + texte de présentation
   superposés (coordonnées et contact désormais inclus dans le texte plutôt
   que dans un bloc séparé). Empilée sur mobile (flux normal, scroll
   vertical classique) ; sur desktop, page plein écran unique (100vh, pas
   de scroll vertical) parcourue avec deux "écrans" en défilement
   horizontal - la photo reste fixe, seul le texte en incrustation change
   (voir .about-screens plus bas et setupAboutScreens() dans le script). */
.about-hero {
  position: relative;
  margin-bottom: 4rem;
}
.about-hero-photo {
  display: block;
  /* Plein écran (comme .project-title, .photo-carousel...) plutôt que
     contenue dans le padding de .project-page, pour qu'elle prenne plus
     de place sur mobile (seul écran où cette règle de base s'applique :
     le media query desktop plus bas redéfinit tout). */
  width: 100vw;
  height: auto;
  margin-left: calc(50% - 50vw);
  border-radius: 0;
}
.about-hero-photo.media-placeholder {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  aspect-ratio: 16 / 9;
}
.about-fit-content {
  margin-top: 1.5rem;
}
.about-hero-title {
  font-family: "Minion Pro", Georgia, "Times New Roman", serif;
  font-style: italic;
  font-size: clamp(2.2rem, 8vw, 3rem);
  letter-spacing: -0.01em;
  margin: 0 0 1rem;
}
.about-hero-description {
  font-size: 0.92rem;
  line-height: 1.65;
  color: #333;
  margin: 1rem 0 0;
}
.about-hero-description p {
  margin: 0 0 0.6em;
}
.about-hero-description p:last-child {
  margin-bottom: 0;
}
.about-hero-description a,
.about-hero-description .about-underline {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.about-hero-description a {
  cursor: pointer;
}
.about-nav-arrow {
  display: none;
}
@media (min-width: 701px) {
  /* Le conteneur de page lui-même doit occuper exactement 100vh sans
     aucune marge/centrage vertical hérité de .project-page, sinon la
     page entière dépasse d'un poil et un scroll vertical réapparaît. */
  .project-page.about-page {
    display: block;
    padding: 0;
    margin: 0;
    max-width: none;
    min-height: 0;
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
  }
  .about-hero {
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    margin: 0;
    overflow: hidden;
  }
  .about-hero-photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 0;
  }
  .about-hero-photo.media-placeholder {
    aspect-ratio: auto;
  }
  /* Piste horizontale plein écran : deux écrans de 100vw, un par-dessus la
     photo (fixe, en dessous dans le DOM) qu'on parcourt au drag, à la
     molette (convertie en horizontal par JS) ou au trackpad. */
  .about-screens {
    position: absolute;
    inset: 0;
    display: flex;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    cursor: grab;
  }
  .about-screens::-webkit-scrollbar { display: none; }
  .about-screens.dragging {
    cursor: grabbing;
    scroll-snap-type: none;
  }
  .about-screen {
    position: relative;
    flex: 0 0 100vw;
    height: 100%;
    scroll-snap-align: start;
    /* Halo clair (pas de bloc/fond visible) : la photo n'offre pas
       toujours assez de contraste sous le texte (portrait sombre...) ;
       text-shadow s'hérite à tous les descendants sans casser le rendu
       "texte à même la photo" voulu. */
    text-shadow: 0 1px 3px rgba(255, 255, 255, 0.85), 0 0 10px rgba(255, 255, 255, 0.7);
  }
  /* .about-fit est réduit (transform: scale, via JS) si son contenu dépasse
     la place disponible (hauteur ou largeur) de son écran, pour ne jamais
     avoir besoin de scroller à l'intérieur d'un écran. */
  .about-fit {
    position: absolute;
    top: 10vh;
    transform-origin: top left;
  }
  /* Le margin-top de .about-fit-content sert au flux mobile (espace sous
     la photo) ; en positionnement absolu ici, .about-fit gère déjà le top,
     ce margin ne ferait qu'ajouter un espace mesuré à tort dans le calcul
     du scale-to-fit. */
  .about-fit-content {
    margin-top: 0;
  }
  .about-fit-intro {
    left: 6vw;
    max-width: min(70vw, 1000px);
  }
  .about-fit-awards,
  .about-fit-background {
    left: 6vw;
    right: 6vw;
  }
  .about-hero-title {
    font-size: clamp(1.9rem, 2.6vw, 2.6rem);
    margin: 0 0 1.1rem;
  }
  .about-hero-description {
    font-size: 0.8rem;
    line-height: 1.6;
    margin-top: 0.9rem;
  }
  .about-fit-background .about-section {
    margin-bottom: 0;
  }
  .about-fit-background .about-section-title {
    font-size: 0.72rem;
    margin: 0 0 0.75rem;
    padding-bottom: 0.4rem;
  }
  .about-fit-background .exp-item {
    padding: 0.4rem 0;
    gap: 0.1rem 1rem;
  }
  .about-fit-background .exp-period,
  .about-fit-background .exp-role {
    font-size: 0.8rem;
    white-space: nowrap;
  }
  .about-fit-background .education-list li {
    padding: 0.35rem 0;
    font-size: 0.8rem;
    white-space: nowrap;
  }
  .background-columns {
    display: flex;
    gap: 4rem;
  }
  .background-columns .about-section {
    flex: 0 0 auto;
  }
  /* Une colonne par festival, alignées sur la même ligne (le nombre
     d'organismes est amené à grandir ; l'écran Awards déborde alors en
     largeur, mais about-fit le réduit automatiquement via transform). */
  .about-fit-awards .award-groups {
    display: flex;
    align-items: flex-start;
    gap: 1.1rem;
  }
  .about-fit-awards .award-group {
    flex: 0 0 auto;
    width: 7.5rem;
  }
  .about-fit-awards .award-org {
    font-size: 0.74rem;
    margin: 0 0 0.5rem;
  }
  .about-fit-awards .award-list {
    gap: 0.25rem;
  }
  .about-fit-awards .award-list li {
    font-size: 0.68rem;
    line-height: 1.35;
  }
  /* Triangles de navigation entre écrans, dans le même style épuré que
     .carousel-arrow. Fixés à l'écran (pas à la photo) : ils restent au
     même endroit quel que soit l'écran affiché. */
  .about-nav-arrow {
    display: flex;
    position: fixed;
    top: 50%;
    transform: translateY(-50%);
    width: 48px;
    height: 48px;
    align-items: center;
    justify-content: center;
    border: none;
    background: transparent;
    color: transparent;
    font-size: 0;
    cursor: pointer;
    z-index: 25;
    padding: 0;
  }
  .about-nav-arrow::before {
    content: "";
    width: 0;
    height: 0;
    border-top: 10px solid transparent;
    border-bottom: 10px solid transparent;
    opacity: 0.6;
    transition: opacity 0.2s ease;
  }
  .about-nav-arrow.prev { left: 24px; }
  .about-nav-arrow.prev::before { border-right: 14px solid var(--ink); }
  .about-nav-arrow.next { right: 24px; }
  .about-nav-arrow.next::before { border-left: 14px solid var(--ink); }
  .about-nav-arrow:hover::before { opacity: 1; }
}

.about-section {
  margin-bottom: 3.5rem;
}

.about-section-title {
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 1.5rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid #e2e0da;
}

.exp-item {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.5rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid #ece9e3;
}
.exp-item:last-child { border-bottom: 0; }

.exp-period {
  margin: 0;
  width: 13rem;
  flex-shrink: 0;
  color: var(--muted);
  font-size: 0.9rem;
}

.exp-role {
  margin: 0;
  font-size: 1rem;
}

.exp-company {
  color: var(--muted);
}

.education-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.education-list li {
  padding: 0.6rem 0;
  border-bottom: 1px solid #ece9e3;
  font-size: 1rem;
}
.education-list li:last-child { border-bottom: 0; }

.awards-photo {
  width: 100%;
  max-width: 420px;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  margin-bottom: 2rem;
}

.award-groups {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 2rem;
}

.award-org {
  font-size: 0.95rem;
  margin: 0 0 0.75rem;
  font-weight: 600;
}

.award-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.award-list li {
  font-size: 0.9rem;
  color: #333;
}
