/* ── Here — gabarits intérieurs. Charte : papier clair, encre, vert de signature,
      angles nets, filets fins, petites capitales très espacées, repères carrés. ── */

/* Le header du site est masqué au départ sur la Home (l'intro le fait apparaître) :
   sur les autres pages il est visible d'emblée. */
body.head-static .site-head{opacity:1}

/* ── Écran d'arrivée d'une page (média plein cadre + titre) ──
   Variante A validée sur `proto-parallax.html` : 88 svh, pas 100. Le bas de la
   section suivante affleure — c'est ce qui donne envie de scroller. */
/* Le titre est centré sur L'ÉCRAN, pas sur la section. Nuance qui se voyait :
   la section fait 88 svh (le bas de la suivante doit affleurer), donc son milieu
   tombe 6 svh au-dessus du milieu de l'écran — assez pour que le titre paraisse
   « trop haut » alors qu'il était parfaitement centré dans sa boîte.
   La retombée de padding en haut rattrape exactement l'écart : le centre du bloc
   vaut (hauteur + padding) / 2 = (H + 100svh − H) / 2 = 50 svh, à toute taille.
   `max(0px, …)` couvre les fenêtres si basses que la section est déjà plus haute
   que l'écran (le plancher de 520 px). */
/* ⚠️ LE BANDEAU FAIT TOUT L'ÉCRAN MOINS LE PASSE-PARTOUT — relevé le 31/08.
   Le cadre du Figma fait 1728 × 1117 (un MacBook Pro 16 pouces) et le média y
   mesure 1077 de haut : soit exactement 1117 − 20 − 20. Le film n'est donc pas
   un bandeau à 88 % de l'écran, il OCCUPE l'écran ; c'est la marie-louise qui
   vient par-dessus. Le plancher de 520 px reste, pour les écrans très bas.
   La hauteur vaut donc l'écran ENTIER, et c'est le passe-partout, posé
   par-dessus, qui retire ses 20 px en haut et en bas : le bandeau visible
   mesure alors 100svh − 2 × --ml, soit 1077 sur les 1117 du Figma. Retirer
   le passe-partout de la hauteur du héros le retirerait deux fois. */
.page-hero{--hero-h:max(520px, 100svh);
  position:relative;height:var(--hero-h);overflow:hidden;
  padding-top:max(0px, calc(100svh - var(--hero-h)));
  display:grid;align-items:center;color:var(--color-text-invert)}
/* Couche 1 de la parallaxe (recette 04). La hauteur obéit à la « règle des 130 % »
   CORRIGÉE : `yPercent` décale l'élément d'un pourcentage de SA PROPRE hauteur,
   donc H ≥ 100 / (1 − 2A/100), et non 100 + 2A comme l'écrit le recueil.
   Pour l'amplitude A = 12 posée dans site.js : 131,6 + 4 de marge = 136 %,
   débord centré = −18 %. ⚠️ Ces deux nombres sont liés à l'amplitude du JS :
   on ne touche à l'un qu'en touchant à l'autre. */
/* ⚠️ SÉLECTEUR DOUBLÉ À DESSEIN. La règle générique `.media{position:relative}`
   est déclarée plus bas dans cette feuille, à spécificité égale : elle gagnait,
   la vidéo redevenait un élément de flux et sa hauteur de 136 % se calculait sur
   la ligne de grille, pas sur le hero. Résultat : le film ne couvrait que le
   tiers haut de l'écran, le reste laissait passer le papier sous le voile.
   Deux classes suffisent à reprendre la main. */
.page-hero .page-hero__media{position:absolute;top:-18%;left:0;right:0;bottom:auto;
  height:136%;z-index:0;will-change:transform}
/* Voile de lisibilité : indispensable puisque la vidéo de fond est téléversée
   par le client et peut être claire. Deux couches — une verticale pour le header
   et le pied, une horizontale côté texte. Le titre reste lisible quoi qu'il arrive. */
.page-hero__scrim{position:absolute;inset:0;z-index:1;
  background:
    linear-gradient(90deg, rgba(12,12,12,.72) 0%, rgba(12,12,12,.42) 42%, rgba(12,12,12,.06) 72%),
    linear-gradient(180deg, rgba(12,12,12,.5), rgba(12,12,12,.12) 35% 60%, rgba(12,12,12,.6))}
/* `.wrap` porte déjà la gouttière : la remettre ici décalait le titre du hero
   d'une gouttière de plus que les blocs de la page. */
.page-hero__inner{position:relative;z-index:2;width:100%;
  display:grid;gap:clamp(1.4rem,3vh,2.4rem)}
/* ⚠️ L'INTERLETTRAGE EST CELUI DE L'ACCUEIL — .06em, PAS .03em. 31/08/2026.
   Ce titre est l'aboutissement du geste : c'est le titre de l'accueil qui vient
   se poser ici. Pour que le navigateur puisse l'interpoler comme UN SEUL objet
   qu'on redimensionne, il faut que les deux ne diffèrent QUE par l'échelle. Or
   la largeur d'un texte vaut la somme des chasses (proportionnelle au corps)
   plus l'interlettrage — et l'interlettrage n'est proportionnel au corps que
   s'il est exprimé en `em` ET identique des deux côtés.
   Mesuré avant correction : accueil 70,4 px / .06em / 1357 px de large, rubrique
   79,04 px / .03em / 1271 px. Le titre d'arrivée était donc PLUS GRAND et
   pourtant PLUS ÉTROIT : aucune homothétie ne relie ces deux formes, et l'œil
   voyait deux mots différents se croiser au lieu d'un seul qui se déplace.
   Avec la même valeur en `em`, la largeur suit exactement le corps et le geste
   redevient un simple agrandissement. */
/* ⚠️ CORPS ET INTERLETTRAGE RELEVÉS DANS LE FIGMA — 31/08/2026.
   Lus à la source (fichier « Here (copie) », nœud 232:368) et non déduits :
   Quablo SemiBold, 60 px sur un cadre de 1728, interlettrage 2,4 px = .04em.
   Nous en étions à 83,2 px et .06em au même cadre — 39 % trop gros. C'est ce
   qui faisait déborder le titre sur la colonne du carré et envoyait les
   renvois sur une seconde ligne, alors que le designer les met sur la ligne
   du titre. Contrôle de cohérence : à 60 px / .04em ma formule de largeur
   donne 681 px pour « private events », le Figma en mesure 678 — nos
   métriques de police et les siennes concordent.
   60 px sur 1728 = 3,472 vw = 3,75 rem. Exprimé des deux façons pour que la
   taille suive la largeur en dessous de 1728 et suive l'échelle de la racine
   au-dessus (cf. le clamp de `tokens.css`), les deux se rejoignant à 1728. */
.page-hero h1{font-family:var(--font-display);font-weight:var(--fw-display);text-transform:uppercase;
  font-size:clamp(2.1rem, 3.472vw, 3.75rem);line-height:var(--lh-tight);letter-spacing:.04em;
  max-width:20ch}
/* ─────────────────────────────────────────────────────────────────────────
   LA COMPOSITION D'ARRIVÉE — relevée sur la maquette validée (31/08/2026)

   Mesurée en faisant tourner la maquette elle-même jusqu'à la fin du geste,
   scène 1180 × 738, plutôt qu'en lisant ses intentions dans le code :
     carré        49,6 % de la largeur du bandeau
     Loft & Art   58,6 %          Conciergerie  83,0 %
     ligne        51,0 % de la hauteur du bandeau
     chapô        58,6 %, bas à 90 %, largeur 37,5 %
   Le bandeau, c'est le héros moins l'épaisseur du passe-partout sur chaque
   bord — d'où `--ml` dans chaque calcul.

   ⚠️ LA LIGNE DÉPEND DE LA LONGUEUR DU TITRE. Règle du designer, lisible en
   comparant ses deux maquettes : sur un titre court le rang tient SUR la ligne
   du titre (51 %) ; sur un titre long il descend sur une SECONDE ligne (78 %)
   et le chapô suit (95,5 %), sinon le titre percute le carré.
   Mesuré sur nos trois titres, de 390 à 3840 px : les TROIS dépassent la
   colonne 47 %, donc les trois prennent la seconde ligne. Ce n'est pas un
   choix, c'est la sortie de la règle appliquée à notre typographie — notre
   titre est plus gros que celui de la maquette (5,49 vw contre 4,29 vw).
   Pour repasser sur la ligne du titre, il suffit de baisser `--ligne-q` : la
   valeur est ici, en un seul endroit. */
/* ⚠️ LA COMPOSITION EN COLONNES EST UN DESSIN DE BUREAU. Les parts de la
   maquette (49,6 / 58,6 / 83 %) supposent une largeur où trois colonnes
   tiennent côte à côte. Mesuré en dessous : « Lofts and Art Residences »
   déborde de 94 px en 390, et « Conciergerie » de 9 px encore en 768. En
   deçà du seuil, le chapô et les renvois reprennent donc le flux normal,
   empilés sous le titre — ce qu'ils faisaient déjà avant. */
