/* ==========================================================================
   SMYLLE — Moctar Thera
   Portfolio en trois sections : Photos, Films, Documentaries.

   Deux partis pris qui viennent de Moctar :

   1. Le fond de la page EST la couleur de marque, #B33237. Ce n'est pas un
      accent posé sur du blanc, c'est le sol sur lequel tout se pose.

   2. Au survol d'une tuile, ce sol prend la couleur de l'image survolée.
      Chaque projet porte sa teinte, calculée sur sa couverture et ramenée
      dans une bande de luminosité où le texte reste lisible. Une photo de
      nuit ne donne donc pas un fond noir : elle donne un fond plus clair.

   La mise en page reprend le rythme de concreterep.com : une grille de 24
   colonnes où la largeur des tuiles alterne.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. VARIABLES
   --ground et --ink sont réécrites en direct par site.js au survol. Tout ce
   qui doit suivre la couleur du fond doit donc passer par ces deux variables,
   jamais par une couleur en dur.
   ----------------------------------------------------------------------- */
:root {
  --ground:      #B33237;
  --ink:         #F7F1EC;
  --ground-base: #B33237;   /* le rouge de repos, jamais réécrit */
  --ink-base:    #F7F1EC;

  --gap: .5rem;
  --pad: .5rem;
  --nav-h: 3rem;
  --ease: cubic-bezier(.22, .61, .36, 1);
  --swap: 0;                /* progression du changement de nom, 0 → 1 */

  --font-display: "EB Garamond", "ITC Garamond", Garamond, "Times New Roman", serif;
  --font-ui: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* --------------------------------------------------------------------------
   2. BASE
   ----------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; background: var(--ground); }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: .8125rem;
  line-height: 1.6;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

/* La bascule de couleur est la signature du site : assez lente pour qu'on la
   voie, assez rapide pour ne pas traîner derrière le curseur. */
html, body { transition: background-color .55s var(--ease), color .55s var(--ease); }

/* `height: auto` est indispensable : les balises portent des attributs width et
   height pour réserver la place avant chargement, sinon la page sursaute.
   Sans cette règle, la largeur est contrainte mais la hauteur reste celle de
   l'attribut, et toutes les images sont étirées. */
img, video { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }

::selection { background: var(--ink); color: var(--ground); }
:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.label {
  font-family: var(--font-ui);
  font-size: .625rem;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   3. BARRE DU HAUT
   Les trois sections occupent le centre, là où la référence pose le nom de
   l'agence : Moctar veut qu'on choisisse Photos ou Films dès l'arrivée.
   ----------------------------------------------------------------------- */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  height: var(--nav-h);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1rem;
  padding: 0 var(--pad);
  background: var(--ground);
  transition: background-color .55s var(--ease);
}

.nav__mark     { justify-self: start; opacity: .75; }
.nav__sections { justify-self: center; display: flex; gap: 1.25rem; }
.nav__right    { justify-self: end; display: flex; gap: 1.25rem; align-items: center; }

/* Les deux langues sont montrees ensemble, celle en cours mise en avant. Un
   bouton unique qui bascule obligerait a deviner s'il nomme la langue
   affichee ou celle qu'on obtiendra en cliquant. */
.lang { display: flex; align-items: center; gap: .3rem; }
.lang__sep { opacity: .35; }
.lang__btn {
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  cursor: pointer;
  opacity: .5;
  transition: opacity .25s var(--ease);
}
.lang__btn:hover { opacity: .85; }
.lang__btn[aria-current="true"] { opacity: 1; cursor: default; }

.nav a { opacity: .62; transition: opacity .25s var(--ease); }
.nav a:hover,
.nav a[aria-current="page"] { opacity: 1; }

/* Sur un telephone les trois sections plus PROFIL plus la bascule de langue ne
   tiennent pas sur une ligne : sans zones nommees, la barre debordait par la
   droite et coupait EN / FR. Deux rangees explicites, la marque et la langue
   en haut, les sections centrees en dessous. */
