/* mlsign v7 — socle : réinitialisation, canevas, échelle, utilitaires.
   Ordre de chargement : mlsign.css, fonts.css, socle.css, zones.css,
   composants.css (+ rapport.css sur les pages qui en portent un).

   LOI DE CE FICHIER : aucune déclaration `color` sur un sélecteur d'élément nu
   (p, h1, li…). À spécificité égale (0,0,1) avec les défauts de zones.css,
   c'est l'ordre de source qui trancherait — et socle.css passe avant. */

/* --- Réinitialisation --------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

/* --- Échelle du site ----------------------------------------------------- */
:root {
  --maxw: 1240px;
  --gutter: clamp(1.25rem, 0.9rem + 2vw, 3rem);
  --section-y: clamp(4rem, 2.5rem + 5vw, 8rem);
  --barre-h: 4rem;

  /* Deux mesures pour deux vitesses : le manifeste tient en une respiration,
     le dossier porte la lecture longue. MESURÉ au navigateur (largeur du bloc
     divisée par la chasse réelle du « 0 » de Switzer, pas par une estimation) :
     le corps de dossier sortait à 62 caractères par ligne. 66ch le pose à
     l'entrée de la fenêtre de confort de la lecture longue sans l'y pousser —
     au-delà, l'œil rate la ligne suivante au retour chariot. */
  --mesure-jour: 46ch;
  --mesure-nuit: 66ch;

  /* L'ÉCHELLE DE RYTHME. Quatre pas, et le rythme naît de leur écart, pas de
     leur valeur : au-dessus de 1240 px ils font 12 / 32 / 60 / 112 px.
     --pas-1 colle ce qui va ensemble (un libellé et son titre, une ligne de
     réassurance et le bouton qu'elle explique) ; --pas-2 est le battement
     courant d'un bloc ; --pas-3 sépare deux groupes DANS une section ;
     --section-y sépare deux sections. Une valeur d'espacement qui ne sort pas
     de cette échelle est un accident : c'est ce qui a produit les quatre
     écarts identiques de 37,6 px du manifeste, où plus rien n'était groupé. */
  --pas-1: 0.75rem;
  --pas-2: clamp(1.25rem, 1rem + 1.1vw, 2rem);
  --pas-3: clamp(2.25rem, 1.75rem + 2.2vw, 3.75rem);

  /* Quarte, peu de tailles, beaucoup d'écart. Le plancher du hero reste
     au-dessus du plafond du h2 sur toute la plage : sinon la hiérarchie
     s'inverse sur téléphone. */
  /* LE PLAFOND N'ÉTAIT JAMAIS ATTEINT. `1.75rem + 5vw` ne touche 7rem qu'à
     1680 px de fenêtre : à 1440, la largeur de travail réelle, le hero sortait
     à 100 px pour un plafond annoncé de 112. La courbe est celle du proto
     d'Axel (v6.css:207) : 56 px jusqu'à 560, puis 10vw, plafond 128 dès 1280.
     Elle atteint sa valeur haute là où l'écran existe. */
  --t-hero: clamp(3.5rem, 10vw, 8rem);
  --t-h2: clamp(2rem, 1.4rem + 2.9vw, 4rem);
  /* LE RANG QUI MANQUAIT. --t-h2 servait aux deux vitesses : une affirmation
     de manifeste, qui tient un écran à elle seule, et un titre de section de
     dossier, qui n'est qu'un repère dans un document. Les deux sortaient à
     64 px, et une page de dossier n'avait donc plus de hiérarchie du tout —
     six titres criaient le même volume que le h1 de la page.
     Un cran en dessous suffit à ranger le dossier : hero 112, section 42,
     sous-bloc 27, texte 17. Le sommet reste au contenu (DESIGN.md, loi 2). */
  --t-h2-dossier: clamp(1.75rem, 1.3rem + 1.55vw, 2.6rem);
  /* Un titre de carte sortait à 27,2 px quand le h2 qui le coiffe en fait 64 :
     l'écart entre les deux rangs était de 2,35, celui d'Axel de 3,2. Le hero
     monte à 128, donc l'échelle entière s'étire par le haut, laisser le rang
     bas où il était l'aurait tassée contre le texte courant, qui fait 17.
     18,95 à 23,20 : au-dessus du corps sans jamais discuter avec le titre.
     Porte sur les onze pages, via .bloc__titre et les h3 de dossier. */
  --t-h3: clamp(1.15rem, 1.05rem + 0.55vw, 1.45rem);
  --t-lead: clamp(1.1rem, 1rem + 0.6vw, 1.45rem);
  --t-base: 1.0625rem;
  --t-petit: 0.9rem;
  --t-micro: 0.75rem;

  --lh-titre: 1.05;
  --lh-texte: 1.55;
  --lh-dossier: 1.45;

  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --duree: 160ms;
}

