/* ===========================================================================
   site.css — Le strict complément à la V2.

   styles.css (la V2) porte tout le design : couleurs, hero, sections, cartes,
   menu, footer, animations. Cette feuille-ci NE redéfinit AUCUNE classe de la V2.
   Elle n'ajoute que ce que la maquette n'avait pas : les pages de texte (services,
   articles, à-propos, contact), dans le même langage visuel.

   Chargée après styles.css.
   =========================================================================== */

/* --- Les pages de contenu texte ------------------------------------------

   Une colonne lisible, sous la barre fixe. Reprend les variables de la V2
   (--ink, --muted, --line, --gut, --maxw) pour rester dans la même identité.

   Le bloc se cale sur la grille du site (--maxw, --gut) et c'est son contenu
   qui porte la mesure de lecture. Auparavant le bloc lui-même faisait 760 px
   centrés dans la fenêtre : sur un écran large, le titre de la page était à
   30 px du bord et son texte commençait 300 px plus loin. C'était le
   décalage le plus visible du site, présent sur les 22 pages de texte. */

.page-texte {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--tete-fiche) var(--gut) var(--section-bas);
}
.page-texte > * { max-width: var(--lecture); margin-inline: auto; }
/* Le premier élément du corps ne cumule pas sa marge avec le dégagement du
   bloc : sinon un corps qui commence par un titre décroche du reste. */
.page-texte > :first-child { margin-top: 0; }

/* --- Les images dans le fil du texte ---------------------------------------

   Relevé sur Bungee : une image posée dans un article fait exactement la
   largeur de la colonne de texte, ni plus ni moins, et ses coins sont droits.
   Seule la couverture, en haut de page, prend toute la largeur et porte des
   coins arrondis. Il n'y a pas d'autre format : c'est ce qui donne au fil de
   lecture son calme.

   Écriture dans le markdown, voir build.py :
     ![Ce que montre l'image](/static/images/wojo/03.jpg)
     [[image]]     ← emplacement en attente
*/
.fig { margin: var(--corps) auto; max-width: var(--lecture); }
.fig .cadre {
  position: relative;
  overflow: hidden;
  aspect-ratio: 3 / 2;
  background:
    repeating-linear-gradient(135deg, rgba(26,23,20,.05) 0 2px, transparent 2px 12px),
    #E5DDCD;
}
.fig .cadre img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fig .cadre image-slot { position: absolute; inset: 0; width: 100%; height: 100%; }
.fig figcaption {
  margin-top: 10px;
  font-family: 'DM Mono', monospace;
  font-size: 12px;
  line-height: 1.45;
  color: var(--muted);
}

.page-texte .eyebrow {
  display: block;
  font-family: 'DM Mono', monospace;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 20px;
}