@media (max-width: 700px) {
  .nav {
    height: auto;
    grid-template-columns: auto 1fr;
    grid-template-areas: "mark right" "sections sections";
    row-gap: .5rem;
    padding: .6rem var(--pad) .7rem;
  }
  .nav__mark     { grid-area: mark; }
  .nav__right    { grid-area: right; gap: .9rem; }
  .nav__sections {
    grid-area: sections;
    justify-self: center;
    flex-wrap: wrap;
    justify-content: center;
    gap: .5rem 1.1rem;
  }
}

/* --------------------------------------------------------------------------
   4. EN-TÊTE — « Moctar Thera » devient « SMYLLE » au défilement
   Les deux mots sont superposés dans la même case de grille et se croisent
   selon --swap, que site.js met à jour au fil du défilement. Le bloc reste
   collé pendant la traversée, sinon on manquerait la transformation.
   ----------------------------------------------------------------------- */
/* GRAND ECRAN : pleine hauteur, rien ne depasse. Une tuile qui pointait le nez
   sous la ligne de flottaison ressemblait a un debordement, pas a une
   composition. */
.masthead {
  min-height: 100svh;
  padding: 0 var(--pad);
}

.masthead__names {
  position: sticky;
  top: 34svh;
  display: grid;
  justify-items: center;
  text-align: center;
}

/* Les deux noms occupent LA MÊME case de grille : c'est ce qui les superpose.
   Sans cette ligne ils s'empilent l'un sous l'autre et on lit les deux à la
   fois au lieu d'en voir un se changer en l'autre. */
.masthead__name {
  grid-area: 1 / 1;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.75rem, 8.5vw, 7rem);
  line-height: .95;
  letter-spacing: -.015em;
  color: var(--ink);
  text-wrap: balance;
  will-change: opacity, transform;
}

/* Le nom d'arrivée s'efface et recule ; celui d'après avance en se posant. */
.masthead__name--a {
  opacity: calc(1 - var(--swap));
  transform: scale(calc(1 - var(--swap) * .06));
}
.masthead__name--b {
  opacity: var(--swap);
  transform: scale(calc(.94 + var(--swap) * .06));
  letter-spacing: calc(.02em + (1 - var(--swap)) * .12em);
}

.masthead__role {
  grid-area: 2 / 1;
  margin: 1.25rem 0 0;
  opacity: .62;
}

/* --------------------------------------------------------------------------
   5. LA GRILLE — 24 colonnes, comme la référence
   ----------------------------------------------------------------------- */
.feed { padding: 0 var(--pad) clamp(4rem, 12vh, 9rem); }

.grid { display: flex; flex-direction: column; gap: var(--gap); }

@media (min-width: 768px) {
  :root { --gap: 1rem; --pad: 1rem; }
  .grid {
    display: grid;
    grid-template-columns: repeat(24, minmax(0, 1fr));
    align-items: center;        /* les hauteurs inégales se centrent entre elles */
    row-gap: clamp(1rem, 4vw, 3.5rem);
  }
  [data-span="full"]  { grid-column: 1 / span 24; }
  [data-span="half"]  { grid-column: 7 / span 12; }
  [data-span="left"]  { grid-column: 3 / span 9; }
  [data-span="right"] { grid-column: 14 / span 9; }
}

/* --------------------------------------------------------------------------
   5 bis. LA GALERIE PHOTOS — passe-partout et planches

   Les tuiles de projet vivent dans une grille serree. Les photographies, non :
   elles sont posees dans une large marge de fond, a la maniere d'un
   passe-partout, avec beaucoup d'air entre elles. Comme le fond prend deja la
   couleur de l'image survolee, chaque photo se retrouve dans sa propre piece.

   Une image sur quatre passe en PLANCHE pleine hauteur d'ecran. C'est la
   respiration qui decoupe le defilement en chapitres. Elle est en "contain" et
   non en "cover" : 61 des 79 photographies sont verticales, un recadrage en
   bandeau large n'en garderait qu'une tranche. Contenue, la photo est entiere
   et les marges laterales font elles-memes le passe-partout.
   ----------------------------------------------------------------------- */
.gal {
  display: flex;
  flex-direction: column;
  gap: clamp(2.5rem, 9vw, 5rem);
  padding: clamp(2rem, 6vh, 4rem) var(--pad) clamp(5rem, 14vh, 10rem);
}

