/* ============================================================================
   PAUL GAYET — styles propres au site.

   `theme.css` porte les valeurs, `base.css` est le fichier du socle et n'est
   pas modifié. Tout ce qui suit est la direction artistique de CE site :
   éditorial, sombre, à séquences.

   Deux règles qu'on ne casse pas ici :

     1. Aucune couleur en dur. On écrit `var(--accent)`, jamais sa valeur.
        Valbonn'Express écrit sa couleur d'accent 51 fois en dur, et changer sa
        charte demande une heure au lieu de dix secondes
     2. Chaque effet a un repli en `prefers-reduced-motion`. Le bloc qui les
        annule est en bas du fichier, en un seul endroit, pour qu'on puisse
        vérifier d'un coup d'œil qu'aucun n'a été oublié
   ========================================================================= */

:root {
  --haut-entete: 66px;
}

body {
  overflow-wrap: break-word;
}

::selection {
  background: var(--accent);
  color: var(--bg);
}

/* Un titre en très grande taille a besoin d'un interlettrage négatif, sinon il
   paraît lâche. Réglage global, appliqué à tous les titres du site. */
h1, h2, h3 {
  letter-spacing: -0.03em;
  font-weight: 800;
}

/* Le mot mis en avant dans un titre : italique serif, dans l'accent. C'est la
   signature typographique du site, et elle ne sert qu'à ça. Un `em` dans un
   paragraphe courant garde l'italique normal. */
h1 em, h2 em, h3 em, .ouverture__role em {
  font-family: var(--font-accent);
  font-weight: 400;
  font-style: italic;
  letter-spacing: 0;
  color: var(--accent);
}

.section-sombre h1 em,
.section-sombre h2 em,
.section-sombre h3 em {
  color: var(--accent-clair);
}

/* --- Grain de pellicule ---------------------------------------------------
   Un aplat noir parfaitement lisse fait « plastique ». Le grain lui donne une
   matière. Dessiné par un filtre SVG en ligne : aucune image à charger, aucune
   requête, et il ne coûte rien à la bande passante. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 400;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='b'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23b)'/%3E%3C/svg%3E");
}

/* --- Rail de progression -------------------------------------------------- */
.regle {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;
  background: var(--accent);
  z-index: 300;
}

/* --- Bandeau de maquette -------------------------------------------------- */
.maquette {
  position: relative;
  z-index: 120;
  background: var(--accent-soft);
  border-bottom: 1px solid var(--line);
  color: var(--body);
  font-size: var(--t-petit);
  text-align: center;
  padding: 10px var(--marge-page);
}

.maquette__marque {
  color: var(--accent);
  border-bottom: 1px dashed var(--accent);
}

/* --- Marques des informations manquantes ----------------------------------
   Un trou doit se VOIR. L'usage courant est d'écrire `[nom du client]` en
   plein texte, et ce crochet finit en ligne : il se lit comme du contenu et
   personne ne le remarque à la relecture. Ici la marque est colorée,
   soulignée en pointillé, et annoncée aux lecteurs d'écran. */
.trou {
  display: inline;
  color: var(--accent);
  border-bottom: 1px dashed var(--accent);
  font-style: normal;
}

.trou::before {
  content: '⟨ ';
}

.trou::after {
  content: ' ⟩';
}

.trou--bloc {
  display: block;
  padding: var(--pas);
  border: 1px dashed var(--accent);
  border-radius: var(--arrondi);
  background: var(--accent-soft);
}

.trou--bloc::before,
.trou--bloc::after {
  content: none;
}

.section-sombre .trou,
.section-sombre .trou--bloc {
  color: var(--accent-clair);
  border-color: var(--accent-clair);
  background: transparent;
}

/* Note de relecture : elle s'adresse à Marie et à Paul, pas au visiteur. Elle
   disparaît avec les marques `.trou` le jour de la mise en ligne. */
.note-trou {
  max-width: var(--largeur-texte);
  margin: var(--section) 0 0;
  padding: var(--pas);
  border-left: 2px solid var(--accent);
  background: var(--accent-soft);
  color: var(--muted);
  font-size: var(--t-petit);
}

.note-trou strong { color: var(--body); }

.note-trou code {
  font-family: var(--font-mono);
  color: var(--accent);
}

/* ==========================================================================
   EN-TÊTE
   ========================================================================== */

.entete {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(8, 8, 10, 0.72);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
  transition: transform var(--transition);
}

/* Masqué à la descente, révélé à la montée. Choix retenu pour le socle le
   21/08 : il rend l'écran au contenu sur mobile. */
.entete.est-cachee {
  transform: translateY(-100%);
}

/* SUR LE HERO, l'en-tête s'efface : le hero porte sa propre barre, celle du
   troisième brief, et les deux se posaient au même pixel en haut de l'écran.
   La classe est posée par le script, la décision est prise ici.

   La règle ne vaut QU'À PARTIR DE 901 px, et c'est ce qui la rend sûre :
   au-dessous, la barre du brief est masquée par `briefs.css` et c'est
   celle-ci qui navigue. Sans ce garde-fou, un visiteur de téléphone se
   retrouverait devant un écran entier sans aucun moyen d'aller ailleurs.

   `visibility` en plus de l'opacité, sinon la barre reste atteignable au
   clavier alors qu'elle est invisible : un arrêt de tabulation sur un lien
   qu'on ne voit pas. Le délai de 0,3 s ne vaut QUE dans ce sens : au retour,
   c'est la transition de `.entete` qui s'applique, elle ne cite pas
   `visibility`, donc la barre redevient atteignable immédiatement. */