@media (min-width:1024px){
/* Parts relevées dans le Figma, bandeau 1688 × 1077 :
     carré  y 558 + 5,5 de demi-hauteur -> (563,5 − 20) / 1077 = 50,5 %
     chapô  bas 934 + 108 = 1042        -> (1042 − 20) / 1077 = 94,9 %
            largeur 672 / 1688 = 39,8 %
   Le titre reste la sauvegarde : s'il devait un jour dépasser la colonne du
   carré, `--ligne-q` descend à .78 et le chapô à .955. */
.page-hero{--ligne-q:.505; --chapo-q:.949}
.page-hero__marque,
.page-hero__cross,
.page-hero__lead{position:absolute;z-index:3;pointer-events:none}
.page-hero__cross a{pointer-events:auto}
/* 13 × 11 dans le Figma (Rectangle 28), sur un cadre de 1728. */
.page-hero__marque{width:.8125rem;height:.6875rem;background:currentColor;
  left:calc(var(--ml,0px) + (100% - 2 * var(--ml,0px)) * .496);
  top:calc(var(--ml,0px) + (100% - 2 * var(--ml,0px)) * var(--ligne-q));
  translate:0 -50%}
/* ⚠️ UN RANG TENDU ENTRE DEUX COLONNES, PAS DEUX COLONNES FIXES — 31/08/2026.
   Le Figma pose les renvois par leur bord gauche, à 58,6 % et 83 %. C'est juste
   tant que le libellé de droite est court — celui du designer l'est. Mais
   l'ordre change selon la page : sur Conciergerie, « Lofts and Art Residences »
   tombe dans la dernière colonne, et il n'y reste pas 17 % de bandeau pour lui.
   Mesuré, débordement de 75 px en 1440, 89 en 1728, 62 en 2560 ; et l'ancrer
   par la droite ne faisait que déplacer le problème — les deux renvois se
   chevauchaient alors en dessous de 1200 px, et ne laissaient que 2 px entre
   1440 et 1728.
   Le rang va donc de 58,6 % à 94 % et répartit l'espace. Pour le cas du
   designer, c'est EXACTEMENT sa composition : « Conciergerie » mesure 188 px
   sur un bandeau de 1688, soit 11,1 %, et son bord gauche retombe donc sur
   83 %. Pour un libellé long, l'espace se resserre au lieu de sortir de
   l'écran. Le rang peut se replier si les deux ne tiennent plus. */
.page-hero__cross{display:flex;justify-content:space-between;flex-wrap:wrap;
  gap:.4rem clamp(1rem, 2vw, 2.5rem);
  left:calc(var(--ml,0px) + (100vw - 2 * var(--ml,0px)) * .586);
  right:calc(var(--ml,0px) + (100vw - 2 * var(--ml,0px)) * .06);
  top:calc(var(--ml,0px) + (100% - 2 * var(--ml,0px)) * var(--ligne-q));
  translate:0 -50%}
/* Typographie relevée dans le Figma (nœud 232:369) : Quablo Bold, 16 px sur
   un cadre de 1728 — soit 1 rem — et 3,2 px d'interlettrage, soit .2em.
   Nous étions en Poppins Medium 14 px / .22em. */
/* ⚠️ `relative` ET NON `static` — 07/09/2026, signalé par Guillaume.
   Ces renvois portent la classe `.ln`, le soulignement dirigé de la charte : un
   `::after` en `position:absolute`, tendu de `left:0` à `right:0`. Il se cale
   donc sur le premier ancêtre positionné. En `static`, ce n'était plus le lien
   mais `.page-hero__cross` — un rang tendu de 58,6 % à 94 % de l'écran : le
   survol d'un mot traçait un trait d'un renvoi à l'autre, par-dessus le vide qui
   les sépare.
   Le `static` venait d'une version où chaque renvoi était posé en absolu à sa
   propre abscisse ; il servait à annuler ce positionnement quand le rang est
   devenu un flex. `relative` l'annule tout autant et rend au trait son repère. */
.page-hero__cross a{position:relative;white-space:nowrap;
  font-family:var(--font-display);font-weight:700;letter-spacing:.2em;
  /* 16 px sur un cadre de 1728, soit 0,926 vw. Figé à 1 rem, le renvoi gardait
     sa taille pendant que le bandeau rétrécissait : mesuré à 1440, « Lofts and
     Art Residences » finissait à 1217 et « Conciergerie » commençait à 1184 —
     33 px de chevauchement. En vw, la proportion du Figma se tient à toutes les
     largeurs ; le plancher garde le texte lisible en dessous, où la composition
     en colonnes cède de toute façon la place au flux. */
  /* ⚠️ 0,82 vw ET NON 0,926 — UN ÉCART ASSUMÉ AVEC LE FIGMA, 31/08/2026.
     Le designer compose ces renvois en 16 px sur un cadre de 1728, soit
     0,926 vw. Cela tient pour SA page : « loft & art residence » et
     « Conciergerie » font ensemble 492 px pour 598 disponibles. Mais l'ordre
     des renvois change selon la rubrique, et il n'a pas dessiné le cas de
     Conciergerie, où se rencontrent les deux libellés les plus longs. Mesuré,
     à sa taille : 594 px de texte pour 598 de place — deux pixels. Le rang se
     repliait donc sur deux lignes.
     0,82 vw ramène le besoin à 527 px et rend 71 px d'intervalle en 1728,
     48 en 1440. C'est 8 % de moins que le Figma, sur un libellé qu'il n'a pas
     eu à cadrer. Le repli reste en filet pour les écrans étroits, où deux
     petites capitales de cette longueur ne tiendront jamais côte à côte. */
  font-size:clamp(.7rem, .82vw, 1rem);
  opacity:1}
.page-hero__lead{margin:0;font-size:var(--fs-body);line-height:var(--lh-read);opacity:.86;
  left:calc(var(--ml,0px) + (100vw - 2 * var(--ml,0px)) * .586);
  top:calc(var(--ml,0px) + (100% - 2 * var(--ml,0px)) * var(--chapo-q));
  width:calc((100vw - 2 * var(--ml,0px)) * .398);
  max-width:none;translate:0 -100%}
}
/* En dessous du seuil : le flux, dans la gouttière, dans l'ordre de lecture
   d'origine — titre, chapô, renvois. */
@media (max-width:1023.98px){
  .page-hero__marque{display:none}
  .page-hero__cross,
  .page-hero__lead{position:static;translate:none;width:auto;max-width:52ch;
    padding-inline:var(--gutter)}
  .page-hero__lead{order:2;margin:0;font-size:var(--fs-body);
    line-height:var(--lh-read);opacity:.86}
  .page-hero__cross{order:3;display:flex;flex-wrap:wrap;
    gap:clamp(1.2rem,3vw,2.6rem);max-width:none}
  .page-hero__cross a{position:relative;translate:none}
}
.page-hero__cross{display:flex;flex-wrap:wrap;gap:clamp(1.2rem,3vw,2.6rem);
  font-size:var(--fs-label);text-transform:uppercase;letter-spacing:var(--ls-label)}
.page-hero__cross a{color:currentColor;text-decoration:none;display:inline-flex;align-items:center;gap:.6rem;
  opacity:.75;transition:opacity var(--dur-fast) var(--ease-out)}
.page-hero__cross a:hover{opacity:1}
/* ⚠️ PAS DE PASTILLE DEVANT CES DEUX RENVOIS — relevé dans le Figma le
   31/08. Le designer ne pose qu'UN carré sur cette ligne, à 49,6 %, et il
   est seul : les deux renvois sont du texte nu. Nous en affichions trois,
   la pastille de chaque lien s'ajoutant au carré. La règle générale reste
   en dessous du seuil, où les renvois reprennent le flux et où le carré,
   lui, disparaît — la pastille y garde donc son rôle de repère. */
.page-hero__cross a::before{content:"";width:7px;height:7px;background:currentColor;flex:none}
@media (min-width:1024px){ .page-hero__cross a::before{display:none} }

