/* ==========================================================================
   FLAA — sections.css
   Mise en page des sections de la page d'accueil.
   ========================================================================== */

/* --------------------------------------------------------------------------
   hero — diaporama plein écran, épinglé
   Composition en grille : mot-symbole à gauche / méta à droite sur la ligne
   médiane, accroche et appel à l'action sur la ligne basse.

   Le hero est `sticky` en haut de page : il reste en place pendant que la
   suite du document glisse par-dessus. Cela suppose deux choses —
     1. aucun ancêtre ne doit être un conteneur de défilement
        (cf. `overflow-x: clip` sur le body, dans base.css) ;
     2. tout ce qui suit doit être opaque et sur un plan supérieur
        (cf. `.site-main > *` plus bas).
   -------------------------------------------------------------------------- */

.hero {
  position: sticky;
  top: 0;
  z-index: 0;
  height: 100svh;
  min-height: 560px;
  overflow: hidden;
  background: #0a0a0a;
  color: #fff;
}

/* Le contenu qui suit recouvre le hero en défilant. Seuls les heros
   eux-mêmes sont exclus : ce sont eux qu'on recouvre. */
.site-main > *:not(.hero):not(.page-hero) {
  position: relative;
  z-index: 1;
  background-color: var(--surface, var(--color-bg));
}

/* `z-index` explicite : sans lui, les `z-index` des diapositives
   remonteraient dans le contexte d'empilement du hero et passeraient
   au-dessus du contenu. */