@media (min-width: 768px) {
  .gal {
    display: grid;
    /* minmax(0, 1fr) et non 1fr : "1fr" vaut "minmax(auto, 1fr)", donc une
       colonne refuse de descendre sous la largeur intrinseque de son contenu.
       Une photographie de 900 px imposait alors des colonnes de 72 px la ou il
       en fallait 52, et la grille depassait de 575 px par la droite. */
    grid-template-columns: repeat(24, minmax(0, 1fr));
    /* Le gap herite du mode telephone valait aussi pour les colonnes : 23
       gouttieres de 80 px mangeaient 1840 px dans une grille de 1265, il ne
       restait plus rien pour les colonnes et les images debordaient de leurs
       pistes. L'espace horizontal vient des marges de la grille, pas d'une
       gouttiere entre colonnes. */
    column-gap: 0;
    row-gap: clamp(4rem, 11vw, 10rem);
  }
  /* Quatre positions sur vingt-quatre colonnes, et surtout : elles
     s'equilibrent. La premiere version partait aux colonnes 6, 13 et 9, donc
     aucune n'etait centree et deux etaient collees a droite ; la page penchait
     et la marge de gauche se vidait.

     Ici le centre est exactement centre (7 colonnes de marge de chaque cote),
     et le decalage gauche est le miroir exact du decalage droit : 4 et 11
     d'un cote, 11 et 4 de l'autre. Sur quatre images, la composition revient
     donc toujours a l'aplomb. */
  [data-mat="center"] { grid-column: 8 / span 10; }   /* marges 7 | 7 */
  [data-mat="left"]   { grid-column: 5 / span 9; }    /* marges 4 | 11 */
  [data-mat="right"]  { grid-column: 12 / span 9; }   /* marges 11 | 4 */
  [data-mat="plate"]  { grid-column: 1 / span 24; }
}

/* CHAQUE photographie est bornee par la hauteur de l'ecran, pas seulement les
   planches. Sans cela, sur un ecran large et court les images ordinaires
   depassaient l'ecran pendant que la planche restait bridee a 86svh : la
   planche devenait la PLUS PETITE de la page, exactement l'inverse de son
   role. Une galerie se regarde d'un coup d'oeil, on ne devrait jamais avoir a
   defiler pour voir une seule photo en entier. */
.gal__frame {
  display: grid;
  place-items: center;
  overflow: hidden;
}
.gal__frame picture { display: block; }
.gal__frame img {
  width: auto;
  max-width: 100%;
  max-height: 70svh;
  height: auto;
  transition: transform .8s var(--ease);
}
.gal__frame:hover img { transform: scale(1.015); }

/* La planche : la photo entiere, aussi grande que la place le permet.

   Surtout PAS de hauteur fixe sur le cadre. La premiere version en donnait
   une, et comme le <picture> qui enveloppe l'image garde une hauteur
   automatique, le "height: 100%" de l'image ne s'accrochait a rien : l'image
   gardait sa taille naturelle et le cadre la coupait par le haut. Sur un ecran
   large et court on ne voyait plus que le ciel.

   Ici c'est l'image qui se borne elle-meme, en largeur ET en hauteur. Sur un
   ecran haut elle est limitee par la largeur, sur un ecran court par la
   hauteur, et dans les deux cas elle est entiere et centree : ce sont les
   marges qui varient, jamais le cadrage de la photographie. */
[data-mat="plate"] .gal__frame {
  display: grid;
  place-items: center;
}
[data-mat="plate"] .gal__frame img {
  width: auto;
  max-width: 100%;
  max-height: 86svh;
}

/* L'ouverture d'une série : son titre, son nombre d'images et le lien vers
   sa page. Un court filet la sépare de la série d'avant. */
.gal__chapter {
  text-align: center;
  padding-top: clamp(1rem, 5vh, 3rem);
}
.gal__chapter:first-child { padding-top: 0; }
.gal__chapter:not(:first-child)::before {
  content: "";
  display: block;
  width: 2.5rem;
  height: 1px;
  margin: 0 auto clamp(2rem, 6vh, 3.5rem);
  background: currentColor;
  opacity: .5;
}
.gal__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.25rem, 7vw, 4rem);
  line-height: 1;
  text-wrap: balance;
}
.gal__count {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .5rem 1.25rem;
  margin: 1rem 0 0;
  opacity: .72;
}
.gal__count a { text-decoration: underline; text-underline-offset: .3em; }
.gal__count a:hover { opacity: 1; }
@media (min-width: 768px) {
  .gal__chapter { grid-column: 1 / -1; }
}