@media (min-width: 901px) {
  .entete.est-sur-hero {
    transform: translateY(-100%);
    opacity: 0;
    visibility: hidden;
    transition: transform var(--transition), opacity var(--transition),
                visibility 0s linear 0.3s;
  }
}

.entete__barre {
  display: flex;
  align-items: center;
  gap: var(--pas);
  height: var(--haut-entete);
  max-width: var(--largeur-max);
  margin: 0 auto;
  padding: 0 var(--marge-page);
}

.entete__marque {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  line-height: 1.1;
}

.entete__nom {
  font-family: var(--font-titre);
  font-weight: 800;
  font-size: 1rem;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.entete__signature {
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Indicateur de chapitre. Il remplace le fil d'Ariane, qui n'a pas de sens sur
   une page unique. */
.entete__chapitre {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 0 auto 0 0;
  padding-left: var(--pas);
  border-left: 1px solid var(--line);
  font-size: var(--t-petit);
  color: var(--body);
}

.entete__chapitre-index {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--accent);
}

.entete__nav {
  display: flex;
  gap: clamp(14px, 1.6vw, 26px);
}

.entete__lien {
  position: relative;
  text-decoration: none;
  font-size: var(--t-petit);
  color: var(--body);
  padding: 6px 0;
  transition: color var(--transition);
}

.entete__lien::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--transition);
}

.entete__lien:hover,
.entete__lien:focus-visible,
.entete__lien.est-active {
  color: var(--ink);
}

.entete__lien:hover::after,
.entete__lien:focus-visible::after,
.entete__lien.est-active::after {
  transform: scaleX(1);
}

/* Le bouton d'action de l'en-tête. Ce n'est pas un lien de navigation : il ne
   porte pas le filet qui se déplie au survol, il porte un cadre. Un lien qui
   ressemble aux six autres n'est pas une action, c'est une septième rubrique. */
.entete__lien--action {
  padding: 8px 14px;
  border: 1px solid var(--accent);
  color: var(--ink);
}
.entete__lien--action::after { display: none; }
.entete__lien--action:hover,
.entete__lien--action:focus-visible {
  background: var(--accent);
  color: var(--bg);
}

/* ==========================================================================
   L'APPEL DU CONTACT

   Le bloc qui a remplacé le formulaire court le 12/09/2026. Il est encadré
   d'accent parce qu'il est la seule action de la section : un bloc qui ne se
   distingue pas de son voisin ne se lit pas comme une action.
   ========================================================================== */

.appel {
  border: 1px solid var(--accent);
  background: var(--accent-soft);
  padding: clamp(24px, 3.4vw, 40px);
}

.appel__sur-titre {
  margin: 0 0 8px;
  font-family: var(--font-mono);
  font-size: var(--t-petit);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}

.appel__titre {
  margin: 0 0 var(--pas);
  font-family: var(--font-titre);
  font-weight: 800;
  font-size: clamp(1.6rem, 3.4vw, 2.4rem);
  line-height: 1.1;
  letter-spacing: -0.03em;
  color: var(--ink);
}

.appel__liste {
  margin: 0 0 calc(var(--pas) * 1.4);
  padding: 0;
  list-style: none;
  color: var(--body);
}

/* Le tiret est décoratif et posé en CSS : dans le texte, il serait lu par un
   lecteur d'écran à chaque ligne. */
.appel__liste li {
  position: relative;
  padding-left: 20px;
  margin-bottom: 8px;
}
.appel__liste li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.7em;
  width: 10px;
  height: 1px;
  background: var(--accent);
}
.appel__liste strong { color: var(--ink); font-weight: 600; }

.appel__action { margin: 0 0 var(--pas); }
.appel__note { margin: 0; font-size: var(--t-petit); color: var(--muted); }

.entete__burger {
  display: none;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 0 12px;
  margin-left: auto;
  background: none;
  border: 1px solid var(--line-strong);
  border-radius: var(--arrondi);
  color: var(--ink);
  font: inherit;
  font-size: var(--t-petit);
  cursor: pointer;
}

.entete__burger-traits,
.entete__burger-traits::before,
.entete__burger-traits::after {
  display: block;
  width: 16px;
  height: 1px;
  background: currentColor;
}

.entete__burger-traits {
  position: relative;
}

.entete__burger-traits::before,
.entete__burger-traits::after {
  content: '';
  position: absolute;
  left: 0;
}

.entete__burger-traits::before { top: -5px; }
.entete__burger-traits::after  { top: 5px; }

/* ==========================================================================
   01 · OUVERTURE
   ========================================================================== */