.hero__slides {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* Visuel unique : il occupe tout le cadre, sans machinerie de transition. */
.hero__slide {
  position: absolute;
  inset: 0;
  opacity: 1;
}

.hero__slide picture,
.hero__slide img {
  width: 100%;
  height: 100%;
}

.hero__img {
  object-fit: cover;
  transform: scale(1.06);
  transition: transform 6000ms var(--ease-out);
}

.hero.is-ready .hero__img,
.hero:not(.is-overture) .hero__img {
  transform: scale(1);
}

/* --- Ouverture -----------------------------------------------------------
   Relevé sur la maquette de référence : les trois visuels ne sont pas des
   vignettes découpées mais des calques *plein écran mis à l'échelle*. Leur
   rapport est donc exactement celui de la fenêtre, ce qui permet au dernier
   de grandir jusqu'au plein cadre sans le moindre raccord.

   Chaque calque a sa propre échelle (0.30 / 0.35 / 0.40) et sa propre
   hauteur de repos : les plus petits sont au-dessus et dépassent par le haut,
   le plus grand est au premier plan et plus bas. Ils montent depuis le bas,
   l'un après l'autre, puis celui de devant passe à l'échelle 1 et recouvre
   tout — les autres n'ont pas besoin de disparaître.
   -------------------------------------------------------------------------- */

.hero__overture {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: none;
}

.hero.is-overture .hero__overture {
  display: block;
}

/* Pendant toute l'ouverture, le hero n'existe pas : fond blanc, pas de voile,
   et surtout pas de diaporama derrière les calques — c'est lui qu'on voyait
   dépasser autour des trois visuels. */
.hero.is-overture:not(.is-ready) {
  background: var(--color-bg);
}

.hero.is-overture:not(.is-ready) .hero__scrim,
.hero.is-overture:not(.is-ready) .hero__slides {
  opacity: 0;
}

/* Le zoom lent de la première diapositive attend la fin de l'ouverture :
   au moment du relais, elle et le calque de premier plan sont strictement
   à la même échelle, donc le raccord est invisible. */
.hero.is-overture:not(.is-ready) .hero__img {
  transform: scale(1);
  transition: none;
}

.hero__card {
  --card-scale: calc(0.3 + var(--card-index, 0) * 0.05);
  --card-rest: calc(var(--card-index, 0) * 9.5vh - 5.5vh);
  --card-enter: 16vh;

  position: absolute;
  inset: 0;
  opacity: 0;
  transform: translate3d(0, calc(var(--card-rest) + var(--card-enter)), 0) scale(var(--card-scale));
  transform-origin: center center;
  transition:
    opacity 900ms var(--ease-out),
    transform 1200ms var(--ease-out);
  transition-delay: calc(var(--card-index, 0) * 300ms);
  will-change: opacity, transform;
}

.hero__card picture,
.hero__card-img {
  width: 100%;
  height: 100%;
}

.hero__card-img {
  object-fit: cover;
}

/* Montée à la place de repos. */
.hero.is-overture-in .hero__card {
  opacity: 1;
  transform: translate3d(0, var(--card-rest), 0) scale(var(--card-scale));
}

/* Le calque de premier plan occupe la fenêtre entière.
   `--ease-out` et non `--ease-in-out` : la courbe démarre avec de la vitesse,
   donc le mouvement prend le relais de la montée sans marquer d'arrêt. */
.hero.is-overture-full .hero__card:last-child {
  transform: translate3d(0, 0, 0) scale(1);
  transition: transform 1250ms var(--ease-out);
  transition-delay: 0ms;
}

.hero.is-ready .hero__overture {
  display: none;
}

/* Les calques épousaient la fenêtre : en paysage sur un écran large, en
   portrait sur un téléphone. On leur impose ici le format du grand écran, en
   les inscrivant dans une bande 16/9 centrée.

   La bande est découpée, pas mise en boîte. `inset` est une propriété de mise
   en page : l'animer obligeait le navigateur à recalculer la disposition et à
   repeindre un calque plein écran à chaque frame, et le `will-change` posé sur
   l'opacité et la transformation ne pouvait rien pour elle. `clip-path` donne
   exactement la même géométrie — même centre, même hauteur visible une fois la
   mise à l'échelle appliquée — mais se compose sur le GPU comme les deux
   autres.

   Contrepartie assumée : la carte fait désormais toute la fenêtre en
   permanence, donc `object-fit: cover` y cadre en portrait du début à la fin.
   Auparavant la boîte passait de 16/9 à plein écran et l'image se recadrait à
   chaque frame — c'était précisément ce recadrage continu qui coûtait cher.
   Le raccord final avec le fond du hero, lui, reste au pixel près : même
   fichier, même boîte, même cadrage. */
@media (max-width: 900px) {
  .hero__card {
    --card-scale: calc(0.66 + var(--card-index, 0) * 0.055);
    --card-rest: calc(var(--card-index, 0) * 7vh - 4vh);
    --card-enter: 12vh;

    clip-path: inset(calc((100% - (100vw * 9 / 16)) / 2) 0 calc((100% - (100vw * 9 / 16)) / 2) 0);
    transition:
      opacity 900ms var(--ease-out),
      transform 1200ms var(--ease-out),
      clip-path 1250ms var(--ease-out);
    /* La forme courte `transition` porte aussi le délai et le remet à zéro :
       sans cette ligne, l'échelonnement de la règle générale était effacé et
       les trois calques montaient ensemble, sans escalier. */
    transition-delay: calc(var(--card-index, 0) * 300ms);
    will-change: opacity, transform, clip-path;
  }

  /* La règle du grand écran restreint la transition à `transform` seul. Sans
     la rétablir ici, la découpe n'était plus animée du tout et la bande
     s'ouvrait d'un coup au lieu de se déployer. */
  .hero.is-overture-full .hero__card:last-child {
    clip-path: inset(0 0 0 0);
    transition:
      transform 1250ms var(--ease-out),
      clip-path 1250ms var(--ease-out);
    transition-delay: 0ms;
  }
}

/* Les sélecteurs reprennent `:not(.is-ready)` : sans lui, ils auraient une
   spécificité inférieure aux règles d'ouverture ci-dessus et ne
   s'appliqueraient jamais. */
@media (prefers-reduced-motion: reduce) {
  .hero.is-overture:not(.is-ready) {
    background: #0a0a0a;
  }

  .hero.is-overture:not(.is-ready) .hero__overture {
    display: none;
  }

  .hero.is-overture:not(.is-ready) .hero__scrim,
  .hero.is-overture:not(.is-ready) .hero__slides {
    opacity: 1;
  }

  .hero.is-overture:not(.is-ready) .hero__content > * {
    opacity: 1;
    clip-path: none;
    transform: none;
  }
}

/* --- Révélation du contenu -----------------------------------------------
   Le texte n'arrive qu'une fois le visuel en plein cadre : pendant
   l'agrandissement, les angles sont encore blancs et un texte blanc y serait
   invisible. */

.hero.is-overture .hero__content > * {
  opacity: 0;
  clip-path: inset(-30% 0 110% 0);
  transform: translate3d(0, 0.3em, 0);
}

.hero.is-ready .hero__content > * {
  opacity: 1;
  clip-path: inset(-30% 0 -30% 0);
  transform: translate3d(0, 0, 0);
  transition:
    opacity 700ms var(--ease-out),
    clip-path 900ms var(--ease-out),
    transform 900ms var(--ease-out);
  transition-delay: calc(var(--anim-index, 0) * 110ms);
}

/* Voile sombre : il n'existe que pour rendre le texte lisible, pas pour teinter
   la photographie.

   Il assombrissait auparavant tout le cadre d'une couche uniforme, qui ne
   servait le texte nulle part et éteignait l'image partout. Elle est retirée.
   Ce qui reste est concentré là où il y a du texte : la moitié gauche, et de
   fines bandes haut et bas pour l'en-tête et la ligne du bas. Le dégradé
   s'éteint à 58 % de la largeur au lieu de 85 : les deux tiers droits de la
   photographie ne sont plus voilés du tout.
 */
.hero__scrim {
  position: absolute;
  z-index: 2;
  inset: 0;
  background:
    linear-gradient(to right, rgba(0, 0, 0, 0.265) 0%, rgba(0, 0, 0, 0.156) 30%, rgba(0, 0, 0, 0.047) 48%, rgba(0, 0, 0, 0.000) 56%),
    linear-gradient(to bottom, rgba(0, 0, 0, 0.229) 0%, rgba(0, 0, 0, 0.000) 20%),
    linear-gradient(to top, rgba(0, 0, 0, 0.229) 0%, rgba(0, 0, 0, 0.000) 26%);
  pointer-events: none;
}

/* En colonne, tout le texte se regroupe au bas du cadre : le voile latéral n'y
   sert plus à rien, c'est celui du bas qui porte la lisibilité.

   Le bloc de texte occupe le dernier quart de la hauteur, et son surtitre
   tombe sur les vitrages éclairés du bâtiment. Le voile monte donc plus haut
   et plus dense qu'auparavant : c'est ce qui tient le contraste sur cette
   bande claire. */
@media (max-width: 900px) {
  .hero__scrim {
    background:
      linear-gradient(to bottom, rgba(0, 0, 0, 0.30) 0%, rgba(0, 0, 0, 0.000) 18%),
      linear-gradient(to top, rgba(0, 0, 0, 0.72) 0%, rgba(0, 0, 0, 0.42) 30%, rgba(0, 0, 0, 0.10) 48%, rgba(0, 0, 0, 0.000) 64%);
  }
}

.hero__content {
  position: absolute;
  z-index: 5;
  inset: var(--header-height) var(--gutter) clamp(24px, 3.7vw, 64px);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: 1fr auto;
  align-items: center;
  gap: var(--space-md);
}

/* — Mot-symbole ————————————————————————————————— */

/* Le slogan et le méta sont centrés dans la même rangée. Une marge basse
   identique sur les deux les remonte chacun de la moitié de sa valeur, sans
   toucher à leur alignement l'un par rapport à l'autre — ce qu'un
   `align-self: start` aurait rompu, le méta se calant alors sur le haut du
   slogan et non sur son milieu. La ligne du bas, elle, ne bouge pas. */
.hero__wordmark,
.hero__meta {
  margin-bottom: clamp(48px, 23vh, 262px);
}

.hero__wordmark {
  grid-column: 1;
  grid-row: 1;
  align-self: center;
}

/* `display: block` est indispensable : ces deux lignes sont des `<span>` dans
   un seul `<h1>`, et une marge verticale reste sans effet sur un inline. */
.hero__name {
  display: block;
  margin: 0;
  font-size: clamp(40px, 6vw, 104px);
  font-weight: 500;
  line-height: 0.86;
  letter-spacing: -0.04em;
}

/* Seconde ligne du slogan : détachée de la première et nettement plus légère,
   pour que le contraste de graisse porte la hiérarchie. */
.hero__tagline {
  display: block;
  margin: 0.14em 0 0;
  font-size: clamp(21px, 3vw, 52px);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.03em;
}

/* — Méta (ligne médiane, à droite) ————————————————— */

.hero__meta {
  grid-column: 2;
  grid-row: 1;
  align-self: center;
  display: flex;
  align-items: center;
  /* La colonne est dimensionnée par le lien du bas, plus large : sans cela le
     méta s'y range à gauche et flotte à quelques dizaines de pixels du bord. */
  justify-content: flex-end;
  gap: clamp(10px, 1.4vw, 24px);
  margin-block: 0 clamp(48px, 23vh, 262px);
  margin-inline: 0;
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

.hero__meta-sep {
  opacity: 0.6;
}

/* — Accroche (ligne basse, à gauche) ——————————————— */

.hero__intro {
  grid-column: 1;
  grid-row: 2;
  align-self: end;
  max-width: 34ch;
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.5;
}

/* — Lien vers l'archive (ligne basse, à droite) ——————— */

.hero__cta {
  position: relative;
  grid-column: 2;
  grid-row: 2;
  align-self: end;
  justify-self: end;
  margin: 0;
}


/* Sur mobile, la grille du grand écran se remet en une seule colonne, calée
   en bas du cadre.

   Piège : les enfants portent les valeurs d'alignement de la grille
   (`align-self: center` sur le slogan et le méta, `align-self: end` et
   `justify-self: end` sur l'accroche et le lien). Dans une colonne flex,
   `align-self` passe sur l'axe horizontal : le slogan se retrouvait centré,
   l'accroche et le lien plaqués à droite, et la colonne descendait en
   escalier. Un `align-items` sur le conteneur ne peut rien contre elles, il
   faut les neutraliser sur les enfants.

   Composition : la ligne de situation devient un surtitre, souligné d'un
   filet qui pose la largeur du bloc ; le slogan suit, puis l'accroche et le
   lien, chacun détaché par sa propre marge plutôt que par un `gap` uniforme
   qui mettait les quatre blocs sur le même plan. */
@media (max-width: 900px) {
  .hero__content {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: 0;
    inset: var(--header-height) var(--gutter) clamp(34px, 8.6vw, 56px);
  }

  .hero__content > * {
    align-self: stretch;
    justify-self: stretch;
    margin: 0;
    text-align: left;
  }

  .hero__meta     { order: 1; }
  .hero__wordmark { order: 2; }
  .hero__intro    { order: 3; }
  .hero__cta      { order: 4; }

  .hero__meta {
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 0.7em;
    margin-bottom: clamp(20px, 5.6vw, 30px);
    padding-bottom: clamp(17px, 4.8vw, 26px);
    border-bottom: 1px solid rgba(255, 255, 255, 0.28);
    white-space: normal;
  }

  .hero__name {
    font-size: clamp(36px, 10.4vw, 54px);
  }

  .hero__tagline {
    margin-top: 0.26em;
    font-size: clamp(19px, 5.4vw, 28px);
  }

  .hero__intro {
    max-width: 32ch;
    margin-top: clamp(26px, 7.4vw, 38px);
    color: rgba(255, 255, 255, 0.85);
  }

  .hero__cta {
    margin-top: clamp(32px, 9vw, 46px);
  }
}


/* --------------------------------------------------------------------------
   intro — accroche, chapô et chiffres clés
   -------------------------------------------------------------------------- */

.intro__title {
  font-size: var(--fs-display-lg);
  letter-spacing: var(--ls-lg);
  text-wrap: initial;
}

.intro__lead {
  max-width: 640px;
  margin-top: var(--space-text);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

/* Les chiffres se rangent en deux colonnes dans la colonne du texte. Le corps
   reste réduit : c'est ce qui garde le bloc court malgré les deux rangées. */
.intro__stats {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: var(--space-block);
  gap: clamp(20px, 2.3vw, 40px) clamp(12px, 1.4vw, 24px);
}

.intro__stats .stat {
  padding-top: clamp(16px, 1.6vw, 28px);
}

.intro__stats .stat__rule {
  margin-bottom: clamp(12px, 1.4vw, 24px);
}

.intro__stats .stat__value {
  font-size: clamp(34px, 3.36vw, 58px);
}

.intro__stats .stat__label {
  margin-top: clamp(6px, 0.7vw, 12px);
}

/* --------------------------------------------------------------------------
   about — image plein cadre puis texte
   -------------------------------------------------------------------------- */

/* Les médias respirent sur la même gouttière que le reste du contenu :
   c'est ce qui les raccroche à la trame plutôt que de les coller aux bords. */
.about__media {
  padding-inline: var(--gutter);
}

.about__body {
  --marker-top: var(--space-2xl);
  padding-top: var(--space-section);
}

.about__title {
  max-width: 12ch;
  margin: 0 0 var(--space-text);
  font-size: var(--fs-display-lg);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: var(--ls-lg);
}

.about__text + .about__text {
  margin-top: 1.5em;
}

.about__text {
  max-width: 640px;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.about__cta {
  margin-top: var(--space-block);
}

/* --------------------------------------------------------------------------
   showreel — visuel pleine largeur
   -------------------------------------------------------------------------- */

/* Un bloc ordinaire : ni épinglage, ni mise à l'échelle, ni logo. Le cadre
   reprend la largeur et le format des autres médias pleine largeur du site.

   Le rythme est porté par un rembourrage, jamais par une marge : entre deux
   enfants directs de `.site-main`, seuls les blocs eux-mêmes peignent un fond,
   et une marge y ouvrirait une bande transparente laissant voir le hero
   collant resté dessous. */
.showreel {
  position: relative;
  /* Rembourrage des deux côtés : la section qui suit peint son propre fond
     dès son premier pixel, sans quoi le visuel lui serait collé. */
  padding: var(--space-section) var(--gutter);
}

.showreel__frame {
  position: relative;
  width: 100%;
  aspect-ratio: 1600 / 797;
  overflow: hidden;
  background: var(--color-ink);
}

.showreel__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Voile bas. Le dosage n'est pas repris d'ailleurs : il est calculé sur cette
   photographie précise, dont le bassin passe en clair exactement sous le
   titre. Relevé sur l'image, le noir nécessaire pour tenir 4,5:1 sous du blanc
   monte jusqu'à 0,54 sur la hauteur du texte ; le dégradé reste au-dessus
   de ces valeurs sur toute la hauteur du texte, puis s'éteint.

   Contrairement aux en-têtes de page, pas de voile plat sur tout le cadre :
   il n'y a rien à lire en haut, et la photographie garde son ciel. */
.showreel__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.60) 0%,
    rgba(0, 0, 0, 0.58) 24%,
    rgba(0, 0, 0, 0.54) 38%,
    rgba(0, 0, 0, 0.20) 52%,
    rgba(0, 0, 0, 0.000) 68%
  );
  pointer-events: none;
}

/* Le titre se découvre au balayage, exactement comme les autres titres du
   thème : c'est `reveal--mask` qui s'en charge, à l'entrée dans le champ. */
.showreel__title {
  position: absolute;
  left: clamp(18px, 2.2vw, 40px);
  right: clamp(18px, 2.2vw, 40px);
  bottom: clamp(18px, 2.2vw, 40px);
  margin: 0;
  color: #fff;
  font-size: var(--fs-display-xl);
  font-weight: 500;
  line-height: 1.02;
  letter-spacing: var(--ls-xl);
  text-wrap: initial;
}

@media (max-width: 900px) {
  /* 48 px : il pesait plus lourd que les titres de section, à 36. */
  .showreel__title {
    font-size: clamp(22px, 6.4vw, 30px);
  }
}

@media (max-width: 900px) {
  .showreel__frame {
    aspect-ratio: 4 / 3;
  }
}

/* --------------------------------------------------------------------------
   services — titre XXL, image, accordéon
   -------------------------------------------------------------------------- */

.services__title {
  font-size: var(--fs-display-lg);
  font-weight: 500;
  line-height: 0.9;
  letter-spacing: var(--ls-2xl);
}

.services__lead {
  max-width: 640px;
  margin-top: var(--space-text);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

/* --- Types de projets : rangée de vignettes qui s'ouvrent au survol -------
   Relevé sur la référence : carrés de 247 px au repos, écart de 10 px, rangée
   centrée. Au survol la vignette double environ et découvre son intitulé.
   L'ouverture est purement CSS ; `:focus-within` la rend accessible au
   clavier. La hauteur de la rangée est réservée d'avance pour que
   l'agrandissement ne fasse pas sauter la mise en page. */

/* Fond sombre : les vignettes et leur légende s'y détachent nettement, et
   c'est le registre de la référence. La règle passe par `.site-main >` avec
   une classe répétée pour dépasser celle qui donne son fond à chaque section
   — même contrainte de spécificité que pour le manifeste. */
/* Le rythme du thème ne pose l'écart qu'au-dessus des sections, ce qui
   convient tant qu'elles n'ont pas de fond propre. Celle-ci en a un : sans
   rembourrage bas, le noir s'arrête net sur la dernière légende. */
.site-main > .services.services {
  /* Le rembourrage bas vaut celui du haut. La légende, posée en absolu, sort
     de la rangée : c'est `.domaines` qui réserve la place de ce débordement,
     là où sa mesure est connue. Auparavant la section réservait 210 px pour un
     débordement de 54, et le bas de section était deux fois plus aéré que le
     haut. */
  padding-bottom: var(--space-section);
  background-color: var(--color-ink);
  color: var(--color-inverse-fg);
}

.services .marker,
.services .services__title,
.services .services__lead {
  color: var(--color-inverse-fg);
}

.services .services__lead {
  opacity: 0.72;
}

/* Classe répétée : le reset porte `ul[class] { padding: 0; margin: 0 }`, de
   spécificité 0,1,1, qui l'emporte sur `.domaines` comme sur `.l-shell`.
   C'est ce qui annulait à la fois la gouttière et l'écart avec le titre. */
.domaines.domaines {
  --domaine-hauteur: clamp(200px, 24vw, 414px);
  --domaine-legende: clamp(120px, 9.6vw, 166px); /* légende réduite + l'écart */

  display: flex;
  align-items: center;
  gap: 10px;
  /* Le reset des listes remet le rembourrage à zéro et neutralise celui de
     `l-shell` : on le repose donc explicitement, sinon la rangée démarre au
     ras du bord au lieu de la gouttière. */
  padding-inline: var(--gutter);
  margin: var(--space-block) 0 0;
  /* La rangée fait exactement la hauteur d'une vignette ouverte : réserver
     en plus la place de la légende créait un vide considérable au-dessus des
     vignettes, l'alignement centré le répartissant des deux côtés. La légende
     déborde donc sous la rangée, et c'est le rembourrage bas de la section
     qui lui fait place. */
  min-height: var(--domaine-hauteur);
  /* Place laissée à la légende, qui déborde sous la rangée. */
  margin-bottom: clamp(52px, 5vw, 88px);
  list-style: none;
}

/* Les vignettes se partagent la largeur disponible au lieu de porter une
   taille fixe : la rangée remplit exactement la coquille, les marges gauche et
   droite sont donc égales par construction, et rien ne se décale au survol. */
.domaine {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  transition: flex-grow 620ms cubic-bezier(0.22, 1, 0.36, 1);
}

.domaine:hover,
.domaine:focus-within {
  z-index: 2;
}

.domaine__link {
  position: relative;
  display: block;
}

.domaine__media {
  position: relative;
  display: block;
  /* Hauteur fixe, largeur variable. Avec un rapport carré, élargir une
     vignette augmentait aussi sa hauteur : la rangée grandissait et poussait
     toute la page à chaque survol. Seule la largeur bouge désormais. */
  width: 100%;
  height: var(--domaine-hauteur);
  overflow: hidden;
  background: #1a1a1a;
  transition: none;
}

.domaine__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Les équerres n'apparaissent que sur la vignette ouverte. L'`inset` du
   composant monte à 58px, calibré pour un média plein cadre : sur une vignette
   il les enfoncerait vers le centre. On les ramène au ras des angles. */
.domaine .media__corners {
  inset: -7px;
  opacity: 0;
  transition: opacity 320ms var(--ease-out);
}

/* La légende est posée sous la vignette sans peser sur le flux : la rangée
   garde la même hauteur, ouverte ou non. */
.domaine__caption {
  position: absolute;
  top: calc(100% + clamp(14px, 1.6vw, 26px));
  left: 0;
  width: min(100%, 460px);
  display: flex;
  flex-direction: column;
  gap: 6px;
  opacity: 0;
  transform: translate3d(0, 8px, 0);
  transition:
    opacity 380ms var(--ease-out) 120ms,
    transform 380ms var(--ease-out) 120ms;
  pointer-events: none;
}

.domaine__name {
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.domaine__text {
  max-width: 42ch;
  color: var(--color-inverse-muted);
  font-size: clamp(12px, 0.93vw, 16px); /* 16 / 1728 */
  line-height: 1.5;
}

/* --- Vignette ouverte par défaut ---
   Comme sur la référence, la section ne s'ouvre pas vide : la première
   vignette est déjà déployée, et se referme dès que la rangée est survolée.

   Les règles de fermeture excluent explicitement la vignette visée. Sans cela,
   la première ne se rouvrait jamais : `.domaines:hover .domaine:first-child`
   pèse quatre sélecteurs quand `.domaine:hover` n'en pèse que deux, et
   l'emportait donc toujours. Ce n'est pas une question d'ordre dans le
   fichier — c'est une question de spécificité, et aucun réordonnancement ne
   l'aurait réglée. */

.domaine:first-child {
  flex-grow: 2.1;
}

.domaine:first-child .media__corners,
.domaine:first-child .domaine__caption {
  opacity: 1;
}

.domaine:first-child .domaine__caption {
  transform: translate3d(0, 0, 0);
}

.domaines:hover .domaine:first-child:not(:hover):not(:focus-within) {
  flex-grow: 1;
}

.domaines:hover .domaine:first-child:not(:hover):not(:focus-within) .media__corners,
.domaines:hover .domaine:first-child:not(:hover):not(:focus-within) .domaine__caption {
  opacity: 0;
}

.domaines:hover .domaine:first-child:not(:hover):not(:focus-within) .domaine__caption {
  transform: translate3d(0, 8px, 0);
}

/* --- État ouvert --- */

.domaine:hover,
.domaine:focus-within {
  flex-grow: 2.1;
}

.domaine__link:hover .media__corners,
.domaine__link:focus-visible .media__corners,
.domaine__link:hover .domaine__caption,
.domaine__link:focus-visible .domaine__caption {
  opacity: 1;
}

.domaine__link:hover .domaine__caption,
.domaine__link:focus-visible .domaine__caption {
  transform: translate3d(0, 0, 0);
}

@media (prefers-reduced-motion: reduce) {
  .domaine__media,
  .domaine__caption {
    transition-duration: 1ms;
  }
}

/* Sous cette largeur, la rangée devient une grille.
   Elle défilait horizontalement jusqu'ici, et c'était un défaut : en CSS,
   `overflow-x: auto` fait aussi passer `overflow-y` à `auto`. La rangée
   devenait donc scrollable dans les deux axes et capturait les gestes
   verticaux — d'où un défilement de page qui se bloquait au doigt. Une grille
   ne crée aucun conteneur défilant, le problème disparaît à la racine.
   Le survol n'existant pas au tactile, la légende reste toujours visible. */
@media (max-width: 900px) {
  .domaines.domaines {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(12px, 3vw, 20px) clamp(10px, 2.4vw, 16px);
    min-height: 0;
    overflow: visible;
  }

  /* La première vignette occupe toute la largeur : elle donne le ton de la
     section, comme la vignette ouverte par défaut sur grand écran. */
  .domaine:first-child {
    grid-column: 1 / -1;
  }

  .domaine,
  .domaine:hover,
  .domaine:focus-within,
  .domaines:hover .domaine:first-child {
    flex: none;
    flex-grow: 0;
  }

  .domaine__media {
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
  }

  .domaine:first-child .domaine__media {
    aspect-ratio: 16 / 9;
  }

  .domaine__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* Les équerres n'ont plus de sens sans survol : elles encadraient une
     vignette qui s'ouvre, or ici elles sont toutes ouvertes. */
  .domaine .media__corners {
    display: none;
  }

  .domaine__caption {
    position: static;
    width: 100%;
    margin-top: 10px;
    opacity: 1;
    transform: none;
  }

  .domaine__text {
    display: none;
  }

  /* La réserve du bas servait à loger une légende posée en absolu sous la
     rangée. Ici les légendes sont dans le flux : la réserve n'est plus que du
     vide au bas de la section. */
  .site-main > .services.services {
    padding-bottom: var(--space-section);
  }
}

/* Aucun conteneur défilant ne doit entraîner la page avec lui lorsqu'il
   atteint sa butée : au doigt, l'enchaînement se lit comme un à-coup. */
.domaines,
.projects__viewport {
  overscroll-behavior-x: contain;
}

/* --------------------------------------------------------------------------
   partners — titre, logotypes, texte de clôture
   -------------------------------------------------------------------------- */

.partners__title {
  font-size: var(--fs-display-xl);
  font-weight: 500;
  line-height: 0.98;
  letter-spacing: var(--ls-xl);
}

.partners__lead,
.partners__outro {
  max-width: 640px;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.partners__lead {
  margin-top: var(--space-text);
}

.partners__logos {
  margin-block: var(--space-block);
  padding-inline: var(--gutter);
}

/* --------------------------------------------------------------------------
   associés — les trois portraits en éventail, sur la page d'accueil
   Un portrait devant, les deux autres de part et d'autre, plus petits et
   désaturés. Les classes de position sont posées par le module JavaScript ;
   toute la géométrie est ici.
   -------------------------------------------------------------------------- */

/* Ni en haut ni en bas : la section se colle à celles qui l'encadrent, et
   seul le creux réservé aux flèches, plus bas, la sépare de la suivante. */
.associes {
  padding: 0 var(--gutter);
}

.associes__inner {
  display: flex;
  flex-direction: column;
  gap: clamp(34px, 5.4vw, 76px);
  padding-bottom: clamp(58px, 5.6vw, 80px);
}

/* Le corps et l'interlettrage viennent de `.section-title`, comme partout
   ailleurs. Ne restent ici que le centrage et la neutralisation du compteur
   en exposant, que cette section n'a pas. */
.associes__title {
  justify-content: center;
  margin: 0;
  text-align: center;
}

/* La largeur du portrait de devant commande tout : la hauteur de la scène et
   l'écartement des deux autres en découlent. */
.associes__stage {
  --associe-l: clamp(200px, 23vw, 372px);
  --associe-ecart: 0.74;
  --associe-echelle: 0.78;
  /* Hauteur du portrait, plus la ligne du prénom. */
  --associe-legende: clamp(34px, 2.6vw, 48px);

  position: relative;
  height: calc(var(--associe-l) * 3 / 2 + var(--associe-legende));
}

.associes__stage:focus {
  outline: none;
}

/* Classe répétée : la remise à zéro générale vise `ul[class]`, dont la
   spécificité dépasse celle d'une classe simple. */
.associes__list.associes__list {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.associe {
  position: absolute;
  top: 0;
  left: 50%;
  display: flex;
  flex-direction: column;
  width: var(--associe-l);
  cursor: pointer;
  transform: translateX(-50%);
  /* Noir et blanc en permanence : la couleur n'apparaît à aucun moment, ni
     au premier plan, ni au survol. */
  filter: grayscale(1);
  transform-origin: center top;
  transition:
    transform 720ms var(--ease-out),
    opacity 520ms var(--ease-out);
  will-change: transform, opacity;
}

.associe__media {
  display: block;
  width: 100%;
  aspect-ratio: 2 / 3;
  overflow: hidden;
  background: #ececec;
}

.associe__img,
.associe .portrait-initials {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 28%;
}

.associe__nom {
  display: block;
  height: var(--associe-legende);
  padding-top: clamp(10px, 0.9vw, 16px);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-align: center;
  text-transform: uppercase;
}

.associe.is-front {
  z-index: 3;
  opacity: 1;
  transform: translateX(-50%) scale(1);
  cursor: default;
}

.associe.is-left {
  z-index: 2;
  opacity: 0.62;
  transform: translateX(calc(-50% - var(--associe-l) * var(--associe-ecart))) scale(var(--associe-echelle));
}

.associe.is-right {
  z-index: 2;
  opacity: 0.62;
  transform: translateX(calc(-50% + var(--associe-l) * var(--associe-ecart))) scale(var(--associe-echelle));
}

.associe.is-left:hover,
.associe.is-right:hover {
  opacity: 0.85;
}

/* Au-delà de trois, les portraits en attente restent hors de la scène. */
.associe.is-away {
  z-index: 1;
  opacity: 0;
  transform: translateX(-50%) scale(0.6);
  pointer-events: none;
}

/* Sous l'éventail et centrées comme lui : posées à droite, elles se
   détachaient d'une composition qui, elle, est symétrique. */
.associes__nav {
  position: absolute;
  left: 50%;
  bottom: calc(-1 * clamp(58px, 5.6vw, 80px));
  z-index: 4;
  display: flex;
  gap: 1px;
  transform: translateX(-50%);
}

.associes__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(40px, 3.24vw, 56px);
  aspect-ratio: 1;
  background: var(--color-inverse-bg);
  color: var(--color-inverse-fg);
  transition: opacity var(--dur-fast) var(--ease-out);
}

.associes__btn:hover {
  opacity: 0.78;
}

.associes__icon {
  width: 40%;
  height: 40%;
}

@media (max-width: 900px) {
  /* Trois portraits en éventail sur un écran de téléphone : les côtés
     doivent rentrer nettement plus, sinon ils mordent les bords et se
     retrouvent aux trois quarts cachés derrière celui de devant. */
  .associes__stage {
    --associe-l: clamp(180px, 52vw, 260px);
    --associe-ecart: 0.62;
    --associe-echelle: 0.60;
    --associe-legende: clamp(30px, 8vw, 42px);
  }

  /* La scène est plus haute que le portrait de devant seul : elle doit tenir
     compte de la légende, qui ne se met pas à l'échelle sur les côtés. */
  .associes__inner {
    gap: clamp(24px, 6vw, 40px);
  }

  .associes__title {
    text-wrap: balance;
  }

  .associes__nav {
    bottom: calc(-1 * clamp(58px, 15vw, 72px));
  }
}

@media (prefers-reduced-motion: reduce) {
  .associe {
    transition: opacity 200ms linear;
  }
}

/* --------------------------------------------------------------------------
   newsletter (dans le pied de page)
   -------------------------------------------------------------------------- */

.newsletter {
  position: relative;
}

/* --------------------------------------------------------------------------
   Pages internes (blog, page, 404) — hérite du même langage typographique.
   -------------------------------------------------------------------------- */

.page-header {
  padding-block: calc(var(--header-height) + var(--space-section)) 0;
}

.page-header__title {
  font-size: var(--fs-display-lg);
  letter-spacing: var(--ls-lg);
}

.page-header__meta {
  margin-top: var(--space-sm);
  color: var(--color-muted);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.entry-content {
  max-width: 640px;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.entry-content > * + * {
  margin-top: 1.2em;
}

.entry-content :is(h2, h3, h4) {
  margin-top: 1.8em;
  font-size: var(--fs-display-sm);
  letter-spacing: var(--ls-sm);
}

.entry-content a {
  border-bottom: 1px solid currentColor;
}

.entry-content img {
  width: 100%;
  height: auto;
}

.post-list {
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--color-rule);
}

.post-card {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-lg);
  padding-block: clamp(20px, 2.315vw, 40px);
  border-bottom: 1px solid var(--color-rule);
}

.post-card__title {
  font-size: var(--fs-display-sm);
  font-weight: 400;
  letter-spacing: var(--ls-sm);
}

.post-card__date {
  flex: 0 0 auto;
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  white-space: nowrap;
}

.pagination {
  display: flex;
  gap: var(--space-sm);
  padding-top: var(--space-block);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.error-404 {
  display: grid;
  place-items: start;
  min-height: 70svh;
  align-content: center;
}

.error-404__code {
  font-size: var(--fs-display-2xl);
  font-weight: 500;
  line-height: 0.9;
  letter-spacing: var(--ls-2xl);
}

/* --------------------------------------------------------------------------
   projects — réalisations à la une
   Grille de trois colonnes en quinconce : la colonne du milieu descend,
   la troisième s'intercale entre les deux.
   -------------------------------------------------------------------------- */

/* Réalisations est immédiatement suivie de la section sombre. Sans
   rembourrage bas, le changement de fond se produit au ras de la dernière
   carte : il faut rendre l'air que le rythme « écart au-dessus seulement »
   ne prévoit pas ici. */
.projects {
  padding-bottom: var(--space-section);
}

.projects__head {
  margin-bottom: var(--space-block);
}

.projects__lead {
  max-width: 640px;
  margin-top: var(--space-text);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.projects__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: start;
  gap: clamp(16px, 1.85vw, 32px) clamp(12px, 1.4vw, 24px);
}

/* --- Carrousel ---------------------------------------------------------- */

.projects__carousel {
  --carousel-gap: clamp(12px, 1.4vw, 24px);
  position: relative;
}

/* Sans JavaScript, la piste reste défilable au doigt / au trackpad. */
.projects__viewport {
  overflow-x: auto;
  /* Explicite : sans cela `overflow-y` bascule aussi sur `auto` et le bloc
     capture les gestes verticaux au doigt. */
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}

.projects__viewport::-webkit-scrollbar {
  display: none;
}

/* Le module carousel.js prend la main : plus de défilement natif. */
.is-carousel .projects__viewport {
  overflow: hidden;
}

.projects__track {
  display: flex;
  align-items: start;
  gap: var(--carousel-gap);
}

.is-carousel .projects__track {
  transform: translate3d(calc(var(--carousel-offset, 0) * -1px), 0, 0);
  transition: transform 760ms var(--ease-in-out);
  will-change: transform;
}

.projects__slide {
  flex: 0 0 calc((100% - 2 * var(--carousel-gap)) / 3);
  min-width: 0;
}

/* Le lien et les commandes partagent la même ligne : lien à gauche, boutons
   à droite, centrés l'un sur l'autre. */
.projects__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-text);
  margin-top: var(--space-block);
}

.projects__nav {
  display: flex;
  flex: 0 0 auto;
  gap: 1px;
}

.projects__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(40px, 3.24vw, 56px);
  aspect-ratio: 1;
  background: var(--color-inverse-bg);
  color: var(--color-inverse-fg);
  transition: opacity var(--dur-fast) var(--ease-out);
}

.projects__btn:hover {
  opacity: 0.78;
}

.projects__btn-icon {
  width: 18px;
  height: 18px;
}

.projects__more {
  flex: 0 1 auto;
}

@media (max-width: 1100px) {
  .projects__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 1100px) {
  .projects__slide {
    flex-basis: calc((100% - var(--carousel-gap)) / 2);
  }
}

@media (max-width: 700px) {
  .projects__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .projects__slide {
    /* Pleine largeur : l'amorce de la carte suivante, lisible sur grand écran,
       ne laissait ici qu'un fragment sans intérêt. */
    flex-basis: 100%;
  }
}

/* --------------------------------------------------------------------------
   Archive et détail d'une réalisation
   -------------------------------------------------------------------------- */

.projects-archive__head {
  margin-bottom: var(--space-text);
}

.project-single__head {
  /* `padding-block` et non le raccourci : celui-ci remettait le rembourrage
     horizontal à zéro et écrasait celui de `.l-column`. Sur grand écran la
     colonne est centrée et cela ne se voyait pas ; sur mobile, où elle occupe
     toute la largeur, le titre touchait les bords de l'écran. */
  padding-block: calc(var(--header-height) + var(--space-section)) var(--space-block);
}

.project-single__eyebrow {
  color: var(--color-muted);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.project-single__title {
  margin-top: var(--space-text);
  font-size: var(--fs-display-lg);
  letter-spacing: var(--ls-lg);
}

.project-single__intro {
  max-width: 640px;
  margin-top: var(--space-text);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.project-single__specs {
  margin-top: var(--space-block);
}

.project-single__gallery {
  padding-inline: var(--gutter);
}

.project-single__nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-section) var(--gutter) 0;
}

/* --------------------------------------------------------------------------
   contact
   Composition relevée sur la maquette : page entièrement sur fond sombre,
   formulaire sans libellés visibles dans la colonne éditoriale, puis les
   coordonnées en très grand face au nom de la ville.
   -------------------------------------------------------------------------- */

/* La page entière est sombre — c'est ce qui la distingue des autres.
   `--surface` pilote aussi le fond opaque posé par `.site-main > *`. */
.contact.page-body {
  --surface: var(--color-ink);
  --color-rule: var(--color-inverse-rule);
  --color-muted: var(--color-inverse-muted);
  background-color: var(--surface);
  color: var(--color-inverse-fg);
}

.contact .marker {
  color: var(--color-inverse-fg);
}

/* Le bloc de clôture n'est plus un bandeau sombre posé sur du clair : la page
   l'est déjà. On retire donc son fond et son rembourrage bas, qui doublerait
   l'écart avant le pied de page. */
.contact .page-lead {
  padding-bottom: 0;
  background: transparent;
}

/* --- Formulaire, dans la colonne éditoriale --- */

/* Relevé sur la maquette (viewport 1728) : titre 72px/500/-0.06em, champs
   champs 24px sur 432px de large au pas de 93px, mention 14px, bouton
   40px/400. */
.contact-form-section__title {
  max-width: 12ch;
  font-size: var(--fs-display-lg);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: var(--ls-lg);
}

.contact__notice {
  margin-top: var(--space-text);
  padding: 12px 16px;
  font-size: var(--fs-small);
  line-height: 1.5;
}

/* Modificateurs assemblés côté PHP : `contact__notice--{type}`. */
.contact__notice--success {
  background: var(--color-inverse-fg);
  color: var(--color-ink);
}

.contact__notice--error {
  border: 1px solid var(--color-inverse-fg);
}

.contact-form {
  max-width: min(100%, clamp(280px, 42vw, 720px));
  margin-top: var(--space-block);
}

@media (max-width: 900px) {
  /* La largeur mesurée sur la fenêtre laissait un formulaire étriqué au
     milieu de l'écran : en colonne, il prend toute la place disponible. */
  .contact-form {
    max-width: none;
  }
}

.contact-form__field {
  margin: 0 0 var(--space-field);
}

/* Pas de libellé visible : le placeholder tient ce rôle, comme la maquette.
   Le `<label>` reste dans le document pour les lecteurs d'écran. */
.contact-form__input {
  width: 100%;
  padding: 0 0 12px;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--color-inverse-rule);
  color: var(--color-inverse-fg);
  font-size: clamp(18px, 1.389vw, 24px); /* 24 / 1728 */
  transition: border-color var(--dur-fast) var(--ease-out);
}

.contact-form__input::placeholder {
  color: var(--color-inverse-muted);
  opacity: 1;
}

.contact-form__input:focus {
  border-color: var(--color-inverse-fg);
  outline: 0;
}

.contact-form__input--area {
  resize: vertical;
  min-height: 4.5em;
}

/* Pot de miel : hors écran plutôt que `display:none`, que certains robots
   savent détecter. */
.contact-form__trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Avis affiché après l'ouverture de la messagerie, et lien de repli quand le
   JavaScript est absent : dans ce cas le formulaire n'aurait aucun effet, on
   le masque et on montre l'adresse. */
.contact-form__avis {
  margin: var(--space-text) 0 0;
  font-size: var(--fs-small);
  color: var(--color-muted);
}

.contact-form__repli {
  display: none;
  margin: var(--space-md) 0 0;
}

.no-js .contact-form {
  display: none;
}

.no-js .contact-form__repli {
  display: block;
}

.contact-form__actions {
  margin: 8px 0 0;
}

.contact-form__submit {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  font-size: var(--fs-display-sm);
  font-weight: 400;
  letter-spacing: var(--ls-md);
}

.contact-form__icon {
  width: 0.62em;
  height: 0.62em;
  stroke-width: 1.4;
  transition: transform var(--dur-base) var(--ease-out);
}

.contact-form__submit:hover .contact-form__icon {
  transform: translateX(0.22em);
}

/* --- Coordonnées, calées sur la gouttière --- */

/* La maquette pose les coordonnées à gauche sur la gouttière et renvoie le
   lien cartographique tout à droite, aligné sur la dernière ligne. */
.contact-details-section__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: var(--space-block);
}