/* Médias placeholder — à remplacer par les visuels du client */
.media{background:var(--color-surface-dark)}
.media--green{background:radial-gradient(120% 100% at 50% 45%, rgba(42,62,47,.92), rgba(20,30,24,.65) 55%, #0b0f0c 88%),linear-gradient(180deg,#20302a,#0c110e)}
.media--dark{background:radial-gradient(120% 100% at 50% 40%, rgba(60,60,54,.5), rgba(12,12,12,.45) 50%, #070707 88%),linear-gradient(180deg,#141414,#070707)}
.media--paper{background:radial-gradient(120% 100% at 50% 40%, #efeee9, #e2e1da 60%, #d5d4cc 100%)}

/* ── Corps de page clair ── */
.page{background:var(--color-bg);color:var(--color-text)}
.wrap{width:min(100% - 2*var(--gutter), var(--content-max));margin-inline:auto}
.section{padding-block:var(--section-y)}
.eyebrow{font-size:var(--fs-label);text-transform:uppercase;letter-spacing:var(--ls-label);
  color:var(--color-text-soft);display:flex;align-items:center;gap:.7rem}
.eyebrow::before{content:"";width:9px;height:9px;background:var(--color-accent);flex:none}
/* `.title` et non `h2.title` : la 404 et les 8 pages légales posent un
   <h1 class="title"> — le sélecteur trop restrictif les laissait au style
   par défaut du navigateur, seules pages du site sans titre en display. */
.title{font-family:var(--font-display);font-weight:var(--fw-display);text-transform:uppercase;
  font-size:clamp(1.5rem, .8rem + 2.4vw, 3rem);line-height:var(--lh-tight);letter-spacing:.03em;
  margin-block:.6em .4em}
.prose{max-width:var(--measure);font-size:var(--fs-body);line-height:var(--lh-read);color:var(--color-text)}
.prose p + p{margin-top:1.1em}

/* Lien « découvrir » : carré + petites capitales */
.cta{display:inline-flex;align-items:center;gap:.7rem;margin-top:1.6rem;
  font-size:var(--fs-label);text-transform:uppercase;letter-spacing:var(--ls-label);
  color:var(--color-text);text-decoration:none}
.cta::before{content:"";width:13px;height:11px;background:var(--color-accent);flex:none;
  transition:transform var(--dur-base) var(--ease-out)}
.cta:hover::before{transform:translateX(4px)}

/* ── Bloc éditorial : texte + média, alterné ── */
.block{display:grid;gap:clamp(1.6rem,4vw,3.5rem);align-items:center;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,340px),1fr));padding-block:clamp(2rem,5vh,4rem)}
.block:nth-child(even) .block__text{order:2}
.block__media{aspect-ratio:4/5;width:100%}
.block--wide .block__media{aspect-ratio:16/9}
.block--wide{grid-template-columns:1fr}
.block--wide .block__text{max-width:var(--measure)}

/* Les gabarits What's up (liste + article) sont plus bas, en fin de feuille,
   avec le relevé Figma qui les justifie. */

/* ── Pied de page (relevé Figma) ── */
.site-foot{background:var(--color-bg);color:var(--color-text);
  padding-block:clamp(3rem,7vh,6rem) clamp(2rem,4vh,3rem);border-top:var(--hairline) solid var(--color-line)}
/* Le « HERE. » du pied : Quablo **Bold (700)**, 40 px, interlettrage 0,4 px.
   C'est le seul 700 du site — partout ailleurs le display est en SemiBold. La
   maquette le veut ainsi : dans le pied, le mot-symbole est la dernière chose
   qu'on lit, il est posé plus lourd que celui de l'en-tête. */
.site-foot__wordmark{font-family:var(--font-display);font-weight:700;
  font-size:clamp(1.6rem,1.1rem + 1.5vw,var(--fs-foot-signe));
  line-height:1.1;text-transform:uppercase;letter-spacing:var(--ls-foot-signe)}
/* ── La répartition des colonnes, relevée au pixel sur le Figma ───────────
   Le bloc mesure 1630 px de large (c'est `--content-max`). Dedans, l'adresse
   commence à 0, « nos services » à 960 et « liens utiles » à 1370 : l'adresse
   est SEULE à gauche, les deux colonnes de liens sont rejetées vers la droite.
   On avait trois colonnes réparties à égalité (`auto-fit`) — lisible, mais
   c'était une autre composition : le pied paraissait plein là où la maquette
   ménage un grand vide au centre. En dessous de 1100 px on retombe sur
   l'empilement souple — trois colonnes n'y tiendraient plus.
   L'adresse garde les 398 px de la maquette : sa colonne fait 960 px de large,
   sans quoi la ligne s'étirerait sur toute cette largeur.

   ⚠️ Les deux colonnes de liens sont écrites en PIXELS, pas en pourcentages.
   En pourcentages (58,9 % / 84,05 %) la composition est juste à 1728 — la
   largeur de la maquette — mais la dernière colonne ne reçoit plus que 16 %
   du bloc : dès 1600 px de fenêtre, « Conditions générales de vente » passait
   sur trois lignes. Avec deux largeurs fixes (410 et 262, relevées sur le
   Figma) et l'adresse qui absorbe le reste, on retrouve EXACTEMENT 960 et 1370
   à 1728, et les colonnes de liens gardent leur largeur en descendant : c'est
   le vide du milieu qui se referme, pas le texte qui se casse. */
.site-foot__grid{display:grid;gap:clamp(2rem,5vw,4rem);margin-top:clamp(1.25rem,2vw,1.75rem);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr))}
.site-foot__grid > :first-child{max-width:398px}
@media (min-width:1100px){
  .site-foot__grid{grid-template-columns:1fr 410px 262px;gap:0}
}
.site-foot address{font-style:normal;font-family:var(--font-body);font-weight:var(--fw-foot);
  font-size:var(--fs-foot);line-height:var(--lh-foot-adresse);color:var(--color-text)}
/* Le saut de ligne entre le lieu et le téléphone vaut UNE ligne du bloc, pas
   « 1em » : à 19 px d'interligne sur 16 px de corps, un `1em` laissait un blanc
   de 16 px là où la maquette en montre 19 — le rythme se cassait juste là. */
.site-foot__lieu{display:block;margin-bottom:calc(1em * var(--lh-foot-adresse))}
.site-foot address a{color:inherit;text-decoration:none}
.site-foot address a:hover{color:var(--color-text)}
/* Titres de colonne : Quablo SemiBold 16/20, et non les petites capitales
   grises en Poppins. L'écart de 32 px jusqu'à la liste vient aussi du relevé —
   il y avait 1,1 rem (17,6 px), la colonne paraissait tassée sous son titre. */
.site-foot h2{font-family:var(--font-display);font-weight:var(--fw-display);
  font-size:var(--fs-foot);line-height:var(--lh-foot-liens);letter-spacing:var(--ls-foot);
  text-transform:uppercase;color:var(--color-text);margin-bottom:2rem}
/* ⚠️ L'INTERLIGNE SE POSE SUR LE `li`, PAS SEULEMENT SUR LE LIEN. Un `<a>` est
   une boîte en ligne : la hauteur de la ligne est celle du plus haut entre lui
   et le « strut » de son parent — le fantôme de texte que le `li` porte avec sa
   propre police. Le `li` héritait du corps (16 px sur 1,35, soit 21,6 px) : le
   pas des liens tombait à 35 px là où la maquette en donne 30 (20 + 10), et le
   titre paraissait décollé de sa liste. On accorde donc le `li` au lien. */
.site-foot ul{list-style:none;padding:0;margin:0;display:grid;gap:10px}
.site-foot li{font-size:var(--fs-foot);line-height:var(--lh-foot-liens)}
.site-foot li a{font-family:var(--font-body);font-weight:var(--fw-foot);font-size:var(--fs-foot);
  line-height:var(--lh-foot-liens);letter-spacing:var(--ls-foot);
  color:var(--color-text);text-decoration:none;
  transition:color var(--dur-fast) var(--ease-out)}
.site-foot li a:hover{color:var(--color-accent)}
/* Réseaux : 32 px, 16 px entre eux, 32 px sous l'adresse — relevé Figma. */
.social{display:flex;gap:16px;margin-top:2rem}
.social a{width:32px;height:32px;display:grid;place-items:center;color:var(--color-text);
  border:var(--hairline) solid var(--color-line);transition:border-color var(--dur-fast) var(--ease-out)}
.social a:hover{border-color:var(--color-accent)}
.social svg{width:17px;height:17px;fill:currentColor}
.site-foot__bottom{display:flex;flex-wrap:wrap;justify-content:space-between;gap:1rem;
  margin-top:clamp(2.5rem,6vh,4rem);padding-top:1.4rem;border-top:var(--hairline) solid var(--color-line);
  font-size:var(--fs-label);text-transform:uppercase;letter-spacing:var(--ls-label);color:var(--color-text-soft)}
.lang-switch{color:var(--color-text);text-decoration:none;display:inline-flex;align-items:center;gap:.6rem}
.lang-switch::before{content:"";width:7px;height:7px;background:var(--color-accent)}

/* ── 404 ── */
.center-page{min-height:100svh;display:grid;place-items:center;text-align:center;padding:var(--gutter)}

/* Les deux wordmarks (header et pied) sont des liens de retour à l'accueil :
   on neutralise le style de lien par défaut du navigateur. */
.wordmark, .site-foot__wordmark{color:currentColor;text-decoration:none}
.wordmark:focus-visible, .site-foot__wordmark:focus-visible{outline:2px solid currentColor;outline-offset:4px}
.site-foot__wordmark{display:inline-block}

/* Vidéos et images de fond téléversées depuis le CMS */
.media{position:relative;overflow:hidden}
.media__video, .media__img, .media__poster{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;display:block;transform-origin:center center;will-change:transform}
/* L'image d'attente est SOUS la vidéo (même boîte, même cadrage) : c'est elle qu'on
   voit tant que la première image du film n'est pas décodée. Elle ne bouge pas seule
   — c'est le conteneur qui porte la parallaxe — donc les deux restent superposées
   au pixel près pendant le relais. */
.media__poster{z-index:0;will-change:auto}
.media__video{z-index:1}
/* ⚠️ LA DÉSATURATION SUIT LA MARIE-LOUISE — règle de Guillaume, 30/08/2026.
   Là où la page est encadrée de papier, l'image est en retrait ; là où elle
   occupe tout l'écran — l'accueil — elle est rendue pleine. Le sélecteur le
   disait déjà par construction (`.page-hero__media` n'existe que sur les
   rubriques) ; `body.has-ml` le dit maintenant explicitement, pour que la
   règle survive au jour où un écran d'arrivée sera posé ailleurs.
   Les TROIS cibles comptent : sans `media__poster`, l'affiche serait plus
   saturée que le film qui la remplace, et l'on verrait la couleur sauter au
   démarrage. */
body.has-ml .page-hero__media .media__video,
body.has-ml .page-hero__media .media__img,
body.has-ml .page-hero__media .media__poster{filter:saturate(.6)}

/* ── §03 bis — LA RÉSERVE VIENT DE L'ÉCHELLE, PAS DE LA HAUTEUR ───────────
   Une image ne peut dériver dans son cadre que si elle déborde : sinon elle
   découvre son bord. Il y a deux façons de fabriquer ce débord, et une seule
   est bonne ici.
   ✗ Agrandir la BOÎTE (height:118%) : avec `object-fit:cover`, changer la
     hauteur de la boîte change le calcul du recadrage. Mesuré sur les blocs
     (boîte 4/5, image 1400×1800) : l'image passait de calée-sur-la-largeur à
     calée-sur-la-hauteur et se retrouvait 15 % plus zoomée, rognée sur les
     côtés. Le mouvement recadrait toutes les photos du site.
   ✓ Agrandir l'IMAGE (scale, dans site.js §03) : le recadrage reste centré et
     proportionnel, on sait exactement ce qu'on perd, et la valeur de repos est
     celle du zoom au scroll — un seul nombre à régler au lieu de deux.
   Il n'y a donc rien à poser ici : la boîte garde sa taille. Le prix du
   mouvement, lui, est réel et assumé : l'image finit à 1,12 au lieu de 1, soit
   6 % rognés de chaque côté. C'est le minimum pour une dérive perceptible. */


/* ── §02 « Recettes de motion éditorial » — apparition en volet ──
   L'état de départ est en CSS, jamais en JS : sinon flash de contenu non stylé.
   opacity .001 et non 0 : à 0 le navigateur peut décharger la couche. */
[data-reveal]{
  clip-path: inset(0 0 100% 0);
  transform: translate3d(0, 26px, 0);
  opacity: .001;
  will-change: clip-path, transform;
}
[data-reveal].is-in{ will-change: auto; }
.no-js [data-reveal], .no-tween [data-reveal]{ clip-path:none; transform:none; opacity:1 }
@media (prefers-reduced-motion: reduce){
  [data-reveal]{ clip-path:none; transform:none; opacity:1 }
}

/* §03 — le conteneur masque le débord du zoom, sinon la page grandit avec l'image */
.page-hero__media, .block__media, .card__media, .art__coverMedia, .art__shot{ overflow:hidden }
.page-hero__inner{ will-change: transform, opacity }


/* ══ § 06 — header qui s'inverse par section (pages intérieures) ══
   On abandonne `mix-blend-mode` hors Home : il crée un contexte d'empilement et
   son rendu dépend de la photo. Ici la couleur bascule proprement, section par section. */
body.head-static .site-head{
  mix-blend-mode:normal;
  color:var(--color-text-invert);
  transition:color 420ms cubic-bezier(.22,1,.36,1);
}
body.head-static .site-head.is-light{ color:var(--color-text) }
body.head-static.head-plain .site-head{ color:var(--color-text-invert) }  /* menu ouvert : toujours blanc */
/* ⚠️ SANS SCRIPT, PERSONNE NE POSE `is-light` : l'en-tête restait BLANC SUR
   PAPIER (mesuré : `rgb(252,252,252)` sur `#FCFCFC`) sans JavaScript, sans GSAP
   et en mouvement réduit — mot-symbole, « réserver », « contact », le bouton du
   menu, tous invisibles sur Contact, What's up, les articles et les mentions.
   On revient alors au procédé de l'accueil : la différence de couleurs, blanc
   sur le film, presque noir sur le papier, sans rien avoir à basculer. */
html.no-js body.head-static .site-head,
html.no-tween body.head-static .site-head{ mix-blend-mode:difference; color:#fff }
html.no-js body.head-static.head-plain .site-head,
html.no-tween body.head-static.head-plain .site-head{ mix-blend-mode:normal }

/* ══ § 07 — compteur à chiffres roulants ══
   La piste fait exactement 10 chiffres de haut : un pas = translateY(-10 %) de la piste.
   Aucun arrondi sub-pixel, contrairement à un calcul en em. */
.odo-wrap{position:fixed;left:var(--gutter);bottom:var(--gutter);z-index:70;
  display:flex;align-items:center;gap:.8rem;opacity:0;pointer-events:none;
  transition:opacity 420ms cubic-bezier(.22,1,.36,1);
  font-size:var(--fs-label);letter-spacing:var(--ls-label);color:var(--color-text)}
.odo-wrap.is-on{opacity:1}
/* spécificité 0,3,0 : bat `.odo-wrap.is-on` sans recourir à !important */
.odo-wrap.is-on.is-off{opacity:0}
.odo{display:inline-flex;align-items:center;gap:.05em;line-height:1;
  font-family:var(--font-body);font-variant-numeric:tabular-nums}
.odo__d{position:relative;width:.62em;height:1.15em;overflow:hidden}
.odo__t{position:absolute;top:0;left:0;width:100%;display:flex;flex-direction:column;
  transition:transform 520ms cubic-bezier(.22,1,.36,1);will-change:transform}
.odo__t span{height:1.15em;flex:0 0 1.15em;display:flex;align-items:center;justify-content:center}
.odo-bar{width:64px;height:1px;background:var(--color-line);position:relative}
.odo-bar i{position:absolute;inset:0 auto 0 0;width:0;background:var(--color-accent);
  transition:width 520ms cubic-bezier(.22,1,.36,1)}
@media (prefers-reduced-motion: reduce){ .odo__t, .odo-bar i{transition:none} }
@media (max-width:900px){ .odo-wrap{display:none} }   /* mange le pouce sur mobile */

/* ══ § 12 — les détails qui font le studio ══ */
/* Soulignement dirigé : sort par la gauche, entre par la droite */
.ln{position:relative;text-decoration:none;display:inline-block}
.ln::after{content:"";position:absolute;left:0;right:0;bottom:-.18em;height:1px;
  background:currentColor;transform:scaleX(0);transform-origin:right;
  transition:transform 480ms cubic-bezier(.22,1,.36,1)}
.ln:hover::after, .ln:focus-visible::after{transform:scaleX(1);transform-origin:left}
.nav a{text-decoration:none}

/* Image au survol : 900 ms minimum, jamais plus de 1.06 */
.card__media{overflow:hidden}
.card__media img, .art__shot img{transition:transform 900ms cubic-bezier(.22,1,.36,1);transform:scale(1.001)}
.card:hover .card__media img, .card:focus-within .card__media img{transform:scale(1.06)}
.card:hover .card__media{opacity:1}

/* Transition de page — natif d'abord, aucun JS */
@view-transition{ navigation: auto }

/* ⚠️ L'ANCIENNE IMAGE NE BOUGE PLUS ET NE PÂLIT PLUS — 30/08/2026.
   Guillaume, sur le clic du mot-symbole « HERE. » : « ça fait un décrochage,
   c'est pas beau ». Relevé dans les animations réellement exécutées par le
   navigateur, plutôt que dans la feuille :

     ::view-transition-old(root)  420 ms  opacité 1 → 0, translateY(0 → −14px)
     ::view-transition-new(root)  520 ms  opacité 0 → 1, translateY(14px → 0)

   Deux défauts, et ils s'additionnent. D'abord 28 px de déplacement vertical en
   sens contraire : la page quittée monte pendant que la page d'arrivée remonte
   d'en dessous — c'est le « tilt ». Ensuite les deux images sont translucides
   AU MÊME MOMENT, si bien que le fond du navigateur transparaît entre elles :
   la page pâlit au milieu du geste. C'est exactement le défaut corrigé le 22/08
   pour les liens du menu ; il restait entier sur tous les autres liens.

   Le remède garde le SERVICE du natif et lui retire son GESTE. L'ancienne image
   est simplement TENUE, opaque, jusqu'à ce que la nouvelle soit prête : plus
   rien ne bouge, et le fond ne peut plus se voir puisqu'il n'y a jamais de trou.
   La nouvelle paraît par-dessus, en opacité seule — `::view-transition-new` est
   peint AU-DESSUS de `::view-transition-old`, c'est ce qui rend le fondu
   possible sans croisement.
   👉 Règle générale, déjà écrite pour le menu : le natif doit tenir l'image,
   pas jouer un mouvement. Ici il n'y a pas de geste maison à protéger — il n'y
   a rien à ajouter non plus. */
::view-transition-old(root){ animation:none }
::view-transition-new(root){ animation: vt-in var(--dur-slow) var(--ease-out) forwards }
@keyframes vt-in { from{ opacity:0 } }
@media (prefers-reduced-motion: reduce){
  ::view-transition-old(root), ::view-transition-new(root){ animation:none }
}

/* ⚠️ LA TRANSITION NATIVE NE DOIT PAS SE SUPERPOSER AUX NÔTRES — 22/08/2026.
   Guillaume : « à chaque fois que je clique sur un lien du menu, on voit que la
   page se recharge. » Le fondu croisé ci-dessus en était une cause directe.
   Pendant ses 420 ms, les DEUX images — celle qu'on quitte et celle qui arrive —
   sont semi-transparentes en même temps, et le fond du navigateur transparaît
   entre elles. Or dans une navigation par le menu, ces deux images sont du VERT
   PLEIN : un aplat qui pâlit au milieu du geste puis redevient plein se lit
   exactement comme un rechargement. Le glissement de 14 px ajoutait le mouvement
   de trop — deux gestes à lire là où le rideau n'en veut qu'un.

   On ne retire donc pas la transition native : on lui retire son ANIMATION dans
   les deux cas où le site en a déjà une à lui.
     · `html.arrive` — l'arrivée par le menu. La classe est posée dans <head>
       avant le premier rendu (base.php), donc elle est déjà là quand la
       transition démarre : la règle s'applique dès la première image.
     · `html.arrive-langue` — le repli de la bascule EN/FR, qui a son propre
       fondu de 220 ms (voir base.css). Sans ça : un fondu par-dessus un fondu.

   Ce qui reste est le seul service qu'on attend du natif, et c'est le bon : le
   navigateur GARDE à l'écran l'image de la page quittée jusqu'à ce que la
   suivante soit prête à peindre, puis l'échange d'un coup. Deux aplats verts
   identiques, aucune couture, aucun trou blanc — et le rideau joue ensuite,
   seul. Le fondu du dessus continue de servir partout ailleurs (pied de page,
   renvois croisés, fil des actualités). */
html.arrive::view-transition-old(root),
html.arrive::view-transition-new(root),
html.arrive-langue::view-transition-old(root),
html.arrive-langue::view-transition-new(root){ animation:none }

.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}


/* ══════════════ PAGE CONTACT ══════════════
   Relevé Figma (frame 1728 × 1306, contenu 1632 avec 48 px de marge) :
   titre x48 y226 (largeur du mot 385) · carré x857 y291 · « A message ? » x1008 y285 ·
   « A project ? » x1419 · formulaire x48 w810 · zone message w810 h167.
   La largeur de contenu (1632) est désormais celle de tout le site — voir tokens.css. */
.contact{--contact-title: clamp(2.2rem, .9rem + 4.05vw, 4.7rem);
  background:var(--color-bg);color:var(--color-text);
  padding-top:clamp(6.5rem, 17.3vh, 15rem);padding-bottom:clamp(2.5rem,6vh,5rem)}

/* Une seule grille : les deux colonnes se chevauchent verticalement (maquette). */
.contact__grid{display:grid;align-items:start;column-gap:0;
  grid-template-columns:minmax(0, 810fr) minmax(0, 150fr) minmax(0, 672fr)}
.contact__main{grid-column:1;display:grid;gap:clamp(2.4rem, 9vh, 7rem)}

.contact__title{font-family:var(--font-display);font-weight:var(--fw-display);
  text-transform:uppercase;font-size:var(--contact-title);line-height:1;
  letter-spacing:.05em;color:var(--color-text);margin:0}

/* le carré est calé sur le milieu de la hauteur du titre */
.contact__mark{grid-column:2;justify-self:start;align-self:start;
  margin-top:calc(.86 * var(--contact-title));width:13px;height:11px;background:var(--color-text)}

.contact__aside{grid-column:3;display:grid;gap:clamp(1.5rem,3.6vh,2.8rem);
  padding-top:calc(.78 * var(--contact-title))}
/* « A project ? » démarre à 1419 sur 1632 de contenu, soit 411/672 de la colonne */
.contact__asks{display:grid;grid-template-columns:minmax(0,411fr) minmax(0,261fr);gap:1rem}
.contact__ask{appearance:none;background:none;border:0;padding:0;cursor:pointer;text-align:left;
  justify-self:start;  /* le filet épouse le mot, pas la colonne */
  font-family:var(--font-body);font-weight:var(--fw-body);font-size:var(--fs-label);
  text-transform:uppercase;letter-spacing:var(--ls-label);color:var(--color-text);
  position:relative;padding-bottom:.35em;
  transition:opacity var(--dur-fast) var(--ease-out)}
.contact__ask::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:currentColor;transform:scaleX(0);transform-origin:right;
  transition:transform 480ms cubic-bezier(.22,1,.36,1)}