.ouverture {
  position: relative;
  /* La hauteur retire l'en-tête ET le bandeau de maquette. Sans le second,
     l'indice « faites défiler » et le bandeau tombaient sous la ligne de
     flottaison, c'est-à-dire que la seule invitation à descendre n'était
     visible qu'une fois descendu. */
  min-height: calc(100svh - var(--haut-entete) - 46px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: calc(var(--section) * 0.5) 0 0;
  overflow: hidden;
}

/* Halo chaud derrière le nom. Il suit le pointeur, ce qui donne l'impression
   d'une source de lumière dans la pièce plutôt que d'un dégradé collé au
   fond. Les deux variables sont écrites par le script. */
.ouverture__lueur {
  position: absolute;
  inset: -20%;
  pointer-events: none;
  background:
    radial-gradient(
      42vmax 42vmax at var(--x, 50%) var(--y, 42%),
      color-mix(in srgb, var(--accent) 26%, transparent) 0%,
      transparent 68%
    );
  opacity: 0.9;
  transition: background 0.6s ease-out;
}

.ouverture__contenu {
  position: relative;
  width: 100%;
  max-width: var(--largeur-max);
  margin: 0 auto;
  padding: 0 var(--marge-page);
}

.ouverture__nom {
  margin: 0 0 var(--pas);
  font-size: var(--t-geant);
  line-height: 0.86;
  letter-spacing: -0.05em;
}

.ouverture__lignes {
  display: block;
}

.ouverture__ligne {
  display: block;
}

/* Le décalage de la seconde ligne est ce qui empêche le bloc de ressembler à
   un titre centré ordinaire. Il reste modeste, et il disparaît sous 700 px où
   la place manque. */
.ouverture__ligne--decalee {
  padding-left: 0.16em;
  color: transparent;
  -webkit-text-stroke: 1px var(--ink);
}

/* Chaque lettre est un `span` créé par le script, pour la cascade d'entrée. */
.ouverture__lettre {
  display: inline-block;
  transform: translateY(0.9em);
  opacity: 0;
}

.js .ouverture__lettre {
  animation: lettre-entre 0.9s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: calc(var(--i) * 0.045s + 0.15s);
}

@keyframes lettre-entre {
  to { transform: translateY(0); opacity: 1; }
}

.ouverture__role {
  /* 26ch et pas 34 : à 34, la coupure tombait après « des sites » et laissait
     « sur mesure. » seul sur sa ligne, le mot en italique se lisant alors comme
     une légende détachée. À 26, elle tombe après « développe ». */
  max-width: 26ch;
  margin: 0 0 calc(var(--pas) * 1.6);
  font-size: var(--t-sous-titre);
  color: var(--body);
}

.ouverture__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}

.ouverture__indice {
  position: relative;
  max-width: var(--largeur-max);
  width: 100%;
  margin: calc(var(--pas) * 2) auto var(--pas);
  padding: 0 var(--marge-page);
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--muted);
}

.ouverture__indice-trait {
  display: block;
  width: 40px;
  height: 1px;
  background: var(--line-strong);
  overflow: hidden;
  position: relative;
}

.ouverture__indice-trait::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform: translateX(-100%);
  animation: trait-glisse 2.4s ease-in-out infinite;
}

@keyframes trait-glisse {
  0%   { transform: translateX(-100%); }
  60%  { transform: translateX(100%); }
  100% { transform: translateX(100%); }
}

/* --- Bandeau défilant ----------------------------------------------------- */
.bandeau {
  position: relative;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  overflow: hidden;
  padding: 12px 0;
}

.bandeau__piste {
  display: flex;
  width: max-content;
  animation: bandeau-defile 34s linear infinite;
}

.bandeau__suite {
  display: flex;
  flex-shrink: 0;
}