.contact-details__row {
  /* Pas de 183px relevé sur la maquette, hauteur du bloc comprise. */
  margin-bottom: clamp(44px, 4.282vw, 74px);
}

.contact-details__row:last-child {
  margin-bottom: 0;
}

.contact-details__term {
  margin: 0 0 0.3em;
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.4;
}

/* La valeur, pas l'étiquette, porte le poids typographique. */
.contact-details__desc {
  margin: 0;
  font-size: var(--fs-display-lg);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: var(--ls-lg);
}

/* Les trois valeurs sont des liens. Le soulignement d'usage disparaît : c'est
   le roulement des lettres qui signale le survol, comme dans le menu. La zone
   cliquable reste celle du texte, pas de la ligne entière. */
.contact-details__link {
  display: inline-block;
  color: inherit;
  text-decoration: none;
}

.contact-details__link:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

/* Sur la maquette, ce lien est souligné en permanence. */
.contact-details-section__map {
  align-self: end;
  border-bottom: 1px solid currentColor;
  padding-bottom: 2px;
  font-size: var(--fs-heading);
  font-weight: 500;
  letter-spacing: -0.03em; /* relevé sur la maquette : -1.08px pour 36px */
}

@media (max-width: 900px) {
  .contact-details-section__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .contact-details-section__map {
    justify-self: start;
  }
}

