/* ============================================================
   BARLOW CONDENSED — la police d'affichage, hebergee en local.
   Impact dependait de ce qui etait installe sur la machine du
   visiteur ; celle-ci s'affiche identiquement partout.
   ============================================================ */
@font-face {
  font-family: 'Barlow Condensed';
  src: url('assets/fonts/BarlowCondensed-600.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Barlow Condensed';
  src: url('assets/fonts/BarlowCondensed-700.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Barlow Condensed';
  src: url('assets/fonts/BarlowCondensed-800.woff2') format('woff2');
  font-weight: 800; font-style: normal; font-display: swap;
}

/* INSTRUMENT SERIF — unslop-ignore — la troisieme voix : le texte courant. Une
   serif editoriale a fort contraste, en bas de casse, sous une affiche
   en capitales grasses. C'est le contraste qui fait lire le paragraphe. */
@font-face {
  font-family: 'Instrument Serif';  /* unslop-ignore — choisi sur specimen a quatre candidates */
  src: url('assets/fonts/InstrumentSerif.woff2') format('woff2');  /* unslop-ignore */
  font-weight: 400; font-style: normal; font-display: swap;
}

/* ============================================================
   SUPER SLOP PRODUCTIONS — charte graphique
   Tous les tokens sont préfixés --ss-*

   Principe : la boîte s'appelle SUPER SLOP. C'est de
   l'autodérision. La marque doit être drôle et sale, pas
   solennelle. Registre = affiche sérigraphiée de concert punk,
   deux encres mal calées, ça dégouline.
   ============================================================ */

:root {
  /* --- COULEURS ---------------------------------------------
     Relevées à la pipette sur l'affiche, pas approximées.     */
  --ss-paper:   #f2efe6;  /* papier os — le fond, partout */
  --ss-paper-2: #e7e3d7;  /* papier ombré — encarts, survols */
  --ss-ink:     #0d0503;  /* encre noire — le texte */
  --ss-slop:    #df692a;  /* encre orange — ACCENT UNIQUE, reglable via le selecteur */
  --ss-muted:   #6f6a60;  /* gris chaud — métadonnées */
  --ss-line:    #cdc7b8;  /* filets */

  /* --- VERDICTS ---------------------------------------------
     Deux signaux, hors palette de marque. L'orange veut dire
     « Super Slop » : s'en servir pour dire « rejete » brouille
     les deux, et depuis le virage au rouille il se confondait
     avec le cadre des tirages.                               */
  --ss-no:      #e02718;  /* rejete */
  --ss-yes:     #17b85a;  /* retenu */

  /* Décalage de calage : la signature. L'orange est toujours
     légèrement hors registre par rapport au noir.             */
  --ss-misreg: 3px;

  /* --- TYPO -------------------------------------------------
     Deux familles.
     Display : Barlow Condensed, hébergée en local. Condensée et
               grasse comme une fonte d'affiche, mais chargée par
               la page — elle ne dépend plus de ce qui est installé
               sur la machine du visiteur. Toujours demandée en 800.
     Mono    : le registre du plateau (feuille de service,
               timecode, ardoise).                             */
--ss-display: 'Barlow Condensed', Impact, 'Franklin Gothic Heavy',
                'Arial Narrow', sans-serif;
  --ss-mono:    ui-monospace, 'Cascadia Mono', Consolas,
                'SF Mono', 'Roboto Mono', monospace;
  --ss-body:    'Helvetica Neue', Helvetica, Arial, sans-serif;
  --ss-serif:   'Instrument Serif', 'Times New Roman', Georgia, serif;  /* unslop-ignore */

  /* --- GÉOMÉTRIE --------------------------------------------
     Angles vifs partout. Rien d'arrondi : c'est de l'imprimé. */
  --ss-radius: 0;
  /* L'arrondi des objets POSES sur le papier — bulles, notes,
     compteurs, panneaux, fiches. Les boutons et les champs gardent
     leurs angles vifs : c'est --ss-radius, et il vaut 0. */
  --ss-round: 1.15rem;
  --ss-gap:    clamp(1.25rem, 4vw, 3.5rem);
  --ss-maxw:   78rem;
}

/* ============================================================
   BASE
   ============================================================ */

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--ss-paper);
  color: var(--ss-ink);
  font-family: var(--ss-body);
  -webkit-font-smoothing: antialiased;
}

/* ============================================================
   TYPOGRAPHIE
   ============================================================ */

.ss-display {
  font-family: var(--ss-display);
  text-transform: uppercase;
  letter-spacing: 0.01em;
  line-height: 0.86;
  font-weight: 800;   /* Barlow Condensed : il faut la demander grasse */
}

/* Ligne d'ardoise : tout ce qui est technique, daté, chiffré. */
.ss-slate {
  font-family: var(--ss-mono);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-size: 0.7rem;
  color: var(--ss-muted);
}

/* Hors-registre : le titre en noir avec son fantôme orange
   décalé. À réserver aux gros titres — illisible en petit.   */
.ss-misreg {
  color: var(--ss-ink);
  text-shadow: calc(var(--ss-misreg) * -1) var(--ss-misreg) 0 var(--ss-slop);
}

/* ============================================================
   LA COULURE — élément signature
   Une bande d'encre qui bave depuis le haut d'un bloc.
   Deux calques : orange décalé, puis noir par-dessus.
   À utiliser une à deux fois par écran, pas plus.
   ============================================================ */

/* La hauteur doit couvrir tout le motif (point le plus bas 93 px,
   + 3 px de décalage orange = 96) sinon les gouttes détachées sont
   tranchées net et lisent comme des taches. */
.ss-drip {
  height: 104px;
  background-repeat: repeat-x;
  /* Le NOIR est devant, à 0 0 ; l'orange est le fantôme décalé derrière.
     Même règle que le logo et les titres. En CSS le premier calque est
     celui du dessus — inverser les deux inverse la marque. */
  background-position: 0 0, calc(var(--ss-misreg) * -1) var(--ss-misreg);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='110'%3E%3Cg fill='%230d0503'%3E%3Crect width='400' height='14'/%3E%3Crect x='30' width='16' height='52'/%3E%3Ccircle cx='38' cy='52' r='12'/%3E%3Crect x='96' width='10' height='30'/%3E%3Ccircle cx='101' cy='30' r='8'/%3E%3Ccircle cx='101' cy='56' r='5'/%3E%3Crect x='170' width='20' height='78'/%3E%3Ccircle cx='180' cy='78' r='15'/%3E%3Crect x='250' width='12' height='40'/%3E%3Ccircle cx='256' cy='40' r='9'/%3E%3Ccircle cx='256' cy='68' r='4'/%3E%3Crect x='320' width='14' height='62'/%3E%3Ccircle cx='327' cy='62' r='11'/%3E%3C/g%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='110'%3E%3Cg fill='%23df692a'%3E%3Crect width='400' height='14'/%3E%3Crect x='30' width='16' height='52'/%3E%3Ccircle cx='38' cy='52' r='12'/%3E%3Crect x='96' width='10' height='30'/%3E%3Ccircle cx='101' cy='30' r='8'/%3E%3Ccircle cx='101' cy='56' r='5'/%3E%3Crect x='170' width='20' height='78'/%3E%3Ccircle cx='180' cy='78' r='15'/%3E%3Crect x='250' width='12' height='40'/%3E%3Ccircle cx='256' cy='40' r='9'/%3E%3Ccircle cx='256' cy='68' r='4'/%3E%3Crect x='320' width='14' height='62'/%3E%3Ccircle cx='327' cy='62' r='11'/%3E%3C/g%3E%3C/svg%3E");
}

/* ============================================================
   GRAIN PAPIER
   Posé en surimpression sur toute la page. Sans lui, les
   aplats font « vectoriel propre » et l'illusion d'imprimé
   tombe. Doit rester quasi invisible.
   ============================================================ */