.contact__ask:hover{opacity:.7}
.contact__ask.is-on::after, .contact__ask:hover::after{transform:scaleX(1);transform-origin:left}
.contact__intro{max-width:46ch;font-size:var(--fs-body);line-height:var(--lh-read)}

/* Formulaire : deux colonnes de 398 sur 810, filets fins sous les champs */
.contact__form{display:grid;grid-template-columns:repeat(2, minmax(0,1fr));
  column-gap:clamp(.7rem,.8vw,.9rem);row-gap:clamp(.45rem,.75vh,.7rem)}
.contact__form .field{display:grid;gap:.28rem;margin:0}
.contact__form .field--right{grid-column:2}
.contact__form .field--full{grid-column:1 / -1}
.contact__form label{font-size:var(--fs-label);text-transform:uppercase;
  letter-spacing:var(--ls-label);color:var(--color-text)}
.contact__form input,
.contact__form textarea{font:inherit;font-size:var(--fs-body);color:var(--color-text);
  background:transparent;border:0;border-bottom:var(--hairline) solid var(--color-text);
  border-radius:0;padding:.2rem 0;transition:border-color var(--dur-fast) var(--ease-out)}
/* ⚠️ LE CHAMP MESSAGE N'A PLUS DE CADRE (22/08/2026).
   Guillaume : « corrige l'alignement des champs. » Le défaut tenait à lui seul :
   les quatre champs simples sont des filets, leur nom commence donc à 0 ; le
   message était une boîte fermée avec 14 px de rembourrage, son nom démarrait
   14 px plus loin. Cinq champs, cinq noms, et un qui ne tombait pas sur la même
   verticale que les autres — c'est ça qu'on voyait sans savoir le nommer.
   On ne peut pas rattraper ça en décalant le texte : un rembourrage nul dans une
   boîte colle les lettres au trait. Le champ prend donc le même filet que les
   autres. Trois conséquences, toutes voulues : les cinq noms s'alignent, le pas
   vertical redevient régulier (43 px partout, contre 9 px avant le cadre), et
   la charte est respectée — Here est faite de filets, jamais de cadres.
   ⚠️ Écart assumé avec la maquette Figma (node 395:1657), qui montre un
   rectangle de 810 × 167. On garde la hauteur, on retire le cadre.
   `resize:none` : la poignée de redimensionnement du coin, sans boîte autour,
   flotte dans le vide et se lit comme un défaut d'affichage. */