/* --------------------------------------------------------------------------
   page-hero — en-tête des pages secondaires
   Relevé sur la maquette : visuel sombre plein écran, accroche dans la
   colonne éditoriale, titre en très grand calé sur la gouttière et coupé
   par le bas du cadre.
   -------------------------------------------------------------------------- */

.page-hero {
  position: sticky;
  top: 0;
  z-index: 0;
  display: flex;
  align-items: flex-end;
  height: 100svh;
  min-height: 520px;
  overflow: hidden;
  background: var(--color-ink);
  color: #fff;
}

.page-hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.page-hero__media picture,
.page-hero__img {
  width: 100%;
  height: 100%;
}

.page-hero__img {
  object-fit: cover;
}

/* Voile posé *au-dessus* du visuel plutôt qu'une opacité sur l'image :
   l'assombrissement est garanti quelle que soit la photo, y compris une vue
   en plein jour. Une opacité aurait éclairci l'image sur le fond sombre. */
.page-hero__scrim {
  position: absolute;
  z-index: 1;
  inset: 0;
  /* Assombrissement minimal : juste ce qu'il faut pour que le texte blanc
     passe, sans effacer la photo. Les deux dégradés portent le contraste
     là où se trouve le texte, en haut et en bas. */
  background:
    linear-gradient(rgba(10, 10, 10, 0.22), rgba(10, 10, 10, 0.22)),
    linear-gradient(to bottom, rgba(0, 0, 0, 0.62) 0%, rgba(0, 0, 0, 0) 34%),
    linear-gradient(to top, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0) 50%);
  pointer-events: none;
}