.gal__cap {
  margin: .85rem 0 0;
  font-family: var(--font-display);
  font-size: .9375rem;
  font-style: italic;
  text-align: center;
  opacity: .62;
}
[data-mat="plate"] .gal__cap { margin-top: 1.25rem; }

/* --------------------------------------------------------------------------
   6. LA TUILE
   ----------------------------------------------------------------------- */
.tile {
  position: relative;
  display: block;
  overflow: hidden;
}

/* Le cadre porte l'image, la boucle et le badge. Le badge est posé sur le
   cadre et non sur la tuile, sinon sur téléphone il tomberait sur la
   légende en dessous. */
.tile__frame {
  position: relative;
  overflow: hidden;
}

.tile__media {
  width: 100%;
  height: auto;
  transition: transform .7s var(--ease), opacity .5s var(--ease);
  backface-visibility: hidden;
}
.tile:hover .tile__media { transform: scale(1.02); }

/* « 17 PHOTOS » dans le coin d'une série. Toujours visible, au doigt comme
   à la souris : c'est lui qui dit qu'on ouvre plusieurs images et non une. */
.tile__badge {
  position: absolute;
  top: .6rem;
  right: .6rem;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .35rem .55rem;
  border-radius: 2px;
  background: rgba(0, 0, 0, .5);
  color: #fff;
  line-height: 1;
  pointer-events: none;
}
.tile__pile { width: .8rem; height: .8rem; flex: none; }
.tile__pile rect { fill: none; stroke: currentColor; stroke-width: 1.4; }
.tile__pile .tile__pile-front { fill: currentColor; }

/* La boucle d'un film est posée par-dessus son affiche et ne se montre qu'une
   fois qu'elle joue. L'attribut `poster` d'une balise vidéo ne tient que
   jusqu'au chargement : ensuite le navigateur montre l'image zéro du fichier,
   presque toujours un fondu au noir. Les affiches de ce site sont choisies
   une par une, on ne les perd pas à la première mise en cache. */
.tile__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
}
.tile__video.is-playing { opacity: 1; }

/* Au doigt, la légende est la seule chose qui nomme la tuile : un titre en
   serif qu'on lit, puis ce qu'elle contient et ce qu'on obtient en touchant.
   L'ancienne légende, une ligne de capitales de 10 px à 72 % d'opacité, ne
   se distinguait pas d'une marge. */
.tile__caption {
  display: grid;
  gap: .3rem;
  padding: .7rem .125rem .4rem;
}
.tile__title {
  font-family: var(--font-display);
  font-size: 1.375rem;
  line-height: 1.1;
}
.tile__line {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: .25rem 1rem;
  opacity: .72;
}
.tile__cta { white-space: nowrap; }

@media (min-width: 768px) and (hover: hover) {
  .tile__caption {
    position: absolute;
    inset: auto 0 0 0;
    z-index: 2;
    padding: 3rem .75rem .75rem;
    background: linear-gradient(transparent, rgba(0, 0, 0, .55));
    color: #fff;
    opacity: 0;
    transform: translateY(.375rem);
    transition: opacity .35s var(--ease), transform .35s var(--ease);
  }
  .tile__title { font-size: 1.25rem; }
  .tile__line { opacity: .85; }
  .tile:hover .tile__caption { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   7. PAGE PROJET
   ----------------------------------------------------------------------- */
.project__head {
  display: grid;
  gap: .75rem;
  padding: clamp(3rem, 10vh, 7rem) var(--pad) clamp(2rem, 6vh, 4rem);
  max-width: 46rem;
  margin-inline: auto;
  text-align: center;
}

.project__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2rem, 5vw, 3.75rem);
  line-height: 1;
}

.project__meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .5rem 1.5rem;
  opacity: .66;
}

.project__client { text-decoration: underline; text-underline-offset: .25em; }
.project__client:hover { opacity: 1; }

.project__blurb {
  margin: .5rem 0 0;
  font-family: var(--font-display);
  font-size: 1.125rem;
  line-height: 1.55;
}