/* --- L'ÉCHELLE DES PALIERS ------------------------------------------------
   UNE MEDIA QUERY NE PEUT PAS LIRE UNE CUSTOM PROPERTY : `(width < var(--p))`
   est invalide, et `@custom-media` demande un post-processeur que ce build n'a
   pas. Les paliers se nomment donc ici, en toutes lettres, et c'est une garde
   de build.mjs qui refuse toute requête hors de cette liste. Sans la garde,
   cette liste ne serait qu'un vœu, et elle a déjà dérivé une fois.

     25rem     400 px   le titre de page cesse de tenir (voir juste dessous)
     26.25rem  420 px   la pilule resserre ses gestes
     35rem     560 px   les gestes du hero s'empilent
     40rem     640 px   une seule colonne, la frise passe en lecture téléphone
     56.25rem  900 px   deux colonnes : scène de demande, constellation, fiches
     60rem     960 px   le rapport déplie ses blocs
     72rem    1152 px   le rapport à quatre colonnes

   ÉCRITES EN INTERVALLE, jamais avec les anciens préfixes de largeur. Une
   borne « au plus » et une borne « au moins » posées sur le même nombre
   s'appliquent TOUTES DEUX à ce nombre exactement : à 900 px de fenêtre, les
   deux règles peignent. Le contournement classique retranche un centième au
   plafond, et il vivait ici à côté d'une borne pleine pour le même seuil —
   deux orthographes, sept usages, et rien pour dire laquelle fait foi.
   `(width < P)` et `(width >= P)` sont des complémentaires exacts, sans
   décimale à entretenir. Aucun défaut visible n'en découlait au moment de la
   bascule (vérifié sélecteur par sélecteur : les paires en conflit ne
   peignaient jamais la même propriété) — c'est une dérive qu'on ferme avant
   qu'elle coûte, pas une réparation.

   En rem et pas en px : qui grossit sa police a un écran relativement plus
   étroit et doit basculer plus tôt. Les décimales sont le prix de
   l'équivalence exacte avec les px d'origine, pas un choix d'échelle.

   « En dessous » s'écrit toujours `<`, « à partir de » toujours `>=`. Un
   palier ne s'applique donc jamais deux fois, sur aucun des deux axes.

   LA HAUTEUR EST UN AUTRE AXE. Le palier paysage de composants.css se lit en
   `height` et n'appartient pas à cette échelle : il ne décrit pas la largeur
   de la colonne mais le fait qu'un téléphone couché n'a plus de hauteur. */

/* LE PLANCHER DU HERO COUPE LES TITRES SOUS 391 px, ET ÇA NE SE VOIT PAS.
   La courbe d'Axel tient 56 px jusqu'à 560 puis suit 10vw. En dessous de
   560 px de fenêtre, --t-hero est donc CLOUÉ à 56 px pendant que la colonne,
   elle, continue de rétrécir.
   Ce qui rend la panne invisible : `html { overflow-x: clip }` (plus bas) est
   une garde contre le défilement latéral, et elle fait ici office de ciseaux.
   Le titre ne pousse pas la page, il est COUPÉ NET. Mesuré à 320 px sur
   /le-rapport/ : « Voilà ce que vous recevez à la fin. » s'affiche « ce que
   vous recev ».
   La cause n'est pas la longueur du titre mais celle de son plus gros morceau
   INSÉCABLE : scripts/typo.mjs lie les mots outils, et « ce que vous recevez »
   arrive en un seul bloc de 19 caractères que rien ne peut casser. Mesuré :
   6,177 px de large par px de police, soit 346 px à 56. Le disponible vaut
   `100vw - 2 × --gutter`, c'est-à-dire 278 px à 320 et 331 à 375 : l'iPhone SE
   coupe lui aussi.
   14vw vaut exactement 56 px à 400 px de fenêtre, donc le raccord avec la
   courbe d'Axel est continu et rien ne bouge au-dessus. On prend 13,5 pour
   garder deux pixels de marge sur le morceau, au prix de 2 px de décrochement
   au raccord — invisible, et c'est un seuil.
   Ne PAS traiter ça en autorisant la césure dans le morceau : elle existerait
   alors sur les treize pages, et c'est précisément ce que typo.mjs empêche. */
@media (width < 25rem) {
  :root { --t-hero: 13.5vw; }
}