/* Réalisations : la façade rétroéclairée de la Cave de la Côte passe en jaune
   et vert saturés exactement là où se posent l'accroche et le titre. Relevé
   sur l'image, il faut 0,54 de noir pour tenir 4,5:1 sous du blanc, contre
   0,22 pour le voile commun.

   Pas de couche plate, contrairement au voile commun : à cette densité elle
   éteignait toute la photographie, dont les panneaux rétroéclairés sont le
   sujet. Le renfort est donc porté par le seul dégradé du bas, calé sur la
   bande occupée par l'accroche et le titre (de 9 % à 37 % de la hauteur en
   partant du bas), et le tiers supérieur de l'image reste intact. Le renfort
   est limité à cette page : l'imposer partout éteindrait les autres visuels
   sans raison. */
/* L'Atelier : la photographie de groupe est claire d'un bord à l'autre, et le
   texte y court de 49 % à 93 % de la hauteur. Relevé sur l'image, il faut 0,40
   sous le titre et 0,47 sous l'accroche, contre 0,22 pour le voile commun. Le
   renfort ne monte pas plus haut que nécessaire : le quart supérieur, où sont
   les visages, garde ses valeurs. */
body.page-template-page-agence .page-hero__scrim {
  background:
    linear-gradient(to bottom, rgba(0, 0, 0, 0.32) 0%, rgba(0, 0, 0, 0) 16%),
    linear-gradient(
      to top,
      rgba(0, 0, 0, 0.54) 0%,
      rgba(0, 0, 0, 0.52) 25%,
      rgba(0, 0, 0, 0.50) 53%,
      rgba(0, 0, 0, 0.18) 64%,
      rgba(0, 0, 0, 0.000) 76%
    );
}