.contact__form textarea{border:0;border-bottom:var(--hairline) solid var(--color-text);
  padding:.2rem 0;min-height:167px;resize:none;line-height:var(--lh-read)}
/* Les étiquettes sont maintenant DANS les champs (voir contact.php) : petites
   capitales espacées, encre douce, pour qu'elles se lisent comme un nom de champ
   et non comme un texte déjà saisi. `opacity:1` parce que Firefox affadit les
   placeholders de son côté. */
.contact__form input::placeholder,
.contact__form textarea::placeholder{
  font-size:var(--fs-label);text-transform:uppercase;letter-spacing:var(--ls-label);
  color:var(--color-text-soft);opacity:1}

/* ⚠️ PLUS D'ANNEAU CARRÉ AUTOUR DES CHAMPS (22/08/2026).
   Guillaume : « un espèce de carré noir qui entoure le champ » au clic. C'était
   l'anneau de focus — et `:focus:not(:focus-visible)` ne le retirait pas, parce
   que la spécification fait TOUJOURS correspondre `:focus-visible` à un champ de
   saisie, souris ou clavier : on attend qu'on y tape. La règle du dessous ne
   servait donc jamais.

   On ne peut pas se contenter de le supprimer : sans repère visible, on ne sait
   plus où l'on est au clavier. Le filet du champ, lui, est déjà là — on le
   double et on le passe à l'encre pleine. Le repère devient un trait épais sous
   le champ au lieu d'une boîte autour : plus fort qu'avant (le filet passait du
   noir au vert, 1,6:1 de contraste inter-états — invisible), et conforme à la
   charte, qui est faite de filets et jamais de cadres. */