.bandeau__suite span {
  padding: 0 clamp(18px, 3vw, 44px);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

/* La piste contient deux copies identiques : on translate d'exactement la
   moitié, donc la boucle est invisible. */
@keyframes bandeau-defile {
  to { transform: translateX(-50%); }
}

/* ==========================================================================
   02 · MANIFESTE
   ========================================================================== */

.manifeste__phrase {
  max-width: 22ch;
  margin: 0;
  font-family: var(--font-titre);
  font-weight: 600;
  font-size: var(--t-manifeste);
  line-height: 1.16;
  letter-spacing: -0.03em;
  color: var(--ink);
  max-inline-size: 24ch;
}

/* Chaque mot est un `span` créé par le script. Sans JavaScript, la phrase
   reste entièrement lisible : c'est le mot qui s'éteint, pas la phrase qui
   naît. */
/* L'effet se fait par la COULEUR seule, jamais par l'opacité. Baisser
   l'opacité d'un texte baisse son contraste réel : la première version
   descendait à 1,4 pour 1, soit 39 mots illisibles à chaque instant. Ici le
   mot éteint tient déjà 4,65 et le mot lu monte à 18,52, ce qui laisse un
   écart de 1 à 4 : l'effet reste franc, et il reste lisible. */
.mot {
  display: inline-block;
  color: var(--mot-eteint);
  transition: color 0.25s linear;
}

.mot.est-lu {
  color: var(--ink);
}

@media (min-width: 900px) {
  .manifeste__phrase { max-inline-size: 20ch; }
}

/* ==========================================================================
   TITRES EN DÉGRADÉ

   Le texte devient transparent et laisse voir le fond du titre, découpé à la
   forme des lettres. Deux précautions qui ne se voient pas mais sans
   lesquelles ça casse :

     - `color: transparent` seul suffirait, mais si le navigateur ne comprend
       pas `background-clip: text`, le titre disparaît. La couleur pleine est
       donc posée d'abord et n'est retirée que dans un `@supports`
     - le mot en italique garde SA couleur : il repeint par-dessus le dégradé,
       ce qui est exactement l'effet voulu, un accent qui tranche sur un titre
       qui s'éteint vers le bas
   ========================================================================== */

.titre-degrade {
  color: var(--ink);
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .titre-degrade {
    background-image: linear-gradient(
      178deg,
      var(--ink) 0%,
      var(--titre-degrade-bas) 100%
    );
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }

  .section-sombre .titre-degrade {
    background-image: linear-gradient(
      178deg,
      var(--on-panel) 0%,
      var(--titre-degrade-bas-clair) 100%
    );
  }
}

/* ==========================================================================
   BANDEAU D'IMAGES — deux rangées en sens inverse, pilotées par le défilement
   ========================================================================== */

.bandeau-images {
  padding: clamp(48px, 9vw, 120px) 0 clamp(20px, 3vw, 40px);
  display: grid;
  gap: 12px;
}

/* Chaque rangée découpe sa piste. C'est ce `hidden` qui garantit qu'une piste
   trois fois plus large que l'écran ne fasse jamais défiler le document. */
.bandeau-images__rangee {
  overflow: hidden;
}

.bandeau-images__piste {
  display: flex;
  width: max-content;
  will-change: transform;
}

.bandeau-images__jeu {
  display: flex;
  gap: 12px;
  padding-right: 12px;
}

/* La plaque a la proportion d'une capture de site, et cette place est tenue
   même vide : la mise en page se juge telle qu'elle sera, pas une fois les
   captures arrivées. */
.plaque {
  flex: 0 0 auto;
  width: clamp(220px, 30vw, 420px);
  aspect-ratio: 420 / 270;
  border-radius: var(--arrondi-plaque);
  border: 1px solid var(--line);
  /* Le liseré clair en haut n'est pas un ornement : sans lui, une plaque en
     dégradé sombre posée sur un fond sombre n'a plus d'arête, et les deux
     rangées se lisent comme une seule tache. C'est lui qui redonne un bord. */
  box-shadow: inset 0 1px 0 rgba(247, 246, 243, 0.16);
  background:
    radial-gradient(120% 100% at 18% 8%,
      color-mix(in srgb, var(--accent) 88%, transparent) 0%, transparent 62%),
    radial-gradient(90% 90% at 88% 86%,
      color-mix(in srgb, var(--accent) 34%, transparent) 0%, transparent 55%),
    linear-gradient(158deg, var(--bg-alt) 0%, var(--card) 100%);
}

/* Six variantes qui tournent, pour qu'aucune plaque voisine ne soit identique.
   Faire varier l'angle et la position de la source lumineuse suffit : ajouter
   une seconde teinte donnerait au site deux accents, donc aucun. */
/* Les variantes ne redéclarent que le fond : le liseré, la taille et l'arrondi
   restent ceux de `.plaque`. */
.plaque:nth-child(6n + 2) {
  background:
    radial-gradient(110% 120% at 82% 12%,
      color-mix(in srgb, var(--accent) 76%, transparent) 0%, transparent 64%),
    linear-gradient(20deg, var(--card) 0%, var(--bg) 100%);
}

.plaque:nth-child(6n + 3) {
  background:
    radial-gradient(140% 80% at 50% 110%,
      color-mix(in srgb, var(--accent) 92%, transparent) 0%, transparent 66%),
    linear-gradient(200deg, var(--bg-alt) 0%, var(--bg) 100%);
}

.plaque:nth-child(6n + 4) {
  background:
    conic-gradient(from 210deg at 30% 40%,
      color-mix(in srgb, var(--accent) 70%, transparent) 0deg,
      transparent 140deg,
      color-mix(in srgb, var(--accent) 30%, transparent) 300deg,
      transparent 360deg),
    linear-gradient(140deg, var(--card) 0%, var(--bg-alt) 100%);
}

.plaque:nth-child(6n + 5) {
  background:
    radial-gradient(70% 130% at 8% 92%,
      color-mix(in srgb, var(--accent) 84%, transparent) 0%, transparent 58%),
    radial-gradient(60% 60% at 70% 20%,
      color-mix(in srgb, var(--ink) 22%, transparent) 0%, transparent 62%),
    linear-gradient(180deg, var(--bg-alt) 0%, var(--card) 100%);
}

.plaque:nth-child(6n + 6) {
  background:
    linear-gradient(118deg,
      color-mix(in srgb, var(--accent) 62%, transparent) 0%,
      transparent 46%),
    linear-gradient(300deg, var(--card) 0%, var(--bg) 100%);
}

/* ==========================================================================
   AIMANT — le bouton suit un peu le pointeur
   ========================================================================== */

.aimant {
  display: inline-block;
  /* Les deux transitions sont différentes exprès : franche à l'approche,
     longue au retour. C'est ce déséquilibre qui donne la sensation d'une
     attraction plutôt que d'un simple décalage. */
  transition: transform 0.3s ease-out;
  will-change: transform;
}

.aimant.est-relache {
  transition: transform 0.6s ease-in-out;
}

/* ==========================================================================
   03 · CE QUE JE FAIS
   ========================================================================== */

.savoir-faire__titre {
  max-width: 16ch;
  margin-bottom: calc(var(--section) * 0.6);
}

.offres {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line);
}

.offre {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: clamp(16px, 4vw, 56px);
  align-items: start;
  padding: clamp(28px, 4vw, 52px) 0;
  border-bottom: 1px solid var(--line);
  overflow: hidden;
}

/* Le volet : un aplat d'accent qui balaie la ligne de gauche à droite au
   moment où elle entre à l'écran, puis découvre le contenu. C'est l'effet le
   moins coûteux du site et l'un des plus remarqués. */
.js [data-volet]::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  z-index: 2;
  pointer-events: none;
}

.js [data-volet] > * {
  opacity: 0;
}

.js [data-volet].est-vu::before {
  animation: volet-balaie 1.05s cubic-bezier(0.7, 0, 0.2, 1) forwards;
  animation-delay: calc(var(--i, 0) * 0.13s);
}