body.post-type-archive-realisation .page-hero__scrim {
  background:
    linear-gradient(to bottom, rgba(0, 0, 0, 0.35) 0%, rgba(0, 0, 0, 0) 18%),
    linear-gradient(
      to top,
      rgba(0, 0, 0, 0.62) 0%,
      rgba(0, 0, 0, 0.58) 20%,
      rgba(0, 0, 0, 0.56) 38%,
      rgba(0, 0, 0, 0.22) 52%,
      rgba(0, 0, 0, 0.000) 68%
    );
}

.page-hero__content {
  position: relative;
  z-index: 2;
  width: 100%;
  padding-bottom: clamp(40px, 7vh, 88px);
}

/* L'accroche occupe la colonne éditoriale, comme partout ailleurs :
   c'est `.l-column` qui la positionne, pas un décalage ad hoc. */
.page-hero__intro {
  max-width: 640px;
  margin: 0 0 clamp(24px, 3vw, 56px);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

/* Titre entier, posé au-dessus du bas du cadre — pas coupé. */
.page-hero__title {
  margin: 0;
  padding-inline: var(--gutter);
  font-size: clamp(56px, 14vw, 240px);
  font-weight: 500;
  line-height: 0.92;
  letter-spacing: -0.06em;
  white-space: nowrap;
}

.page-hero .marker {
  top: 0;
  color: #fff;
}

/* --- Bloc éditorial sombre qui suit --- */

.page-lead {
  position: relative;
  padding-block: var(--space-section);
  background: var(--color-ink);
  color: var(--color-inverse-fg);
}

.page-lead .marker {
  top: var(--space-2xl);
  color: var(--color-inverse-fg);
}

.page-lead__lead {
  max-width: 640px;
  font-size: var(--fs-display-sm);
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: -0.05em;
}

.page-lead__body {
  max-width: 640px;
  margin-top: var(--space-text);
  color: rgba(255, 255, 255, 0.72);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}



/* Les paragraphes de l'intro gardent l'espacement du corps de texte. */
.intro__lead p + p {
  margin-top: var(--space-text);
}

.agence__marquee {
  margin-block: var(--space-section) 0;
}

/* Équipe en grille (page Agence), distincte du carrousel de l'accueil. */
.team-grid__title {
  margin-bottom: var(--space-block);
  font-size: var(--fs-display-lg);
  letter-spacing: var(--ls-lg);
}

.team-grid__list {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(20px, 2.3vw, 40px) clamp(12px, 1.4vw, 24px);
}

/* Portrait manquant : plutôt qu'un cadre vide, les initiales dans la
   typographie du site. L'absence devient un parti pris lisible. */
.portrait-initials {
  display: grid;
  place-items: center;
  background: #ececec;
  color: var(--color-muted);
}

.portrait-initials__text {
  font-size: clamp(28px, 3.24vw, 56px);
  font-weight: 500;
  letter-spacing: var(--ls-md);
}

.team-card__formation {
  margin-top: 2px;
  color: var(--color-muted);
  font-size: var(--fs-small);
  line-height: 1.5;
}

.team-card__media {
  overflow: hidden;
  aspect-ratio: 2 / 3;
  background: #ececec;
}

.team-card__media picture,
.team-card__img {
  width: 100%;
  height: 100%;
}

.team-card__img {
  object-fit: cover;
  /* Noir et blanc en permanence. Le survol ne joue plus que sur l'échelle. */
  filter: grayscale(1);
  transform: scale(1.001);
  transition: transform 900ms var(--ease-out);
}

.team-card:hover .team-card__img {
  transform: scale(1.04);
}

.team-card__name {
  margin-top: clamp(12px, 1.2vw, 20px);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  line-height: 1.4;
}

.team-card__role {
  margin-top: 2px;
  color: var(--color-muted);
  font-size: var(--fs-small);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.7;
}

@media (max-width: 1100px) {
  .team-grid__list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 700px) {
  .team-grid__list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Sous cette largeur, deux colonnes ne laissent plus la place au nom, à la
   fonction et à la formation sans coupures disgracieuses. */
@media (max-width: 480px) {
  .team-grid__list {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* --------------------------------------------------------------------------
   manifesto — texte encadré par deux colonnes défilantes
   La section bascule en sombre quand elle entre dans le champ. Le basculement
   est piloté par un IntersectionObserver et non par la boucle de défilement :
   il ne dépend d'aucune frame, ce qui le rend fiable même quand les
   animations sont ralenties.
   -------------------------------------------------------------------------- */

.manifesto {
  /* Un seul jeton commande la taille : la largeur des colonnes latérales, la
     hauteur visible et le pas de l'animation en découlent. */
  --manifesto-item: clamp(96px, 11.5vw, 190px);
  --manifesto-gap: clamp(8px, 0.9vw, 16px);

  position: relative;
  display: grid;
  grid-template-columns: var(--manifesto-item) minmax(0, 1fr) var(--manifesto-item);
  align-items: center;
  gap: var(--space-lg);
  overflow: hidden;
  padding: var(--space-section) var(--gutter);
  background-color: var(--color-ink);
  color: var(--color-inverse-fg);
}

/* La section est sombre en permanence. Elle basculait auparavant du blanc au
   noir à l'entrée dans le champ ; la bascule a été retirée.

   La classe est répétée pour égaler la spécificité de `.site-main > *:not(...)`
   — trois classes — et l'emporter par l'ordre du fichier. */
.site-main > .manifesto.manifesto {
  background-color: var(--color-ink);
}


/* --- Colonnes défilantes --- */

/* Hauteur calée sur exactement quatre vignettes et leurs trois écarts. */
.manifesto__col {
  height: calc(4 * var(--manifesto-item) + 3 * var(--manifesto-gap));
  overflow: hidden;
  mask-image: linear-gradient(to bottom, transparent, #000 12%, #000 88%, transparent);
}

.manifesto__track {
  display: flex;
  flex-direction: column;
  gap: var(--manifesto-gap);
  animation: flaa-manifesto-up 54s linear infinite;
}

/* Sens inverse pour la colonne de droite : c'est le décalage entre les deux
   qui donne son mouvement à la section. */
.manifesto__col--down .manifesto__track {
  animation-name: flaa-manifesto-down;
}

.manifesto__item {
  flex: 0 0 auto;
  margin: 0;
  overflow: hidden;
  aspect-ratio: 1;
  background: #ececec;
}

.manifesto__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* La piste contient deux exemplaires de la liste, et il faut la translater
   d'exactement une liste pour boucler sans saut.

   `-50%` ne suffit pas : la piste mesure vingt vignettes et dix-neuf écarts,
   sa moitié vaut donc dix vignettes et neuf écarts et demi, alors qu'une
   liste en vaut dix. D'où le demi-écart ajouté, sans quoi la boucle recule
   d'un demi-écart à chaque tour. */
@keyframes flaa-manifesto-up {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, calc(-50% - var(--manifesto-gap) / 2), 0); }
}

@keyframes flaa-manifesto-down {
  from { transform: translate3d(0, calc(-50% - var(--manifesto-gap) / 2), 0); }
  to   { transform: translate3d(0, 0, 0); }
}

/* --- Texte central --- */

.manifesto__label {
  margin: 0;
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.manifesto__title {
  margin: var(--space-text) 0 0;
  max-width: 24ch;
  font-size: var(--fs-display-sm);
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: var(--ls-md);
}

.manifesto__text {
  margin: var(--space-text) 0 0;
  max-width: 52ch;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  opacity: 0.72;
}

@media (prefers-reduced-motion: reduce) {
  .manifesto__track {
    animation: none;
  }
}

/* Versions horizontales des deux pistes, pour la mise en colonne. Même
   principe que les verticales : la piste porte deux fois la liste, la
   translater de la moitié de sa largeur ramène au point de départ. */
@keyframes flaa-manifesto-gauche {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(-50% - var(--manifesto-gap) / 2), 0, 0); }
}

@keyframes flaa-manifesto-droite {
  from { transform: translate3d(calc(-50% - var(--manifesto-gap) / 2), 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

/* En colonne, les deux bandes basculent à l'horizontale : l'une au-dessus du
   texte, l'autre en dessous, défilant en sens contraire. C'est la composition
   du grand écran tournée d'un quart de tour — la section garde son mouvement
   au lieu de se réduire à une vignette centrée.

   Le gabarit écrit déjà bande / texte / bande dans cet ordre : la grille à une
   colonne suffit, aucun `order` n'est nécessaire. */
@media (max-width: 900px) {
  .manifesto {
    --manifesto-item: clamp(104px, 28vw, 150px);

    grid-template-columns: minmax(0, 1fr);
    gap: clamp(26px, 6.5vw, 44px);
  }

  /* Les bandes débordent la gouttière : un défilement qui s'arrête avant le
     bord de l'écran ne se lit pas comme un défilement. */
  .manifesto__col {
    width: auto;
    height: var(--manifesto-item);
    margin-inline: calc(-1 * var(--gutter));
    mask-image: linear-gradient(to right, transparent, #000 9%, #000 91%, transparent);
  }

  .manifesto__col--down {
    display: block;
  }

  /* `width: max-content` est indispensable, et c'est la seule différence de
     fond avec la version verticale. En colonne, la hauteur d'une piste est
     dictée par son contenu, donc `-50%` vaut bien la moitié de la liste
     doublée. En ligne, la piste prend la largeur de son parent : `-50%`
     n'aurait valu que la moitié de l'écran et la boucle aurait sauté. */
  .manifesto__track {
    flex-direction: row;
    width: max-content;
    animation-name: flaa-manifesto-gauche;
    animation-duration: 42s;
  }

  /* Spécificité de deux classes, comme la règle verticale qu'elle remplace :
     un sélecteur à une classe ne l'emporterait pas. */
  .manifesto__col--down .manifesto__track {
    animation-name: flaa-manifesto-droite;
  }

  .manifesto__item {
    width: var(--manifesto-item);
  }
}

/* --------------------------------------------------------------------------
   feature — projet à la une, puis comparaison avant / après
   -------------------------------------------------------------------------- */

.feature {
  padding-bottom: var(--space-section);
}

/* Comparateur à gauche, texte à droite, l'un et l'autre centrés sur la même
   ligne médiane. Le comparateur prend la plus grande part : c'est le sujet de
   la section, le texte ne fait que l'annoncer. */
.feature__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr);
  align-items: center;
  gap: clamp(28px, 4.6vw, 80px);
}

/* Exergue : le nom du projet, que le titre ne porte plus. Même traitement que
   celui du manifeste, pour que les deux se lisent comme un même motif. */
.feature__label {
  margin: 0 0 var(--space-text);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.feature__title {
  max-width: 12ch;
  font-size: var(--fs-display-lg);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: var(--ls-lg);
}

.feature__text {
  max-width: 58ch;
  margin-top: var(--space-text);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.feature__cta {
  margin-top: var(--space-text);
}

/* --- Avant / après : comparateur au curseur ---
   Le champ `range` natif porte toute l'interaction : glisser, toucher et
   flèches du clavier, sans un seul gestionnaire d'événement à écrire. Le JS ne
   fait que reporter sa valeur dans une variable CSS. Sans JS, le curseur reste
   au milieu et les deux moitiés restent comparables. */

.beforeafter {
  min-width: 0;
}

.compare {
  --pos: 50%;

  position: relative;
  overflow: hidden;
  /* Format des deux photographies : tout autre rapport les recadrerait
     différemment et la façade cesserait de coïncider de part et d'autre. */
  aspect-ratio: 16 / 9;
  background: #ececec;
  touch-action: pan-y;
}

.compare__base,
.compare__overlay {
  position: absolute;
  inset: 0;
  display: block;
}

/* L'image « après » n'est révélée qu'à droite du curseur. */
.compare__overlay {
  clip-path: inset(0 0 0 var(--pos));
}

.compare__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.compare__handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--pos);
  z-index: 2;
  width: 2px;
  margin-left: -1px;
  background: var(--color-inverse-fg);
  pointer-events: none;
}

.compare__handle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: clamp(36px, 3.2vw, 52px);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border: 2px solid var(--color-inverse-fg);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.18);
  backdrop-filter: blur(2px);
}

/* Le champ couvre toute la zone pour qu'on puisse saisir n'importe où. */
.compare__range {
  position: absolute;
  inset: 0;
  z-index: 3;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: ew-resize;
  appearance: none;
  /* Le champ couvre tout le bloc : sans cette règle il absorbait aussi les
     balayages verticaux, et la page ne défilait plus au doigt sur le
     comparateur. Le glissement horizontal reste à lui. */
  touch-action: pan-y;
}

.compare__range::-webkit-slider-thumb {
  appearance: none;
  width: 48px;
  height: 100%;
}

.compare__range:focus-visible ~ .compare__handle::after {
  border-width: 3px;
}

.compare__tag {
  position: absolute;
  bottom: clamp(12px, 1.4vw, 22px);
  z-index: 2;
  padding: 6px 10px;
  background: rgba(10, 10, 10, 0.62);
  color: var(--color-inverse-fg);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  pointer-events: none;
}

.compare__tag--avant { left: clamp(12px, 1.4vw, 22px); }
.compare__tag--apres { right: clamp(12px, 1.4vw, 22px); }

@media (max-width: 900px) {
  .feature__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-block);
  }

  /* Le texte annonce, le comparateur illustre : dans une colonne, il vient
     donc après. Sur grand écran l'ordre est inverse parce que l'œil lit
     l'image en premier, ce qui ne vaut plus quand tout s'empile. */
  .feature__body {
    order: 1;
  }

  .beforeafter {
    order: 2;
  }
}