.contact__form input:focus,
.contact__form input:focus-visible{
  outline:none;border-bottom-width:2px;border-bottom-color:var(--color-text);
  padding-bottom:calc(.2rem - 1px)}
.contact__form textarea:focus,
.contact__form textarea:focus-visible{
  outline:none;border-bottom-width:2px;border-bottom-color:var(--color-text);
  padding-bottom:calc(.2rem - 1px)}
/* Le nom du champ s'efface dès la première frappe — c'est le comportement natif
   du placeholder ; on l'accompagne pour que ce ne soit pas un clignotement. */
.contact__form input::placeholder,
.contact__form textarea::placeholder{transition:opacity var(--dur-fast) var(--ease-out)}
.contact__form input:focus::placeholder,
.contact__form textarea:focus::placeholder{opacity:.45}

.contact__send{grid-column:1 / -1;justify-self:end}
.contact__send .cta{margin-top:0;background:none;border:0;cursor:pointer;
  font-family:var(--font-body);font-weight:var(--fw-body);color:var(--color-text)}
.contact__send .cta::before{background:var(--color-text)}

/* Sous 900 px : une colonne, ordre de lecture de la maquette conservé */
@media (max-width:900px){
  .contact__grid{grid-template-columns:1fr;row-gap:clamp(1.6rem,4vh,2.6rem)}
  /* on ouvre le conteneur pour intercaler l'aparté ENTRE le titre et le formulaire :
     titre → « A message ? / A project ? » + chapô → formulaire */
  .contact__main{display:contents}
  .contact__title{order:1}
  .contact__aside{order:2;grid-column:1;padding-top:0}
  .contact__form{order:3;grid-column:1}
  .contact__mark{display:none}
  .contact__asks{grid-template-columns:1fr 1fr}
  .contact__form{grid-template-columns:1fr}
  .contact__form .field--right{grid-column:1}
  .contact__send{justify-self:start}
}


/* ══════════════ WHAT'S UP IN REIMS ══════════════
   Relevé Figma — LISTE `Actualités` node 396:1837 (1728 × 4448) et
   ARTICLE `Actualités` node 396:1990 (1728 × 4448).
   Contenu 1632 (1728 − 2 × 48). Les deux pages sont sur papier, sans hero.
   ------------------------------------------------------------------ */

/* ── Bandeau de titre ──
   Même géométrie que Contact : titre x48 y226 · carré x857 y291 ·
   « A message ? » x1008 y285 · « A project ? » x1419 · chapô x1008 y374 w672.
   Le designer a repris le bandeau de Contact tel quel : les deux entrées
   mènent donc au formulaire, ce sont des liens et non des onglets. */
.band{--band-title: clamp(2rem, 3.68vw, 4rem);
  display:grid;align-items:start;column-gap:0;
  grid-template-columns:minmax(0, 810fr) minmax(0, 150fr) minmax(0, 672fr);
  padding-top:clamp(6.5rem, 20.5vh, 15rem)}
.band__title{grid-column:1;margin:0;
  font-family:var(--font-display);font-weight:var(--fw-display);text-transform:uppercase;
  font-size:var(--band-title);line-height:1;letter-spacing:.02em;color:var(--color-text);
  text-wrap:balance}
/* le carré est calé sur le milieu de la hauteur du titre */
.band__mark{grid-column:2;justify-self:start;align-self:start;
  margin-top:calc(.95 * var(--band-title));width:13px;height:11px;background:var(--color-text)}
.band__aside{grid-column:3;display:grid;gap:clamp(1.5rem,6vh,4.2rem);
  padding-top:calc(.78 * var(--band-title))}
/* « A project ? » démarre à 1419 sur 1632 de contenu, soit 411/672 de la colonne */
.band__asks{display:grid;grid-template-columns:minmax(0,411fr) minmax(0,261fr);gap:1rem}
.band__ask{justify-self:start;color:var(--color-text);text-decoration:none;
  font-size:var(--fs-label);text-transform:uppercase;letter-spacing:var(--ls-label)}
.band__intro{font-size:var(--fs-body);line-height:var(--lh-read);margin:0}

/* ── Grille de cartes ──
   3 × 535 avec 13 px de gouttière = 1633 ≈ 1632. Pas de date sur les cartes :
   la maquette n'en montre aucune, la date reste sur la page article. */
.news__grid{display:grid;grid-template-columns:repeat(3, minmax(0,1fr));
  column-gap:clamp(10px, .8vw, 13px);
  row-gap:clamp(3rem, 7.9vw, 8.5rem);          /* 776 de pas − 379 d'image − 261 de texte = 136 */
  padding-top:clamp(2rem, 5.4vw, 6rem)}        /* bas de l'aparté y482 → 1re image y544 */
.card{margin:0;height:100%}
.card.is-hidden{display:none}
.card__link{display:flex;flex-direction:column;height:100%;text-decoration:none;color:inherit}
.card__fig{position:relative;display:block}
.card__media{aspect-ratio:535/379;width:100%;display:block}
/* Le carré est À CHEVAL sur le bord bas de l'image (Figma : image 544→923, carré 917→928)
   et en retrait de 65 px du bord gauche de l'image, soit 12.15 % de sa largeur. */
.card__mark{position:absolute;left:12.15%;bottom:0;transform:translateY(50%);
  width:13px;height:11px;background:var(--color-text);z-index:2}
/* Tout le texte de la carte est aligné sur ce carré, pas sur le bord de l'image. */
.card__body{flex:1;display:flex;flex-direction:column;align-items:flex-start;
  padding-left:12.15%;padding-right:11.6%;padding-top:clamp(1.5rem,2.5vw,2.13rem)}
.card__title{display:block;margin:0;font-family:var(--font-body);font-weight:600;
  font-size:clamp(.8125rem,.72rem + .4vw,1.125rem);text-transform:uppercase;
  letter-spacing:.19em;line-height:1.45;color:var(--color-text);max-width:16ch}
.card__lead{display:block;margin:clamp(.9rem,1.5vw,1.35rem) 0 0;
  font-size:var(--fs-body);line-height:1.7;color:var(--color-text)}
/* « Show more » est plus gros que les autres petites capitales du site (Figma ≈ 14 px) */
.card__cta, .news__more, .art__foot .cta{font-size:clamp(.79rem,.75rem + .2vw,.875rem)}
.card__cta{margin-top:auto;padding-top:clamp(1.1rem,1.8vw,1.6rem)}
.card__cta::before{background:var(--color-text)}
.card__link:hover .card__cta::before{transform:translateX(4px)}
.card__media{transition:opacity var(--dur-base) var(--ease-out)}

/* Le contrôle de bas de liste est calé sur la 2ᵉ colonne (Figma x596 y2980). */
.news__foot{display:grid;grid-template-columns:repeat(3, minmax(0,1fr));
  padding-top:clamp(3rem,6vw,6rem)}
.news__more{grid-column:2;justify-self:start;margin-top:0;
  background:none;border:0;padding:0;cursor:pointer;
  font-family:var(--font-body);font-weight:var(--fw-body);color:var(--color-text)}
.news__more::before{background:var(--color-text)}

.news{padding-bottom:clamp(3rem,7vh,6rem)}


/* ── Article ──
   Couverture 1728 × 947 à y0 · nav dans les marges (x48 / x1497, y1056) ·
   colonne de texte de 810 CENTRÉE (x459 → x1269) · galerie sur toute la largeur. */