.js [data-volet].est-vu > * {
  animation: volet-decouvre 0.01s linear forwards;
  animation-delay: calc(var(--i, 0) * 0.13s + 0.5s);
}

@keyframes volet-balaie {
  0%   { transform: scaleX(0); transform-origin: left; }
  48%  { transform: scaleX(1); transform-origin: left; }
  52%  { transform: scaleX(1); transform-origin: right; }
  100% { transform: scaleX(0); transform-origin: right; }
}

@keyframes volet-decouvre {
  to { opacity: 1; }
}

.offre__numero {
  font-family: var(--font-mono);
  font-size: var(--t-petit);
  color: var(--accent);
  padding-top: 0.35em;
}

.offre__corps {
  min-width: 0;
}

.offre__titre {
  margin: 0 0 10px;
  font-size: clamp(1.35rem, 2.6vw, 2.1rem);
}

.offre__texte {
  margin: 0;
  color: var(--body);
}

/* Le trait qui se dessine au survol. Il est en `auto` de colonne, donc il
   n'occupe rien tant qu'il ne s'ouvre pas. */
.offre__marque {
  align-self: center;
  display: block;
  width: clamp(24px, 6vw, 72px);
  height: 1px;
  background: var(--line-strong);
  transition: background var(--transition), transform var(--transition);
  transform-origin: right;
}

.offre:hover .offre__marque {
  background: var(--accent);
  transform: scaleX(1.35);
}

/* ==========================================================================
   04 · MÉTHODE — les cartes qui s'empilent
   ========================================================================== */

.methode {
  padding: var(--section) 0;
}

.methode__intro {
  margin-bottom: calc(var(--section) * 0.5);
}

.methode__titre {
  max-width: 14ch;
}

.pile {
  list-style: none;
  margin: 0 auto;
  padding: 0 var(--marge-page);
  max-width: var(--largeur-max);
}

/* Le cœur de l'effet tient en une ligne : chaque élément est `sticky`, avec un
   `top` qui augmente de carte en carte. La suivante vient donc recouvrir la
   précédente en laissant dépasser un liseré. Aucune bibliothèque. */
.pile__element {
  position: sticky;
  top: calc(var(--haut-entete) + 24px);
  padding-bottom: 18px;
}

.pile__element:nth-child(1) { top: calc(var(--haut-entete) + 24px); }
.pile__element:nth-child(2) { top: calc(var(--haut-entete) + 44px); }
.pile__element:nth-child(3) { top: calc(var(--haut-entete) + 64px); }
.pile__element:nth-child(4) { top: calc(var(--haut-entete) + 84px); }

/* Le recul est piloté par le script, qui n'écrit qu'une variable. Le CSS
   décide ce qu'on en fait, donc changer l'ampleur de l'effet ne demande pas de
   toucher au JavaScript. `--recul` vaut 0 quand la carte est seule à l'écran
   et 1 quand la suivante l'a entièrement recouverte. */
.etape {
  transform: scale(calc(1 - var(--recul, 0) * 0.06));
  transform-origin: center top;
  transition: transform 0.15s linear;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(16px, 3vw, 40px);
  align-items: start;
  min-height: clamp(240px, 34vh, 320px);
  padding: clamp(24px, 4vw, 48px);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--arrondi-carte);
}

.pile__element:nth-child(even) .etape {
  background: var(--bg-alt);
}

/* Le corps existe pour une raison de grille, pas de style : sans lui, le titre
   et le texte sont deux enfants de plus dans une grille à deux colonnes, donc
   le texte repart à la ligne suivante SOUS le numéro. Défaut trouvé sur la
   capture, pas en relisant le CSS. */
.etape__corps {
  max-width: var(--largeur-texte);
}

.etape__numero {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--t-petit);
  color: var(--accent);
}

.etape__titre {
  margin: 0 0 12px;
  font-size: clamp(1.4rem, 3vw, 2.3rem);
}

.etape__texte {
  margin: 0;
  color: var(--body);
}

/* ==========================================================================
   05 · RÉALISATIONS — défilement horizontal
   ========================================================================== */

.travaux {
  position: relative;
  background: var(--bg-alt);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.travaux__scene {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  align-items: center;
  /* Ce `hidden` est la sécurité qui empêche tout débordement horizontal du
     document : la piste est plus large que l'écran par construction, elle est
     découpée ici et jamais par le `body`. */
  overflow: hidden;
}

.travaux__piste {
  display: flex;
  align-items: center;
  gap: clamp(20px, 3vw, 48px);
  padding: 0 var(--marge-page);
  will-change: transform;
}

.travaux__ouverture {
  flex: 0 0 auto;
  width: min(38ch, 74vw);
  padding-right: clamp(20px, 4vw, 60px);
}

.travaux__titre {
  margin-bottom: var(--pas);
}

.travaux__legende {
  margin: 0;
  color: var(--muted);
  font-size: var(--t-petit);
}

.projet {
  flex: 0 0 auto;
  width: min(420px, 78vw);
  padding: clamp(18px, 2vw, 26px);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--arrondi-carte);
  transition: border-color var(--transition), transform var(--transition);
}

.projet:hover {
  border-color: var(--accent);
  transform: translateY(-6px);
}

.projet__index {
  margin: 0 0 14px;
  font-family: var(--font-mono);
  font-size: var(--t-petit);
  color: var(--accent);
}

/* L'emplacement de la capture. Il occupe la vraie place d'une image, pour que
   la mise en page soit jugée telle qu'elle sera, et pas une fois les images
   arrivées. */
