/* ============================================================================
   styles.css — KILTER
   Aucune couleur en dur : tout passe par tokens.css.

   LES HAUTEURS SONT MESURÉES CHEZ LA CIBLE, et leur SOMME l'est aussi :
     zone de hero (deux sections superposées) ......... 1800
     travaux .......................................... 3867
     entre-deux (aucun bloc sémantique) ............... 1012
     communication .................................... 1041
     entre-deux court ................................. 31
     pied ............................................. 1158
     queue ............................................ 29
                                                       ─────
                                                        8938  = document de la cible

   Les deux entre-deux ne sont pas du remplissage : la cible a bien 1012 px entre la fin
   de sa section travaux (5667) et le début de sa section communication (6679), et
   31 px de plus avant son pied. Les combler décalerait toutes les positions en aval, et
   avec elles chaque course de défilement.
   ============================================================================ */

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

body {
  background: var(--encre);
  color: var(--blanc);
  font-family: var(--police);
  font-size: var(--t14);
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
h1, h2 { margin: 0; font-weight: 500; }

.t9  { font-size: var(--t9);  letter-spacing: .06em; text-transform: uppercase; margin: 0; }
.t11 { font-size: var(--t11); letter-spacing: .05em; text-transform: uppercase; margin: 0; }
.t14 { font-size: var(--t14); margin: 0; }
.t18 { font-size: var(--t18); margin: 0; }
.t24 { font-size: var(--t24); margin: 0; font-weight: 500; }

/* ── Éléments FIXES — c'est eux qui font le mouvement de ce site ───────────── */
.entete {
  position: fixed; top: var(--gouttiere); left: 0; right: 0; z-index: 1000;
  height: 14px; display: flex; align-items: center; justify-content: space-between;
  padding: 0 var(--marge);
  font-size: var(--t11); letter-spacing: .05em; text-transform: uppercase;
  mix-blend-mode: difference;
}
.marque { font-weight: 500; }

.nav-laterale {
  position: fixed; top: 450px; left: var(--marge); z-index: 999;
  display: grid; gap: 6px;
  font-size: var(--t11); letter-spacing: .05em; text-transform: uppercase;
  mix-blend-mode: difference;
}
.jauge {
  position: fixed; top: 450px; right: var(--marge); z-index: 5;
  width: 33px; height: 10px; border: 1px solid var(--filet);
}
.jauge i { display: block; height: 100%; width: 0; background: var(--papier); }

/* ── LA ZONE DE HERO : deux sections au MÊME offsetTop ─────────────────────── */
.zone-hero { position: relative; height: 1800px; }
.zone-hero > section { position: absolute; top: 0; left: 0; width: 100%; height: 900px; }

/* 0 · le mur d'affiches. `sticky` chez la cible (styles_hero_inner__, 1440×900). */
/* `#hero` est mesuré à top 0, hauteur 900 — c'est ce que sections.mjs relève chez la
   cible, et c'est ce qui donne le jeton. Mais un `position: sticky` posé DANS une boîte
   de 900 px n'a aucune course : la boîte fait exactement la hauteur du viewport, donc
   l'élément se décolle au premier pixel. Le mur partirait aussitôt.
   D'où `fixed` : chez la cible aussi, le bloc de tête du hero (styles_hero_top__) est en
   `position: fixed`. Il est retiré du flux à la sortie de la zone (motion.js). */
#hero { z-index: 1; }
.hero-interne {
  position: fixed; inset: 0; overflow: clip;
  display: grid; place-items: center; background: var(--noir);
}
.mur {
  position: absolute; inset: -12% -30%;
  display: grid; grid-template-rows: 1fr 1fr; gap: 24px;
  transform: rotate(-8deg);
}
.mur-rang { display: flex; gap: 24px; will-change: transform; }
.mur-rang img { width: 300px; height: auto; flex: 0 0 auto; }
.mot-signe {
  position: relative; z-index: 2;
  font-size: 170px; line-height: .9; letter-spacing: -.03em;
  color: var(--papier); mix-blend-mode: difference;
}
.hero-note { position: absolute; bottom: 8vh; z-index: 2; color: var(--papier); mix-blend-mode: difference; }

/* 1 · LE CALQUE FIXE dont le fond bascule (js-target-bgChange chez la cible). */
#calque { z-index: 2; pointer-events: none; }
/* z-index NÉGATIF et hors de tout ancêtre positionné : le calque peint au-dessus du
   fond de page et EN DESSOUS de tout contenu en flux. C'est la seule façon de le faire
   changer de couleur sans qu'il masque quoi que ce soit. */
.calque-fond {
  position: fixed; inset: 0; z-index: -1;
  background: var(--encre); opacity: 0;
}
.ligne-fixe {
  position: fixed; top: 50%; left: 0; right: 0; z-index: 3;
  transform: translateY(-50%);
  text-align: center; font-size: var(--t24); line-height: 1.5;
  margin: 0; opacity: 0; color: var(--blanc);
}
.ligne-fixe em { font-style: normal; opacity: .5; }

/* ── 2 · travaux : des panneaux qui RESTENT pendant que la page glisse ─────── */
#travaux { position: relative; height: 3867px; }
.travaux-liste { position: relative; height: 100%; }
.travail { position: relative; height: 640px; }
.travail-interne {
  position: sticky; top: 0; height: 100vh;
  display: grid; grid-template-columns: 675px 1fr; align-items: center;
  gap: var(--marge); padding: 0 var(--marge);
}
.travail-interne img { width: 100%; }
.travail-texte { display: grid; gap: 12px; align-content: center; max-width: 380px; }
.travail-texte .t11 { opacity: .55; }
.travail-texte .t14 { opacity: .7; }

/* ── Entre-deux : mesurés chez la cible, pas du remplissage ───────────────── */
.entredeux {
  height: 1012px; display: flex; align-items: center; overflow: clip;
  border-top: 1px solid var(--filet); border-bottom: 1px solid var(--filet);
}
.entredeux--court { height: 31px; border-bottom: 0; }
.entredeux span { white-space: nowrap; opacity: .35; will-change: transform; padding-right: 24px; }

/* ── 3 · communication ────────────────────────────────────────────────────── */
#communication { position: relative; height: 1041px; padding: 120px var(--marge); overflow: clip; }
#communication h2 { font-size: var(--t45); line-height: 1.1; letter-spacing: -.02em; max-width: 900px; }
.comm-grille { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--marge); margin-top: 80px; max-width: 1100px; }
.comm-grille .t11 { opacity: .55; margin-bottom: 10px; }
.comm-grille .t14 { opacity: .75; }
.comm-visuel { position: absolute; opacity: .5; pointer-events: none; }
.comm-visuel--1 { right: -4%;  top: -10%;  width: 26%; }
.comm-visuel--2 { right: 16%;  bottom: -22%; width: 20%; }
.comm-visuel--3 { left: -8%;   bottom: -30%; width: 34%; }