/* ─────────────────────────────────────────────────────────────────────────
   L'ARTICLE, RECALÉ SUR LE FIGMA (node 396:1990, relevé du 22/08/2026)

   Toutes les valeurs ci-dessous sont celles de la maquette, à sa largeur : 1728.
   Elles sont écrites selon une seule règle, décidée avec Guillaume :
   « exacte à 1728, proportionnelle en dessous ». D'où la forme systématique
   `clamp(plancher, N vw, plafond)` où **N = px ÷ 17,28** — à 1728 la part en
   `vw` vaut exactement le pixel dessiné, au-delà le plafond la retient, en
   dessous elle décroît avec la fenêtre. Le plancher n'est pas décoratif : il
   garde la page lisible là où une proportion pure donnerait 11 px.

   La maquette n'existant qu'à une largeur, c'est la seule façon honnête de
   parler de « pixel perfect » : exact là où la maquette existe, cohérent
   partout ailleurs. */
.art{--art-col: 50.625rem;   /* = 810px en 1728 ; en rem, la colonne suit l’échelle */
  --art-nav:   clamp(.8125rem, .926vw,  1rem);      /* 16 px — petites capitales */
  --art-titre: clamp(2rem,     2.894vw, 3.125rem);  /* 50 px — le titre */
  --art-chapo: clamp(1rem,     1.157vw, 1.25rem);   /* 20 px — chapô et intro */
  --art-h2:    clamp(1.15rem,  1.505vw, 1.625rem);  /* 26 px — sous-titre */
  --art-txt:   clamp(.9375rem, .926vw,  1rem);      /* 16 px — corps long */
  --art-acc:   clamp(1rem,     1.042vw, 1.125rem)   /* 18 px — accroche large */}
.art__cover{position:relative;width:100%;aspect-ratio:1728/947;max-height:88svh;overflow:hidden}
.art__coverMedia{position:absolute;inset:0;width:100%;height:100%}
/* Même réserve de débord que l'écran d'arrivée, et pour la même raison : la
   couverture reçoit la parallaxe à trois couches (site.js §04, amplitude 12 %).
   136 % de haut, débord centré à −18 % — voir le calcul en tête de cette feuille.
   Sélecteur doublé pour passer devant la règle ci-dessus. */
.art__cover .art__coverMedia{top:-18%;height:136%;bottom:auto}

/* Le titre est au centre, la navigation dans les marges de part et d'autre :
   c'est la seule chose qui vit hors de la colonne de texte, avec la galerie. */
.art__head{display:grid;
  grid-template-columns:minmax(0,411fr) minmax(0,810fr) minmax(0,411fr);
  column-gap:0;align-items:start;
  padding-top:clamp(1.2rem,2.9vw,3.2rem)}
/* ⚠️ Un rôle typographique NOUVEAU : la petite capitale en police de titrage.
   La maquette compose « previous article », « next article » et la date en
   Quablo **Bold** 16/22, interlettrage 0,2 em — pas en Poppins comme les autres
   petites capitales du site. C'est le seul endroit où le display sert à si
   petit corps, et c'est ce qui donne au bandeau de l'article son air de
   colophon. Les deux graisses de Quablo étant déjà chargées, ça ne coûte rien.
   Le calage vertical vient aussi du relevé : la nav se pose 59 px sous le haut
   du titre (elle croise sa hauteur d'œil), et non alignée sur la date. */
.art__prev, .art__next{font-family:var(--font-display);font-weight:700;
  font-size:var(--art-nav);line-height:1.375;letter-spacing:.2em;
  text-transform:uppercase;padding-inline:0 clamp(1rem,2vw,2rem);
  align-self:start;margin-top:clamp(1.4rem,3.414vw,59px)}
.art__prev{grid-column:1;justify-self:start}
.art__next{grid-column:3;justify-self:end;text-align:right}
.art__prev a, .art__next a{color:var(--color-text);text-decoration:none}
.art__prev .is-off, .art__next .is-off{color:var(--color-line)}
.art__id{grid-column:2;display:grid;gap:clamp(.5rem,1.1vw,19px)}
/* 50 px et non 64 : à 64 le titre passait sur DEUX lignes dans la colonne de
   810, ce qui n'était pas une intention de dessin mais un accident de largeur.
   Les trois titres d'article tiennent tous sur une ligne à 50. */
.art__title{margin:0;font-family:var(--font-display);font-weight:var(--fw-display);
  text-transform:uppercase;font-size:var(--art-titre);
  line-height:1.1;letter-spacing:.04em;color:var(--color-text)}
.art__date{margin:0;font-family:var(--font-display);font-weight:700;
  font-size:var(--art-nav);line-height:1.375;letter-spacing:.2em;
  text-transform:uppercase;color:var(--color-text)}

/* Colonne de lecture : 810 sur 1632, centrée sur la page (milieu 864). */
.art__col{width:min(100%, var(--art-col));margin-inline:auto;
  padding-top:clamp(1.6rem,2.894vw,50px)}          /* date → chapô : 50 */
.art__lead{margin:0;font-size:var(--art-chapo);line-height:1.35;letter-spacing:.04em;
  color:var(--color-text)}
.art__h2{margin:clamp(2.2rem,6.424vw,111px) 0 0;   /* chapô → sous-titre : 111 */
  font-family:var(--font-display);font-weight:var(--fw-display);text-transform:uppercase;
  font-size:var(--art-h2);line-height:1.231;letter-spacing:.04em;
  max-width:24ch}
/* Le paragraphe d'introduction est en QUABLO dans la maquette, pas en Poppins :
   le display y sert de graisse d'attaque avant le corps long. C'est le pendant
   de l'accroche pleine largeur, plus bas — même police, même rôle. */
.art__intro{margin:clamp(1.1rem,1.968vw,34px) 0 0;  /* sous-titre → intro : 34 */
  font-family:var(--font-display);font-weight:var(--fw-display);
  font-size:var(--art-chapo);line-height:1.3;letter-spacing:.04em;
  color:var(--color-text)}

/* Galerie : elle ressort de la colonne et reprend la grille des cartes. */
.art__gallery{display:grid;grid-template-columns:repeat(3, minmax(0,1fr));
  gap:clamp(10px,.8vw,13px);
  margin-top:clamp(1.6rem,2.894vw,50px)}           /* intro → galerie : 50 */
.art__shot{aspect-ratio:535/379;width:100%}

/* Corps : trois pistes. Tout se pose au centre sur 810 ; seule la citation
   ressort sur 1492 — c'est l'accroche pleine largeur de la maquette. */
.art__body{display:grid;
  grid-template-columns:1fr min(100%, var(--art-col)) 1fr;
  padding-top:clamp(1.8rem,3.125vw,54px);          /* galerie → corps : 54 */
  /* ⚠️ LE SEUL ENDROIT OÙ L'ON NE SUIT PAS LA MAQUETTE À LA LETTRE, et c'est
     assumé. Elle donne 16/20, soit 1,25 d'interligne. La graisse Regular, oui —
     c'est bien elle qu'il fallait, le corps était en Medium. Mais 1,25 sur un
     article de 800 mots fait un mur : la maquette est remplie de faux-texte,
     elle ne le montre pas. On garde 16 px et la graisse juste, on desserre à
     1,5. Écart accepté par Guillaume le 22/08/2026, en connaissance de cause. */
  font-size:var(--art-txt);font-weight:400;line-height:1.5;color:var(--color-text)}
.art__body > *{grid-column:2;margin:0}
.art__body > * + *{margin-top:1.15em}
.art__body h2, .art__body h3{font-family:var(--font-display);font-weight:var(--fw-display);
  text-transform:uppercase;letter-spacing:.04em;line-height:1.28;
  margin-top:clamp(2.2rem,4.6vw,5rem)}
.art__body h2{font-size:var(--art-h2);line-height:1.231}
.art__body h3{font-size:clamp(1rem,.9rem + .5vw,1.25rem)}
.art__body a{color:var(--color-text);text-decoration:underline;text-underline-offset:.22em}
.art__body img{width:100%;height:auto;display:block}
.art__body ul, .art__body ol{padding-left:1.2em}
.art__body li + li{margin-top:.4em}
/* L'accroche pleine largeur : Quablo SemiBold 18/23, et calée sur la marge de
   DROITE, pas centrée — dans la maquette elle finit à 1680 comme le reste du
   contenu, et démarre donc à 188. Centrée, elle démarrait à 118 : 70 px de
   décalage, invisibles à l'œil nu mais faux au relevé. */
.art__body blockquote{grid-column:1 / -1;justify-self:end;
  width:min(100%, 1492px);margin-top:clamp(2.6rem,5vw,5.4rem);
  padding:0;border:0;
  font-family:var(--font-display);font-weight:var(--fw-display);
  font-size:var(--art-acc);line-height:1.278;letter-spacing:.04em}
.art__body blockquote + *{margin-top:clamp(2.6rem,5vw,5.4rem)}
.art__body blockquote p{margin:0}
.art__body blockquote p + p{margin-top:.5em}