.projet__vignette {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 16 / 10;
  margin-bottom: var(--pas);
  border: 1px dashed var(--line-strong);
  border-radius: var(--arrondi);
  background: var(--bg);
}

.projet__vide {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: center;
  padding: 0 12px;
}

.projet__titre {
  margin: 0 0 var(--pas);
  font-size: clamp(1.2rem, 2vw, 1.6rem);
}

.projet__fiche {
  margin: 0;
  display: grid;
  gap: 8px;
  font-size: var(--t-petit);
}

.projet__fiche > div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
}

.projet__fiche dt {
  color: var(--muted);
}

.projet__fiche dd {
  margin: 0;
  text-align: right;
}

/* ==========================================================================
   BLOCS EMPILÉS

   Les deux dernières sections se chevauchent : chacune remonte sur la
   précédente et arrondit largement ses deux coins hauts. L'effet ne coûte rien
   et il fait beaucoup, parce qu'il donne au bas de page une épaisseur que des
   sections posées bout à bout n'ont jamais.

   Le `z-index` est indispensable : sans lui, la section qui remonte passe SOUS
   la précédente et son arrondi ne se voit pas.
   ========================================================================== */

.bloc-empile {
  position: relative;
  z-index: 2;
  border-radius: var(--arrondi-bloc) var(--arrondi-bloc) 0 0;
  margin-top: calc(var(--section) * -0.55);
}

/* La seconde remonte sur la première, donc elle passe devant. */
.contact.bloc-empile {
  z-index: 3;
  background: var(--bg);
}

/* ==========================================================================
   06 · EN CE MOMENT — la seule section claire
   ========================================================================== */

.en-ce-moment {
  border-top: 1px solid var(--line);
}

.en-ce-moment__grille {
  display: grid;
  gap: clamp(28px, 5vw, 72px);
  align-items: start;
}

@media (min-width: 900px) {
  .en-ce-moment__grille {
    grid-template-columns: 1.35fr 1fr;
  }
}

.en-ce-moment__titre {
  max-width: 12ch;
}

.fiche {
  margin: 0;
  display: grid;
  gap: 0;
}

.fiche__ligne {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--pas);
  padding: 14px 0;
  border-bottom: 1px solid rgba(18, 18, 15, 0.16);
  font-size: var(--t-petit);
}

.fiche__ligne:first-child {
  border-top: 1px solid rgba(18, 18, 15, 0.16);
}

.fiche dt {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  opacity: 0.7;
}

.fiche dd {
  margin: 0;
  text-align: right;
}

/* Sur fond sombre, les filets de la fiche reprennent la couleur du site. */
.fiche--sombre .fiche__ligne {
  border-bottom-color: var(--line);
}

.fiche--sombre .fiche__ligne:first-child {
  border-top-color: var(--line);
}

/* ==========================================================================
   08 · ACCESSIBILITÉ

   La section a porté la charte du brief « Prisma » jusqu'au 30/08/2026. Elle
   est écrite ici dans celle du site, et elle n'a demandé qu'un fond, quelques
   largeurs et un encart : tout le reste vient de composants qui existaient
   déjà, `.eyebrow`, `.titre-degrade`, `.offres`, `.bouton`.

   Elle est posée sur --bg-alt et non sur --bg, pour deux raisons qui vont
   ensemble : elle se détache à peine de la section précédente, et le contact
   qui remonte sur elle en --bg redevient visible. Deux blocs de la même
   couleur se chevauchant, l'arrondi ne se verrait pas.

   Ratios mesurés sur --bg-alt (#101014), tous très au-dessus du seuil :
     --ink                17.57   les titres
     --body                9.06   le texte courant et les points
     --muted               5.65   les mentions
     --accent             14.42   le surtitre et les numéros
     --titre-degrade-bas   6.12   le bas du dégradé du titre
   ========================================================================== */

/* Le fond vient de `.section-alt`, le vocabulaire du socle, plutôt que d'une
   règle de plus ici : deux déclarations de la même couleur finissent par
   diverger. */
.acces__intro {
  margin-bottom: calc(var(--section) * 0.7);
}

.acces__titre {
  max-width: 18ch;
  margin-bottom: 0.4em;
}

/* L'astérisque appelle la note de fin de section. Il est retiré aux lecteurs
   d'écran : seul l'œil fait le lien entre une marque et un renvoi, et la note
   commence de toute façon par une phrase qui se suffit à elle-même. */
.acces__marque {
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: 0.4em;
  vertical-align: super;
  margin-left: 0.12em;
}

/* Deux colonnes sous le titre, comme « En ce moment » et comme le contact :
   la promesse et son bouton à gauche, ce qui la fonde à droite. En une seule
   colonne, quatre paragraphes larges de 62ch laissaient toute la moitié droite
   de la page vide, ce qui se lit comme une section inachevée. */
.acces__colonnes {
  display: grid;
  gap: clamp(24px, 5vw, 72px);
  align-items: start;
}

@media (min-width: 900px) {
  .acces__colonnes {
    grid-template-columns: 1fr 1.15fr;
  }
}

.acces__chapeau {
  max-width: 26ch;
  margin: 0;
  font-size: var(--t-sous-titre);
  color: var(--ink);
}

.acces__texte {
  max-width: var(--largeur-texte);
  margin: 0 0 var(--pas);
  color: var(--body);
}

.acces__texte--dernier {
  margin-bottom: 0;
}

.acces__action {
  margin: calc(var(--pas) * 1.4) 0 0;
}

.acces__intertitre {
  max-width: 34ch;
  margin: 0;
  font-family: var(--font-titre);
  font-size: var(--t-sous-titre);
  color: var(--ink);
}

