/* =========================================================================
   UST — socle : fontes, réinitialisation, éléments, focus, motion
   Aucune valeur littérale ici : tout vient de tokens.css.
   ========================================================================= */

/* --- Fontes auto-hébergées (C6) ------------------------------------------
   Trois familles, deux sous-ensembles chacune (latin, latin-ext), woff2.
   Spectral n'existe pas en variable : deux instances statiques, 300 et 400.
   Epilogue et Martian Mono sont variables, INSTANCIÉES aux seules graisses
   employées (wght 400-600 et 300-500) — l'axe complet 100-900 pesait 40 %
   de plus. Total servi : 166 Ko sur huit fichiers, 67 Ko sur le chemin
   critique (les trois latin).
   Aucun <link> vers fonts.googleapis.com nulle part : le Caddyfile pose
   font-src 'self', la CSP de production bloquerait le CDN.                 */

@font-face {
  font-family: "Spectral"; font-style: normal; font-weight: 300;
  font-display: swap; src: url("/assets/fonts/spectral-300-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Spectral"; font-style: normal; font-weight: 300;
  font-display: swap; src: url("/assets/fonts/spectral-300-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Spectral"; font-style: normal; font-weight: 400;
  font-display: swap; src: url("/assets/fonts/spectral-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Spectral"; font-style: normal; font-weight: 400;
  font-display: swap; src: url("/assets/fonts/spectral-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Epilogue"; font-style: normal; font-weight: 400 600;
  font-display: swap; src: url("/assets/fonts/epilogue-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Epilogue"; font-style: normal; font-weight: 400 600;
  font-display: swap; src: url("/assets/fonts/epilogue-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Martian Mono"; font-style: normal; font-weight: 300 500;
  font-display: swap; src: url("/assets/fonts/martianmono-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Martian Mono"; font-style: normal; font-weight: 300 500;
  font-display: swap; src: url("/assets/fonts/martianmono-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --- LE HAN (R6) ---------------------------------------------------------
   LES HUIT @font-face CI-DESSUS NE COUVRENT QUE LE LATIN. Leurs unicode-range
   s'arrêtent à U+A7FF : aucun idéogramme n'y entre, et aucune police han n'est
   hébergée sous /assets/fonts/. Le Caddyfile pose font-src 'self' et la CSP de
   production bloquerait un CDN, ce qui est la bonne politique et ne change pas.
   Le chinois tombait donc sur la fin de la pile de --f-corps, c'est-à-dire
   « sans-serif » : sur une machine sans police CJK, le navigateur n'a rien à
   dessiner et rend des carrés vides. Mesuré sur la machine de recette, qui ne
   porte que Lato et FontAwesome : l'accueil chinois sortait « 12 □□□□ ».

   CE QUE FAIT CE BLOC, ET CE QU'IL NE FAIT PAS. Il NOMME les familles han
   installées sur les systèmes où vit un lecteur chinois, au lieu de laisser le
   choix au hasard de « sans-serif » : macOS et iOS (PingFang SC), Windows
   (Microsoft YaHei), Android et Linux (Noto Sans CJK SC, Source Han Sans SC).
   La pile latine reste EN TÊTE : les noms de modèle, les nombres et les unités
   d'une page chinoise restent en Epilogue et en Martian Mono, comme partout
   ailleurs sur le site, et seul le han bascule.

   IL NE GARANTIT RIEN SUR UNE MACHINE QUI N'A AUCUNE POLICE HAN. Seule une
   police hébergée le garantirait : il faudrait sous-tirer un Noto Sans SC aux
   idéogrammes réellement employés par les tables zh. C'est une décision de
   poids servi, elle appartient au client, et elle est écrite dans
   _design/LANGUE-ZH-ETAT.md. */
:lang(zh) {
  --f-display: Spectral, "Iowan Old Style", Georgia, "PingFang SC", "Hiragino Sans GB",
    "Microsoft YaHei", "Noto Serif CJK SC", "Source Han Serif SC", serif;
  --f-corps: Epilogue, ui-sans-serif, system-ui, -apple-system, "PingFang SC",
    "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", "Source Han Sans SC",
    "Heiti SC", sans-serif;
  --f-data: "Martian Mono", ui-monospace, "SFMono-Regular", Menlo, "PingFang SC",
    "Microsoft YaHei", "Noto Sans CJK SC", monospace;
}

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

/* Zéro smooth scroll (§8) : le défilement n'est pas un effet. */
html { -webkit-text-size-adjust: 100%; }

body {
  background: var(--nuit);
  color: var(--texte);
  font-family: var(--f-corps);
  font-size: var(--d-corps);
  font-weight: var(--g-corps);
  line-height: var(--i-corps);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

img, svg, video { display: block; max-width: 100%; }
img, video { height: auto; }
input, button, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }

/* --- Titrage — Spectral 300, plafonné à 96 px (§6) ------------------------ */
h1, h2, h3, h4, h5, h6 { text-wrap: balance; font-weight: var(--g-corps); }

.d-hero, .d-h1, .d-h2 {
  font-family: var(--f-display);
  font-weight: var(--g-display);
  line-height: var(--i-serre);
  letter-spacing: var(--l-display);
  /* Spectral sert des chiffres elzéviriens : un nom de produit — « DWARF 3 »
     — exige des chiffres capitales. */
  font-variant-numeric: lining-nums;
}
.d-hero, .d-h1 { font-size: var(--d-display); }
.d-h2 { font-size: var(--d-h2); }
.d-hero em, .d-h1 em, .d-h2 em { font-style: italic; font-weight: var(--g-display-forte); }

.d-h3 {
  font-family: var(--f-corps); font-size: var(--d-h3);
  font-weight: var(--g-corps-moyen); line-height: var(--i-titre); letter-spacing: -.015em;
}
.d-h4 {
  font-family: var(--f-corps); font-size: var(--d-h4);
  font-weight: var(--g-corps-fort); line-height: var(--i-titre); letter-spacing: -.01em;
}
.d-lead { font-size: var(--d-lead); color: var(--champ); line-height: 1.55; }

/* La lampe n'éclaire que ce que la main touche (loi n° 2) : un mot accentué
   par l'auteur se marque à la graisse, pas à la couleur d'accent. */
strong { font-weight: var(--g-corps-fort); color: var(--texte); }

p { max-width: var(--lecture); }
p + p { margin-top: var(--e-3); }

/* --- La donnée : Martian Mono, 12 px plancher (C8) ------------------------
   Elle porte exclusivement la donnée mesurée — poses, dates, définitions,
   désignations, prix, rapports. Jamais un paragraphe. */
.mono {
  font-family: var(--f-data); font-size: var(--d-mono);
  font-weight: var(--g-mono); line-height: var(--i-mono);
  letter-spacing: var(--l-mono); font-variant-numeric: tabular-nums;
}
/* Règle dure du système (§6) : tout nombre mesuré est en Martian Mono,
   y compris dans un titre ; l'unité reste dans la famille de la prose. */
.nombre {
  font-family: var(--f-data); font-weight: var(--g-mono);
  font-variant-numeric: tabular-nums; letter-spacing: 0;
}
.brow {
  font-family: var(--f-data); font-size: var(--d-mono);
  font-weight: var(--g-mono); line-height: var(--i-mono);
  text-transform: uppercase; letter-spacing: var(--l-brow);
  color: var(--label);
}

/* --- Liens --------------------------------------------------------------- */
a { color: inherit; text-decoration-color: var(--filet-haut); text-underline-offset: .25em; }
.lien {
  color: var(--lampe); text-decoration: none; font-weight: var(--g-corps-moyen);
  display: inline-block; line-height: 1.5; padding-bottom: 2px;
  border-bottom: 1px solid var(--lampe-bord);
  transition: color var(--t-ui) ease, border-color var(--t-ui) ease;
}
@media (hover: hover) {
  a:hover { text-decoration-color: currentColor; }
  .lien:hover { color: var(--lampe-haute); border-color: var(--lampe-haute); }
}

/* --- Focus tokenisé ------------------------------------------------------ */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: var(--focus-l) solid var(--focus-couleur);
  outline-offset: var(--focus-o);
  border-radius: 2px;
}

.saut {
  position: absolute; left: var(--marge); top: var(--e-1); z-index: 100;
  transform: translateY(-200%);
  background: var(--ciel); color: var(--texte); border: 1px solid var(--filet-haut);
  padding: var(--e-2) var(--e-3); border-radius: var(--r-s);
  font-weight: var(--g-corps-moyen); text-decoration: none;
}
.saut:focus { transform: translateY(0); }

::selection { background: var(--selection); color: var(--nuit); }

/* --- Mise en page -------------------------------------------------------- */
.enveloppe { padding-inline: var(--marge); }
.contenu   { max-width: var(--contenu); margin-inline: auto; }
.etroit    { max-width: var(--etroit); margin-inline: auto; }
.section   { padding-block: var(--section); }

/* LA MENTION DE RÉGIME (D6, M1 à M5), ET POURQUOI ELLE A UN STYLE (R1 bis).
   Elle n'en avait aucun : .note et .mention n'existaient nulle part dans les
   feuilles, et le <p> sortait nu, collé au bord gauche de la fenêtre, à x = 0,
   au-dessus d'une colonne de contenu qui commence à x = 100. Elle n'était pas
   seulement fausse, elle avait l'air cassée. Le gabarit lui donne maintenant la
   même .enveloppe et le même .contenu que toutes les sections du site : elle est
   donc dans la colonne. Il lui reste à se lire comme une note et non comme un
   paragraphe du texte, d'où le filet d'accent et le fond de panneau. */
.mention__enveloppe { padding-top: var(--e-5); }
.mention {
  color: var(--label);
  font-size: var(--d-petit);
  background: var(--ciel);
  border-left: 2px solid var(--lampe);
  border-radius: var(--r-s);
  padding: var(--e-3);
  max-width: 68ch;
}
/* LA SECTION DE TÊTE RESPIRE MOINS PAR LE HAUT. Sur une page qui vend, le
   pli est une ressource : 150 px de vide au-dessus du premier mot, c'est
   150 px de moins pour la photographie, le prix et l'appel.
   ET MOINS PAR LE BAS AUSSI, PARCE QUE L'AIR Y ÉTAIT COMPTÉ DEUX FOIS.
   Le bas gardait --section, et la section suivante ajoutait le sien : deux
   fois 150 px à 1440, soit 300 px mesurés entre le dernier mot de
   l'ouverture et le premier de la section suivante, quand le héros de
   l'accueil, qui est le même bloc dans le même rôle, n'en laisse que 206. L'écart se
   voyait sur les 62 pages qui ouvrent au filet ou au nu, et le plus sur les
   plus courtes, où il occupait tout le milieu du premier écran.
   La valeur n'est pas choisie : c'est --e-6, exactement le padding-block que
   .hero se donne au-delà de 62rem. L'ouverture rend donc le même air que
   l'étalon, mesuré à 196 px au lieu de 300. */
.section--tete { padding-top: clamp(2rem, 1.1rem + 2.8vw, 4rem); padding-bottom: var(--e-6); }
/* Le fil d'Ariane porte sa propre marge basse pour les pages qui ne sont pas
   en pile. Dans une pile, la gouttière s'en charge, et les deux s'ajoutaient. */
.pile > .fil { margin-bottom: 0; }
.section-large { padding-block: var(--section-large); }
/* Un filet, jamais une différence de fond seule : la hiérarchie des plans
   vit sous 2:1 et doit survivre à un téléphone en plein soleil (§5). */
.section--filet { border-top: 1px solid var(--filet); }
/* LE FOND RELEVÉ D'UNE SECTION, ET IL A ENFIN UN NOM.
   Quinze sections des gabarits écrivaient `style="background: var(--ciel)"`
   en style en ligne. Ce n'était pas une valeur littérale — c'est bien le
   jeton — mais c'était la même décision recopiée quinze fois, donc quinze
   endroits à corriger le jour où l'alternance change. Le rythme de sections
   de la doctrine (_design/COHERENCE.md) s'écrit avec cette classe.
   Les styles en ligne restants posent exactement la même valeur : ils
   gagnent tant qu'ils sont là, et rien ne bouge à mesure qu'ils partent. */
.section--ciel { background: var(--ciel); }

.pile { display: flex; flex-direction: column; }
.pile-2 { gap: var(--e-2); } .pile-3 { gap: var(--e-3); }
.pile-4 { gap: var(--e-4); } .pile-5 { gap: var(--e-5); }
.pile-6 { gap: var(--e-6); } .pile-8 { gap: var(--e-8); }

.grille { display: grid; gap: var(--gouttiere); }
.autofit   { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); }
.autofit-l { grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr)); }

.defile-x { overflow-x: auto; overscroll-behavior-x: contain; }

.u-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* --- Révélation au défilement — 560 ms, jouée une fois (§8) --------------
   L'état caché est conditionné à .js, classe posée avant le premier rendu :
   sans JavaScript la page est COMPLÈTE. Ne pas régresser en refactorisant. */
.js [data-rev] {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--t-revele) var(--courbe), transform var(--t-revele) var(--courbe);
  transition-delay: calc(var(--i, 0) * var(--t-cadence));
}
.js [data-rev].vu { opacity: 1; transform: none; }

/* --- Les deux gardes, obligatoires (§8) ---------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .js [data-rev] { opacity: 1; transform: none; transition: none; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
/* Toute règle de survol est gardée : rien ne se déclenche au doigt. */
@media (hover: none) {
  .js [data-rev] { opacity: 1; transform: none; }
}

/* Cible tactile minimale (WCAG 2.2, 2.5.8) pour les liens de texte isolés
   dans une liste : sans cela un lien de source mesure 23 px de haut. */
li > a:only-child, .lex__voir a,
/* Le forum ajoute ses liens de texte isolés à la même règle plutôt que de
   recopier la valeur cinq fois : le titre d'un sujet dans la liste, les deux
   pas de la pagination, les actions sous un message, chaque appareil déclaré
   dans une fiche, et les deux résumés de <details>. */
.sujet__lien, .forum-pages__pas, .msg__action, .fiche__appareils a,
.msg__signal > summary, .forum-droits__fermer > summary {
  display: inline-flex; align-items: center; min-height: 1.5rem;
}