/* Le contrôle de bas d'article est calé sur la 2ᵉ colonne (Figma x596 y2980). */
.art__foot{display:grid;grid-template-columns:repeat(3, minmax(0,1fr));
  padding-block:clamp(3rem,6vw,6rem) clamp(3rem,7vh,6rem)}
.art__foot .cta{grid-column:2;justify-self:start;margin-top:0}
.art__foot .cta::before{background:var(--color-text)}


/* ── Sous 900 px : une colonne, l'aparté passe sous le titre ── */
@media (max-width:900px){
  .band{grid-template-columns:1fr;row-gap:clamp(1.6rem,4vh,2.6rem);
    padding-top:clamp(5rem,14vh,9rem)}
  .band__title{grid-column:1}
  .band__mark{display:none}
  .band__aside{grid-column:1;padding-top:0}
  .band__asks{grid-template-columns:1fr 1fr}

  .news__grid{grid-template-columns:1fr;row-gap:clamp(2.5rem,9vw,4rem);
    padding-top:clamp(2.5rem,9vw,4rem)}
  .card__body{padding-left:0}
  .card__mark{left:0}
  .card__lead, .card__title{max-width:none}
  .news__foot{grid-template-columns:1fr}
  .news__more{grid-column:1}

  /* La couverture en 1728 × 947 ne fait plus que 214 px de haut sur un téléphone :
     on repasse en hauteur d'écran, l'image est recadrée par object-fit. */
  .art__cover{aspect-ratio:auto;height:52svh;min-height:280px;max-height:none}

  /* L'article : titre d'abord, navigation en bas de bandeau, sur une ligne. */
  .art__head{grid-template-columns:1fr;row-gap:clamp(1.2rem,4vw,2rem)}
  .art__id{grid-column:1;order:1}
  .art__prev{grid-column:1;order:2;margin-bottom:0}
  .art__next{grid-column:1;order:3;justify-self:start;text-align:left;margin-bottom:0}
  .art__gallery{grid-template-columns:1fr;gap:clamp(10px,2vw,13px)}
  .art__foot{grid-template-columns:1fr}
  .art__foot .cta{grid-column:1}
}

/* Entre 640 et 900 px la grille de cartes tient encore à deux colonnes. */
@media (min-width:640px) and (max-width:900px){
  .news__grid{grid-template-columns:repeat(2, minmax(0,1fr))}
  .art__gallery{grid-template-columns:repeat(2, minmax(0,1fr))}
}


/* ══════════════ MARIE-LOUISE ══════════════
   Un passe-partout de papier posé sur les quatre bords de la fenêtre, sur les
   pages rubrique. Il NE DÉFILE PAS : c'est l'image qui passe derrière, comme
   dans un cadre — d'où le `position:fixed`.

   Un seul nœud plutôt que quatre barres : une bordure sur un `inset:0` fixe.
   L'intérieur d'une bordure est transparent, donc rien à masquer, et aucun
   risque de liseré d'un pixel aux raccords d'angle.

   z-index 78 : AU-DESSUS du contenu, mais SOUS le voile vert du menu (80) —
   quand le menu s'ouvre, le vert doit recouvrir le cadre, pas s'arrêter à lui.

   Tout ce qui est calé sur le bord de la fenêtre (header, pied, compteur,
   largeur de contenu) rentre à l'intérieur du cadre via `--ml`. */
.ml{display:none}
body.has-ml{--ml:calc(var(--gutter) / 3)}   /* 16 px en 1728, dans les 48 de gouttière */
/* ⚠️ ARRONDI AU PIXEL ENTIER — 31/08/2026. La gouttière est fluide, donc le
   tiers tombe souvent sur une fraction (13,33 px en 1440). Un `border` et une
   boîte positionnée n'arrondissent pas une fraction au même endroit : en
   remplaçant le bord par quatre barres, le bord intérieur du cadre se
   déplaçait d'un sous-pixel sur une partie du pourtour. Mesuré — la zone qui
   diffère commençait exactement à `--ml`, et à 3840 px, où le tiers vaut
   16 px pile, il n'y avait AUCUNE différence : la fraction était bien la
   cause. Un cadre calé sur des pixels entiers est de toute façon plus net.
   Sous `@supports` : si `round()` manquait, la propriété deviendrait invalide
   et les barres n'auraient plus d'épaisseur du tout. */
/* ⚠️ ÉPAISSEUR RELEVÉE DANS LE FIGMA : 20 px sur un cadre de 1728, soit
   1,157 vw, soit 1,25 rem — le média y va de x=20 à x=1708 sur 1728 de large.
   Le tiers de gouttière en donnait 16 : le cadre était un cinquième trop
   mince. `min()` fait suivre la largeur en dessous de 1728 et l'échelle de la
   racine au-dessus, comme pour le titre. */
body.has-ml{--ml:min(1.157vw, 1.25rem)}
@supports (width: round(1px, 1px)){
  body.has-ml{--ml:round(min(1.157vw, 1.25rem), 1px)}
}
body.has-ml .ml{display:block;position:fixed;inset:0;z-index:78;pointer-events:none}
/* Les quatre barres. Chacune couvre TOUTE la longueur de son côté : elles se
   recouvrent aux angles, et deux aplats de la même encre superposés donnent le
   même aplat — le cadre est identique, au pixel, à l'ancien `border`.
   `transform-origin` est posé sur le bord extérieur : une barre à `scale 0` est
   donc collée à son côté, et grandit vers l'intérieur. */
body.has-ml .ml i{position:absolute;background:var(--color-bg);display:block}
body.has-ml .ml i:nth-child(1){top:0;left:0;right:0;height:var(--ml);transform-origin:top}
body.has-ml .ml i:nth-child(2){bottom:0;left:0;right:0;height:var(--ml);transform-origin:bottom}
body.has-ml .ml i:nth-child(3){left:0;top:0;bottom:0;width:var(--ml);transform-origin:left}
body.has-ml .ml i:nth-child(4){right:0;top:0;bottom:0;width:var(--ml);transform-origin:right}
/* L'écran d'arrivée est DANS la marie-louise, comme le reste de la page : le film
   est un tirage posé sur le papier, pas une image qui déborde du cadre.
   (Une version « plein bord » a existé : il suffisait de peindre l'écran d'arrivée
   au-dessus du passe-partout — `body.has-ml .page-hero{z-index:79}` — pour que le
   film recouvre le cadre tant qu'il est à l'écran. Une ligne à remettre si on veut
   y revenir.) */

body.has-ml .site-foot{padding-bottom:clamp(2rem,4vh,3rem)}
/* Au-delà de 1632 px de contenu, le wordmark du header doit s'aligner sur la
   colonne de texte, pas rester collé au bord de l'écran : en 2560 il y avait
   386 px d'écart entre le « Here. » du header et le titre du hero. */
.site-head{padding-inline:max(var(--gutter),
                              calc((100% - var(--content-max)) / 2))}
/* le compteur est déjà calé sur la gouttière : il n'a plus rien à compenser */
/* Testé puis écarté : caler le titre du hero sur la gouttière SEULE (parce que son
   image est plein bord) le désalignait du wordmark du header, posé juste au-dessus
   de lui sur la même vidéo — 48 px contre 71. Une seule colonne de texte pour toute
   la page vaut mieux qu'un titre aligné sur une image qui, elle, déborde. Le hero
   garde donc la colonne du cadre ; seule son IMAGE est plein bord. */

/* Le cadre est décoratif : sous `prefers-reduced-motion` il ne bouge pas non
   plus (il est fixe), rien à neutraliser. À l'impression, on le retire. */
@media print{ body.has-ml .ml{display:none} }

/* ── Formulaire de contact : mention RGPD et message d'erreur ────────────────
   La mention est obligatoire dès qu'on collecte des données personnelles. Elle
   est discrète mais lisible : petit corps, encre adoucie, jamais sous 13 px. */
.contact__rgpd{grid-column:1 / -1;margin:.4rem 0 0;font-size:.79rem;line-height:1.55;
  color:var(--color-text-soft, #5A5A52);max-width:62ch}
.contact__rgpd a{color:inherit;text-underline-offset:3px}
.contact__rgpd a:hover{color:var(--color-text)}
.contact__erreur{grid-column:1 / -1;margin:.8rem 0 0;font-size:.86rem;
  border-left:2px solid #A6402E;padding-left:.8rem;color:var(--color-text)}
.contact__erreur a{color:inherit}

/* ── Repère de version ────────────────────────────────────────────────────
   Provisoire : il n'existe que pendant la mise au point, pour distinguer d'un
   coup d'œil la version affichée de celle que le navigateur garde en cache.
   Volontairement effacé — un repère de travail ne doit pas peser dans la
   composition. Il disparaît avec `Site::AFFICHER_VERSION`. */
.site-foot__version{color:var(--color-text-soft);opacity:.55;
  font-variant-numeric:tabular-nums;letter-spacing:var(--ls-label)}