.page-texte h1 {
  font-size: clamp(36px, 4.9vw, 70px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.03em;
  margin: 0 auto max(16px, .46em);
}

.page-texte .chapo {
  font-size: clamp(18px, 1.9vw, 24px);
  line-height: 1.45;
  color: var(--ink-soft);
  margin: 0 auto var(--corps-marge);
  padding-bottom: var(--corps);
  border-bottom: 1px solid var(--line);
}

.page-texte h2 {
  font-size: clamp(19px, 1.5vw, 22px);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: var(--corps-marge) auto max(16px, .4em);
}

.page-texte h3 { font-size: 18px; font-weight: 600; margin: var(--corps) auto max(16px, .4em); }
.page-texte p { font-size: 17.6px; line-height: 26.4px; margin: 0 auto var(--corps); color: var(--ink-soft); }
.page-texte ul, .page-texte ol { margin: 0 auto var(--corps); padding-left: 22px; }
.page-texte li { font-size: 17.6px; line-height: 26.4px; margin-bottom: 6px; color: var(--ink-soft); }
/* Liens du corps de texte (15/09 retour Félix : « on voit pas que c'est cliquable ») :
   soulignés, plus épais au survol. Les liens à classe (boutons, cartes) n'en ont pas. */
.page-texte a:not([class]),
.intro-texte a:not([class]),
.coordonnees p a:not([class]) {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .18em;
  transition: text-decoration-thickness .2s;
}
.page-texte a:not([class]):hover,
.intro-texte a:not([class]):hover,
.coordonnees p a:not([class]):hover { text-decoration-thickness: 2px; }

.page-texte blockquote {
  margin: var(--corps) auto;
  padding: 4px 0 4px 24px;
  border-left: 2px solid var(--ink);
  font-size: clamp(19px, 2vw, 25px);
  line-height: 1.4;
  color: var(--ink);
}
.page-texte blockquote p { font-size: inherit; color: inherit; }

/* La date et la branche d'un article, dans le style monospace de la V2. */
.article-meta {
  font-family: 'DM Mono', monospace;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 18px;
}

/* Le renvoi en bas d'une page service — le maillage interne, absent du site actuel. */
.voir-aussi {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--gut) var(--section-bas);
}
.voir-aussi > * { max-width: var(--lecture); }
.voir-aussi .mono {
  font-family: 'DM Mono', monospace;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.voir-aussi ul { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 10px; }
.voir-aussi a { color: var(--ink); text-decoration: none; font-size: 18px; font-weight: 600; }
.voir-aussi a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* --- Une grille de cartes pour les listes (services, journal, réalisations) --

   Réutilise le vocabulaire de la V2 (arches, frames) mais en version liste :
   des vignettes cliquables sur toute la largeur. */

.liste-page {
  padding: var(--tete-liste) var(--gut) 0;
  max-width: var(--maxw);
  margin: 0 auto;
}
/* Une liste qui suit déjà une entrée de page n'a pas à reprendre le
   dégagement du haut : les gabarits le posaient en style en dur. */
.blog-hero + .liste-page { padding-top: 0; }
.articles + .liste-page,
.une + .liste-page { padding-top: var(--section-bas); }
/* Les lignes gardent un fort dégagement quand elles ferment la page ; suivies
   de l'index, leur bas s'ajoutait au haut de l'index et creusait un trou. */
.articles:has(+ .liste-page) { padding-bottom: 0; }
.liste-intro { max-width: var(--lecture); padding: 0 0 var(--items); }

.grille-cartes {
  display: grid;
  gap: var(--items) var(--grille);
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}

.carte {
  display: block;
  text-decoration: none;
  color: inherit;
}
.carte .frame {
  aspect-ratio: 4 / 3;
  background: var(--bg-2);
  border-radius: 14px;
  overflow: hidden;
  margin-bottom: 12px;
}
.carte h2, .carte h3 {
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.015em;
  margin: 0 0 8px;
}
.carte p { font-size: 15px; line-height: 1.55; color: var(--muted); margin: 0; }
.carte .tag {
  display: inline-block;
  margin-top: 8px;
  font-family: 'DM Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --- Le pied ajouté (services) ------------------------------------------- */

.footnav-services { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.footnav-services a {
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 15px;
  width: fit-content;
}
.footnav-services a:hover { text-decoration: underline; text-underline-offset: 3px; }
/* Les services du pied sur deux colonnes (15/09), lus colonne par colonne. */
.news-block .footnav-services { display: block; columns: 2; column-gap: 40px; }
.news-block .footnav-services a { display: block; break-inside: avoid; margin-bottom: 8px; }

/* --- Rien ne dépasse de l'écran ------------------------------------------ */
html, body { max-width: 100%; overflow-x: hidden; }
/* `hidden` sur html et body fait de body un conteneur de défilement, ce qui
   neutralise tout position: sticky (l'en-tête des fiches réalisation).
   `clip` coupe le débordement de la même façon sans créer ce conteneur. */
@supports (overflow: clip) {
  html, body { overflow-x: clip; }
}
img, video { max-width: 100%; height: auto; }

/* Le footer V2 : ses liens en ligne dépassent dès 500 px de large (mesuré :
   478 px de liens pour 470 px disponibles). Le repli était conditionné à
   480 px, donc il ne se déclenchait jamais dans la plage où le problème se
   produit. Sans condition : une liste de liens passe à la ligne quand elle
   n'a plus la place, quelle que soit la largeur de l'écran. */
.footnav { flex-wrap: wrap; gap: 12px 32px; }

/* Le titre d'une page liste : un vrai H1 (pour le SEO), mais à l'allure des titres
   de section de la V2 (.shead h2). On reprend ses propriétés exactes. */
/* Le point qui ferme les grands titres de liste, en gris : c'est une marque de
   la maquette, pas une couleur à recopier dans chaque gabarit. */
.point { color: var(--muted); }

/* L'intitulé du formulaire de contact et le message des listes vides : deux
   réglages qui vivaient en attribut `style`. */
.formulaire h2 { margin: 0 0 max(16px, .4em); }
.liste-vide { padding: 0; color: var(--muted); }

.shead .shead-h1 {
  font-size: var(--h2); /* 15/09 retour Félix : titres réduits */
  line-height: 0.95;
  font-weight: 600;
  letter-spacing: -0.035em;
  margin: 0;
}

/* ===========================================================================
   Pages intérieures façon Bungee — dans le langage de la V2.

   Chaque composant ci-dessous transpose une structure du template Bungee
   (bungee.framer.website) avec les variables et le vocabulaire de la V2 :
   --line pour les filets, DM Mono pour les métadonnées, Hanken Grotesk pour
   les titres, data-reveal pour l'apparition au scroll.
   =========================================================================== */

/* --- Le badge « texte provisoire » ----------------------------------------
   Posé sur toute page dont le texte n'est pas encore celui de Félix. */
.provisoire-note {
  display: inline-block;
  font-family: 'DM Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px dashed var(--muted-2);
  border-radius: 8px;
  padding: 7px 13px;
  margin-top: var(--corps);
}

/* --- L'entrée de page (H1 énorme, façon « Projects. ») --------------------
   .blog-hero (styles.css) porte déjà la taille ; on ajoute le wrap.

   Le petit intitulé entre parenthèses précède le titre sur toutes les entrées
   de page. Son écart au titre était posé au cas par cas dans les gabarits, en
   style en dur, avec trois valeurs pour la même intention. Il est ici, une
   fois. */
.blog-hero .mono,
.fiche-hero .mono,
.projet-tete .mono,
.contact-hero .mono,
.manifeste .mono { display: block; margin-bottom: 18px; }
.manifeste .mono { margin-bottom: 20px; }

/* --- La liste plein écran (façon /projects de Bungee) ---------------------- */
.index-liste { border-top: 1px solid var(--line); }
.index-item {
  display: grid;
  grid-template-columns: 74px 1fr auto clamp(96px, 11vw, 170px);
  /* Sur la ligne de base du titre, pas au milieu de la ligne. Centrés, le
     numéro et le tag tombaient à mi-hauteur du bloc titre + description,
     c'est-à-dire nulle part : ils flottaient entre deux textes au lieu de se
     poser sur l'un d'eux. La vignette, elle, n'a pas de ligne de base. */
  align-items: baseline;
  gap: clamp(16px, 3vw, 44px);
  padding: calc(var(--items) / 2) 0;
  border-bottom: 1px solid var(--line);
}
.index-item .thumb { align-self: start; }
.index-item .num {
  font-family: 'DM Mono', monospace;
  font-size: 13px;
  letter-spacing: 0.05em;
  color: var(--muted);
  white-space: nowrap;
}
.index-item .index-titre h2, .index-item .index-titre h3 {
  margin: 0;
  /* 15/09 retour Félix : titres réduits. Sous le titre de page (80 px), les
     entrées de liste ne doivent plus lui disputer la taille. */
  font-size: clamp(24px, 3.35vw, 48px);
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.02;
  transition: transform 0.4s var(--ease);
}
.index-item:hover .index-titre h2, .index-item:hover .index-titre h3 { transform: translateX(12px); }
.index-item .index-titre p {
  margin: 8px 0 0;
  font-size: 15px;
  line-height: 1.5;
  color: var(--muted);
  max-width: 52ch;
}
/* 15/09 retour Félix : les rôles d'une réalisation, à l'allure du tag des cartes. */
.index-item .index-titre p.index-roles {
  margin-top: 10px;
  max-width: none;
  font-family: 'DM Mono', monospace;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.index-item .tag {
  font-family: 'DM Mono', monospace;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}
.index-item .thumb {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: 12px;
  overflow: hidden;
  background:
    repeating-linear-gradient(135deg, rgba(26,23,20,.05) 0 2px, transparent 2px 12px),
    #E5DDCD;
  transition: transform 0.5s var(--ease);
}
.index-item:hover .thumb { transform: scale(1.04); }
.index-item .thumb image-slot { position: absolute; inset: 0; width: 100%; height: 100%; }

@media (max-width: 760px) {
  .index-item { grid-template-columns: 1fr clamp(96px, 26vw, 140px); }
  .index-item .num, .index-item .tag { display: none; }
}

/* --- La fiche (façon page projet de Bungee) --------------------------------
   Sert aux pages service, aux réalisations et aux pages locales. */
/* L'entrée de fiche, sur le modèle de Bungee : un bloc de 900 px centré dans
   la page, dont le contenu est aligné à gauche. Le bloc est centré, le texte
   ne l'est pas. C'est ce qui donne un axe unique du haut en bas de la page
   sans jamais centrer une ligne de texte, qui se lit mal.

   Mesures relevées sur la page de référence, à 1440 px de large : titre à
   70 px sur un interligne de 70, graisse 500, et une ligne de métadonnées en
   mono de 14 px juste au-dessus. */
.fiche-hero {
  max-width: calc(var(--titre) + var(--gut) * 2);
  margin: 0 auto;
  padding: var(--tete-fiche) var(--gut) 0;
}
.fiche-hero h1, .projet-tete h1 {
  margin: 0;
  font-size: clamp(36px, 4.9vw, 70px);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1;
}
.fiche-chapo {
  max-width: 58ch;
  margin: var(--corps) 0 0;
  font-size: clamp(17px, 1.35vw, 20px);
  line-height: 1.5;
  color: var(--ink-soft);
}
/* La ligne de métadonnées au-dessus du titre, à la place de la date de la
   référence. Même graisse, même taille, même rôle : situer avant de nommer. */
.fiche-date {
  font-family: 'DM Mono', monospace;
  font-size: 14px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 16px;
}

/* La couverture, seul bloc à prendre toute la largeur. Coins à 32 px, la
   mesure relevée sur la référence : c'est le seul endroit du site où l'arrondi
   est aussi marqué, et c'est ce qui le distingue des images du corps. */
.couverture {
  max-width: var(--maxw);
  margin: var(--corps-marge) auto 0;
  padding-inline: var(--gut);
}
.couverture .fiche-frame { border-radius: 32px; }

/* Les repères du projet, dans la colonne de texte, juste avant le récit. */
.fiche-meta {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--corps);
  border-bottom: 1px solid var(--line);
  padding: 0 0 var(--corps);
  margin: 0 auto var(--corps-marge);
}
.fiche-meta .k, .projet-infos .k {
  font-family: 'DM Mono', monospace;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}
.fiche-meta .v, .projet-infos .v { font-size: 16px; font-weight: 600; line-height: 1.35; }
.fiche-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--r-lg);
  overflow: hidden;
  background:
    repeating-linear-gradient(135deg, rgba(26,23,20,.05) 0 2px, transparent 2px 12px),
    #E5DDCD;
}
.fiche-frame image-slot { position: absolute; inset: 0; width: 100%; height: 100%; }

/* Précédent / Suivant : deux pastilles centrées sous la colonne. Mesures de la
   référence : hauteur 56, coins à 12, 24 px de retrait horizontal, texte à
   17,6 px en graisse 500, et 18 px entre les deux. */
.pagination {
  max-width: calc(var(--lecture) + var(--gut) * 2);
  margin: 0 auto;
  padding: 64px var(--gut) 0;
  display: flex;
  justify-content: center;
  gap: var(--corps);
  flex-wrap: wrap;
}
.pagination a {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 56px;
  padding: 0 24px;
  border-radius: 12px;
  background: var(--card);
  border: 1px solid var(--line);
  font-size: 17.6px;
  font-weight: 500;
  color: var(--ink);
  max-width: 46%;
  transition: background 0.25s, border-color 0.25s;
}
.pagination a:hover { background: #fff; border-color: var(--muted-2); }
.pagination .sens { color: var(--muted); }
@media (max-width: 560px) {
  .pagination a { max-width: 100%; width: 100%; justify-content: center; }
}

/* Le renvoi vers le film complet, sous la bande-annonce. */
.autres-videos {
  margin: 18px 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 26px;
  justify-content: center;
}
.autres-videos a {
  font-family: 'DM Mono', monospace;
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
  padding-bottom: 3px;
  transition: color 0.25s, border-color 0.25s;
}
.autres-videos a:hover { color: var(--ink); border-color: var(--ink); }

/* Le corps d'une fiche reprend la colonne de texte, sans le grand dégagement
   du haut (le hero de la fiche l'a déjà pris). */
/* ---- Le rythme vertical, une règle -----------------------------------------

   L'écart entre deux blocs appartient au bloc du dessous. Un bloc ne pose donc
   rien sous lui, sauf s'il est le dernier avant le pied de page.

   C'est la correction de fond du calage : chaque section portait jusqu'ici son
   écart en haut et en bas, si bien que tout intervalle entre deux blocs valait
   la somme des deux. Sur /a-propos, le manifeste et les chiffres étaient
   séparés de 216 px, les chiffres et le texte de 206 px, sans que personne
   n'ait demandé un tel vide : il était le produit d'une addition. */
.page-texte.fiche-corps { padding-top: var(--corps-marge); padding-bottom: 0; }
.page-texte.corps-article { padding-top: var(--corps-marge); padding-bottom: 0; }

/* « Autres services. » / « Autres réalisations. » */
.fiche-suite { max-width: var(--maxw); margin: 0 auto; padding: var(--section-bas) var(--gut) 0; }
/* Trois cartes, plus petites (Félix, 13/09). Sous 900 px, la règle commune
   de `.proj-grid` repasse à une colonne. La grille de l'accueil garde ses deux. */
@media (min-width: 901px) {
  .fiche-suite .proj-grid { grid-template-columns: repeat(3, 1fr); }
}

/* Le grand appel final (façon « Have a project in mind? »).
   Il tenait un écran entier à lui seul : dégagement fort en haut et en bas,
   plus un titre à 110 px. Ramené à une bande basse — même largeur, même
   centrage, mais on voit le pied de page arriver derrière. */
/* Bungee, calque CTA Variant 1 : 96 px dessus-dessous et 48 px avant le lien, aux trois tailles. */
.cta-fin {
  text-align: center;
  padding: var(--cta) var(--gut);
}
/* L'appel porte seul l'écart qui le précède. Sans cette règle, la section
   d'avant y ajoutait le sien et les deux blocs se retrouvaient séparés de
   trois cents pixels de vide, sur presque toutes les pages du site. */
.liste-page:has(+ .cta-fin),
.fiche-suite:has(+ .cta-fin),
.stats:has(+ .cta-fin),
.article-nav:has(+ .cta-fin),
.page-texte:has(+ .cta-fin) { padding-bottom: 0; }
.cta-fin .mono { display: block; margin-bottom: 16px; }
.cta-fin h2 {
  margin: 0 auto;
  max-width: 14ch;
  font-size: var(--h2); /* 15/09 retour Félix : titres réduits */
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 0.95;
}
.cta-fin p { margin: var(--corps) auto 0; max-width: 44ch; color: var(--ink-soft); font-size: 17px; }
.lien-souligne {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-top: 48px;
  font-size: 18px;
  font-weight: 500;
  padding-bottom: 5px;
  border-bottom: 1.5px solid var(--ink);
  transition: gap 0.3s var(--ease);
}
.lien-souligne:hover { gap: 16px; }
.lien-souligne .pl { position: relative; width: 15px; height: 15px; }
.lien-souligne .pl::before, .lien-souligne .pl::after { content: ''; position: absolute; inset: 0; margin: auto; background: var(--ink); }
.lien-souligne .pl::before { width: 100%; height: 1.6px; }
.lien-souligne .pl::after { width: 1.6px; height: 100%; }

@media (max-width: 760px) {
  .fiche-meta { grid-template-columns: 1fr 1fr; }
}

/* --- La une du journal (façon page blog de Bungee) -------------------------
   Trois articles en tête : le premier en encart sur toute la largeur, les deux
   suivants côte à côte. L'encart large est volontairement bas de plafond — une
   image en 21/8 tient dans l'écran avec son titre, là où le 4/3 des lignes
   pousse le reste de la page sous la ligne de flottaison. */
/* L'entrée de page garde sa taille ailleurs (liste des services, des
   réalisations) ; ici elle se resserre pour que l'encart de la une entre dans
   le premier écran avec son titre. */
.blog-hero:has(+ .une) { padding-bottom: var(--items); }
/* 15/09 retour Félix : titres réduits. Le titre du journal reprend la taille
   commune des entrées de page (--h1-page), plus petite que l'ancien resserrement. */

.une { padding: 0 0 var(--section-bas); }
.une-grille {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--items) var(--cartes-journal);
}
.carte { display: block; }
.carte .frame { aspect-ratio: 3 / 2; border-radius: var(--r-lg); overflow: hidden; }
.carte .frame image-slot { transition: transform 0.9s var(--ease); }
.carte:hover .frame image-slot { transform: scale(1.03); }
.carte-corps { padding-top: 16px; }
.carte-corps .meta { display: flex; gap: 14px; align-items: center; margin-bottom: 8px; }
.carte-corps h2 {
  margin: 0;
  font-size: clamp(21px, 1.9vw, 31px);
  font-weight: 600;
  letter-spacing: -0.022em;
  line-height: 1.1;
  text-wrap: pretty;
}
.carte-resume { padding-top: 8px; }
.carte-corps p {
  margin: 0;
  color: var(--ink-soft);
  font-size: 17px;
  line-height: 1.5;
  max-width: 52ch;
}
.carte .read {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-top: 16px;
  font-size: 16px;
  border-bottom: 1.5px solid var(--ink);
  padding-bottom: 4px;
  transition: gap 0.3s var(--ease);
}
.carte:hover .read { gap: 16px; }

/* L'encart pleine largeur. Le corps passe en deux colonnes : le titre tient la
   gauche, le résumé et le lien la droite. Empilés, ils ajoutaient cent pixels
   de hauteur à un bloc dont tout l'intérêt est d'être large et court. */
.carte-large { grid-column: 1 / -1; }
.carte-large .frame { aspect-ratio: 21 / 8; }
.carte-large .carte-corps {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: var(--grille);
  align-items: end;
  padding-top: 20px;
}
.carte-large .carte-corps h2 { font-size: clamp(28px, 3.2vw, 54px); letter-spacing: -0.032em; line-height: 1.02; }
.carte-large .carte-corps p { max-width: 46ch; }
.carte-large .carte-resume { padding-top: 0; padding-bottom: 5px; }
.carte-large .read { margin-top: 16px; }

@media (max-width: 900px) {
  .une-grille { grid-template-columns: 1fr; }
  .carte-large .frame { aspect-ratio: 16 / 9; }
  .carte-large .carte-corps { grid-template-columns: 1fr; gap: 12px; align-items: start; }
  .carte-large .carte-resume { padding-bottom: 0; }
}

/* --- Le journal (façon « Creative Dispatch ») ------------------------------
   La suite des vedettes réutilise .articles/.article de la V2. En dessous,
   l'index complet des titres, groupé par branche. */
.branche-bloc { border-top: 1px solid var(--line); padding: var(--items) 0 0; }
.branche-bloc > .mono { display: block; }
.titres-liste { list-style: none; margin: 16px 0 0; padding: 0; }
.titres-liste a {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  padding: 15px 4px;
  border-bottom: 1px solid var(--line-soft);
  font-size: clamp(18px, 1.7vw, 25px);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
  transition: padding-left 0.3s var(--ease), color 0.3s;
}
.titres-liste a:hover { padding-left: 14px; }
.titres-liste .etat {
  font-family: 'DM Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

/* --- L'article (façon page blog de Bungee) --------------------------------- */
/* Même bloc de titre que les fiches : 900 px centrés, contenu aligné à gauche. */
.article-hero {
  max-width: calc(var(--titre) + var(--gut) * 2);
  margin: 0 auto;
  padding: var(--tete-fiche) var(--gut) 0;
}
.article-hero .article-meta { margin-bottom: 18px; font-size: 14px; }
.article-hero h1 {
  margin: 0;
  font-size: clamp(36px, 4.9vw, 70px);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1;
  text-wrap: pretty;
}
.article-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background:
    repeating-linear-gradient(135deg, rgba(26,23,20,.05) 0 2px, transparent 2px 12px),
    #E5DDCD;
}
.article-frame image-slot { position: absolute; inset: 0; width: 100%; height: 100%; }

.article-nav {
  max-width: calc(var(--large) + var(--gut) * 2);
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  gap: var(--corps);
  border-top: 1px solid var(--line);
  padding: 20px var(--gut) 0;
}
.article-nav a { display: block; max-width: 44%; }
.article-nav a.suivant { text-align: right; margin-left: auto; }
.article-nav .sens {
  font-family: 'DM Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  display: block;
  margin-bottom: 8px;
}
.article-nav .titre { font-size: clamp(16px, 1.4vw, 21px); font-weight: 600; letter-spacing: -0.015em; line-height: 1.2; }
.article-nav a:hover .titre { text-decoration: underline; text-underline-offset: 3px; }

/* --- À propos (façon /about : le manifeste plein écran) -------------------- */
.manifeste {
  max-width: var(--maxw);
  margin: 0 auto;
  text-align: center;
  padding: var(--tete-page) var(--gut) 0;
}
.manifeste h1 {
  margin: 0 auto max(16px, .46em);
  font-size: var(--h1-page); /* 15/09 retour Félix : titres réduits */
  font-weight: 600;
  letter-spacing: -0.038em;
  line-height: 0.95;
  max-width: 16ch;
}
.manifeste .manifeste-lead {
  margin: 0 auto;
  max-width: 40ch;
  font-size: clamp(19px, 1.7vw, 24px); /* accroche : 24 px comme celle de l'accueil */
  line-height: 1.35;
  letter-spacing: -0.01em;
  font-weight: 500;
}
.manifeste .manifeste-lead em { font-style: normal; color: var(--muted); }

/* --- Contact ---------------------------------------------------------------- */
.contact-hero {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--tete-page) var(--gut) 0;
}
.contact-hero h1 {
  margin: 0;
  max-width: 15ch;
  font-size: var(--h1-page); /* 15/09 retour Félix : titres réduits */
  font-weight: 600;
  letter-spacing: -0.038em;
  line-height: 0.96;
}
.contact-grid {
  max-width: var(--maxw);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr 1.1fr;
  gap: var(--grille);
  align-items: start;
  padding: var(--corps-marge) var(--gut) 0;
}
/* 15/09 retour Félix : le paragraphe prend la taille des champs du formulaire (18 px). */
.coordonnees p { margin: 0 0 16px; font-size: 18px; line-height: 1.7; color: var(--ink-soft); max-width: 46ch; }
.coordonnees .email-grand {
  display: inline-block;
  margin: 16px 0 var(--corps);
  font-size: clamp(22px, 2.3vw, 36px);
  font-weight: 500;
  letter-spacing: -0.02em;
  border-bottom: 2px solid var(--ink);
  padding-bottom: 5px;
  transition: opacity 0.25s;
}
.coordonnees .email-grand:hover { opacity: 0.6; }
.coordonnees .detail { font-family: 'DM Mono', monospace; font-size: 13px; letter-spacing: 0.04em; color: var(--muted); margin: 0 0 8px; }
.form-note { margin-top: 14px; }