/* --------------------------------------------------------------------------
   error-404 — page introuvable
   -------------------------------------------------------------------------- */

.error-404 {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 72svh;
  padding-bottom: var(--space-section);
  overflow: hidden;
  isolation: isolate;
}

/* Même traitement que le filigrane du pied de page : derrière le contenu,
   dans la teinte fantôme, hors de toute sélection. */
.error-404__watermark {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: -1;
  transform: translate(-50%, -50%);
  color: var(--color-ghost-ink);
  font-size: clamp(180px, 34vw, 560px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: var(--ls-2xl);
  white-space: nowrap;
  user-select: none;
  pointer-events: none;
}

.error-404__label {
  margin: 0 0 var(--space-text);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.error-404__title {
  max-width: 14ch;
  margin: 0;
  font-size: var(--fs-display-lg);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: var(--ls-lg);
}

.error-404__text {
  max-width: 46ch;
  margin: var(--space-text) 0 0;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.error-404__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md) var(--space-lg);
  margin-top: var(--space-block);
}

@media (max-width: 700px) {
  .error-404__actions {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* --------------------------------------------------------------------------
   project-film — film d'une réalisation
   -------------------------------------------------------------------------- */

.project-single__film {
  margin-top: var(--space-section);
}

.project-film {
  position: relative;
  margin: 0;
  background: var(--color-ink);
}

.project-film__video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

/* --------------------------------------------------------------------------
   news — page Actualités
   -------------------------------------------------------------------------- */

/* Pas de rembourrage bas ici : la section vit dans `.page-body`, qui porte
   déjà l'écart avant le pied de page. Le poser deux fois donnait 320 px de
   vide sous la pagination. */

/* L'en-tête partage le bord gauche de la grille, mais son texte ne court pas
   sur toute la largeur : il garde une mesure lisible. */
.news__head {
  margin-bottom: var(--space-block);
}

.news__title {
  max-width: 14ch;
  font-size: var(--fs-display-lg);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: var(--ls-lg);
}

.news__text {
  max-width: 58ch;
  margin-top: var(--space-text);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.news__cta {
  margin-top: var(--space-text);
}

.news__empty {
  margin-top: var(--space-block);
  color: var(--color-muted);
  font-size: var(--fs-body);
}

/* Classe répétée : le reset des listes (`ul[class]`) pèse une classe et un
   attribut, et écrasait la gouttière de `l-shell` — la première colonne
   touchait le bord de l'écran. */
.news-list.news-list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-lg) clamp(16px, 2vw, 32px);
  margin: 0;
  padding-inline: var(--gutter);
  list-style: none;
}

.news-item {
  min-width: 0;
}

.news-card {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.news-card__media {
  aspect-ratio: 4 / 3;
  margin: 0 0 var(--space-text);
}

.news-card__date {
  margin: 0;
  color: var(--color-muted);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

/* Le texte n'est plus un chapô sous un titre, c'est la publication elle-même :
   il porte donc la carte. */
.news-card__text {
  margin: clamp(10px, 1.2vw, 16px) 0 0;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

/* Le lien se colle au bas de la carte : les cartes d'une même rangée alignent
   leur lien quelle que soit la longueur du texte. */
.news-card__link {
  margin: auto 0 0;
  padding-top: var(--space-text);
}

.news-card__anchor {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding-bottom: 0.14em;
  border-bottom: 1px solid currentColor;
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.news-card__icon {
  width: 1em;
  height: 1em;
  transition: transform var(--dur-base) var(--ease-out);
}

.news-card__anchor:hover .news-card__icon {
  transform: translateX(3px);
}

/* Classe répétée ici aussi : la règle de base l'est, et un sélecteur simple
   n'aurait pas fait le poids — la grille serait restée à trois colonnes sur
   téléphone. */
@media (max-width: 1000px) {
  .news-list.news-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .news-list.news-list {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* --------------------------------------------------------------------------
   news-band — trois dernières actualités, sur la page d'accueil
   -------------------------------------------------------------------------- */

/* Le rythme haut vient de `.l-section` ; le bas est celui que `.site-main`
   pose avant le pied de page. Les deux valent `--space-section` : la section
   respire autant des deux côtés, sans les additionner. */
.news-band {
  position: relative;
  z-index: 2;
  background: var(--color-bg);
}

/* Titre à gauche, lien calé au bord droit — comme le hero et les autres
   en-têtes de section. */
.news-band__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-md);
  margin-bottom: var(--space-block);
}

.news-band__title {
  max-width: 18ch;
  margin: 0;
  font-size: var(--fs-display-lg);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: var(--ls-lg);
}

.news-band__cta {
  flex: 0 0 auto;
  margin: 0;
}

/* Classe répétée : le reset des listes pèse une classe et un attribut, et
   écraserait la gouttière. */
.news-band__list.news-band__list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(16px, 2vw, 32px);
  margin: 0;
  padding-inline: var(--gutter);
  list-style: none;
}

.news-band__item {
  min-width: 0;
}

.news-brief {
  display: block;
  color: inherit;
}

.news-brief__media {
  display: block;
  aspect-ratio: 16 / 10;
  margin-bottom: var(--space-text);
}

.news-brief__media .media__img {
  transition: transform var(--dur-slow) var(--ease-out);
}

.news-brief:hover .media__img {
  transform: scale(1.03);
}

.news-brief__date {
  display: block;
  color: var(--color-muted);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.news-brief__text {
  display: block;
  margin-top: clamp(6px, 0.8vw, 12px);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

@media (max-width: 900px) {
  .news-band__head {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-text);
  }

  .news-band__list.news-band__list {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-lg);
  }
}

/* --------------------------------------------------------------------------
   pager — pagination de l'archive des actualités
   -------------------------------------------------------------------------- */

/* Le vocabulaire est celui de la page d'accueil : le compteur reprend celui de
   la fiche d'équipe — deux nombres séparés d'un filet — et les flèches
   reprennent ses boutons carrés pleins. Rien de nouveau n'est introduit. */
.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  margin-top: var(--space-block);
  padding-top: var(--space-text);
  border-top: 1px solid var(--color-rule);
}

.pager__count {
  display: flex;
  align-items: center;
  gap: clamp(8px, 0.93vw, 16px);
  margin: 0;
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  font-variant-numeric: tabular-nums;
}

.pager__rule {
  width: clamp(24px, 2.3vw, 40px);
  height: 1px;
  background: currentColor;
}

/* Classe répétée : le reset des listes pèse une classe et un attribut. */
.pager__list.pager__list {
  display: flex;
  align-items: center;
  gap: clamp(4px, 0.6vw, 10px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.pager__page {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: clamp(32px, 2.6vw, 44px);
  padding: 0.5em 0.2em;
  border-bottom: 2px solid transparent;
  color: var(--color-muted);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  font-variant-numeric: tabular-nums;
  transition: color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}

a.pager__page:hover {
  color: var(--color-fg);
}

.pager__page.is-current {
  border-bottom-color: var(--color-fg);
  color: var(--color-fg);
}

.pager__nav {
  display: flex;
  gap: 1px;
}

.pager__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(40px, 3.24vw, 56px);
  aspect-ratio: 1;
  background: var(--color-inverse-bg);
  color: var(--color-inverse-fg);
  transition: opacity var(--dur-fast) var(--ease-out);
}

a.pager__btn:hover {
  opacity: 0.78;
}

/* Une extrémité atteinte : le bouton reste en place pour que la barre ne se
   déforme pas, mais il ne se donne plus comme cliquable. */
.pager__btn.is-disabled {
  opacity: 0.22;
  pointer-events: none;
}

.pager__icon {
  width: 18px;
  height: 18px;
}

@media (max-width: 760px) {
  /* En colonne étroite, les numéros passent au-dessus et défilent seuls si la
     série est longue ; le compteur et les flèches gardent leur ligne. */
  .pager {
    flex-wrap: wrap;
    gap: var(--space-text);
  }

  .pager__list.pager__list {
    order: 3;
    width: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }

  .pager__list.pager__list::-webkit-scrollbar {
    display: none;
  }

  .pager__count {
    order: 1;
  }

  .pager__nav {
    order: 2;
    margin-left: auto;
  }
}