.acces__liste {
  margin-top: var(--pas);
}

/* Les points d'un document. Pas de puce dessinée : le composant `.offre` est
   déjà une liste, et une seconde série de marques ferait deux niveaux de
   ponctuation pour un seul niveau de lecture. Le retrait suffit à les tenir
   ensemble. */
.acces__points {
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 6px;
  max-width: var(--largeur-texte);
  color: var(--body);
  font-size: var(--t-texte);
}

.acces__points li {
  position: relative;
  padding-left: 18px;
}

.acces__points li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 8px;
  height: 1px;
  background: var(--accent);
}

.acces__parcours {
  max-width: var(--largeur-texte);
  margin: var(--pas) 0 0;
  color: var(--muted);
  font-size: var(--t-petit);
}

.acces__parcours code {
  font-family: var(--font-mono);
  color: var(--accent);
}

/* La note de réserve. Elle ressemble à `.note-trou` et n'en est pas une : les
   notes de relecture disparaissent le jour de la mise en ligne, celle-ci est
   adressée au client et reste. Elle porte donc sa propre classe, sans quoi un
   nettoyage de fin la ferait tomber avec les autres. */
.acces__note {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  max-width: var(--largeur-texte);
  margin: calc(var(--section) * 0.5) 0 0;
  padding: var(--pas);
  background: var(--card);
  border-left: 2px solid var(--accent);
  color: var(--body);
  font-size: var(--t-petit);
}

.acces__note strong {
  color: var(--ink);
}

.acces__note-marque {
  font-family: var(--font-mono);
  color: var(--accent);
}

/* ==========================================================================
   07 · CONTACT
   ========================================================================== */

.contact__titre {
  max-width: 14ch;
  margin-bottom: calc(var(--section) * 0.5);
}

.contact__grille {
  display: grid;
  gap: clamp(32px, 5vw, 72px);
  align-items: start;
}

@media (min-width: 900px) {
  .contact__grille {
    grid-template-columns: 1fr 1.1fr;
  }
}

.contact__texte {
  color: var(--body);
  margin-bottom: calc(var(--pas) * 1.5);
}

/* --- Formulaire, repris du composant du socle ----------------------------- */
.form {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 34rem;
}

.form__champ {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* Aucune couleur ici, volontairement : l'étiquette hérite de la couleur de sa
   section. Posée en dur, elle resterait sombre dans une section sombre. */
.form__champ label {
  font-size: var(--t-petit);
}

.form__champ input,
.form__champ textarea {
  min-height: 44px;
  padding: 12px 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--arrondi);
  background: var(--bg-alt);
  color: var(--ink);
  font: inherit;
  transition: border-color var(--transition);
}

.form__champ textarea {
  resize: vertical;
}

.form__champ input:focus,
.form__champ textarea:focus {
  border-color: var(--accent);
}

.form__mention {
  margin: 0;
  font-size: var(--t-petit);
  color: var(--muted);
}

.form__reponse {
  margin: 0;
  font-size: var(--t-petit);
  color: var(--accent);
}

.form__reponse:empty {
  display: none;
}

/* ==========================================================================
   PIED DE PAGE
   ========================================================================== */

.pied {
  padding: var(--section) 0 0;
  border-top: 1px solid var(--line);
  /* Le nom géant est calibré pour tenir, mais il est en `vw` : ce `clip`
     garantit qu'aucun réglage de zoom ou de police système ne le fasse
     déborder du document. */
  overflow: clip;
}

.pied__grille {
  display: grid;
  gap: clamp(28px, 4vw, 56px);
  align-items: start;
}

@media (min-width: 760px) {
  .pied__grille {
    grid-template-columns: 1fr auto 1fr;
  }
}

.pied__nom {
  margin: 0;
  font-family: var(--font-titre);
  font-weight: 800;
  font-size: 1.2rem;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.pied__signature {
  margin: 4px 0 0;
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}

.pied__nav {
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: var(--t-petit);
}

.pied__nav a,
.pied__legal a {
  color: var(--body);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color var(--transition), border-color var(--transition);
  align-self: flex-start;
}

.pied__nav a:hover,
.pied__legal a:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.pied__legal {
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: var(--t-petit);
}

.pied__note {
  margin: 6px 0 0;
  max-width: 42ch;
  color: var(--muted);
  font-size: var(--t-petit);
}

/* Le nom en très grand qui ferme la page. Taille en `vw` calculée pour tenir
   dans la largeur : 10 caractères en Bricolage 800 occupent environ 0,56 em
   chacun, donc 15vw donne à peu près 84 % de la largeur. */
.pied__signature-geante {
  margin: var(--section) 0 0;
  /* Sans ce fond de page, la dernière ligne du nom est coupée net par le bord
     du document. Relevé sur la capture du pied. */
  padding-bottom: clamp(20px, 3vw, 48px);
  text-align: center;
  font-family: var(--font-titre);
  font-weight: 800;
  font-size: clamp(2rem, 15vw, 13rem);
  line-height: 0.9;
  letter-spacing: -0.05em;
  white-space: nowrap;
  color: transparent;
  -webkit-text-stroke: 1px var(--line-strong);
  user-select: none;
}

/* ==========================================================================
   APPARITION AU SCROLL — la mécanique générique
   ========================================================================== */

/* `.js` est posé par le script sur `<html>`. Sans lui, rien n'est masqué :
   une page sans JavaScript reste entièrement lisible, ce qui est la seule
   façon acceptable de faire des apparitions au défilement. */
.js [data-apparait] {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--transition-lente), transform var(--transition-lente);
  transition-delay: calc(var(--i, 0) * 0.08s);
}