/* La confirmation d'envoi du formulaire de contact (Félix, 16/09/2026) : pas de
   page de remerciement, le texte prend la place du formulaire, à la même taille
   que la colonne de gauche. `app.js` pose `.envoye` sur le formulaire, ce qui
   masque tout sauf ce paragraphe ; en cas d'échec, le message s'affiche au-dessus
   et le formulaire reste rempli. Le focus s'y pose : pas de contour, c'est un
   message, pas une commande. */
.form-etat { margin: 0 0 var(--corps); font-size: 18px; line-height: 1.7; color: var(--ink-soft); max-width: 46ch; }
.form-etat:focus { outline: none; }
.form-etat.erreur { color: var(--ink); border-left: 2px solid var(--ink); padding-left: 14px; }
.formulaire.envoye > *:not(.form-etat) { display: none; }
.formulaire.envoye .form-etat { margin: 0; }

.field textarea {
  width: 100%;
  background: none;
  border: none;
  border-bottom: 1px solid var(--line);
  padding: 14px 2px;
  font-family: inherit;
  font-size: 18px;
  color: var(--ink);
  min-height: 120px;
  resize: vertical;
  transition: border-color 0.3s;
}
.field textarea::placeholder { color: var(--muted); }
.field textarea:focus { outline: none; border-color: var(--ink); }