/* --- Canevas ------------------------------------------------------------- */
html {
  background-color: var(--papier);
  /* La garde contre les debordements horizontaux : les pleins-bords calcules
     en vw comptent la barre de defilement (Windows), clip absorbe l'ecart au
     lieu d'ouvrir un defilement lateral. */
  overflow-x: clip;
  overscroll-behavior-y: none;
  -webkit-text-size-adjust: 100%;
  /* La barre est fixe : une ancre doit atterrir sous elle. */
  scroll-padding-block-start: calc(var(--barre-h) + 1rem);
}
@media (prefers-reduced-motion: no-preference) {
  html:focus-within { scroll-behavior: smooth; }
}

body {
  font-family: var(--font-texte);
  font-size: var(--t-base);
  font-weight: var(--wght-texte);
  line-height: var(--lh-texte);
  -webkit-font-smoothing: antialiased;
}

/* Compensation optique du clair-sur-sombre. En :where() — spécificité (0,0,0),
   incapable de gagner un arbitrage, comme les défauts de zones.css. */
:where(.zone-nuit) { letter-spacing: 0.008em; }

/* --- Éléments ------------------------------------------------------------ */
img, video, canvas, svg, picture { display: block; max-inline-size: 100%; }
img, video { block-size: auto; }

/* LA LIGNE DE PARTAGE DES DEUX VOIX. La serif ne descend pas jusqu'en bas :
   elle prend le rang éditorial (le titre de page, le titre de section), et le
   rang de structure, un titre de carte, un intertitre de bloc, reste en
   Switzer 700. C'est le découpage du proto d'Axel, où seuls le hero, les h2, le
   pivot et le refrain passent en var(--serif) et où les h3 de carte sortent en
   suisse à 18 px. Deux voix qui se répondent à deux rangs se lisent comme une
   hiérarchie ; la même voix partout redevient un fond.
   La graisse suit la famille : --wght-display (400, la seule que la serif
   possède) en haut, --wght-titre (700) en bas. */
h1, h2, h3, h4 {
  font-size: inherit;
  line-height: var(--lh-titre);
  text-wrap: balance;
  letter-spacing: -0.012em;
  /* FILET DE SÉCURITÉ, PAS LE CORRECTIF. scripts/typo.mjs soude les mots-outils
     au mot qu'ils introduisent et plafonne le bloc insécable à 20 caractères
     (BLOC_MAX) — une mesure calibrée pour du texte courant. Sur un titre de
     hero, 20 caractères font 448 px : « ce que vous recevez » est ressorti
     soudé sur /le-rapport/, et la page défilait à l'horizontale à 414 px.
     Sans opportunité de coupure, le navigateur ne peut que déborder.
     Les deux propriétés vont ensemble et dans cet ordre : `hyphens` coupe au
     bon endroit et POSE LE TRAIT D'UNION — la page est en lang="fr-CH", le
     navigateur sait où sont les syllabes — et `overflow-wrap` reste dessous
     pour le cas qu'aucun dictionnaire ne rattrape. Sans le premier, la coupure
     tombait sur « rec / evez », qui se lit comme un bogue de rendu.
     Ça ne se voit jamais tant qu'un titre tient dans sa colonne, et le vrai
     correctif est un BLOC_MAX qui connaît le corps du texte : il appartient à
     scripts/typo.mjs, pas à la feuille.

     `hyphens: auto` ACCOMPAGNAIT CETTE LIGNE ET N'Y EST PLUS. Il ne cohabite
     pas avec `text-wrap: balance` : l'équilibreur traite un point de césure
     comme une occasion de plus d'égaliser ses lignes, et il la prend même quand
     le mot entier tiendrait. « Ça marche pour un évé-nement ponctuel ? »
     sortait ainsi sur /questions/, à 1440 px comme à 414, dans une colonne où
     le mot tenait trois fois. Une césure sur un titre de page publique se lit
     comme un défaut d'exécution, et celle-là revenait à chaque rendu.
     VÉRIFIÉ AVANT DE LE RETIRER, sur les treize pages à 414, 360 ET 320 px :
     aucun titre ne déborde de sa colonne sans lui, et aucune page ne défile à
     l'horizontale. Le bloc soudé de 20 caractères passe donc partout, et
     `overflow-wrap` suffit à tenir le cas qu'aucun dictionnaire ne rattrape —
     lui ne coupe que si le mot NE PEUT PAS tenir, jamais par confort. */
  overflow-wrap: break-word;
}
h1, h2 {
  font-family: var(--font-display);
  font-weight: var(--wght-display);
  /* 1,05 était calé sur Switzer. Instrument Serif a une hauteur d'x plus basse
     et des jambages plus longs : au même interligne les lignes se serrent et
     les descendantes touchent la ligne suivante. 1,08 est le palier d'Axel pour
     ce rang (v6.css:283), et le hero redescend à 1,02 chez lui comme ici. */
  line-height: 1.08;
}
h3, h4 {
  font-family: var(--font-texte);
  font-weight: var(--wght-titre);
}
/* `pretty` interdit les lignes veuves et rééquilibre les deux dernières
   lignes. Il a d'abord été posé sur p, puis étendu à li et dd (les réponses
   de /confidentialite/ sont des dd, les puces des grilles des li), et le
   16.08 la même leçon a resservi un cran plus loin : les libellés du tunnel
   sont des label et des legend, les corps des cartes de choix des span, les
   titres de terrain des dt — la moitié du texte du site échappait ENCORE au
   correcteur. La propriété s'hérite : posée sur la racine, elle atteint tout
   ce qui porte du texte, et les titres la recouvrent d'un `balance` plus
   haut. Passage demandé par Nazaire (« la règle en français des retours à la
   ligne »), la moitié insécable de cette règle vivant déjà dans
   scripts/typo.mjs.
   AUCUN `hyphens`, AUCUN `word-break`, AUCUN `overflow-wrap` ici : ils
   couperaient les blocs insécables que scripts/typo.mjs a soudés. Le filet de
   sécurité des titres reste cantonné aux titres, un cran plus haut. */