/* Les partenaires d'un projet, en petit : ils comptent pour ceux qui savent
   les lire et ne doivent pas voler la vedette au titre. */
.project__credits {
  margin: .25rem 0 0;
  opacity: .55;
  line-height: 1.7;
}

/* Le lien vers le film complet. Encadre plutot que souligne : c'est la seule
   action de la page, elle doit se voir sans crier. */
.project__watch {
  justify-self: center;
  margin-top: 1.5rem;
  padding: .7rem 1.4rem;
  border: 1px solid currentColor;
  transition: background-color .3s var(--ease), color .3s var(--ease);
}
.project__watch:hover {
  background: var(--ink);
  color: var(--ground);
}

/* 52rem et non 68 : a pleine largeur une photo verticale occupait deux
   hauteurs d'ecran et il fallait defiler pour en voir une seule. Moctar l'a
   demande, et c'est aussi ce qui rend une serie de vingt-six images
   parcourable au lieu d'interminable. */
.project__media {
  display: grid;
  gap: clamp(.5rem, 2.5vw, 2rem);
  padding: 0 var(--pad) clamp(4rem, 12vh, 9rem);
  max-width: 52rem;
  margin-inline: auto;
}

/* Une vidéo dont le format est connu ne dépasse pas l'écran en hauteur : la
   vidéo verticale de Gee-Gees Spotlight faisait sinon près de deux écrans. */
.project__media video.is-sized {
  width: min(100%, calc(86svh * var(--ar)));
  height: auto;
  aspect-ratio: var(--ar);
  margin-inline: auto;
}

/* Les chapitres d'un projet qui regroupe plusieurs choses, comme X.Vision :
   le film, l'équipe, les affiches. */
.project__chapter {
  text-align: center;
  padding-top: clamp(2.5rem, 9vh, 5rem);
}
.project__media > .reveal:first-child .project__chapter { padding-top: 0; }
.project__subtitle {
  margin: 0 0 .6rem;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.75rem, 4.5vw, 2.5rem);
  line-height: 1.05;
}
.project__chapter .label { margin: 0; opacity: .66; }

.project__nav {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 2rem var(--pad) clamp(4rem, 10vh, 7rem);
  border-top: 1px solid currentColor;
  max-width: 68rem;
  margin-inline: auto;
}
.project__nav a { opacity: .66; }
.project__nav a:hover { opacity: 1; }

/* --------------------------------------------------------------------------
   8. PAGE PROFIL
   ----------------------------------------------------------------------- */
/* La page profil ALTERNE : une photo, un texte a cote, et le cote s'inverse a
   chaque bloc. La version precedente empilait les trois photos puis les trois
   paragraphes, et une pile de photos suivie d'une pile de texte ne se lit pas,
   elle se saute. Chaque image porte maintenant un morceau du propos. */
.profile {
  max-width: 66rem;
  margin-inline: auto;
  padding: clamp(2rem, 6vh, 4rem) var(--pad) clamp(5rem, 14vh, 9rem);
}

.profile__block {
  display: grid;
  gap: clamp(1.25rem, 4vw, 3rem);
  align-items: center;
  margin-bottom: clamp(3.5rem, 12vh, 7rem);
}
.profile__block:last-child { margin-bottom: 0; }

@media (min-width: 820px) {
  .profile__block { grid-template-columns: 1fr 1fr; }
  /* En portrait le cote n'existe pas : on empile toujours photo puis texte,
     dans l'ordre de lecture. L'inversion ne vaut que sur grand ecran. */
  .profile__block--right .profile__figure { order: 2; }
}

/* Meme regle que la galerie : la photo est bornee par la hauteur de l'ecran.
   En une seule colonne, un portrait pleine largeur fait 1,33 fois la largeur
   en hauteur, soit plus d'un ecran de photo avant d'atteindre le texte qui va
   avec — et c'est justement le rapprochement des deux qui est demande ici. */
.profile__figure {
  margin: 0;
  display: grid;
  place-items: center;
}
.profile__figure img {
  width: auto;
  max-width: 100%;
  max-height: 70svh;
}

.profile__text p {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  line-height: 1.65;
  margin: 0 0 1.25rem;
}
.profile__text p:last-of-type { margin-bottom: 0; }