.ss-grain::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9999;
  opacity: .32;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}

/* ============================================================
   BOUTONS / LIENS
   Un seul bouton plein par écran. Le reste souligné.
   ============================================================ */

.ss-btn {
  display: inline-block;
  font-family: var(--ss-mono);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 0.78rem;
  padding: 1rem 1.7rem;
  border-radius: var(--ss-radius);
  border: 2px solid var(--ss-ink);
  background: var(--ss-slop);
  color: var(--ss-paper);
  text-decoration: none;
  cursor: pointer;
  /* ombre portée dure = calage décalé, jamais de flou */
  box-shadow: var(--ss-misreg) var(--ss-misreg) 0 var(--ss-ink);
  transition: transform .12s ease, box-shadow .12s ease;
}
/* LE BOUTON DE FIN DE CHAPITRE. Plus grand, centre : il ferme une page,
   il ne sert pas dans un flux comme un bouton de formulaire. */
.ss-btn--big { font-size: 1.05rem; letter-spacing: .16em; padding: 1.35rem 2.6rem; }
.endcta { text-align: center; margin: clamp(2.6rem, 7vh, 4.4rem) 0 0; }
.ss-btn:hover {
  transform: translate(var(--ss-misreg), var(--ss-misreg));
  box-shadow: 0 0 0 var(--ss-ink);
}

.ss-link {
  color: var(--ss-ink);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
  text-decoration-color: var(--ss-slop);
}
.ss-link:hover { background: var(--ss-slop); color: var(--ss-paper); }

/* ============================================================
   BLOC / ENCART
   ============================================================ */

.ss-panel {
  background: var(--ss-paper-2);
  border: 2px solid var(--ss-ink);
  border-radius: var(--ss-radius);
  padding: 1.4rem 1.5rem;
}

/* ============================================================
   BLOC DE GÉNÉRIQUE (billing block)
   Le pavé de crédits en bas d'affiche. Condensé, centré,
   étroit, illisible de loin — et c'est le but.
   ============================================================ */

.ss-billing {
  font-family: var(--ss-display);
  text-transform: uppercase;
  text-align: center;
  font-size: clamp(.6rem, 1.35vw, .88rem);
  line-height: 1.32;
  letter-spacing: .01em;
  color: var(--ss-ink);
  max-width: 60rem;
  margin-inline: auto;
  transform: scaleY(1.35);       /* l'étirement vertical du vrai bloc */
  transform-origin: top center;
}
.ss-billing .sm { font-size: .78em; }

/* ============================================================
   ACCESSIBILITÉ
   ============================================================ */

:where(a, button, [tabindex]):focus-visible {
  outline: 3px solid var(--ss-slop);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}


/* ============================================================
   NAVIGATION D'EN-TETE
   Trois entrees. Le badge WIP dit ce qui n'est pas fini, plutot
   que de laisser croire que si.
   ============================================================ */
.topnav { display: flex; gap: 1.7rem; align-items: center; }
.topnav .wip {
  font-size: .52rem; letter-spacing: .12em; font-weight: 400;
  background: var(--ss-slop); color: var(--ss-paper);
  padding: .15em .4em; margin-left: .35em; vertical-align: .18em;
}
/* LA PAGE OU L'ON EST — a l'aplat. Le soulignement seul ne distinguait
   rien : les trois liens le portaient. */
/* « page » : on y est. « location » : on est dedans (une fiche
   projet est dans Work). Meme aplat — le visiteur veut savoir ou
   il se trouve, pas a quel niveau de l'arborescence. */
.topbar .cta[aria-current] {
  background: var(--ss-slop); color: var(--ss-paper);
  border-bottom-color: transparent;
  padding: .3em .55em; margin: -.3em -.55em;
}
/* Le badge s'inverse : sur l'orange, son orange n'existait plus. */
.topbar .cta[aria-current] .wip {
  background: var(--ss-paper); color: var(--ss-slop);
}
@media (max-width: 620px) { .topnav { gap: .9rem; } }


/* ============================================================
   AU-DESSUS DU GRAIN — regle de site
   Le grain est un calque de PAGE, pose en z-index 2. Sans cette regle
   il se depose aussi sur les tirages et sur les surfaces claires, qui
   portent deja leur propre grain argentique : on obtient du bruit sur
   du bruit.

   La liste vivait recopiee dans le <style> de l'accueil, donc chaque
   nouvelle surface d'une autre page passait dessous — c'est ce qui est
   arrive aux bulles de /process. Elle est ici, une fois, pour toutes
   les pages.
   ============================================================ */
picture, img, figure,
.sheet, .screen, .nowcard, .studiomark, .specshelf,
.crew div, .serv div,
.notes blockquote, .pair figure,
.talk__m, .talk__av,
/* Ajoutees au fil des pages — c'est la liste qui doit suivre, pas les
   surfaces qui doivent s'en passer. */
.nums b, .steps__d, .meter, .kinds > div, .arc > div, .brief, footer {
  position: relative;
  z-index: 3;
}

/* ============================================================
   BANDEAU DEFILANT — mobilier de site
   Vivait dans le <style> de l'accueil : /process a recu son HTML
   sans son CSS et l'affichait en texte nu. Le mobilier se definit
   UNE fois, ici.
   ============================================================ */
/* ---------- bandeau defilant, colle en bas ----------
   Il ne passe plus dans le flux : il reste au bord bas de la fenetre,
   toujours visible. L'inclinaison saute — une bande penchee ne peut pas
   epouser proprement le bord de l'ecran, elle laisserait un coin de
   papier a nu. Le decalage de calage reste, porte par le filet orange. */
.marquee {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  background: var(--ss-ink); color: var(--ss-paper);
  overflow: hidden; padding-block: .55rem;
  border-top: 3px solid var(--ss-slop);
  pointer-events: none;
}
/* La page se termine au-dessus du bandeau, jamais dessous. */
body { padding-bottom: 3.4rem; }
/* Boucle parfaite : le ruban contient EXACTEMENT deux copies et rien
   entre elles. Un gap entre les copies décalerait le raccord, puisque
   -50% translate d'une copie pile — l'espacement doit donc être inclus
   dans la copie elle-même (padding-right sur le span). */
.marquee__track { display: flex; width: max-content; gap: 0; animation: roll 40s linear infinite; }
.marquee span {
  font-family: var(--ss-display); text-transform: uppercase;
  font-size: clamp(1rem, 2.2vw, 1.5rem); letter-spacing: .05em; white-space: nowrap;
  padding-right: .32em;   /* = l'espace qui suit une etoile dans le ruban */
}
.marquee span .hot { padding-right: 0; }
.marquee .hot { color: var(--ss-slop); }
@keyframes roll { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .marquee__track { animation: none; } }

/* ============================================================
   RYTHME AUTOUR DES BANDEAUX
   Un paragraphe coince entre deux images pleine largeur recoit ~40 px
   de chaque cote la ou les sections respirent a 88 : les masses des
   images pesent sur lui. L'air autour d'un texte encadre d'images se
   cale sur la respiration des sections, pas sur la marge de paragraphe.
   ============================================================ */
/* APRES l'image : le voisin, quel qu'il soit — le plus souvent un
   conteneur, pas un paragraphe, ce qui est precisement pourquoi
   l'ancienne regle ne s'appliquait presque jamais. */
figure.bleed + *, figure.wallshot + *, .specshelf + *, .screen + *,
.roomshot + *,
/* AVANT l'image : c'est l'image qui prend la marge. */
* + figure.bleed, * + figure.wallshot, * + .specshelf, * + .screen,
* + .roomshot {
  margin-top: clamp(2.75rem, 7vh, 4.75rem);
}
/* Deux images qui se suivent gardent leur propre rythme : la marge
   compte une fois, pas deux. */
figure.bleed + figure.bleed, .specshelf + figure.bleed,
figure.bleed + .specshelf { margin-top: clamp(1.4rem, 3.5vh, 2.4rem); }