.js [data-apparait].est-vu {
  opacity: 1;
  transform: none;
}

/* ==========================================================================
   RESPONSIVE
   ========================================================================== */

@media (max-width: 900px) {
  .entete__nav {
    display: none;
    position: absolute;
    top: var(--haut-entete);
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 0;
    padding: var(--pas) var(--marge-page) calc(var(--pas) * 1.5);
    background: var(--bg);
    border-bottom: 1px solid var(--line);
  }

  .entete__nav.est-ouvert {
    display: flex;
  }

  .entete__lien {
    padding: 14px 0;
    border-bottom: 1px solid var(--line);
    font-size: var(--t-texte);
  }

  .entete__burger {
    display: inline-flex;
  }

  .entete__chapitre {
    display: none;
  }

  /* Le défilement horizontal est désactivé sous 900 px : au doigt, un
     défilement latéral piloté par le défilement vertical est désorientant, et
     c'est la première source de débordement sur mobile. Les projets
     s'empilent. */
  .travaux {
    padding: var(--section) 0;
  }

  .travaux__scene {
    position: static;
    height: auto;
    overflow: visible;
  }

  .travaux__piste {
    flex-direction: column;
    align-items: stretch;
    transform: none !important;
    max-width: var(--largeur-max);
    margin: 0 auto;
  }

  .travaux__ouverture,
  .projet {
    width: auto;
    max-width: none;
    padding-right: 0;
  }

  .projet {
    padding: clamp(18px, 2vw, 26px);
  }

  /* Les cartes empilées deviennent une simple liste : sur un écran court,
     quatre cartes `sticky` finissent par masquer leur propre contenu. */
  .pile__element,
  .pile__element:nth-child(1),
  .pile__element:nth-child(2),
  .pile__element:nth-child(3),
  .pile__element:nth-child(4) {
    position: static;
    padding-bottom: 14px;
  }

  .etape {
    min-height: 0;
  }
}

@media (max-width: 700px) {
  .ouverture__ligne--decalee {
    padding-left: 0;
  }

  .offre {
    grid-template-columns: auto 1fr;
  }

  .offre__marque {
    display: none;
  }
}

/* ==========================================================================
   RÉDUIRE LES ANIMATIONS

   Tous les effets du site sont annulés ici, en un seul endroit. `base.css`
   ramène déjà les durées à 0,01 ms, ce qui suffit pour les transitions mais
   PAS pour ce site : un élément animé qui part de `opacity: 0` resterait
   invisible, et le nom du hero ne s'afficherait jamais. Il faut donc en plus
   imposer l'état final.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .js [data-apparait],
  .js [data-volet] > *,
  .ouverture__lettre,
  .js .ouverture__lettre {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }

  .js [data-volet]::before {
    display: none;
  }

  .mot {
    color: var(--ink);
  }

  .bandeau__piste,
  .ouverture__indice-trait::after {
    animation: none;
  }

  /* Les rangées d'images ne glissent plus et les cartes ne reculent plus. Le
     script ne les branche pas non plus : un effet neutralisé en CSS continue
     à être calculé à chaque pixel de défilement. */
  .bandeau-images__piste {
    transform: none !important;
  }

  .etape {
    transform: none !important;
  }

  .aimant {
    transform: none !important;
    transition: none;
  }

  .ouverture__indice-trait::after {
    transform: none;
  }

  /* Le halo cesse de suivre le pointeur : le script ne l'écoute plus, et sa
     transition est neutralisée pour qu'il ne « rattrape » pas une position. */
  .ouverture__lueur {
    transition: none;
  }

  /* Le défilement horizontal piloté par le scroll est un mouvement ample :
     c'est exactement ce que ce réglage demande d'éviter. La section redevient
     une liste verticale, sur toutes les largeurs. */
  .travaux__scene {
    position: static;
    height: auto;
    overflow: visible;
  }

  .travaux__piste {
    flex-direction: column;
    align-items: stretch;
    transform: none !important;
  }

  .travaux__ouverture,
  .projet {
    width: auto;
    padding-right: 0;
  }

  .projet:hover {
    transform: none;
  }
}

/* ==========================================================================
   IMPRESSION

   `base.css` traite déjà `[data-apparait]`. Restent les effets propres à ce
   site : sans ces règles, une impression sort avec des sections vides.
   ========================================================================== */

@media print {
  /* Le bandeau d'images est décoratif et n'apporte rien sur papier, où il
     sortirait de toute façon coupé au milieu d'une plaque. */
  .bandeau-images,
  .grain,
  .regle,
  .ouverture__lueur,
  .bandeau,
  .ouverture__indice,
  .pied__signature-geante {
    display: none !important;
  }

  .js [data-volet] > *,
  .ouverture__lettre {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }

  .js [data-volet]::before { display: none; }

  /* Seule couleur en dur du fichier, et elle est assumée : sur du papier
     blanc, c'est de l'encre noire qu'il faut, pas la couleur du thème. */
  .mot { color: #000 !important; }

  .travaux__scene { position: static; height: auto; overflow: visible; }
  .travaux__piste { flex-direction: column; transform: none !important; }
  .projet, .travaux__ouverture { width: auto; }

  .pile__element { position: static; }
  .etape { transform: none !important; }
  .bloc-empile { margin-top: 0; border-radius: 0; }
}