@media (max-width: 900px) {
  .contact-grid { grid-template-columns: 1fr; gap: var(--items); }
  .article-nav a { max-width: 100%; }
}

/* ---- Lecteur vidéo à façade -------------------------------------------------
   La vignette YouTube s'affiche seule ; l'iframe n'est injectée qu'au clic
   (voir app.js). Une iframe YouTube chargée d'emblée coûte près d'un mégaoctet
   et plusieurs requêtes tierces, payés même par ceux qui ne lancent jamais la
   vidéo. Le bouton reprend celui du showreel de la maquette. */
.fiche-frame.lecteur{ position:relative; cursor:pointer; overflow:hidden; }
.fiche-frame.lecteur img{ width:100%; height:100%; object-fit:cover; display:block; }
.fiche-frame.lecteur .play{
  position:absolute; inset:0; margin:auto;
  width:clamp(64px,7vw,96px); height:clamp(64px,7vw,96px);
  border:0; border-radius:50%; cursor:pointer;
  background:var(--paper,#F5F1EA); box-shadow:0 8px 40px rgba(0,0,0,.28);
  transition:transform .35s var(--ease,cubic-bezier(.2,.7,.2,1));
}
.fiche-frame.lecteur .play::after{
  content:''; position:absolute; inset:0; margin:auto;
  width:0; height:0; border-style:solid; border-width:13px 0 13px 21px;
  border-color:transparent transparent transparent var(--ink,#1A1714);
  transform:translateX(3px);
}
.fiche-frame.lecteur:hover .play{ transform:scale(1.09); }
.fiche-frame.lecteur iframe{ width:100%; height:100%; border:0; display:block; }
/* Le showreel de l'accueil, même façade (reel_video, 16/09/2026). */
.reel-frame.lecteur{ cursor:pointer; }
.reel-frame.lecteur iframe{ position:absolute; inset:0; width:100%; height:100%; border:0; display:block; }

/* ---- Fil d'Ariane -----------------------------------------------------------
   Le fil d'Ariane prend la place du dégagement de tête : barre + 16 px, puis
   24 px (16 en mobile) jusqu'au titre, l'écart de Bungee entre ses blocs
   d'en-tête. */
.fil{
  padding-top: calc(var(--barre) + 16px);
  font-size:13px; letter-spacing:.02em;
}
.fil + .projet,
.fil + .fiche-hero,
.fil + .manifeste,
.fil + .contact-hero,
.fil + .article-hero,
.fil + .blog-hero,
.fil + .page-texte{ padding-top: var(--corps); }
.fil ol{ display:flex; flex-wrap:wrap; gap:8px; list-style:none; margin:0; padding:0; }
.fil li + li::before{ content:'/'; margin-right:8px; opacity:.4; }
.fil a{ color:var(--muted,#7A736B); text-decoration:none; }
.fil a:hover{ color:var(--ink,#1A1714); }
.fil [aria-current]{ color:var(--muted,#7A736B); opacity:.7; }

/* ---- Liens de pied de page supplémentaires ---------------------------------- */
/* Le bloc `.footer-plus` (réalisations et derniers articles) est retiré du pied
   le 15/09 : Félix le trouvait fouillis. */

/* ── La fiche de faits de /a-propos ──────────────────────────────────────────
   Une liste de définitions, pas un tableau : la relation clé-valeur est portée
   par le balisage, ce qui la rend lisible par un lecteur d'écran comme par un
   modèle de langage qui vient chercher un fait précis.
   La grille passe à une colonne en dessous de 620 px, où deux colonnes
   couperaient les valeurs longues en colonnes de deux mots. */
.faits {
  max-width: calc(var(--lecture) + var(--gut) * 2);
  margin: 0 auto;
  padding: var(--corps-marge) var(--gut) 0;
}
.faits-boite {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 40px;
}
.faits h2 {
  margin: 0 0 max(16px, .4em);
  font-size: clamp(19px, 1.5vw, 22px);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.faits dl { margin: 0; display: grid; gap: 16px; }
.fait {
  display: grid;
  grid-template-columns: minmax(140px, 200px) 1fr;
  gap: 8px 24px;
  align-items: baseline;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
}
.fait:last-child { padding-bottom: 0; border-bottom: 0; }
.faits dt {
  font-family: 'DM Mono', monospace;
  font-size: 13px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--muted);
}
.faits dd {
  margin: 0;
  font-size: 16px;
  line-height: 24px;
  color: var(--ink-soft);
}
@media (max-width: 620px) {
  .fait { grid-template-columns: 1fr; gap: 4px; }
}

/* L'écart entre deux blocs appartient au bloc du dessous : sans cela, la fiche
   de faits et l'appel final additionnent leurs marges. */
.faits:has(+ .cta-fin) { padding-bottom: 0; }
.page-texte:has(+ .faits) { padding-bottom: 0; }

/* ---- Les images, une fois `image-slot` retiré ------------------------------
   Le 10 septembre 2026, les gabarits ont cessé de poser `<image-slot>` : ce
   composant ne produit aucune balise `<img>`, donc Google ne voyait aucune
   image ni aucun `alt` sur tout le site, et hors du runtime de la maquette il
   ne dessinait qu'un cadre marqué « + Ajouter ».

   Tout le CSS de la maquette visait `image-slot`. Ces règles sont la
   transposition exacte de celles-là, sélecteur pour sélecteur, plus les deux
   propriétés que le composant portait en interne et qu'une balise `<img>`
   attend qu'on lui donne : `object-fit` et `display`.

   En production, il n'y a pas d'emplacement vide : sans image, le gabarit ne
   rend pas le cadre du tout. Seul l'aperçu (`build.py --tout`) en dessine un,
   `.photo-vide`, stylé en fin de fichier. */

.strip .arch img,
.intro-strip .bud img,
.proj .frame img,
.post .frame img,
.article .frame img,
.carte .frame img,
.testi-photo img,
.reel-frame img,
.fig .cadre img,
.index-item .thumb img,
.fiche-frame img,
.article-frame img,
.boucle {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.strip .arch img { border-radius: inherit; }

/* Le léger zoom au survol, repris de la maquette. */
.proj .frame img,
.post .frame img,
.article .frame img,
.carte .frame img { transition: transform .9s var(--ease); }
/* 15/09 retour Félix (saccade) : sans will-change, l'image ne recevait son
   calque qu'au début du zoom et le perdait à la fin, repeinte d'un coup à
   l'échelle finale (à-coup visible). Calque permanent sur les cartes de
   l'accueil et du bas des fiches, zoom plus court. */
.proj .frame img,
.post .frame img { transition: transform .6s cubic-bezier(.22,.61,.36,1); will-change: transform; }

.proj:hover .frame img,
.post:hover .frame img { transform: scale(1.04); }

.article:hover .frame img,
.carte:hover .frame img { transform: scale(1.03); }

/* ---- L'emplacement vide, dans l'aperçu seulement ---------------------------
   Posé par la macro `vide()` de `_visuel.html` quand `build.py --tout` construit
   une page dont l'image manque. Il remplit son cadre, qui garde la forme fixée
   plus haut, et reprend la teinte rayée de la maquette. Le mot « photo » dit
   que la place attend une image et non qu'une image n'a pas chargé. */
.photo-vide {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: inherit;
  background:
    repeating-linear-gradient(135deg, rgba(26,23,20,.05) 0 2px, transparent 2px 12px),
    #E5DDCD;
}
.photo-vide::after {
  content: "photo";
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 11px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(26,23,20,.4);
}

/* --- Fiche projet (façon /projects/asterisk de Bungee) ----------------------
   Relevé du 12 septembre 2026 (docs/superpowers/specs/mesures_bungee/asterisk/) :
   calque Container en ligne, 452 px pour Header, 72 px d'écart, 64 px sous la
   grille ; Header collant, 32 px sous le titre, 40 px avant la liste, lignes
   de 12 px d'écart et 20 px de fond ; Case Study Text à 56 px sous le film.
   Sous 1200 px, une colonne, et l'en-tête reprend sa place dans le flux. */
.projet {
  display: grid;
  grid-template-columns: 452px minmax(0, 1fr);
  gap: 72px;
  align-items: start;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--corps) var(--gut) 64px;
}
.projet-tete {
  position: sticky;
  top: calc(var(--barre) + var(--corps));
}
.projet-tete h1 { margin: 0 0 max(16px, .46em); }
.projet-tete .fiche-chapo { max-width: 410px; margin: 0; }
.projet-infos {
  display: grid;
  gap: 12px;
  margin: 40px 0 0;
}
.projet-infos > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--corps);
  padding: 0 0 20px;
  border-bottom: 1px solid var(--line);
}
.projet-infos dt, .projet-infos dd { margin: 0; }
.projet-infos .k { margin-bottom: 0; }
.projet-infos .v { text-align: right; }
.projet-tete .autres-videos { margin: var(--corps) 0 0; }
.projet-recit { min-width: 0; }
.projet-recit .page-texte.fiche-corps {
  max-width: none;
  margin: 0;
  padding: var(--corps-marge) 0 0;
}
.projet-recit .page-texte > * { margin-inline: 0; }

/* La couverture a le format et la largeur des photos du récit : 3/2, sur la
   colonne de lecture. Un film garde son 16/9 à la même largeur, il est juste
   moins haut. Toutes les photos de la fiche ont un arrondi très léger
   (demande de Félix, 13 septembre 2026). */
.projet-recit > .fiche-frame {
  aspect-ratio: 3 / 2;
  max-width: var(--lecture);
  border-radius: 6px;
}
.projet-recit > .fiche-frame.lecteur { aspect-ratio: 16 / 9; }
.projet-recit .fig .cadre { border-radius: 6px; }

@media (max-width: 1199px) {
  .projet {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--corps-marge);
  }
  .projet-tete { position: static; }
  .projet-infos { margin-top: var(--corps); }
}
@media (max-width: 809px) {
  .projet-infos > div { padding: 8px 0; }
}

/* Protection des photos (13/09/2026) : ni glisser-déposer hors de la page, ni menu
   « Enregistrer l'image » à l'appui long sur mobile. Une capture d'écran reste
   possible : la vraie protection est le filigrane des fichiers publiés. */
img, video { -webkit-user-drag: none; -webkit-touch-callout: none; user-select: none; }