/* ============================================================
   LA BARRE DE MENU — UNE SEULE, POUR TOUT LE SITE
   Fixe, en verre depoli : elle laisse deviner ce qui passe dessous
   sans le laisser concurrencer la marque. Elle ne change RIEN au
   defilement — pas d'etat « scrolled », pas de saut de hauteur.
   Recopiee dans chaque page, elle vieillissait separement : /process
   en gardait une version au simple degrade, sous laquelle un titre de
   12 rem remontait jusque dans le logo.
   ============================================================ */
.topbar {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; padding: 1.15rem clamp(1.5rem, 5vw, 4rem);
  background: rgba(233, 228, 215, .58);
  -webkit-backdrop-filter: blur(16px) saturate(1.06) brightness(1.16);
          backdrop-filter: blur(16px) saturate(1.06) brightness(1.16);
  pointer-events: none;
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .topbar { background: #e4dfd1; }
}
/* Le grain de la barre est le MEME calque que celui de la page : meme
   motif, meme multiply. Cuit dans le fond, il sortait a pleine
   puissance et la barre virait au gris. */
.topbar::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.55' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='2.4' intercept='-0.7'/%3E%3CfeFuncG type='linear' slope='2.4' intercept='-0.7'/%3E%3CfeFuncB type='linear' slope='2.4' intercept='-0.7'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 200px 200px; mix-blend-mode: multiply; opacity: .26;
}
/* La marque et les liens repassent au-dessus du grain. */
.topbar > * { position: relative; z-index: 1; }
/* La barre porte une OMBRE, pas une trainee claire : un degrade de la
   couleur du mur delavait le haut de l'image ; une ombre dit la meme
   chose sans toucher aux valeurs de la photo. */
.topbar::after {
  content: ""; position: absolute; left: 0; right: 0; top: 100%;
  height: 1.6rem; pointer-events: none;
  background: linear-gradient(rgba(13,5,3,.26), rgba(13,5,3,0));
}
.topbar a { pointer-events: auto; color: var(--ss-ink); text-decoration: none; }
/* La marque est le tirage lui-meme, recadre au ras de l'encre. */
.topbar .brand { display: flex; align-items: center;
                 padding: .35rem .6rem; margin: -.35rem -.6rem; }
.topbar .brand img,
.topbar .brand .tint { display: block; height: clamp(60px, 8.4vw, 84px);
                       width: auto; aspect-ratio: 1024 / 768; }
.topbar .cta { font-family: var(--ss-mono); font-size: .84rem; letter-spacing: .14em;
               text-transform: uppercase; border-bottom: 2px solid var(--ss-slop); }
@media (max-width: 820px) { .topbar .cta { font-size: .72rem; letter-spacing: .12em; } }
/* LA CIBLE DU DOIGT FAIT 44 PX. Les liens du menu mesuraient 16 a 30 px
   de haut : la taille du TEXTE, pas celle d'un doigt. La zone est posee
   AUTOUR du lien plutot qu'ajoutee dedans — sinon la barre grandit et
   l'aplat de la page courante devient un pave. */
@media (pointer: coarse) {
  .topbar .cta { position: relative; }
  .topbar .cta::after {
    content: ""; position: absolute; z-index: 1;
    left: -.3rem; right: -.3rem; top: 50%;
    height: 44px; transform: translateY(-50%);
  }
}
/* Le nom reste dans le document pour les lecteurs d'ecran. */
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden;
      clip-path: inset(50%); white-space: nowrap; }

/* ============================================================
   L'IMAGE FLOUE ET LE CHARGEUR
   Une image qui arrive laissait un rectangle VIDE — flagrant en
   changeant d'onglet sur /process, ou rien ne disait qu'une image
   arrivait ni laquelle. Chaque image porte donc sa propre version de
   24 px, inscrite dans la page et etalee en fond : le navigateur la
   lisse tout seul, ce qui donne le flou SANS filtre — un filtre aurait
   floute l'image finale par-dessus.
   Les PNG a transparence en sont exclus a la fabrication : un fond
   derriere un logo ajoure se verrait au travers.
   ============================================================ */
img {
  background-image: var(--lqip, none);
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
/* LE FONDU. L'image nette arrive PAR-DESSUS sa propre miniature floue
   au lieu de la remplacer d'un coup : le fond ne disparait qu'une fois
   le fondu termine, donc il n'y a jamais de trou.

   L'affiche (data-progressif) est exclue : elle se peint passe apres
   passe, et la cacher jusqu'a la fin annulerait ce rendu progressif. */
img { transition: opacity .32s ease; }
/* .lb__img est exclue : elle est creee par le script, donc elle ne
   recoit jamais la marque « chargee » posee au chargement de la page.
   La visionneuse gere sa propre arrivee, juste en dessous. */
img:not(.is-loaded):not([data-progressif]):not(.lb__img) { opacity: 0; }
img.is-loaded { opacity: 1; }
img.is-loaded:not([data-progressif]) { transition: opacity .32s ease, background-image 0s .32s; }
img.is-loaded { background-image: none; }
/* Le texte de remplacement ne se dessine PAS par-dessus le flou : tant
   que l'image est en route, il n'a rien a dire. S'il elle echoue,
   boot.js la marque quand meme chargee — et l'alternative reapparait,
   la ou elle sert vraiment. */
img:not(.is-loaded) { color: transparent; font-size: 0; }

/* LE CHARGEUR — un trait orange sous la barre de menu, qui avance avec
   les images de la page et s'efface quand tout est la. Pas de disque qui
   tourne : le site n'attend jamais assez longtemps pour meriter ca. */
.loadbar {
  position: fixed; left: 0; top: 0; height: 3px; width: 0;
  background: var(--ss-slop); z-index: 60; pointer-events: none;
  transition: width .3s ease, opacity .5s ease .2s;
}
.loadbar.done { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .loadbar { transition: none; }
  img { transition: none; }
}


/* ============================================================
   LE PIED DE PAGE — LE MEME PARTOUT
   Une mention legale, pas une fin de chapitre : pas de filet, du texte
   au plus bas rang, une opacite qui le met derriere tout le reste.
   Il etait recopie trois fois, et de trois facons differentes.
   ============================================================ */
footer {
  display: flex; justify-content: space-between; align-items: baseline;
  flex-wrap: wrap; gap: .6rem 1.4rem;
  background: var(--ss-slop); color: var(--ss-paper);
  /* Pleine fenetre, quel que soit le conteneur qui la porte. */
  width: 100vw; margin-left: calc(50% - 50vw); margin-bottom: 0;
  /* Le retrait interieur est celui de la page : les mentions restent
     alignees sur le texte au-dessus au lieu de coller au bord. */
  padding: clamp(.8rem, 1.6vw, 1.15rem) clamp(1.25rem, 5vw, 4rem);
  /* Deux pixels DERRIERE le bandeau : au demi-pixel pres, deux aplats
     qui se touchent laissent toujours passer un filet de papier. Celui
     qui passe dessous n'en laisse aucun. */
  padding-bottom: calc(clamp(.8rem, 1.6vw, 1.15rem) + 2px);
  margin-bottom: -2px;
}
/* Sur l'aplat, tout passe en papier : la couleur d'encre eteinte des
   mentions n'aurait plus assez de contraste. */
footer .ss-slate { font-size: .62rem; letter-spacing: .14em; color: var(--ss-paper); }

/* ============================================================
   LA VISIONNEUSE
   Une image cliquable doit se comporter comme un bouton : elle prend le
   focus, elle repond a Entree, et elle ouvre en grand. On navigue a
   gauche/droite, on sort avec Echap ou en cliquant a cote.
   Le fond est noir : c'est la seule surface du site qui ait le droit de
   l'etre, parce qu'elle n'est plus la page — elle est devant.
   ============================================================ */
img.zoomable { cursor: zoom-in; }
img.zoomable:focus-visible { outline: 3px solid var(--ss-slop); outline-offset: 3px; }

.lb { position: fixed; inset: 0; z-index: 100; display: none;
      background: rgba(10, 8, 6, .975);
      -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); }