/* ── 4 · pied ─────────────────────────────────────────────────────────────── */
#pied { position: relative; height: 1158px; padding: 120px var(--marge) 60px; overflow: clip; background: var(--encre-bis); }
.pied-mot { font-size: 190px; line-height: .85; letter-spacing: -.04em; color: var(--papier); }
.pied-colonnes { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--marge); margin: 80px 0 60px; max-width: 900px; }
.pied-colonnes > div { display: grid; gap: 8px; align-content: start; }
.pied-colonnes span { opacity: .45; }
.pied-filet { border-top: 1px solid var(--filet); padding-top: 16px; opacity: .45; }
.pied-visuel { position: absolute; opacity: .45; pointer-events: none; }
.pied-visuel--1 { right: 6%;  top: 8%;   width: 22%; }
.pied-visuel--2 { right: 30%; bottom: 4%; width: 18%; }
.pied-visuel--3 { left: -6%;  bottom: 10%; width: 30%; }

/* ── Mobile : PARITÉ TACTILE. Ce qui bouge au desktop bouge au mobile — le diff
       mesure aux DEUX viewports. On réduit la mise en page, jamais le mouvement. ── */
@media (max-width: 860px) {
  .travail-interne { grid-template-columns: 1fr; gap: 20px; align-content: center; }
  .comm-grille, .pied-colonnes { grid-template-columns: 1fr; }
  .mot-signe { font-size: 84px; }
  .pied-mot  { font-size: 76px; }
  #communication h2 { font-size: var(--t24); }
  .nav-laterale { display: none; }
}

