/* ================================================================
   Thiebaut & Ruchet — light theme, Pompéi signature
   Fonts : Instrument Serif (display), Geist (sans), Geist Mono
   Couleur signature : rouge vermeil #9B2915 (Pompéi)
   Architecture : variance section par section, full-bleed sélectif,
   esperluette rouge italique = signe de marque récurrent
   ================================================================ */

/* ---------- Fonts self-hosted (anti-FOUT) ---------- */
/* Les WOFF2 sont sous theme/fonts/, sous-range latin uniquement
   (~73 Ko total) — couvre tous les accents français, ligatures œ,
   ponctuation U+2000-206F. Plus de requête vers fonts.googleapis.com,
   donc plus de cascade bloquante et plus de font-swap visible passé
   le premier chargement. font-display: swap est conservé : au tout
   premier visiteur avec cache vide, le texte apparaît en Georgia /
   system-ui pendant ~50-100 ms avant swap — négligeable vs. avant
   (la cascade Google faisait 300-600 ms). Les <link rel="preload">
   dans index.html s'assurent que les trois fichiers critiques
   (serif regular, sans regular, mono regular) démarrent leur
   téléchargement avec le HTML. */
@font-face {
  font-family: 'Instrument Serif';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('theme/fonts/instrumentserif-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Instrument Serif';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('theme/fonts/instrumentserif-400italic.woff2') format('woff2');
}
@font-face {
  /* Geist est une variable font : le même WOFF2 sert 400 et 500
     via l'axe wght — le navigateur pick le bon hint. */
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url('theme/fonts/geist-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('theme/fonts/geistmono-400.woff2') format('woff2');
}

/* ---------- Variables structurelles (indépendantes du thème) ---------- */
:root {
  --serif: "Instrument Serif", Georgia, serif;
  --sans: "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --measure: 64ch;
  --pad-x: clamp(1.5rem, 5vw, 5rem);
  --container: 1280px;

  /* Header — identité marque constante à travers palettes.
     Fond rouge Pompéi (#9B2915), la couleur de l'icône du site : le header
     reste visuellement ancré sur la signature rouge quel que soit le thème
     actif (jour, nuit, teal, engine-astres). Wordmark + nav + pill outline
     en blanc pur pour un contraste typographique propre. */
  --header-bg: #9B2915;
  --header-fg: #FFFFFF;
}

/* ---------- Thèmes (palettes) ------------------------------------------
   Chaque palette est une classe sur <body>. Elle pilote couleurs texte,
   fond, accents, et les tints spécifiques aux éléments « verre », header
   scrolled, grain et curseur. Pour ajouter une palette : ajouter un bloc
   ici + l'entrée correspondante dans theme/themes.js. */

/* Jour — blanc + rouge Pompéi (palette d'origine) */
body.theme-jour {
  --rouge: #9B2915;
  --rouge-2: #C4502E;
  --ocre: #E8A24B;
  --terre: #6E2A1A;

  --fg: #14110F;
  --bg: #FFFFFF;
  --muted: #6B6B6B;
  --rule: #E6E3DE;

  /* Hairline signature — rouge Pompéi à 22% d'opacité pour segmenter
     les sections blanches entre elles. Signe chromatiquement la palette
     au lieu d'un filet anthracite neutre qui disparaîtrait. */
  --hairline: rgba(155, 41, 21, 0.22);

  /* Dalles verre (mêmes params HUD que le prototype) */
  --verre-bg:            rgba(250, 248, 244, 0.20);
  --verre-border:        rgba(20, 17, 15, 0.06);
  --verre-bevel-top:     rgba(255, 255, 255, 0.55);
  --verre-bevel-bottom:  rgba(20, 17, 15, 0.06);

  /* Grain désactivé en palette claire — incompatible avec l'objectif
     blanc uniforme des cabinets élite (aucun d'eux n'a de grain sur fond
     clair). On conserve les tokens pour que .grain reste fonctionnel si
     on le réactive, mais l'opacité est à 0. */
  --grain-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.5 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  --grain-blend:   multiply;
  --grain-opacity: 0;
}

/* Nuit — teal profond + filaments crème/or */
body.theme-nuit {
  --rouge: #D4B577;                 /* or chaud — accent principal */
  --rouge-2: #9C8050;               /* or bronze — accent secondaire */
  --ocre: #E8D4A8;                  /* crème lumineuse — pointes/highlights */
  --terre: #5A4A2C;                 /* ambre profond — ombre chaude */

  --fg: #EDE2C9;                    /* crème chaude — texte principal */
  --bg: #091114;                    /* teal profond presque noir — fond */
  --muted: #8E8469;                 /* crème sourde — texte secondaire */
  --rule: #1E2F35;                  /* hairline teal — séparateur sombre */

  /* Hairline signature — or chaud à 22% pour segmenter sur fond sombre */
  --hairline: rgba(212, 181, 119, 0.22);

  --verre-bg:            rgba(9, 17, 20, 0.42);
  --verre-border:        rgba(232, 212, 168, 0.10);
  --verre-bevel-top:     rgba(232, 212, 168, 0.22);
  --verre-bevel-bottom:  rgba(0, 0, 0, 0.35);

  /* Grain blanc en screen pour un vrai grain clair sur fond sombre */
  --grain-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.5 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  --grain-blend:   screen;
  --grain-opacity: 0.08;
}

/* Teal — inversion de la palette nuit : teal devient accent, fond repasse en blanc */
body.theme-teal {
  --rouge: #2F5F6B;                 /* teal profond — accent principal */
  --rouge-2: #4A8290;               /* teal clair — accent secondaire */
  --ocre: #B8D1D6;                  /* teal pâle — pointes/highlights */
  --terre: #163038;                 /* teal quasi-noir — ombre froide */

  --fg: #1C2E32;                    /* teal profond — texte principal */
  --bg: #FFFFFF;                    /* blanc pur — fond */
  --muted: #6B7F85;                 /* teal sourd — texte secondaire */
  --rule: #DCE4E6;                  /* hairline teal très pâle */

  /* Hairline signature — teal profond à 22% sur blanc */
  --hairline: rgba(47, 95, 107, 0.22);

  --verre-bg:            rgba(255, 255, 255, 0.30);
  --verre-border:        rgba(28, 46, 50, 0.10);
  --verre-bevel-top:     rgba(255, 255, 255, 0.55);
  --verre-bevel-bottom:  rgba(28, 46, 50, 0.08);

  /* Grain désactivé en palette claire — cf. note palette jour. */
  --grain-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.5 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  --grain-blend:   multiply;
  --grain-opacity: 0;
}

/* ---------- Overrides par moteur -------------------------------------
   Certains moteurs ont un fond saturé sombre quelle que soit la palette
   (astres : bain rouge / teal cosmos profond sous toutes les palettes).
   Le texte des palettes claires (jour, teal) y devient illisible.
   On repousse alors les tokens vers des valeurs "dark-palette" (crème
   sur sombre, grain blanc). Spécificité égale aux palettes — placé
   après donc gagne. */

/* body.engine-astres — deux scopes distincts.

   Historiquement, tous les overlays astres (--fg crème, --bg teal-black,
   accents gold) étaient posés sur <body> tout entier parce que le canvas
   astres couvrait la page complète et le texte des sections post-hero
   était bien sur fond cosmique. Depuis que .page-wash est passé en
   position: absolute; height: 100dvh, le canvas astres n'habille plus
   que le hero (section 00) — passé la première page, ce sont les fonds
   de palette (blanc pour jour/teal, teal-black pour nuit) qui prennent
   le relais.

   Conséquence : on ne peut plus forcer --fg crème à l'échelle du <body>,
   sinon les sections 01-07 en palette claire (jour/teal) se retrouvent
   avec du texte crème sur du blanc — illisible. Les overrides sont donc
   scindés :

   1. Le grain-* reste au niveau <body> — le .grain est fixed full-viewport,
      il traverse toutes les sections. Garder le grain screen blanc sur
      toute la page est sans dommage (screen sur blanc = invisible, effet
      seulement visible là où le fond est sombre, ie. sur le hero astres).

   2. Les tokens texte/accents/verre basculent sur .hero uniquement.
      Dans le hero, le fond est le bain astres saturé, le texte doit être
      crème et les accents gold. Passé le hero, on retombe sur les tokens
      de palette (dark text sur blanc en jour/teal, crème sur teal-black
      en nuit). --bg n'est plus overridé du tout : le html garde sa couleur
      palette-défaut pour les sections post-hero. */

body.engine-astres {
  /* Grain blanc en screen : le grain noir en multiply disparaît sur fond sombre. */
  --grain-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.5 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  --grain-blend:   screen;
  --grain-opacity: 0.08;
}

body.engine-astres .hero {
  --fg: #EDE2C9;                    /* crème chaude — lisible sur bain saturé */
  --muted: #B8A987;                 /* crème sourde */
  --rule: rgba(237, 226, 201, 0.18);

  /* Accents forcés en gold chaud (tokens de la palette nuit) pour toutes les
     palettes. Motivation : les valeurs originales de --rouge (#9B2915 pour
     jour, #2F5F6B pour teal) sont trop proches des fonds astres saturés
     (#1E0C06 brun-crimson en jour, #06141A teal-black en teal). Les
     esperluettes, liens, kickers et pucerons utilisant var(--rouge)
     deviennent illisibles — même hue que le bain cosmique. Le gold chaud
     #D4B577 contraste à la fois sur le crimson chaud (hue voisin mais
     luminance très supérieure) et sur le teal-black (hue complémentaire
     + haute luminance). Cohérent avec l'esthétique "bain cosmique, accents
     dorés" qu'astres installe déjà en nuit. */
  --rouge:   #D4B577;
  --rouge-2: #9C8050;
  --ocre:    #E8D4A8;
  --terre:   #5A4A2C;

  --verre-bg:            rgba(9, 17, 20, 0.42);
  --verre-border:        rgba(232, 212, 168, 0.10);
  --verre-bevel-top:     rgba(232, 212, 168, 0.22);
  --verre-bevel-bottom:  rgba(0, 0, 0, 0.35);

  /* color: explicite parce que body.theme-X définit color: var(--fg) sur
     <body> directement (hérité), et les tokens locaux sur .hero ne
     rétroactent pas sur la color: du parent. On pose color: ici pour que
     le texte du hero hérite bien du crème. */
  color: var(--fg);
}

/* (Pas d'override body.engine-gyre : le composite du trait est paramétré
   par preset — 'multiply' sur blanc pour jour/teal, 'lighter' sur teal-black
   pour nuit. Chaque palette garde donc ses tokens naturels.) */

* { box-sizing: border-box; margin: 0; padding: 0; }

html {
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

html {
  overflow-x: clip;
  background: var(--bg);
}
body {
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.55;
  color: var(--fg);
  background: transparent;
  position: relative;
  overflow-x: clip;
}

/* Nappe globale animée, ancrée au haut du document.
   Ancien comportement : position: fixed → le canvas restait collé au
   viewport pendant que le contenu défilait par-dessus, créant une
   sensation de "glissement étage" artificielle (surtout combinée à
   l'isolation opaque des sections post-hero : on voyait le plasma
   "découpé" par le bord supérieur de main, ce qui trahissait le
   fait que la nappe était statique).

   Nouveau : position: absolute ancré sur body (qui est relative) →
   le canvas prend place comme un bloc "premier viewport" qui scrolle
   naturellement vers le haut avec le reste. Passé le hero il quitte
   le champ visuel par le haut, exactement comme si c'était un fond
   de section héros. 100dvh au lieu de 100vh pour suivre la hauteur
   visible dynamique (barre d'URL mobile). */
.page-wash {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100dvh;
  z-index: -1;
  pointer-events: none;
}

/* ---------- Isolation du background au hero ----------
   Le .page-wash (canvas WebGL plasma) est ancré en position: absolute
   sur body : il couvre uniquement la hauteur du premier viewport et
   scrolle avec le document, donc quitte naturellement le champ passé
   le hero. Au-delà, c'est le fond de html (background: var(--bg)) qui
   prend le relais pour toutes les sections suivantes — pas besoin de
   rendre main/.ecrire/.site-footer opaques, ni de full-bleed manuel.
   Chaque palette pose son --bg, et les sections post-hero l'utilisent
   telle quelle. Le moteur astres ne touche plus au --bg global : il
   ne repeint que le hero (où son canvas est visible), les tokens
   texte/accents crème+gold sont scopés à .hero uniquement (cf. bloc
   body.engine-astres .hero). */

/* ---------- Esperluette = couleur de marque, sinon hérite ---------- */
.amp { color: var(--rouge); }
.sep { color: var(--muted); margin: 0 0.4em; }

/* ---------- Grain ---------- */
.grain {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9;
  opacity: var(--grain-opacity);
  mix-blend-mode: var(--grain-blend);
  background-image: var(--grain-image);
}

/* ---------- Curseur : natif système partout ---------------------------
   Le curseur custom rouge a été retiré. Après tour du patron de référence
   (cabinets M&A, MBB, BB universelles), aucun n'utilise de curseur custom
   — c'est un signal "studio / agence créative" qui détonne avec le registre
   visé. Les propriétés natives (pointer sur liens, text sur inputs, default
   ailleurs) suffisent à guider l'interaction. */

/* ---------- Focus ring -----------------------------------------------
   Le ring par défaut du navigateur (fin noir dotted) détonne avec la
   DA. On le remplace par un trait plein en var(--rouge) — donc rouge
   Pompéi en jour/teal, or chaud en nuit — avec un offset qui respire.
   Uniquement via :focus-visible pour ne pas déclencher au clic souris
   sur les boutons/liens, et conserver le comportement clavier intact.
   Le fallback browser reste actif si :focus-visible n'est pas supporté
   (anciennes versions) — on ne met donc PAS outline:none sur :focus. */
:focus-visible {
  outline: 2px solid var(--rouge);
  outline-offset: 3px;
  border-radius: 1px;
}
/* Le lien underline par défaut (border-bottom: 1px solid currentColor)
   crée déjà un signal visuel ; on garde seulement l'outline, pas de
   double-indicateur qui alourdirait. */
a:focus-visible { outline-offset: 4px; }

/* ---------- Typographie ---------- */
h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.01em;
}
h2 { font-size: clamp(2rem, 4.5vw, 3.5rem); }
h3 { font-size: clamp(1.25rem, 2.2vw, 1.6rem); }

p { max-width: var(--measure); }

a {
  color: var(--rouge);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  transition: opacity 160ms ease;
}
a:hover { opacity: 0.65; }

.kicker {
  font-family: var(--mono);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--rouge);
}
.kicker .num { color: var(--rouge); margin-right: 0.6em; }
.kicker .dash {
  font-family: var(--serif);
  font-style: italic;
  text-transform: none;
  font-size: 1.4em;
  color: var(--rouge);
  line-height: 1;
  margin-right: 0.55em;
  vertical-align: -0.05em;
}

.tag, .badge, .firms {
  font-family: var(--mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.section-note, .sub { color: var(--muted); }
.lede { font-size: 1.25rem; }

/* ---------- Layout container ---------- */
main,
.site-footer {
  max-width: var(--container);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--pad-x);
  padding-right: var(--pad-x);
  position: relative;
  z-index: 1;
}

/* ---------- Header marque ----------
   Barre rouge Pompéi (--header-bg) révélée au scroll uniquement.
   En haut de page (section 00), le wordmark géant du hero porte
   déjà le nom du cabinet — une barre rouge en surimpression avec
   le même wordmark serait un doublon typographique. On masque donc
   le header tant que la page n'a pas scrollé (translate -100% hors
   champ) ; la classe .is-scrolled (toggled par le JS d'index.html
   au-delà de 60% de la hauteur hero) le ramène dans le viewport,
   avec une ombre discrète qui décolle la barre du contenu. */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  width: 100%;
  background: var(--header-bg);
  border-bottom: 1px solid transparent;
  /* Masqué par défaut : translaté hors champ vers le haut. */
  transform: translateY(-100%);
  transition: transform 340ms ease, box-shadow 320ms ease;
  /* pointer-events: none évite que la barre invisible intercepte
     encore les clics tout en haut de la page (zone hero). */
  pointer-events: none;
}
.site-header-inner {
  max-width: var(--container);
  margin: 0 auto;
  padding: 1.25rem var(--pad-x);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.site-header .wordmark {
  font-family: var(--serif);
  font-size: 1.4rem;
  color: var(--header-fg);
  border: 0;
  letter-spacing: -0.005em;
}
/* L'esperluette globale est en var(--rouge) (Pompéi) — invisible sur la
   barre rouge Pompéi du header. On la force en --header-fg (blanc) dans ce
   contexte précis, tout en conservant son italique serif qui la distingue
   typographiquement des deux patronymes. Le reste du site (hero, prose,
   etc.) garde l'accent rouge. */
.site-header .wordmark .amp {
  color: var(--header-fg);
}
/* Bouton Contact — pill outline blanc sur fond rouge Pompéi.
   Anciennement : pill rouge solide (bg=--rouge, color=--bg). Sur barre
   rouge permanente, le pill bascule en outline blanc pour préserver la
   hiérarchie (la barre est la surface brand, le pill est l'accent). Au
   hover : fill inverse (bg blanc, texte rouge) — classique outline→filled. */
.site-header .top-nav a.btn-ecrire {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.55rem 1.25rem;
  font-family: var(--mono);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  line-height: 1;
  color: var(--header-fg);
  background: transparent;
  border: 1px solid var(--header-fg);
  border-radius: 999px;
  transition: color 180ms ease, background-color 180ms ease, transform 180ms ease, box-shadow 180ms ease;
}
.site-header .top-nav a.btn-ecrire:hover {
  opacity: 1;                                /* annule le -35% opacity du hover global des <a> */
  color: var(--header-bg);
  background: var(--header-fg);
  transform: translateY(-1px);
  box-shadow: 0 3px 14px rgba(0, 0, 0, 0.22);
}
.site-header.is-scrolled {
  transform: translateY(0);
  pointer-events: auto;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.18), 0 4px 16px rgba(0, 0, 0, 0.08);
}

/* ---------- Full-bleed utility ---------- */
.full-bleed {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}

/* ---------- HERO ---------- */
/* Le hero occupe la totalité du viewport vertical au chargement. 100dvh
   (dynamic viewport height) au lieu de 100vh : sur mobile, la barre d'URL
   qui apparaît/disparaît change la hauteur du viewport dynamique, et 100vh
   reste figée sur la valeur "barre cachée" — ça génère des débordements
   disgracieux lors du scroll. 100dvh suit la hauteur visible réelle.
   Flexbox centré : le contenu reste au milieu de l'écran même si le hero
   fait plus que le contenu nécessite. Le header fixed transparent
   surimprimé reste au-dessus sans réserver d'espace dans le flux. */
.hero {
  position: relative;
  overflow: hidden;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  padding-top: clamp(5rem, 12vh, 9rem);
  padding-bottom: clamp(4rem, 12vh, 9rem);
}
/* width: 100% car le hero est désormais un flex container et le hero-inner
   serait sinon aligné à sa largeur de contenu seul au lieu de prendre toute
   la largeur disponible. */
.hero > .hero-inner { width: 100%; }
.hero-inner {
  position: relative;
  z-index: 1;
  max-width: var(--container);
  margin: 0 auto;
  padding-left: var(--pad-x);
  padding-right: var(--pad-x);
}
.hero .kicker { margin-bottom: 2rem; }

.hero-title {
  font-family: var(--serif);
  font-weight: 400;
  /* min baissé de 3.5rem à 3rem : sur un écran 320 px (iPhone SE 1ère gén.,
     Galaxy Fold plié), 3rem = 48 px laisse "Thiebaut" respirer dans la
     zone utile (272 px une fois --pad-x déduit) sans toucher aux bornes
     desktop. 11vw garde le scaling naturel au-dessus de 320 px. */
  font-size: clamp(3rem, 11vw, 9.5rem);
  line-height: 0.92;
  letter-spacing: -0.025em;
  margin-bottom: 2.5rem;
  color: var(--fg);
}
.hero-title .line { display: block; }

.hero-meta {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
  margin-bottom: 1.5rem;
  align-items: end;
}
.hero-meta .lede {
  max-width: 28ch;
  color: var(--fg);
  font-family: var(--serif);
  font-size: clamp(1.4rem, 2.6vw, 2rem);
  line-height: 1.25;
}
.hero-side .firms { display: block; }
.hero .sub { max-width: 56ch; color: var(--muted); }

@media (min-width: 768px) {
  .hero-meta {
    grid-template-columns: 2fr 1fr;
    gap: 3rem;
  }
  .hero-side { text-align: right; }
}

/* ---------- Sections — head ---------- */
.section {
  /* Respiration verticale renforcée — l'air structurel entre sections
     blanches successives devient lui-même un marqueur de frontière.
     Combiné au hairline Pompéi, l'œil lit clairement la fin d'un bloc
     et le début du suivant sans avoir besoin d'alternance chromatique. */
  padding-top: clamp(6rem, 12vh, 9rem);
  padding-bottom: clamp(6rem, 12vh, 9rem);
}

.section-head { margin-bottom: 3rem; }
.section-head .kicker { margin-bottom: 1.25rem; }
.section-head h2 { margin-bottom: 1.25rem; }
.section-head .section-note { max-width: 60ch; }

/* ================================================================
   Refonte UI · avril 2026 — trois matérialités
   ----------------------------------------------------------------
   Le site ne traite plus toutes les sections avec le même dispositif
   « dalle verre sur plasma ». On distingue désormais :

   1. PROSE FLOTTANTE (sections 01 Interventions · 04 Exemples ·
      05 Cabinet · 06 Préalables) — texte-first, hairline rules, pas
      de dalle, pas de glyph décoratif. Registre éditorial.

   2. DISPOSITIF TYPOGRAPHIQUE (section 02 Méthode) — stepper quatre
      temps, grands chiffres italique serif, filet de continuité.
      Pas de dalle verre non plus : c'est la typo qui scande.

   3. GLASS SIGNATURE (section 03 Principes · 07 Contact) — réservée
      aux deux moments du site où l'on cherche l'effet de dalle :
      le manifeste (trois engagements) et le point de contact. Le
      reste du site respire autour.

   Tout passe par les var(--*) : le fichier tient sur les trois
   palettes (jour / nuit / teal) et sur l'override engine-astres
   sans ajouter un seul override par palette.
   ================================================================ */

/* ---------- 01 Interventions — prose flottante, trois colonnes ----------
   Hairline de séparation seulement, pas de bordure latérale, pas de fond.
   Glyph discret (28 px) en tête pour amorcer chaque bloc ; il reste un
   repère visuel, pas une icône figurée. Sur desktop la grille se fait
   en trois colonnes égales, colonnes séparées par un filet vertical
   pour la scansion latérale. */
.prose-cols {
  display: flex;
  flex-direction: column;
  gap: 0;
}
.prose-col {
  padding: 2rem 0;
  border-top: 1px solid var(--rule);
}
.prose-col:first-child { border-top: 0; padding-top: 0; }
.prose-col:last-child { padding-bottom: 0; }
.prose-col h3 { margin-bottom: 0.75rem; }
.prose-col p { color: var(--fg); max-width: 44ch; }

.prose-glyph {
  display: inline-block;
  color: var(--rouge);
  margin-bottom: 1.25rem;
  width: 28px;
  height: 28px;
  opacity: 0.85;
}
.prose-glyph svg { width: 100%; height: 100%; display: block; }

@media (min-width: 960px) {
  .prose-cols {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    column-gap: 2.5rem;
    row-gap: 0;
  }
  .prose-col {
    padding: 0 0 0 2rem;
    border-top: 0;
    border-left: 1px solid var(--rule);
  }
  .prose-col:first-child {
    border-left: 0;
    padding-left: 0;
  }
  .prose-col:last-child { padding-bottom: 0; }
}

/* ---------- 02 Méthode — stepper quatre temps, chiffres serif ----------
   Sur mobile : rail vertical, chaque étape avec son numéro en valeur
   absolue à gauche du titre. Sur desktop : quatre colonnes, chiffres
   en haut de colonne, filet vertical de continuité. Pas de dalle,
   pas de 2×2 — c'est une séquence, elle se lit en une seule scansion.
   La section se termine sur le dernier jalon (Livraison) — pas de
   bandeau récapitulatif ajouté, les quatre titres portent déjà la
   promesse contractuelle (cadrage → CDC → sprint → livraison). */
.stepper {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.stepper-item {
  position: relative;
  padding: 1.75rem 0 1.75rem 3.5rem;
  border-top: 1px solid var(--rule);
}
.stepper-item:first-child { border-top: 0; padding-top: 0; }
.stepper-item:last-child { padding-bottom: 0; }
.stepper-item h3 {
  margin-bottom: 0.5rem;
  padding-top: 0.1em;
}
.stepper-item p { color: var(--fg); max-width: 56ch; }

.stepper-num {
  position: absolute;
  top: 1.75rem;
  left: 0;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(2rem, 5vw, 2.4rem);
  color: var(--rouge);
  line-height: 1;
  letter-spacing: -0.02em;
}
.stepper-item:first-child .stepper-num { top: 0; }

@media (min-width: 768px) {
  .stepper {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    column-gap: 1.75rem;
    row-gap: 0;
  }
  .stepper-item {
    padding: 0 0 0 1.75rem;
    border-top: 0;
    border-left: 1px solid var(--rule);
  }
  .stepper-item:first-child {
    border-left: 0;
    padding-left: 0;
  }
  .stepper-item:last-child { padding-right: 0; }
  .stepper-num {
    position: static;
    display: block;
    /* Échelle alignée sur .pilier-num (section 03) : les items internes
       — qu'il s'agisse d'étapes ou de principes — partagent le même
       niveau hiérarchique, donc la même taille. Cela évite aussi la
       collision de format avec le « 02 » arabe du kicker de section,
       qui reste à clamp(3.5rem, 6vw, 5.5rem) et domine nettement. */
    font-size: clamp(3rem, 5vw, 4rem);
    margin-bottom: 1.5rem;
    line-height: 0.85;
  }
  .stepper-item h3 {
    padding-top: 0;
    margin-bottom: 0.75rem;
  }
}

/* ---------- 03 Principes — trois piliers, matérialité signature --------
   Le glass treatment arrive plus bas (« Matière verre »). Ici : la
   grille, le chiffre romain en hero, le corps éditorial en dessous.
   Sur mobile chaque pilier empile num + body ; sur desktop la grille
   passe en trois colonnes avec dalles dépolies. */
.piliers {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
.pilier {
  position: relative;
  display: block;
}
.pilier-num {
  display: block;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(2.5rem, 5vw, 3.5rem);
  color: var(--rouge);
  line-height: 0.9;
  letter-spacing: -0.02em;
  margin-bottom: 1.25rem;
}
.pilier-body h3 { margin-bottom: 0.75rem; }
.pilier-body p { max-width: 42ch; color: var(--fg); }

@media (min-width: 960px) {
  .piliers {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem;
  }
  .pilier-num { font-size: clamp(3rem, 5vw, 4rem); }
}

/* ---------- 04 Exemples — stack alternée, chiffre-clé en contrepoint ----
   Finie la grille 12 colonnes zig-zag sans hiérarchie ; finis les glyphs
   SVG décoratifs. Chaque exemple devient un dialogue entre un corps de
   texte et un chiffre-clé hero qui donne la mesure opérationnelle
   (4 sites, ½ journée, etc.). L'alternance (exemple--inv) swap l'ordre
   texte/chiffre un exemple sur deux pour rompre la répétition. */
.exemples-stack {
  display: flex;
  flex-direction: column;
  gap: 0;
}
.exemple {
  padding: 2.5rem 0;
  border-top: 1px solid var(--rule);
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
  align-items: center;
}
.exemple:first-child { border-top: 0; padding-top: 0; }
.exemple:last-child { padding-bottom: 0; }

.exemple-text .badge {
  display: inline-block;
  margin-bottom: 0.75rem;
  color: var(--rouge);
}
.exemple-text h3 {
  margin-bottom: 0.75rem;
  max-width: 26ch;
}
.exemple-text .tag {
  display: block;
  margin-bottom: 1.25rem;
  color: var(--muted);
}
.exemple-text p { color: var(--fg); max-width: 58ch; }

.exemple-hero {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 1.5rem 0;
  border-top: 1px solid var(--rouge);
  border-bottom: 1px solid var(--rule);
  gap: 0.35rem;
}
.exemple-num {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(3rem, 7vw, 5.5rem);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--rouge);
}
.exemple-legend {
  font-family: var(--mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  max-width: 30ch;
}

@media (min-width: 960px) {
  .exemple {
    grid-template-columns: 7fr 5fr;
    column-gap: 3rem;
    padding: 3.5rem 0;
  }
  .exemple--inv .exemple-text { order: 2; }
  .exemple--inv .exemple-hero {
    order: 1;
    align-items: flex-end;
    text-align: right;
  }
  .exemple--inv .exemple-hero .exemple-legend { text-align: right; }
  .exemple-hero { padding: 2rem 0; }
}

/* ---------- 05 Cabinet — deux bios, métadonnées en aside mono ----------
   Chaque fondateur : nom + rôle à gauche (hero), metadata (formation,
   parcours, lien LinkedIn) en colonne mono à droite. Registre « who's
   who » : aucune icône, aucun portrait, le parcours fait le travail. */
.bios {
  display: flex;
  flex-direction: column;
  gap: 0;
}
.bio {
  padding: 2.5rem 0;
  border-top: 1px solid var(--rule);
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
}
.bio:first-child { border-top: 0; padding-top: 0; }
.bio:last-child { padding-bottom: 0; }
.bio-main h3 {
  margin-bottom: 0.5rem;
  font-size: clamp(1.75rem, 3vw, 2.25rem);
}
.bio-main .role {
  color: var(--muted);
  font-family: var(--mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  max-width: none;
}
.bio-meta {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  font-family: var(--mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.bio-formation { color: var(--fg); max-width: none; }
.bio-parcours { color: var(--muted); max-width: none; }
.bio-link { max-width: none; }
.bio-link a {
  color: var(--rouge);
  border-bottom: 0;
}
.bio-link a:hover { opacity: 0.65; }

@media (min-width: 768px) {
  .bio {
    grid-template-columns: 1.2fr 1fr;
    column-gap: 3rem;
    align-items: start;
    padding: 3rem 0;
  }
  .bio-meta { align-items: flex-end; text-align: right; }
}

/* ---------- 06 Préalables — clauses contractuelles (label / résumé / corps)
   Registre de clauses : label mono à gauche (comme un intitulé
   d'article), à droite un résumé en h3 (« Licence perpétuelle, code
   source inclus. ») puis le paragraphe contractuel. Deux niveaux de
   lecture : diagonale pour saisir les trois points en 5 secondes,
   intégrale pour le détail. */
.clauses {
  display: flex;
  flex-direction: column;
  gap: 0;
}
.clause {
  padding: 2rem 0;
  border-top: 1px solid var(--rule);
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
}
.clause:first-child { border-top: 0; padding-top: 0; }
.clause:last-child { padding-bottom: 0; }
.clause-label {
  font-family: var(--mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--rouge);
  max-width: none;
}
.clause-body h3 {
  margin-bottom: 0.75rem;
  color: var(--fg);
  font-size: clamp(1.15rem, 2vw, 1.5rem);
  line-height: 1.2;
}
.clause-body p { color: var(--fg); max-width: 62ch; }

@media (min-width: 768px) {
  .clause {
    grid-template-columns: 1fr 3fr;
    column-gap: 3rem;
    padding: 2.5rem 0;
    align-items: start;
  }
  .clause-label { padding-top: 0.5rem; }
}

/* ---------- 03 Le parti pris — introduction éditoriale --------------- */
.parti-intro {
  font-family: var(--serif);
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  line-height: 1.3;
  max-width: 56ch;
  margin-bottom: 3rem;
  color: var(--fg);
}
.parti-intro::first-letter {
  font-family: var(--serif);
  color: var(--rouge);
  font-size: 5em;
  float: left;
  line-height: 0.85;
  padding-right: 0.1em;
  padding-top: 0.05em;
}

/* ---------- 07 Écrire — full-bleed ---------- */
.ecrire {
  position: relative;
  padding-top: clamp(5rem, 14vh, 10rem);
  padding-bottom: clamp(5rem, 14vh, 10rem);
}
.ecrire-inner {
  max-width: var(--container);
  margin: 0 auto;
  padding-left: var(--pad-x);
  padding-right: var(--pad-x);
  position: relative;
  z-index: 1;
}
.ecrire .kicker { margin-bottom: 2rem; }

.ecrire .email {
  font-family: var(--serif);
  /* min baissé de 2.5rem à 1.75rem : contact@thiebautruchet.com (26 car.)
     à 40 px (ancien min) dépassait la largeur d'un iPhone 375 px. À 28 px
     le mot tient sans wrap ; en dessous, overflow-wrap joue. */
  font-size: clamp(1.75rem, 7vw, 5.5rem);
  margin-bottom: 2rem;
  max-width: none;
  line-height: 1;
  letter-spacing: -0.02em;
  /* Filet de sécurité : sur les plus petits écrans, si la taille calculée
     reste trop large, l'adresse coupe proprement plutôt que de produire un
     scroll horizontal. break-word privilégie les coupures raisonnables
     (après @ et .) ; anywhere est le fallback ultime. */
  overflow-wrap: anywhere;
  word-break: break-word;
}
.ecrire .email a {
  color: var(--fg);
  border-bottom: 0;
}
.ecrire .email a:hover { color: var(--rouge); }

/* Stretched-link : le <a> du mail reste ponctuel dans le DOM mais
   gagne un ::before absolu qui couvre .ecrire-inner et capte les clics.
   → toute la dalle ouvre le client mail. .ecrire-inner est déjà
   position: relative grâce aux repères de coin, donc c'est son cadre
   qui sert de containing block pour l'overlay. */
.ecrire-inner { cursor: pointer; }
.ecrire .email a::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  /* transparent — c'est juste un capteur d'événements */
}

/* Ligne unique mono sous l'adresse : trois pastilles d'information
   (visio · Paris · réponse 48h) séparées par des puces ·. Remplace
   l'ancien duo sub/firms qui dispersait l'information. */
.ecrire-meta-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.25rem;
  font-family: var(--mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  max-width: none;
}
.ecrire-meta-line .sep { margin: 0 0.35rem; }

/* ---------- Footer ---------- */
.site-footer {
  display: flex;
  justify-content: space-between;
  padding-top: 2rem;
  padding-bottom: 2rem;
  border-top: 1px solid var(--rule);
  margin-top: 0;
  font-family: var(--mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

/* ---------- Mini-nav latérale ---------- */
.section-nav {
  position: fixed;
  top: 50%;
  right: 1.5rem;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  z-index: 50;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  transition: opacity 260ms ease;
}
/* Quand aucune section n'est active (typiquement sur le hero avant le
   premier scroll), on masque complètement la mini-nav : afficher sept
   numéros en gris pâle sans aucune indication de position active n'a
   pas de sens et encombre le champ visuel. L'IntersectionObserver
   positionne is-active dès que section 01 atteint 35% de visibilité,
   donc la nav réapparaît naturellement au scroll. */
.section-nav:not(:has(.is-active)) {
  opacity: 0;
  pointer-events: none;
}
.section-nav a {
  color: var(--muted);
  border: 0;
  padding: 0.2rem 0.4rem;
  opacity: 0.4;
  transition: opacity 200ms ease, color 200ms ease, transform 200ms ease;
  display: block;
  position: relative;
}
.section-nav a::before {
  content: "";
  position: absolute;
  left: -8px;
  top: 50%;
  transform: translateY(-50%);
  width: 4px;
  height: 1px;
  background: currentColor;
  opacity: 0;
  transition: opacity 200ms ease, width 200ms ease;
}
.section-nav a.is-active {
  color: var(--rouge);
  opacity: 1;
}
.section-nav a.is-active::before {
  opacity: 1;
  width: 12px;
}
.section-nav a:hover { opacity: 1; }

@media (max-width: 1100px) {
  .section-nav { display: none; }
}

/* ---------- Reveal ---------- */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 700ms ease, transform 700ms ease;
}
.reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* ---------- Responsive global ---------- */
@media (min-width: 768px) {
  body { font-size: 18px; }
}

/* ---------- Matière verre — dalles dépolies ----------
   Inspiré de atelier/verre : papier teinté semi-opaque + backdrop-filter
   qui floute le plasma qui passe derrière, hairline biseauté (top lumineux,
   bottom sombre), repères de coin rouge pour les dalles signature.
   Placé en fin de fichier pour gagner les conflits de spécificité sur
   les deux seules sections glass conservées après la refonte d'avril
   2026 : 03 Principes (.pilier) et 07 Contact (.ecrire-inner). */

/* 1) Section 03 "Principes" : 3 dalles verre (les 3 engagements)
   Paramètres HUD : blur 15 · opacity 0.20 · radius 0 · lift 0.
   Le glass est réservé à cette section + section 07 — c'est la
   matérialité signature du cabinet, elle ne porte que sur les deux
   moments les plus chargés symboliquement (manifeste + contact). */
.pilier {
  padding: clamp(1.75rem, 2.5vw, 2.25rem) clamp(1.5rem, 2.2vw, 2rem);
  background: var(--verre-bg);
  backdrop-filter: blur(15px) saturate(1.02);
  -webkit-backdrop-filter: blur(15px) saturate(1.02);
  border-radius: 0;
  border: 1px solid var(--verre-border);
  box-shadow:
    inset 0 1px 0 var(--verre-bevel-top),
    inset 0 -1px 0 var(--verre-bevel-bottom);
}

/* 2) Section 07 "Écrire" : grande dalle verre, format vitrine
   Paramètres HUD : blur 15 · opacity 0.20 · radius 0 · lift 0 */
.ecrire-inner {
  max-width: 1180px;
  padding: clamp(3rem, 6vh, 4.5rem) clamp(2rem, 5vw, 4rem);
  background: var(--verre-bg);
  backdrop-filter: blur(15px) saturate(1.02);
  -webkit-backdrop-filter: blur(15px) saturate(1.02);
  border-radius: 0;
  border: 1px solid var(--verre-border);
  box-shadow:
    inset 0 1px 0 var(--verre-bevel-top),
    inset 0 -1px 0 var(--verre-bevel-bottom);
}
/* Repères de coin rouge (signature atelier/verre) */
.ecrire-inner::before,
.ecrire-inner::after {
  content: '';
  position: absolute;
  width: 12px;
  height: 12px;
  border-color: var(--rouge);
  border-style: solid;
  border-width: 0;
  opacity: 0.55;
  pointer-events: none;
}
.ecrire-inner::before {
  top: 14px; left: 14px;
  border-top-width: 1px; border-left-width: 1px;
}
.ecrire-inner::after {
  bottom: 14px; right: 14px;
  border-bottom-width: 1px; border-right-width: 1px;
}

/* ---------- Allègement mobile des dalles verre ------------------------
   Sur mobile (≤ 768 px), les deux dalles signature (pilier × 3 et
   ecrire-inner) scrollent chacune sur toute la largeur utile
   par-dessus le canvas WebGL animé plein écran. Un backdrop-filter
   blur(15px) à cette échelle sur GPU mobile ancien = pic garanti.
   On descend le blur à 8 px : la lecture « verre dépoli » tient,
   la charge GPU chute de ~60 %. Le saturate(1.02) reste identique —
   c'est le blur qui est coûteux, pas la saturation. Le fond
   semi-opaque (--verre-bg) garde sa lisibilité texte.
   Depuis la refonte d'avril 2026, seules les sections 03 et 07
   portent encore du glass ; les autres sections sont en prose
   flottante et n'ont pas de backdrop-filter à alléger. */
@media (max-width: 768px) {
  .pilier,
  .ecrire-inner {
    backdrop-filter: blur(8px) saturate(1.02);
    -webkit-backdrop-filter: blur(8px) saturate(1.02);
  }
}

/* ---------- Densité verticale mobile ----------------------------------
   Sur desktop, le site respire : entre chaque section, ~128 px d'air
   cumulé (padding 4rem top + 4rem bottom au minimum). Six sections ×
   128 px = 768 px de scroll uniquement en blancs structurels.
   Sur mobile, la colonne unique rend cet air moins nécessaire — et plus
   coûteux, puisqu'il allonge la distance qui sépare le lecteur du
   contenu suivant. On resserre d'environ 35 % les padding verticaux
   (hero, sections, ecrire) et les marges de tête de section, sans
   jamais descendre sous 2,5 rem pour préserver le souffle éditorial.
   Les padding internes des dalles, eux, restent identiques — c'est le
   blanc structurel qu'on comprime, pas la lecture. */
@media (max-width: 768px) {
  .hero {
    padding-top: clamp(2.5rem, 8vh, 5rem);
    padding-bottom: clamp(2.5rem, 8vh, 5rem);
  }
  .hero .kicker { margin-bottom: 1.5rem; }
  .hero-title { margin-bottom: 1.75rem; }

  .section {
    padding-top: clamp(3.5rem, 9vh, 5.5rem);
    padding-bottom: clamp(3.5rem, 9vh, 5.5rem);
  }
  .section-head { margin-bottom: 2rem; }

  .ecrire {
    padding-top: clamp(3.5rem, 10vh, 6rem);
    padding-bottom: clamp(3.5rem, 10vh, 6rem);
  }
  .ecrire .kicker { margin-bottom: 1.5rem; }
  .ecrire .email { margin-bottom: 1.5rem; }
}

/* ---------- Switcher thème (dev uniquement, derrière ?dev=1) ----------
   Widget flottant bas-droite, volontairement discret. Visible seulement
   quand l'URL contient ?dev=1 (cf. theme/app.js). Ne doit jamais fuiter
   en prod : si c'est visible, c'est un bug côté URL. */
.tr-switcher {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 10001;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.625rem 0.875rem 0.75rem;
  background: rgba(20, 17, 15, 0.78);
  color: #FFFFFF;
  border: 0;
  border-radius: 6px;
  backdrop-filter: saturate(180%) blur(8px);
  -webkit-backdrop-filter: saturate(180%) blur(8px);
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.25);
  /* Le contenu (rangées de boutons) peut être plus étroit que la légende
     "THÈME · DEV" — on force une largeur plancher pour que la legend rentre
     entièrement dans la bordure supérieure du fieldset. */
  min-width: 180px;
  max-width: 280px;
}
.tr-switcher legend {
  /* Par défaut, une <legend> chevauche la bordure supérieure du <fieldset>.
     Avec bordure invisible + fond coloré, ce dépassement devient un glitch
     visuel (titre qui flotte au-dessus de la boîte). On force la legend
     dans le flux normal via float: left + width: 100% — truc cross-browser
     éprouvé pour neutraliser le placement natif. */
  float: left;
  width: 100%;
  padding: 0;
  margin: 0;
}
/* Bouton toggle qui remplit toute la legend : ligne titre + chevron aligné
   à droite. Clic sur n'importe quelle zone du titre collapse/expand. */
.tr-switcher__toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 0 0 0.125rem;
  margin: 0 0 0.125rem;
  background: transparent;
  border: 0;
  cursor: pointer;
  font: inherit;
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: rgba(255, 255, 255, 0.55);
  white-space: nowrap;
  transition: color 140ms ease;
}
.tr-switcher__toggle:hover { color: rgba(255, 255, 255, 0.85); }
/* Triangle dessiné en CSS (border-hack) plutôt qu'un glyphe texte :
   évite toute dépendance à la font mono et à son fallback. Pointe vers le
   bas par défaut ; en état collapsé, la règle ci-dessous le retourne. */
.tr-switcher__chev {
  display: inline-block;
  width: 0;
  height: 0;
  margin-left: 0.5rem;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  transition: transform 160ms ease;
  flex-shrink: 0;
}
/* Etat collapsé : le chevron pointe vers le haut, le body est caché, les
   paddings de la fieldset se resserrent → la boîte se réduit à sa barre de
   titre. On garde le même ancrage bottom-right et la même largeur max. */
.tr-switcher.is-collapsed {
  padding: 0.5rem 0.75rem;
  gap: 0;
}
.tr-switcher.is-collapsed .tr-switcher__toggle {
  padding-bottom: 0;
  margin-bottom: 0;
}
.tr-switcher.is-collapsed .tr-switcher__chev {
  transform: rotate(180deg);
}
.tr-switcher.is-collapsed .tr-switcher__body {
  display: none;
}
.tr-switcher__label {
  margin: 0.25rem 0 0.125rem;
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: rgba(255, 255, 255, 0.55);
  max-width: none;
}
.tr-switcher__row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  align-items: center;
}
.tr-switcher__btn {
  font: inherit;
  padding: 0.35rem 0.6rem;
  background: rgba(255, 255, 255, 0.08);
  color: #FFFFFF;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 3px;
  cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}
.tr-switcher__btn:hover {
  background: rgba(255, 255, 255, 0.15);
  border-color: rgba(255, 255, 255, 0.32);
}
.tr-switcher__btn.is-on {
  background: #FFFFFF;
  color: #14110F;
  border-color: #FFFFFF;
}
.tr-switcher__hint {
  font-size: 0.6rem;
  color: rgba(255, 255, 255, 0.4);
  padding: 0 0.25rem;
}

@media (max-width: 640px) {
  .tr-switcher {
    right: 8px;
    bottom: 8px;
    max-width: calc(100vw - 16px);
  }
}

/* ================================================================
   Pages éditoriales secondaires — mentions légales, notes, case
   studies. Même grammaire typographique que la home, mais layout
   long-form centré sur une seule mesure de lecture (~64ch).

   body.page-article pilote l'état "page sans hero" : le contenu pousse
   sous l'espace du header (qui est déjà visible en permanence via la
   barre rouge Pompéi du .site-header).
   ================================================================ */

/* Pages éditoriales : la barre rouge Pompéi est déjà permanente via
   .site-header (wordmark + pill toujours visibles). La classe .is-scrolled
   statique, posée dans le markup, ajoute l'ombre subtile sans dépendance JS.
   Aucun override spécifique n'est nécessaire ici. */

/* Conteneur article : mêmes paddings et max-width que main de la
   home, mais avec padding-top qui compense le header fixed. */
.article {
  max-width: var(--container);
  margin: 0 auto;
  padding-left: var(--pad-x);
  padding-right: var(--pad-x);
  padding-top: clamp(7rem, 14vh, 10rem);
  padding-bottom: clamp(5rem, 10vh, 8rem);
  position: relative;
  z-index: 1;
}

/* Tête d'article : kicker mono, titre serif, date de mise à jour.
   Ligne de séparation hairline sous la tête. */
.article-head {
  max-width: var(--measure);
  margin-bottom: 4rem;
  padding-bottom: 2rem;
  border-bottom: 1px solid var(--rule);
}
.article-head .kicker {
  margin-bottom: 1.25rem;
}
.article-title {
  font-family: var(--serif);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.01em;
  font-size: clamp(2rem, 4.5vw, 3.25rem);
  color: var(--fg);
  margin-bottom: 1.5rem;
}
.article-updated {
  font-family: var(--mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

/* Corps d'article : mesure de lecture unique, sections séparées
   par un espace généreux. */
.article-body {
  max-width: var(--measure);
}
.article-section {
  margin-bottom: 3rem;
}
.article-section:last-of-type {
  margin-bottom: 2rem;
}

/* H2 d'article = même registre que les kickers de la home (mono,
   uppercase, rouge) — signale une sous-section éditoriale sans
   concurrencer le H1 serif. */
.article-h2 {
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--rouge);
  line-height: 1.4;
  margin-bottom: 1rem;
}
.article-body p {
  margin-bottom: 1rem;
}
.article-body p:last-child {
  margin-bottom: 0;
}
.article-body a {
  /* liens dans un paragraphe éditorial : on conserve l'underline
     par défaut (border-bottom 1px) qui tient lieu de soulignement
     typographique propre, sans imposer de deuxième signal. */
  word-break: break-word;
}

/* Lede typique des templates notes (intro italique au-dessus du
   corps). Optionnel — affiché seulement si .article-lede est
   présent dans le markup. */
.article-lede {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.25rem;
  line-height: 1.4;
  color: var(--fg);
  margin-bottom: 2.5rem;
  max-width: var(--measure);
}

/* Signature bas d'article (auteur / date / retour). */
.article-sign {
  margin-top: 4rem;
  padding-top: 2rem;
  border-top: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.article-sign p { margin-bottom: 0.5rem; }

/* Lien retour accueil (en bas de corps). */
.article-back {
  margin-top: 3rem;
  font-family: var(--mono);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.article-back a {
  color: var(--rouge);
  border-bottom: 0;
}

/* Footer : on tolère un troisième bloc (lien mentions légales)
   grâce au justify-content: space-between existant. Styling du lien
   lui-même : muted, underline subtil, pas le rouge d'accent pour
   rester au niveau "utilitaire". */
.site-footer a {
  color: var(--muted);
  border-bottom: 1px solid transparent;
  transition: color 200ms ease, border-color 200ms ease;
}
.site-footer a:hover {
  color: var(--fg);
  border-bottom-color: currentColor;
  opacity: 1;
}

/* Case study — sections contexte / intervention / résultat. Même
   layout article long, plus un bloc de méta en tête (durée, type). */
.case-meta {
  font-family: var(--mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-top: 1.25rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem 1.2rem;
}
.case-meta .sep { margin: 0; }

/* Responsive — à partir du petit écran, on serre un peu les
   marges verticales pour éviter les trous inutiles. */
@media (max-width: 640px) {
  .article {
    padding-top: clamp(5rem, 12vh, 7rem);
    padding-bottom: 4rem;
  }
  .article-head {
    margin-bottom: 2.5rem;
  }
  .article-section {
    margin-bottom: 2.25rem;
  }
  /* Footer à 3 colonnes devient lisible en pile sur mobile.
     (2 colonnes restaient supportables ; 3 textes en flex-row
     se compriment, on bascule en column pour l'aération.) */
  .site-footer {
    flex-direction: column;
    gap: 0.5rem;
    align-items: flex-start;
  }
}

/* ================================================================
   Bandeau manifeste — section 03 Principes
   ----------------------------------------------------------------
   Une seule section de la page bascule en registre sombre : 03
   Principes. Couleur : brun-crimson #1E0C06 — Pompéi sous-exposé,
   famille chromatique directe, déjà présent dans les engines (fond
   astres jour). Ni teal ni anthracite corporate : le sombre doit
   appartenir à la palette signature, pas s'y greffer.

   Pourquoi cette section et pas une autre : les Principes portent
   l'engagement déontologique (interlocuteur unique, forfait,
   actifs mutualisés). C'est le moment où le cabinet prend position.
   Le changement de registre chromatique signale éditorialement ce
   basculement — les six autres sections sont descriptives et
   restent en blanc pur.

   Technique : full-bleed obtenu par box-shadow + clip-path plutôt
   que par un break-out du conteneur. Le layout de la section ne
   bouge pas, seule sa peinture s'étend aux bords du viewport.
   Alignement grille inchangé.
   ================================================================ */
body.theme-jour .section[data-tone="dark"],
body.theme-teal .section[data-tone="dark"] {
  /* Réécriture locale des tokens : le texte bascule en crème chaude,
     les verre-* sont retunés pour un glass lisible sur dark. Scope
     limité à la section : on sort sans rien casser ailleurs. */
  --fg:    #F2E7D9;
  --muted: rgba(242, 231, 217, 0.62);
  --rule:  rgba(242, 231, 217, 0.10);
  --verre-bg:           rgba(255, 240, 220, 0.04);
  --verre-border:       rgba(242, 231, 217, 0.12);
  --verre-bevel-top:    rgba(255, 230, 210, 0.18);
  --verre-bevel-bottom: rgba(0, 0, 0, 0.42);

  background: #1E0C06;
  color: var(--fg);

  /* Full-bleed sans breakout — le container reste intact, la peinture
     déborde latéralement par box-shadow, les bords verticaux sont
     clippés pour que la couleur ne fuite pas au-dessus/au-dessous. */
  box-shadow: 0 0 0 100vmax #1E0C06;
  clip-path: inset(0 -100vmax);

  /* Respiration renforcée — le bandeau manifeste mérite plus d'air
     que les sections descriptives courantes. */
  padding-top: clamp(6rem, 14vh, 10rem);
  padding-bottom: clamp(6rem, 14vh, 10rem);
}

/* Tokens typographiques internes hérités via --fg */
.section[data-tone="dark"] .pilier-body p,
.section[data-tone="dark"] .parti-intro {
  color: var(--fg);
}

/* Kicker, pilier-num et esperluette restent en var(--rouge) : le rouge
   Pompéi #9B2915 tient sa saturation sur le brun-crimson. L'accent
   chromatique signature reste actif dans le bandeau sombre. */

/* Mobile : on réduit la respiration renforcée pour ne pas rallonger
   artificiellement la colonne. */
@media (max-width: 768px) {
  body.theme-jour .section[data-tone="dark"],
  body.theme-teal .section[data-tone="dark"] {
    padding-top: clamp(3.5rem, 10vh, 6rem);
    padding-bottom: clamp(3.5rem, 10vh, 6rem);
  }
}

/* ================================================================
   Contact (section 07) — boîte rouge Pompéi contenue
   ----------------------------------------------------------------
   Le site s'ouvre par un en-tête fixe rouge Pompéi (--header-bg) et
   se referme par une BOÎTE rouge Pompéi posée sur la page blanche —
   pas un bandeau full-bleed. La boîte reprend la couleur signature
   du cabinet (cohérence avec le header fixe) tout en restant un
   objet typographique borné, lisible comme un bristol de contact
   ou une carte de visite agrandie.

   Différence avec l'en-tête : le header est un bandeau de marque
   omniprésent (scrollé, fixe) ; la boîte 07 est un objet concret
   qu'on aborde en fin de lecture. Même famille chromatique, deux
   registres matériels distincts — le bandeau est continu, la boîte
   est un point d'arrivée.

   Scope : toute palette. Le rouge Pompéi (#9B2915) est un constant
   de marque, pas un token dépendant du thème — la boîte reste
   identique en jour, nuit et teal.

   Tokens réécrits localement sur .ecrire-inner (cascade vers enfants)
     --fg     : crème chaud lisible sur #9B2915
     --muted  : crème atténué pour la meta-line mono
     --rule   : filet crème très discret si besoin
     --rouge  : bascule en crème — tout ce qui utilisait --rouge dans
                ce scope (repères de coin, hover email, kicker,
                num/dash du kicker) passe automatiquement au crème
                sans édit ponctuelle. Accent de marque préservé par
                inversion plutôt que par réécriture.

   Matérialité : aplat rouge uni, pas de glass, pas de wash, pas de
   backdrop-filter. Les bevels internes du glass disparaissent —
   c'est une boîte pleine, pas une dalle dépolie. Les quatre repères
   de coin deviennent crème et signent les angles en discret.

   Layout : .ecrire garde son padding vertical (respiration de page)
   mais ne porte aucune couleur — c'est la page qui reste blanche
   autour de la boîte. .ecrire-inner conserve son max-width 1180 px
   et son padding interne : la boîte est large mais pas pleine
   largeur, elle reste un objet contenu.

   Typographie : l'adresse mail garde sa taille display serif
   (clamp 1.75rem → 5.5rem). Crème sur rouge Pompéi dans la boîte,
   elle est la pièce maîtresse — hiérarchie visuelle évidente.
   ================================================================ */

/* Boîte rouge : tous les overrides (peinture, tokens, neutralisation
   glass) sont portés par .ecrire-inner. Sélecteur compound pour gagner
   en spécificité sur le bloc « dalle verre » historique (ligne 1082)
   et sur les overrides de palette (jour/teal/nuit) qui forçaient
   transparent dans la version précédente. */
.ecrire-inner,
body.theme-jour .ecrire-inner,
body.theme-teal .ecrire-inner,
body.theme-nuit .ecrire-inner {
  background: var(--header-bg);
  color: #F7EFE2;
  --fg:    #F7EFE2;
  --muted: rgba(247, 239, 226, 0.72);
  --rule:  rgba(247, 239, 226, 0.18);
  --rouge: #F7EFE2;
  border-color: transparent;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* Email : le hover basculait sur --rouge (= crème ici, donc
   aucun shift perceptible) et un simple passage à blanc pur crée
   à très grand corps serif un effet contre-intuitif (stroke plus
   fin en rendu sous-pixel, lecture comme un affaiblissement plutôt
   qu'un lift). On abandonne le shift chromatique et on pose une
   affordance typographique classique : un filet underline qui se
   révèle au hover. La couleur reste identique (crème chaud, lecture
   maximale sur rouge Pompéi), l'interactivité est signalée par la
   règle sous l'adresse. */
.ecrire .email a {
  transition: text-decoration-color 180ms ease;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 0.035em;
  text-underline-offset: 0.12em;
}
.ecrire .email a:hover {
  color: var(--fg);
  /* Annule le -35% opacity du hover global des <a> (ligne 282) : sur
     rouge Pompéi, une opacité < 1 mélange le texte crème avec le rouge
     derrière et lit comme un affaiblissement/assombrissement. Même
     pattern que .btn-ecrire:hover. */
  opacity: 1;
  text-decoration-color: currentColor;
}

/* Les repères de coin héritent de border-color: var(--rouge) qui
   vaut désormais crème dans ce scope — aucune règle ponctuelle
   nécessaire. Ils deviennent quatre points crème à 55% d'opacité
   aux coins de la dalle. */

/* ================================================================
   Ouverture de chapitre — signature typographique par section
   ----------------------------------------------------------------
   Référence : ouvertures de chapitre en édition fine-press (Gallimard
   NRF, Phaidon, Pléiade, rapports annuels LVMH/Hermès), et hiérarchie
   typographique des cabinets boutique (Bredin Prat, Sullivan &
   Cromwell, Lazard) qui s'appuie sur l'échelle + le whitespace plutôt
   que sur des filets.

   Principe : le numéro de section n'est plus un overline mono discret
   (« 01 — ») mais un ordinal italique Instrument Serif en rouge Pompéi
   d'une taille substantielle, posé au-dessus d'un H2 display serif
   agrandi. Le couple ordinal + titre forme la frontière — pas besoin
   de trait horizontal. C'est le passage d'un chapitre à l'autre qui
   ouvre l'espace, comme dans un livre relié.

   Sur la section sombre 03, l'ordinal bascule en ocre #D4B577 (famille
   Pompéi, déjà présent dans la palette astres), le rouge deviendrait
   boueux sur brun-crimson.
   ================================================================ */
.section[data-n] { position: relative; }

.section-head .kicker {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(3.5rem, 6vw, 5.5rem);
  line-height: 1;
  letter-spacing: -0.02em;
  text-transform: none;
  color: var(--rouge);
  margin-bottom: clamp(1rem, 2vh, 1.5rem);
}
.section-head .kicker .num {
  color: inherit;
  margin-right: 0;
  font-feature-settings: "onum" 1, "lnum" 0; /* chiffres old-style si dispo */
}
.section-head .kicker .dash { display: none; }

.section-head h2 {
  font-size: clamp(2.5rem, 5vw, 4rem);
  letter-spacing: -0.015em;
  line-height: 1.05;
}

/* Section sombre 03 — ordinal en ocre Pompéi (sur palette jour/teal,
   où la section bascule localement en bandeau brun-crimson) */
body.theme-jour .section[data-tone="dark"] .section-head .kicker,
body.theme-teal .section[data-tone="dark"] .section-head .kicker {
  color: #D4B577;
}