.lb.on { display: grid; grid-template-rows: 1fr auto; }
.lb__stage { position: relative; display: grid; place-items: center;
             padding: clamp(1.5rem, 6vw, 6rem); min-height: 0; }
.lb__img { display: block; width: 100%; height: 100%;
           object-fit: contain;
           background-size: cover; background-position: center; }
/* On agrandit, mais pas indefiniment : au-dela d'une fois et demie, on
   ne montre plus l'image mais l'interpolation. La variable est posee
   par le script d'apres la taille reelle du fichier. La hauteur laisse
   toujours de quoi lire la legende sans que l'image la touche. */
.lb__img { max-width: var(--lb-max, 100%); max-height: 78vh; margin-inline: auto; }
/* Tant que la grande n'est pas peinte, on garde la miniature floue de la
   vignette : la visionneuse ne s'ouvre jamais sur du vide. */
.lb__img { opacity: 1; transition: filter .35s ease; }
.lb__img.loading { filter: blur(14px); transform: scale(1.01); }
/* Un mot dans la barre du bas pendant le chargement : un flou seul ne
   dit pas si quelque chose arrive ou si c'est cassé. */
.lb__load { color: var(--ss-slop); }
.lb__load::after { content: "6"; animation: lb-dots 1s steps(4, end) infinite; }
@keyframes lb-dots { 0% { opacity: .25 } 50% { opacity: 1 } 100% { opacity: .25 } }
.lb__bar { display: flex; align-items: center; justify-content: space-between;
           gap: 1rem; padding: .9rem clamp(1rem, 4vw, 3.5rem) 1.6rem;
           font-family: var(--ss-mono); font-size: .66rem; letter-spacing: .16em;
           text-transform: uppercase; color: #cfc7b8; }
.lb__cap { flex: 1; min-width: 0; }
.lb__n { color: var(--ss-slop); }
.lb button { font: inherit; letter-spacing: inherit; text-transform: inherit;
             background: none; color: #ece6da; border: 2px solid #4a4238;
             padding: .5rem .8rem; cursor: pointer; }
.lb button:hover { border-color: var(--ss-slop); color: var(--ss-slop); }
.lb__nav { position: absolute; top: 50%; transform: translateY(-50%);
           font-size: 1.1rem; padding: .7rem .95rem; }
.lb__nav--p { left: clamp(.4rem, 2vw, 1.5rem); }
.lb__nav--n { right: clamp(.4rem, 2vw, 1.5rem); }
.lb__x { position: absolute; top: clamp(.6rem, 2vw, 1.4rem);
         right: clamp(.6rem, 2vw, 1.4rem); }
@media (max-width: 700px) { .lb__nav { font-size: .95rem; padding: .55rem .7rem; } }
/* La page derriere ne defile plus pendant qu'on regarde. */
html.lb-open, body.lb-open { overflow: hidden; }


/* ============================================================
   LE NOM DE L'OUTIL, A L'APLAT
   Meme etat actif que le menu et les onglets : fond orange, texte
   papier. Le liseret negatif evite que l'aplat touche la ligne du
   dessus quand le nom tombe en bout de ligne.
   ============================================================ */
.ss-mark {
  background: var(--ss-slop); color: var(--ss-paper);
  font-weight: 400;
  /* Rien en haut ni en bas : le fond d'un element en ligne couvre deja
     toute la hauteur du caractere. */
  padding: 0 .2em; border-radius: .18em;
  box-decoration-break: clone; -webkit-box-decoration-break: clone;
}
/* A pleine taille, le symbole gonflait la boite sans rien dire de plus. */
.ss-mark sup { font-size: .5em; vertical-align: .62em; margin-left: .04em; }

/* ============================================================
   LOGOS TEINTABLES — POUR TOUTES LES PAGES
   Deux masques alpha superposes — l'encre, puis l'orange — colories par
   un aplat. L'orange suit donc var(--ss-slop) : il suit le selecteur de
   teinte, au lieu d'etre cuit dans un fichier.
   Ces regles etaient enfermees dans l'accueil : le film et /process
   affichaient logotype.png, ou l'orange est cuit A L'ANCIENNE teinte.
   D'ou une marque differente selon la page.
   ============================================================ */
.tint { display: block; position: relative; }
.tint::before, .tint::after {
  content: ""; position: absolute; inset: 0;
  -webkit-mask-size: contain;      mask-size: contain;
  -webkit-mask-repeat: no-repeat;  mask-repeat: no-repeat;
  -webkit-mask-position: center;   mask-position: center;
}
.tint::before { background: var(--ss-ink); }
.tint::after  { background: var(--ss-slop); }
.tint--logotype { aspect-ratio: 1024 / 768; }
.tint--logotype::before { -webkit-mask-image: url("assets/logotype-ink.png"); mask-image: url("assets/logotype-ink.png"); }
.tint--logotype::after  { -webkit-mask-image: url("assets/logotype-or.png");  mask-image: url("assets/logotype-or.png"); }
.tint--mark { aspect-ratio: 912 / 578; width: 100%; max-width: 26rem; margin-inline: auto; }
.tint--mark::before { -webkit-mask-image: url("assets/mark-ink.png"); mask-image: url("assets/mark-ink.png"); }
.tint--mark::after  { -webkit-mask-image: url("assets/mark-or.png");  mask-image: url("assets/mark-or.png"); }
/* Sans masques CSS, on retombe sur le fichier d'origine : la teinte ne
   suivra pas, mais le logo s'affiche. */
@supports not ((mask-image: url(a)) or (-webkit-mask-image: url(a))) {
  .tint::before, .tint::after { display: none; }
  .tint--logotype { background: url("assets/logotype.png") center/contain no-repeat; }
  .tint--mark     { background: url("assets/mark-studio.png") center/contain no-repeat; }
}
@media (max-width: 900px) { .tint--mark { max-width: 18rem; } }

/* ============================================================
   LES HORLOGES DES BUREAUX
   Quatre villes, l'heure vraie, une aiguille de secondes orange. Elles
   disent la meme chose que le pied de page ("Paris — New York — Los
   Angeles") mais en la MONTRANT : un studio qui tourne sur trois
   fuseaux se voit mieux qu'il ne se lit.
   Sur papier, pas sur noir : le cadran est un trait d'encre, comme le
   reste de la page.
   ============================================================ */
/* Pas de rembourrage haut : la marge vient de la regle de rythme des
   images pleine largeur, sinon les deux s'additionnent. */
.clocks { padding-block: 0 clamp(1.4rem, 3vh, 2.2rem); }
/* Le titre du bloc, pas l'etiquette d'un titre : il prend le troisieme
   rang de la charte (.t-h3) et n'a donc plus de reglage de fonte ici. */
.clocks__t { margin: 0 0 clamp(1.4rem, 3.5vh, 2.2rem); }
/* D'un bord a l'autre de la mesure : les quatre cadrans occupent la
   largeur du conteneur au lieu de se tasser dans un coin. */
/* Pleine mesure, aligne a gauche — comme TOUS les paragraphes du site.
   Une colonne centree de 62 caracteres etait une mise en page inventee
   pour ce bloc, et un site ou chaque bloc invente la sienne n'a plus de
   charte. */
.clocks__lede { margin: 0 0 clamp(2rem, 5vh, 3.2rem); }
.clocks__row { display: flex; flex-wrap: wrap; justify-content: space-between;
               gap: clamp(1.2rem, 3vw, 2.4rem); }
/* La taille n'est pas ecrite : chaque cadran prend une PART de la rangee,
   plafonnee. Une ville de plus se place sans rien recalculer. */
.clock { text-align: center; flex: 1 1 7rem; min-width: 0; }
.clock svg { display: block; width: 100%; max-width: 12.4rem; height: auto;
             margin-inline: auto; }
.clock__n { display: block; margin-top: 1rem;
            font-family: var(--ss-mono); font-size: .64rem; letter-spacing: .18em;
            text-transform: uppercase; color: var(--ss-muted); }
/* Sous 620 px, quatre cadrans a cette taille ne tiennent plus cote a
   cote : ils passent a deux par rangee, centres. */
@media (max-width: 620px) {
  .clocks__row { justify-content: center; }
  .clock { flex: 0 0 calc(33.33% - 1.6rem); }
}
.clock__f { fill: none; stroke: var(--ss-ink); stroke-width: 2; opacity: .5; }
/* LE JOUR ET LA NUIT. Le fond s'assombrit apres midi : un aplat d'encre
   tres dilue, pas une couleur — l'accent est deja pris par les secondes.
   Il est dessine SOUS les reperes pour ne pas les eteindre. */
.clock__dial { fill: transparent; transition: fill .6s ease; }
.clock.is-pm .clock__dial { fill: rgba(20, 12, 6, .16); }
@media (prefers-reduced-motion: reduce) { .clock__dial { transition: none; } }
.clock__tick { stroke: var(--ss-ink); stroke-width: 2; opacity: .55; }
.clock__tick--h { stroke-width: 3.4; opacity: .85; }
.clock__h, .clock__m { stroke: var(--ss-ink); stroke-linecap: round; }
.clock__h { stroke-width: 4.4; }
.clock__m { stroke-width: 3; }
/* La seule couleur du cadran : les secondes. */
.clock__s { stroke: var(--ss-slop); stroke-width: 1.6; stroke-linecap: round; }
.clock__pin { fill: var(--ss-slop); }
/* LE CREDIT — troisieme mention du pied de page, au meme rang que les
   deux autres : elle se donne, elle ne se reclame pas. */
/* Sur l'orange, un soulignement orange n'existe pas. */
footer .credit a { color: inherit; border-bottom: 1px solid currentColor; }

/* ============================================================
   LES BULLES SE REVELENT AVEC LA MOLETTE
   Pas d'animation declenchee : chaque replique porte une PROGRESSION
   (--p, de 0 a 1) calculee depuis sa position a l'ecran. Elle s'ouvre
   donc exactement au rythme ou l'on descend, et s'arrete si l'on
   s'arrete. Une animation lancee se joue a SA vitesse, pas a la
   notre — c'est ce qui la faisait paraitre trop rapide.

   Une fois arrivee, la replique est verrouillee (.is-in) : remonter ne
   la rejoue pas.

   L'etat de depart est pose par le SCRIPT (.talk--anim) : sans
   JavaScript, les bulles doivent etre lisibles, pas invisibles.
   ============================================================ */
/* Le fondu POSE la replique, la frappe la DIT : deux temps. La bulle
   monte a l'opacite pleine, puis seulement le texte s'ecrit. */
.talk--anim .talk__row .talk__m {
  opacity: var(--p, 0);
  transform:
    translate(calc(var(--fx, -1) * (1 - var(--p, 0)) * 1.4rem),
              calc((1 - var(--p, 0)) * .7rem))
    scale(calc(.88 + .12 * var(--p, 0)));
  will-change: transform, opacity;
}
.talk--anim .talk__row--them .talk__m { transform-origin: left center; }
.talk--anim .talk__row--me   .talk__m { transform-origin: right center; }
/* L'avatar suit la meme progression, sans bouger de place. */
.talk--anim .talk__row .talk__av {
  opacity: var(--p, 0);
  transform: scale(calc(.8 + .2 * var(--p, 0)));
}
/* Arrivee : plus aucun calcul, la replique reste posee. */
.talk--anim .talk__row.is-in .talk__m,
.talk--anim .talk__row.is-in .talk__av {
  opacity: 1; transform: none; will-change: auto;
}
@media (prefers-reduced-motion: reduce) {
  .talk--anim .talk__row .talk__m,
  .talk--anim .talk__row .talk__av { opacity: 1; transform: none; }
}

/* LA REPLIQUE S'ECRIT PENDANT QU'ELLE ENTRE.
   Meme mecanique que les notes, mais la cadence ne vient PAS d'une
   horloge : c'est la meme progression de defilement qui fait entrer la
   bulle qui ecrit son texte. Une conversation se lit au rythme ou on
   descend dedans, pas a celui d'un minuteur lance en arriere-plan.

   Le texte pas encore ecrit reste dans le document, seulement rendu
   invisible : les lettres gardent leur place, donc la bulle ne change
   jamais de taille pendant la frappe et la colonne ne saute pas. */
.talk--anim .tw-off { visibility: hidden; }
/* UN SEUL curseur, et seulement PENDANT la frappe : avant le premier
   caractere il n'y a rien a annoncer, apres le dernier la replique est
   dite. `.tw-cur` est pose par le script sur le morceau en cours. */
.talk--anim .talk__row.is-typing:not(.is-typed) .tw-on.tw-cur::after {
  content: ""; display: inline-block;
  width: .5em; height: 1em;
  /* Il se dessine mais n'occupe RIEN : sans cette compensation il
     ajoute une demi-cadratin au bout de la ligne et la bulle gagne
     une ligne au dernier caractere. */
  margin-left: .06em; margin-right: -.56em;
  vertical-align: -.16em; background: var(--ss-slop);
  animation: tw-blink .8s steps(1, end) infinite;
}
@media (prefers-reduced-motion: reduce) {
  .talk--anim .tw-off { visibility: visible; }
  .talk--anim .tw-on::after { display: none; }
}


/* ============================================================
   LE SYMBOLE DE MARQUE DANS UN TITRE
   A pleine chasse dans un display de 177 px, « TM » ferait un mot de
   plus. Il se met a l'echelle du titre et se cale en haut de capitale.
   ============================================================ */
h1 sup, h2 sup, .t-h1 sup, .t-h2 sup, .t-h3 sup {
  font-size: .26em; vertical-align: .95em; letter-spacing: .02em;
  margin-left: .06em; font-weight: 800;
}

/* ============================================================
   LES JAUGES SE REMPLISSENT EN DEFILANT
   Chaque barre part de zero et court vers sa valeur, l'une apres
   l'autre. Une seule fois : remonter ne relance rien.

   L'etat a zero est pose par le SCRIPT (.meter--anim) : sans
   JavaScript, une jauge vide serait un chiffre faux, pas une animation
   manquante.
   ============================================================ */
.meter--anim .fill { width: 0 !important; }
.meter--anim.is-in .fill {
  width: var(--w) !important;
  transition: width .9s cubic-bezier(.2, .85, .25, 1);
}
/* LE CAMEMBERT SE DESSINE. Chaque part part d'une longueur nulle et
   court jusqu'a la sienne, gardee dans --len par le HTML. C'est le
   trait qui s'allonge, pas une opacite qui monte : une part de
   camembert se lit a sa longueur d'arc. */
.meter--anim .pie__seg { transition: stroke-dashoffset .8s cubic-bezier(.32, 0, .18, 1); }
/* Les colonnes montent depuis le bas : l'echelle part du pied, sinon
   elles grandiraient par le milieu. */
.meter--anim .histo__bar i { transform-origin: bottom; transition: transform .7s cubic-bezier(.32, 0, .18, 1); }

@media (prefers-reduced-motion: reduce) {
  .meter--anim .fill, .meter--anim.is-in .fill { width: var(--w) !important; transition: none; }
  .meter--anim .pie__seg, .meter--anim .histo__bar i { transition: none; }
}

/* ============================================================
   LA CROIX PUIS LA COCHE
   Les deux tampons se TRACENT quand la paire arrive : la croix
   d'abord, la coche ensuite. C'est l'ordre du jugement — on tue avant
   de garder, et la paire raconte cette seconde-la.

   Les traits sont dessines par stroke-dashoffset : on anime le
   PARCOURS du trait, pas une opacite. Un tampon qui apparait en fondu
   n'a pas ete pose par quelqu'un.

   L'etat non trace est mis par le SCRIPT (.pair--anim) : sans
   JavaScript, les tampons doivent etre la.
   ============================================================ */
.pair--anim .stamp path {
  stroke-dasharray: 160;
  stroke-dashoffset: 160;
}
.pair--anim.is-in .stamp path {
  animation: trace .34s cubic-bezier(.5, 0, .3, 1) both;
}
/* La croix : ses deux traits se croisent, l'un juste apres l'autre. */
.pair--anim.is-in figure:first-child .stamp path:nth-child(1) { animation-delay: .05s; }
.pair--anim.is-in figure:first-child .stamp path:nth-child(2) { animation-delay: .24s; }
/* La coche attend que la croix soit posee. */
.pair--anim.is-in figure:nth-child(2) .stamp path { animation-delay: .62s; animation-duration: .42s; }
@keyframes trace { to { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce) {
  .pair--anim .stamp path { stroke-dashoffset: 0; }
  .pair--anim.is-in .stamp path { animation: none; }
}


/* ============================================================
   RESPIRATION DES SECTIONS
   Deux sections voisines CUMULENT leur rembourrage : la valeur ci-
   dessous se voit donc doublee entre deux blocs. Elle vivait en quatre
   exemplaires (5,5 rem sur deux pages, 5 sur les deux autres, sans
   raison), et elle etait calee sur une epoque ou un filet orange
   occupait ce vide.
   ============================================================ */
.sec { padding-block: clamp(2.2rem, 5.5vh, 3.6rem); }

/* ============================================================
   SEPARATEUR DE SECTIONS — UN FILET, PAS UNE BARRE
   Un trait d'un pixel, sur toute la fenetre, entre deux sections.
   L'ancien etait un segment orange centre : il redisait le sur-titre
   numerote juste en dessous. Celui-ci ne dit rien, il ORGANISE — c'est
   le filet d'une page imprimee, pas un ornement.

   Pose en ::before de la section qui SUIT, jamais avant un pied de
   page : une bande orange pleine largeur n'a pas besoin qu'on lui
   annonce qu'elle arrive.
   ============================================================ */
.sec + .sec:not(:has(footer))::before {
  content: "";
  display: block;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-top: calc(-1 * clamp(2.2rem, 5.5vh, 3.6rem));
  margin-bottom: clamp(2.2rem, 5.5vh, 3.6rem);
  border-top: 1px solid rgba(20, 12, 6, .16);
}

/* Le meme filet, pose a la main quand la coupure n'est pas entre deux
   sections : sur une fiche projet, entre le lecteur et la grille. */
hr.filet {
  width: 100vw; margin-left: calc(50% - 50vw);
  margin-block: clamp(2.2rem, 5.5vh, 3.6rem);
  border: 0; border-top: 1px solid rgba(20, 12, 6, .16);
}

/* LE SOUS-TITRE D'UNE FICHE — « WA Grants », « Gomorra ».
   Il porte une vraie information, mais il n'est pas le nom du projet :
   petit, en mono, juste sous le titre qu'il precise. */
.subt {
  font-family: var(--ss-mono); text-transform: uppercase; letter-spacing: .18em;
  font-size: .78rem; color: var(--ss-muted);
  margin: .9rem 0 0;
}

/* ============================================================
   LES NOTES S'ECRIVENT
   Les cartes sont deja la, vides, a leur taille definitive : c'est le
   TEXTE qui arrive, lettre apres lettre, comme si on le tapait.

   Le texte pas encore ecrit n'est pas retire du document, il est rendu
   INVISIBLE : les lettres gardent leur place, donc la carte ne change
   jamais de hauteur et la grille ne bouge pas d'un pixel. Vider puis
   remplir ferait sauter les douze cartes a chaque caractere.

   L'etat est pose par le SCRIPT (.notes--anim) : sans JavaScript, les
   notes doivent etre lisibles.
   ============================================================ */
.notes--anim .tw-off { visibility: hidden; }
.notes--anim blockquote cite { visibility: hidden; }
.notes--anim blockquote.is-done cite { visibility: visible; }
/* Le curseur : un trait orange au bout de ce qui est ecrit. */
.notes--anim blockquote:not(.is-done) .tw-on::after {
  content: ""; display: inline-block;
  width: .5em; height: 1em;
  /* Il se dessine mais n'occupe RIEN : sans cette compensation il
     ajoute une demi-cadratin au bout de la ligne, bascule a la ligne
     suivante en fin de mesure, et la carte gagne une ligne. */
  margin-left: .06em; margin-right: -.56em;
  vertical-align: -.16em; background: var(--ss-slop);
  animation: tw-blink .8s steps(1, end) infinite;
}
@keyframes tw-blink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .notes--anim .tw-off, .notes--anim blockquote cite { visibility: visible; }
  .notes--anim blockquote .tw-on::after { display: none; }
}


/* ============================================================
   CORPS DE CARTE
   Un cran sous le texte courant, pour ce qui vit dans une boite
   etroite : les entrees de /start, les etapes, les listes en deux
   colonnes, les trois actes du film. Chacun avait invente sa taille
   (1,05, 1,08, 1,12 rem) et tous etaient trop petits. Une seule valeur.
   ============================================================ */
.steps p, .pair2 li, .arc p, .arc blockquote {
  font-size: clamp(1.28rem, 1.75vw, 1.68rem); line-height: 1.45;
}
/* Les entrees de /start sont sur deux colonnes, donc assez larges pour
   le corps courant du site : elles n'ont aucune raison d'etre reduites.
   C'est la mesure qui decide de la taille, pas le fait d'etre dans une
   boite. */

/* Un volet cache doit disparaitre. « hidden » pose display:none avec la
   specificite d'un attribut ; une regle de classe le bat, et le
   formulaire affichait ses quatre onglets l'un sous l'autre. */
.bf[hidden], .screens__pane[hidden] { display: none; }

/* ============================================================
   LE MUR DE TIRAGES — GABARIT DE FICHE
   Le geste de The Last Battle : chaque image est un tirage punaise au
   mur. Cadre papier, ombre orange decalee, un bout de scotch en haut,
   et une inclinaison propre a chaque tirage qui se redresse au survol.

   Il vivait dans le <style> de /film. Les six fiches de projet le
   reprennent, donc il descend ici : sept copies d'un meme geste, c'est
   sept facons de vieillir separement.

   Les inclinaisons CYCLENT par six (6n+1 a 6n) : la page du film n'a
   que six tirages, une fiche de projet peut en avoir vingt-six.
   ============================================================ */
.wall {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.6rem, 3.5vw, 2.8rem) clamp(1.2rem, 2.5vw, 2rem);
  margin-top: clamp(2rem, 5vh, 3rem);
}
@media (max-width: 900px) { .wall { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .wall { grid-template-columns: 1fr; } }

.wall figure {
  margin: 0; position: relative;
  display: flex; flex-direction: column; gap: .55rem;
  transition: transform .18s ease;
}
.wall figure:nth-child(6n + 1) { transform: rotate(-2.3deg); }
.wall figure:nth-child(6n + 2) { transform: rotate(1.6deg) translateY(.7rem); }
.wall figure:nth-child(6n + 3) { transform: rotate(-1.1deg); }
.wall figure:nth-child(6n + 4) { transform: rotate(2.1deg); }
.wall figure:nth-child(6n + 5) { transform: rotate(-1.8deg) translateY(.5rem); }
.wall figure:nth-child(6n)     { transform: rotate(1.3deg); }
.wall figure:hover, .wall figure:focus-within { transform: rotate(0deg) scale(1.035); z-index: 3; }

.wall .shot {
  position: relative;
  border: 3px solid var(--ss-paper);
  background: var(--ss-ink);
  box-shadow: 6px 6px 0 var(--ss-slop);
}
.wall .shot img { display: block; width: 100%; height: auto; }
/* le bout de scotch */
.wall .shot::before {
  content: "";
  position: absolute; top: -.8rem; left: 50%;
  width: 4.4rem; height: 1.6rem;
  transform: translateX(-50%) rotate(-4deg);
  background: rgba(242, 239, 230, .34);
  border-inline: 1px dashed rgba(242, 239, 230, .5);
  z-index: 2;
}
.wall figcaption {
  display: flex; align-items: baseline; gap: .55rem;
  font-family: var(--ss-mono); text-transform: uppercase;
  letter-spacing: .12em; font-size: .62rem; color: var(--ss-ink);
}
.wall figcaption .idx { color: var(--ss-slop); font-weight: 700; }
/* La legende dit maintenant une PHRASE, pas une etiquette : les
   capitales espacees d'une etiquette rendent une phrase illisible.
   Le numero, lui, reste une etiquette. */
.wall figcaption .tc {
  color: var(--ss-muted);
  text-transform: none; letter-spacing: .01em; font-size: .72rem;
}

/* LE BANDEAU DE FAITS — format, plans, pipeline, sortie. */
.film-facts { display: grid; grid-template-columns: repeat(4, 1fr);
              gap: clamp(1rem, 2.5vw, 2rem); margin: clamp(1.8rem, 5vh, 3rem) 0 0; }
@media (max-width: 760px) { .film-facts { grid-template-columns: repeat(2, 1fr); } }
.film-facts dt { font-family: var(--ss-mono); font-size: .6rem; letter-spacing: .18em;
                 text-transform: uppercase; color: var(--ss-muted); margin: 0 0 .35rem; }
.film-facts dd { margin: 0; font-family: var(--ss-mono); font-size: .78rem;
                 line-height: 1.5; color: var(--ss-ink); }

/* LA PASTILLE D'ETAT — un point orange qui clignote comme un temoin. */
.now { display: inline-flex; align-items: center; gap: .5rem;
       font-family: var(--ss-mono); text-transform: uppercase; letter-spacing: .18em;
       font-size: .62rem; color: var(--ss-muted); }
.now .dot { width: 8px; height: 8px; background: var(--ss-slop);
            animation: rec 1.8s steps(1) infinite; }
@keyframes rec { 0%, 60% { opacity: 1 } 61%, 100% { opacity: .15 } }
@media (prefers-reduced-motion: reduce) { .now .dot { animation: none; } }

/* ============================================================
   LE LECTEUR VIDEO
   Une FACADE : l'affiche du projet et un bouton. YouTube n'est charge
   qu'au clic, donc la page ne depose ni requete ni cookie tiers tant
   que personne n'a demande a voir le film. C'est aussi ce qui evite
   qu'une banniere de consentement s'invite sur une page qui n'en a pas.
   ============================================================ */
.player { position: relative; margin: clamp(2rem, 5vh, 3rem) 0 0;
          border-radius: var(--ss-round); overflow: hidden;
          background: var(--ss-ink); aspect-ratio: 16 / 9;
          box-shadow: 0 2px 5px rgba(13,5,3,.14), 0 20px 44px -18px rgba(13,5,3,.5); }
.player img, .player iframe { display: block; width: 100%; height: 100%;
                              border: 0; object-fit: cover; }
.player__go {
  position: absolute; inset: 0; display: grid; place-items: center;
  /* DEVANT L'AFFICHE. Les pages font remonter images et figures a
     z-index 3 pour passer au-dessus du grain de papier. Le bouton, lui,
     n'avait pas de rang : l'affiche se peignait PAR-DESSUS lui, le
     disque orange disparaissait, et le clic tombait sur l'image — donc
     sur la visionneuse — au lieu de lancer le film. */
  z-index: 4;
  border: 0; cursor: pointer;
  /* PLUS DE VOILE SUR L'AFFICHE. Un aplat sombre a 28 % couvrait toute
     l'image : le seul objet reellement pose PAR-DESSUS le visuel, et il
     se lisait comme un calque oublie. Il ne reste qu'un degrade au bas
     du cadre, la ou le mot doit rester lisible. */
  background: linear-gradient(to top, rgba(13, 5, 3, .5), rgba(13, 5, 3, 0) 34%);
  transition: background .25s ease;
}
.player__go:hover, .player__go:focus-visible {
  background: linear-gradient(to top, rgba(13, 5, 3, .58), rgba(13, 5, 3, .1) 34%);
}
.player__go:focus-visible { outline: 3px solid var(--ss-slop); outline-offset: -3px; }
/* Le triangle est trace, pas ecrit : un caractere de lecture change de
   forme et de calage d'une fonte a l'autre. */
.player__go i {
  display: block; width: clamp(3.4rem, 6vw, 5rem); aspect-ratio: 1;
  border-radius: 50%; background: var(--ss-slop);
  box-shadow: 0 6px 24px rgba(13,5,3,.45);
  position: relative; transition: transform .25s ease;
}
.player__go i::after {
  content: ""; position: absolute; top: 50%; left: 54%;
  transform: translate(-50%, -50%);
  border-left: .95em solid var(--ss-paper);
  border-block: .6em solid transparent;
  font-size: clamp(1rem, 1.6vw, 1.35rem);
}
.player__go:hover i { transform: scale(1.08); }
.player__go b { position: absolute; bottom: 1.1rem; left: 1.2rem;
                font-family: var(--ss-mono); font-size: .62rem; letter-spacing: .18em;
                text-transform: uppercase; font-weight: 400; color: var(--ss-paper); }
@media (prefers-reduced-motion: reduce) {
  .player__go, .player__go i { transition: none; }
}

/* ============================================================
   L'ATTENTE DU FILM — NOTRE ECRAN, PAS CELUI DE YOUTUBE
   Entre le clic et la premiere image, l'embed montre un rectangle noir
   et une roue minuscule : la page changeait de maison le temps du
   chargement. On pose donc NOTRE ecran par-dessus, et on ne le retire
   qu'une fois le lecteur pret.

   Le fond est la propre affiche du projet, floutee et assombrie : on
   attend DEVANT le film qu'on a demande, pas devant un trou noir. Et
   l'eclair se charge de bas en haut, comme une jauge.

   z-index 5 : au-dessus des images (3) et du bouton (4).
   ============================================================ */
.player__wait {
  position: absolute; inset: 0; z-index: 5;
  display: grid; place-items: center;
  background: var(--ss-ink);
  overflow: hidden; pointer-events: none;
  transition: opacity .3s ease;
}
.player__wait.is-out { opacity: 0; }
/* Le flou deborde du cadre : un flou s'arrete net sur ses bords et
   laisse un lisere clair tout autour si on ne l'etend pas. */
.player__blur {
  position: absolute; inset: -8%;
  background-size: cover; background-position: center;
  filter: blur(26px) saturate(.8) brightness(.5);
}
.player__bolt { position: relative; width: clamp(5rem, 11vw, 8.5rem); height: auto; }
.player__bolt .b--ghost { fill: var(--ss-paper); opacity: .16; }
.player__bolt .b--on {
  fill: var(--ss-slop);
  clip-path: inset(100% 0 0 0);
  animation: bolt-charge 1.25s cubic-bezier(.45, 0, .2, 1) infinite;
}
@keyframes bolt-charge {
  0%   { clip-path: inset(100% 0 0 0); }
  52%  { clip-path: inset(0 0 0 0); }
  72%  { clip-path: inset(0 0 0 0); }
  100% { clip-path: inset(0 0 100% 0); }
}
.player__lbl {
  position: absolute; bottom: 1.1rem; left: 1.2rem;
  font-family: var(--ss-mono); font-size: .62rem; letter-spacing: .18em;
  text-transform: uppercase; font-weight: 400; color: var(--ss-paper); opacity: .7;
}
@media (prefers-reduced-motion: reduce) {
  .player__bolt .b--on { animation: none; clip-path: none; }
}


/* ============================================================
   DEGAGEMENT SOUS LA BARRE FIXE
   La barre de menu est en position fixe : le premier bloc d'une page
   passe donc DESSOUS si personne ne l'en degage. La regle existait en
   trois versions et manquait sur les fiches de projet, dont le titre
   se cachait derriere le logo.
   Quand un fil d'Ariane ouvre la page, c'est lui qui prend le
   degagement, et le bloc suivant se resserre.
   ============================================================ */
.head, .film-head { padding-block: clamp(7.5rem, 16vh, 10rem) clamp(2rem, 5vh, 3rem); }
.crumbs { padding-top: clamp(7.5rem, 16vh, 10rem); }
.crumbs + .head { padding-top: clamp(1rem, 2.5vh, 1.8rem); }

/* Une ancre non plus. Un lien vers #quelquechose amene le HAUT de la
   cible sur le HAUT de la fenetre, donc sous la barre fixe. On reserve
   la hauteur de la barre a tout element qui peut etre vise. */
[id] { scroll-margin-top: clamp(8rem, 15vh, 10rem); }


/* ============================================================
   LE FOND DE PAGE — LE MEME PARTOUT
   Le grain et le rognage horizontal vivaient recopies a l'identique
   dans onze pages ; les deux pages de service ne les avaient pas. Sans
   `overflow-x: clip`, un pied de page pleine fenetre pousse la page de
   cote ; sans le grain, la page est lisse la ou tout le site ne l'est
   pas.
   ============================================================ */
body {
  overflow-x: clip;
  position: relative;   /* bloc conteneur du calque de grain */
}
/* LE GRAIN DU MUR.
   Trois choses le rendaient invisible avant : opacite trop basse, bruit
   trop fin, et surtout un bruit RVB colore qui se moyenne en voile gris.
   Ici il est desature (feColorMatrix saturate 0), plus gros, et pose en
   multiply — il assombrit comme une vraie texture papier au lieu de se
   superposer. stitchTiles evite la couture entre tuiles. */
body::before {
  /* ABSOLUTE, pas fixed : en fixed la texture reste collee a l'ecran et
     se lit comme un filtre de moniteur. En absolute elle appartient au
     document et defile avec lui, comme le grain d'une feuille. */
  content: ""; position: absolute; top: 0; left: 0;
  width: 100%; height: 100%; z-index: 2;
  pointer-events: none;
  mix-blend-mode: multiply;
  opacity: .4;
  background-size: 200px 200px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.55' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='2.4' intercept='-0.7'/%3E%3CfeFuncG type='linear' slope='2.4' intercept='-0.7'/%3E%3CfeFuncB type='linear' slope='2.4' intercept='-0.7'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
}


/* ============================================================
   LES PAGES DE SERVICE — CONTACT, MENTIONS LEGALES
   /legal n'a pas de feuille locale : tout ce qu'elle emploie est ici.
   ============================================================ */
/* Un lien de corps, orange et souligne : /legal en est plein. */
.ss-link { color: var(--ss-slop); text-underline-offset: .18em; }


/* ============================================================
   LA GRILLE SE POSE A L'ARRIVEE
   Une seule fois, au chargement, de la premiere vignette a la
   derniere. Rien a voir avec le defilement : c'est la page qui
   s'installe.

   Le rang vient du HTML (--i) et non d'un script : une animation
   d'accueil qui attend un fichier JS arrive apres lui, et les
   vignettes sauteraient au lieu de se poser.
   ============================================================ */
@keyframes tuile-pose {
  from { opacity: 0; transform: translateY(1.1rem) scale(.985); }
  to   { opacity: 1; transform: none; }
}
.grid .tile {
  animation: tuile-pose .62s cubic-bezier(.22, .7, .3, 1) both;
  animation-delay: calc(var(--i, 0) * 75ms);
}
/* Sans animation, rien ne doit rester invisible. */
@media (prefers-reduced-motion: reduce) {
  .grid .tile { animation: none; opacity: 1; transform: none; }
}


/* ============================================================
   LES DEUX FLECHES DE COTE
   Sur une fiche projet, passer au suivant demandait de descendre
   jusqu'au pied de page. Elles restent la, a mi-hauteur, contre le
   bord de la FENETRE et non de la mesure : c'est un geste de
   navigation, il appartient a l'ecran.

   Le chevron est TRACE — deux bords et une rotation — parce qu'un
   caractere de fleche change de forme et de calage d'une fonte a
   l'autre, et celui-ci doit tenir a la taille d'un titre.
   ============================================================ */
.sidenav {
  position: fixed; top: 50%; transform: translateY(-50%);
  z-index: 55; display: grid; place-items: center;
  /* PLUS ETROITE QUE LA MARGE. La fleche mesurait 5vw et le retrait de
     page aussi : elles se touchaient exactement, et le texte semblait
     coller au bouton. A 3,4vw il reste toujours du papier entre les
     deux, quelle que soit la largeur. */
  width: clamp(2.2rem, 3.4vw, 3.2rem); height: clamp(4.6rem, 9vw, 7rem);
  background: var(--ss-slop); color: var(--ss-paper);
  text-decoration: none;
  transition: width .18s ease, background .18s ease;
}
.sidenav--p { left: 0; border-radius: 0 var(--ss-round) var(--ss-round) 0; }
.sidenav--n { right: 0; border-radius: var(--ss-round) 0 0 var(--ss-round); }
.sidenav i {
  display: block;
  width: clamp(.9rem, 1.9vw, 1.5rem); height: clamp(.9rem, 1.9vw, 1.5rem);
  border-top: clamp(4px, .55vw, 7px) solid currentColor;
  border-right: clamp(4px, .55vw, 7px) solid currentColor;
}
.sidenav--n i { transform: rotate(45deg) translate(-12%, 12%); }
.sidenav--p i { transform: rotate(-135deg) translate(-12%, 12%); }
.sidenav:hover, .sidenav:focus-visible { width: clamp(2.6rem, 4.2vw, 4rem); background: var(--ss-ink); }
.sidenav:focus-visible { outline: 3px solid var(--ss-slop); outline-offset: 3px; }
/* Sous 900 px il n'y a plus de marge a occuper : elles mangeraient le
   texte. Le pager du bas fait le meme travail, sans se poser dessus. */
@media (max-width: 900px) { .sidenav { display: none; } }
@media (prefers-reduced-motion: reduce) { .sidenav { transition: none; } }


/* ============================================================
   MESURE DE PAGE
   Une seule largeur pour tout le site. L'accueil courait a 124 rem et
   les autres pages a 108 : la meme phrase s'arretait 256 px plus loin
   d'une page a l'autre, ce qui se voit sur les paragraphes longs.
   ============================================================ */
.wrap { max-width: 108rem; margin-inline: auto;
        padding-inline: clamp(1.25rem, 5vw, 4rem); }


/* ============================================================
   PLEINE FENETRE
   Une image qui sort de la mesure : elle prend la largeur de la
   fenetre, sa legende revient dans la mesure. La regle vivait en huit
   exemplaires identiques dans les pages, et sa legende y gardait une
   mesure de 78 rem — donc une legende qui ne s'alignait sur rien.
   ============================================================ */
figure.bleed {
  width: 100vw; margin-left: calc(50% - 50vw); max-width: none;
  margin-block: clamp(1.4rem, 3vh, 2.4rem) clamp(2rem, 4vh, 3rem);
}
figure.bleed img { display: block; width: 100%; height: auto; }
figure.bleed figcaption {
  font-family: var(--ss-mono); text-transform: uppercase; letter-spacing: .16em;
  font-size: .62rem; color: var(--ss-muted);
  max-width: 108rem; margin: .7rem auto 0;
  padding-inline: clamp(1.25rem, 5vw, 4rem);
}