/* Les portraits de Moctar. La premiere image porte, les deux autres se
   partagent la ligne en dessous : trois images de meme taille se
   neutraliseraient, et la page Profil n'a qu'un sujet. */
.profile__gallery {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap);
  margin-bottom: clamp(2rem, 6vh, 3.5rem);
}
.profile__gallery > *:first-child { grid-column: 1 / -1; }
.profile__gallery img { width: 100%; }

.profile p {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  line-height: 1.65;
  margin: 0 0 1.25rem;
}

.profile__contact {
  margin-top: clamp(2.5rem, 8vh, 4rem);
  padding-top: 1.5rem;
  border-top: 1px solid currentColor;
  display: grid;
  gap: .5rem;
}

/* --------------------------------------------------------------------------
   8 bis. LA VISIONNEUSE
   La section Photos montre les images elles-memes. Un clic doit donc ouvrir
   l'image, pas une page : renvoyer vers une fiche projet ferait perdre la
   place dans une galerie de quarante-trois vignettes.
   ----------------------------------------------------------------------- */
.lb {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: clamp(2.5rem, 7vh, 4rem) clamp(.75rem, 4vw, 3.5rem);
  background: rgba(0, 0, 0, .93);
}
.lb[hidden] { display: none; }

.lb__img {
  max-width: 100%;
  max-height: 84svh;
  width: auto;
  height: auto;
  object-fit: contain;
}

.lb__bar {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem clamp(.75rem, 4vw, 2rem);
  color: rgba(255, 255, 255, .7);
}

.lb button {
  background: none;
  border: 0;
  padding: .5rem;
  font: inherit;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .7);
  cursor: pointer;
}
.lb button:hover { color: #fff; }

.lb__close { position: absolute; top: .5rem; right: clamp(.5rem, 3vw, 1.5rem); }
.lb__nav { display: flex; gap: 1.25rem; }

/* --------------------------------------------------------------------------
   8 ter. LE RETOUR EN HAUT
   Discret : il ne se montre qu'une fois la premiere hauteur d'ecran passee, et
   reste a demi efface tant qu'on ne le vise pas. Sur des pages qui font
   quarante-trois photographies, remonter a la main est une corvee.
   ----------------------------------------------------------------------- */
.toTop {
  position: fixed;
  right: clamp(.6rem, 2vw, 1.5rem);
  bottom: clamp(1rem, 4vh, 2.5rem);
  z-index: 60;
  width: 2.4rem;
  height: 2.4rem;
  display: grid;
  place-items: center;
  padding: 0;
  background: none;
  border: 1px solid currentColor;
  border-radius: 50%;
  font: inherit;
  line-height: 1;
  color: var(--ink);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transform: translateY(.5rem);
  transition: opacity .35s var(--ease), transform .35s var(--ease),
              background-color .3s var(--ease), color .3s var(--ease);
}
.toTop.is-visible { opacity: .42; pointer-events: auto; transform: none; }
.toTop.is-visible:hover,
.toTop.is-visible:focus-visible {
  opacity: 1;
  background: var(--ink);
  color: var(--ground);
}

/* --------------------------------------------------------------------------
   9. PIED DE PAGE
   ----------------------------------------------------------------------- */
.foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.5rem var(--pad);
  border-top: 1px solid currentColor;
  opacity: .66;
}

/* --------------------------------------------------------------------------
   10. APPARITION AU DÉFILEMENT
   Ne s'applique que si le script tourne : sans JavaScript rien n'est caché.
   ----------------------------------------------------------------------- */
.js-anim .reveal { opacity: 0; transform: translateY(1.25rem); }
.js-anim .reveal.is-in {
  opacity: 1;
  transform: none;
  transition: opacity .8s var(--ease), transform .8s var(--ease);
}

@media (prefers-reduced-motion: reduce) {
  .js-anim .reveal { opacity: 1; transform: none; transition: none; }
  .tile:hover .tile__media { transform: none; }
  html, body { transition: none; }
  .masthead__name { transition: none; }
}

/* --------------------------------------------------------------------------
   11. ÉTAT VIDE — une section sans projet ne doit jamais casser la page
   ----------------------------------------------------------------------- */
.empty {
  grid-column: 1 / -1;
  padding: 4rem 0;
  text-align: center;
  opacity: .6;
}