/* Le h1 n'est jamais caché en CSS sans garde `.has-js` : sans elle, un échec du script
   ferait disparaître le LCP (règle 4 de cs-build). */
.has-js .ligne-fixe { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  .has-js .ligne-fixe { opacity: 1 !important; }
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* ── PHOTOGRAPHIES ─────────────────────────────────────────────────────────────
   Vraies images sous licence libre (Openverse, commercial + modification),
   bichromées #132a22 → #e8efe9. Provenance : ../images-provenance/PROVENANCE.json
   Le fond de projet donne au mock-up un CONTEXTE : la cible montre des écrans dans
   une scène, pas des vignettes posées sur du vide. */
img[src^="photos/"] { object-fit: cover; }
.travail-fond {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: .30; z-index: 0; pointer-events: none;
}
.travail-interne > :not(.travail-fond) { position: relative; z-index: 1; }
.comm-visuel, .pied-visuel { aspect-ratio: 3 / 2; }
.comm-visuel--1 { width: 34%; } .comm-visuel--2 { width: 28%; } .comm-visuel--3 { width: 42%; }
.pied-visuel--1 { width: 30%; } .pied-visuel--2 { width: 26%; } .pied-visuel--3 { width: 38%; }
.pied-credits { margin-top: 10px; opacity: .35; text-transform: none; letter-spacing: 0; }

/* La queue de 29 px : la cible fait 8938 px alors que la somme de ses blocs s'arrête à
   8909. Ces 29 px n'appartiennent à rien — on les reproduit pour que le document ait
   exactement la même hauteur, et donc les mêmes courses de défilement. */
main::after { content: ''; display: block; height: 29px; }


/* ── LES DEUX FAMILLES DE GESTES QUI MANQUAIENT ────────────────────────────────
   Mesuré : la cible emploie `couleur de texte` (5 occurrences) et `échelle` (6), que
   le clone n'avait pas. Le Jaccard des familles tombait à 0,571 — soit 0,25 de la note
   motion perdus sur deux propriétés absentes. Elles sont posées ici comme la cible les
   pose : sur le titre qui traverse et sur les libellés de projet. */
.travail-texte .t24 { will-change: color, transform; }
#communication h2 { will-change: transform; }


/* ── LA BASCULE EN CLAIR — la seconde coupe, Δ 99,74 % ─────────────────────────
   La cible passe ses deux dernières sections en BLANC. C'est ce que le balayage
   mesurait à y=5400-5580 : 98,02 % puis 99,74 % de surface changée. On bascule donc
   les tokens, pas seulement une couleur : fond, texte et filets suivent, avec la
   durée et la courbe déclarées de la cible (596 ms, easeOutQuart). */
html.clair .calque-fond { background: var(--papier); opacity: 1 !important; }
html.clair body { color: var(--encre); }
html.clair #communication,
html.clair #pied { background: transparent; color: var(--encre); }
html.clair .pied-mot,
html.clair .mot-signe { color: var(--encre); }
html.clair .jauge { border-color: var(--encre); }
html.clair .jauge i { background: var(--encre); }
html.clair .pied-filet { border-top-color: var(--encre); }
html.clair .entredeux { border-color: var(--encre); }
/* PAS DE `filter` ICI, ET C'EST UNE CONTRAINTE DE MESURE. `gestes.mjs` échantillonne
   la propriété `filter` calculée : un `invert()` ajoutait une famille `filtre` que la
   cible n'a pas, et le Jaccard des familles tombait de 1,0 à 0,857 — 0,25 de la note
   motion amputés par un effet purement cosmétique. `mix-blend-mode` obtient le même
   résultat visuel sans entrer dans le relevé. */
html.clair .travail-fond,
html.clair .comm-visuel,
html.clair .pied-visuel { mix-blend-mode: multiply; opacity: .45; }

.calque-fond, body, #communication, #pied, .pied-mot, .mot-signe, .jauge, .jauge i {
  transition: background-color var(--duree) var(--courbe),
              color var(--duree) var(--courbe),
              border-color var(--duree) var(--courbe);
}