body { text-wrap: pretty; }
/* Les titres qui n'en portent pas la balise : une question de fieldset et un
   terme de définition titrent leur bloc, ils s'équilibrent comme des titres. */
dt, legend { text-wrap: balance; }
ul, ol { padding: 0; list-style: none; }
dl, dd { margin: 0; }
hr { border: 0; border-block-start: var(--hairline) solid; }

/* --- Utilitaires --------------------------------------------------------- */
/* Toute durée, tout horodatage, tout compteur passe par .num. */
.num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* UN NOM DE FICHIER N'EST PAS UN NOMBRE, et la nuance se paie cash. Le nom du
   visuel portait .num pour la seule mono, et héritait au passage de son
   insécable — qui est là pour que « 11 h 35 » ne se coupe jamais en fin de
   ligne, pas pour figer une chaîne de vingt caractères.
   Mesuré à 390 px sur /le-rapport/ : « 01-votre-pub-ici.mp4 » clouait la
   colonne Visuel à 230 px, le tableau sortait à 410 dans une boîte de 346, et
   « Temps » — LA COLONNE FACTURÉE, sur la page qui EST la preuve — passait
   65 px hors écran, sans masque ni ombre pour signaler qu'il y avait une suite.
   `anywhere` et pas `break-word` : seul `anywhere` entre dans le calcul de la
   largeur min-content, donc seul lui laisse la colonne du tableau rétrécir.
   Le navigateur coupe d'abord aux tirets du nom, la césure arbitraire ne sert
   que de dernier recours. */
.fichier {
  font-family: var(--font-mono);
  overflow-wrap: anywhere;
}

.vh {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Micro-étiquette : la seule capitale autorisée du site (DESIGN.md).
   Switzer, jamais mono — le mono ne parle qu'à partir du pivot.

   ELLE ÉTAIT POSÉE SEIZE FOIS, ET C'EST CE QUI LA RENDAIT LAIDE. Un kicker en
   capitales espacées au-dessus d'un titre, c'est une voix ; le même objet
   répété au-dessus de chaque section, de chaque carte et de chaque terrain,
   c'est du décor — il ne dit plus « regarde ça », il dit « ici commence un
   bloc ». Le mot n'y est pour rien, c'est la répétition qui use.
   L'interlettrage descend de 0,12 à 0,08 : à 12 px, 0,12em fait crier une
   ligne de six lettres. Et les capitales ne restent QUE sur le kicker du
   premier écran, le seul endroit où l'étiquette est une entrée en matière et
   pas un intertitre. Ailleurs elles tombent (règle plus bas), et le mot
   reparaît tel qu'il est écrit dans le JSON — « Slot », « Loop », le nom du
   terrain — parce que la casse venait d'ici, jamais de la copy. Aucun texte
   n'est touché. */
.etiquette {
  font-size: var(--t-micro);
  font-weight: var(--wght-titre);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--texte-secondaire);
}
/* Les étiquettes RÉPÉTÉES perdent la capitale et l'interlettrage : elles
   redeviennent ce qu'elles sont, un nom au-dessus de son bloc. */
.carte__nom,
.terrain__titre.etiquette,
.rapport__specimen-etiquette {
  letter-spacing: 0;
  text-transform: none;
}

/* --- Mouvement réduit ----------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
