@import url('https://fonts.googleapis.com/css2?family=Archivo:wght@400;500;600;700&family=Inconsolata:wght@400;500;600&display=swap');

/* ═══════════════════════════════════════════════════════════════════════════
   MAZETERY — la marque, pas le livre.
   ═══════════════════════════════════════════════════════════════════════════

   ⚠️ LA RÈGLE QUI TIENT TOUT LE RESTE : le magenta #CA174B et l'or #F8C534
   appartiennent au LIVRE UN. Ici, ils n'apparaissent qu'à un seul endroit —
   DANS l'image de la couverture, qui est une photo d'objet. Rien de la chrome
   (bouton, liens, filets, bandeau, tracé animé, focus) ne les emploie.

   Ce n'est pas de la coquetterie. Le jour où le livre deux arrive avec son
   violet, une page de marque ornée de magenta se lirait comme la page du livre
   un étendue à toute la collection. Et à l'entrée du donjon, le lecteur doit
   sentir qu'il change de niveau : il ne le sentira pas si les deux surfaces ont
   la même couleur d'accent.

   L'anthracite est le SEUL token partagé avec le site du livre. C'est ce qui
   fait que les deux surfaces appartiennent visiblement à la même maison, sans
   que la marque emprunte la voix d'un de ses titres.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ---------- surfaces ---------- */
  --brand-charcoal: #1d282f; /* le fond — partagé avec le site du livre */
  --brand-sunken: #16222a; /* surface enfoncée */

  /* ---------- accent et encres ---------- */
  --brand-verdigris: #4fb89e; /* 7,9:1 sur l'anthracite */
  --brand-verdigris-hover: #5ecfb2;
  --brand-bone: #e7e2d6; /* 12,4:1 */
  --ink-body: #b6c0c3; /* 8,2:1 */
  --ink-muted: #8c9aa0; /* 5,1:1 */

  /* L'encre POSÉE SUR le verdigris — surligneur et bouton. Un blanc y tomberait
     à 2,3:1 ; cet anthracite verdi y tient 8,9:1 et reste dans la famille. */
  --ink-on-verdigris: #12211f;

  /* ---------- filets ---------- */
  --hairline: rgba(231, 226, 214, 0.16);
  --hairline-faint: rgba(231, 226, 214, 0.12);
  --hairline-pill: rgba(231, 226, 214, 0.3);

  /* ---------- typographie ----------
     Archivo pour la voix de la marque, PAS l'Oswald du livre. Une condensée
     lourde est une voix de titre : si la marque parle comme ça, chaque livre
     perd la sienne. Archivo est un grotesque droit et sobre — un cadre neutre
     autour de titres qui crient. Inconsolata reste pour le corps : la grille
     monospace EST la promesse de la collection. */
  --font-marque: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --font-corps: 'Inconsolata', Consolas, ui-monospace, monospace;

  /* ---------- échelle d'espacement : 4 · 8 · 14 · 22 · 24 · 44 · 56 ---------- */
  --gouttiere: 24px;
  --gouttiere-entete: 22px;
  --cible-min: 44px;
  --cible-bouton: 56px;

  /* ⚠️ RAYON ZÉRO PARTOUT. La seule courbe autorisée dans le système est le
     halo circulaire derrière le livre — qui est un flou, pas une bordure.
     Même règle que sur le site du livre. */
  --rayon: 0;

  --transition-couleur: 120ms ease-out;
  --transition-base: 200ms ease-out;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  background: var(--brand-charcoal);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--brand-charcoal);
  color: var(--ink-body);
  font-family: var(--font-corps);
  font-size: 14px;
  line-height: 1.55;
}

a {
  color: var(--brand-verdigris);
  text-decoration: underline;
  text-decoration-color: rgba(79, 184, 158, 0.5);
  text-underline-offset: 2px;
  transition: color var(--transition-couleur);
}

a:hover {
  color: var(--brand-bone);
  text-decoration-color: currentColor;
}

/* Un seul anneau de focus pour toute la page, en os : le verdigris est déjà la
   couleur du bouton, un anneau verdigris sur fond verdigris ne se verrait pas. */
:focus-visible {
  outline: 2px solid var(--brand-bone);
  outline-offset: 3px;
}

/* ─────────────────────────────────────────────────────── en-tête ─────────── */

/* LE BANDEAU DE MARQUE — deux éléments empilés : une barre, puis un filet.
   C'est ce qui manquait à la page : sans lui, le nom flottait sur le même fond
   que tout le reste et la page « faisait cheap ». Une barre a une surface, un
   bord et une hauteur — elle affirme qu'on est chez quelqu'un. */

.mz-entete {
  /* Pleine largeur, à toutes les tailles. Une barre qui s'arrête avant le bord
     de l'écran n'est plus une barre, c'est un encart. Ce qui se centre au-delà
     de 640, c'est son CONTENU. */
  background: var(--brand-sunken);
}

.mz-entete__barre {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  min-height: 62px;
  padding: 0 18px;
  border-bottom: 1px solid rgba(231, 226, 214, 0.14);
}

/* Le filet sous la barre : une rangée de cases avec UNE CASE VIDE au milieu.
   ⚠️ Le segment en os n'est pas un accident de dégradé — c'est un trou
   délibéré, le même geste que la grille du héros, où le chemin n'existe que
   parce qu'il manque des cases ailleurs. Ne pas le « lisser ». */
.mz-filet {
  height: 3px;
  background: linear-gradient(
    90deg,
    var(--brand-verdigris) 0 44%,
    var(--brand-bone) 44% 56%,
    var(--brand-verdigris) 56%
  );
}

/* Le logotype : la case, puis le nom. */
.mz-logo {
  display: flex;
  align-items: center;
  gap: 11px;
  margin: 0;
  text-decoration: none;
}

.mz-logo:hover .mz-logo__nom {
  color: #fff;
}

/* ⚠️ LA CASE EST FAITE DE DEUX BOÎTES IMBRIQUÉES, PAS D'UN SVG NI D'UNE POLICE
   D'ICÔNES. Un cadre de 15 et un carré plein en retrait de 3 : une case et son
   contenu, le motif dont toute la collection est faite. Deux `<span>` coûtent
   zéro requête, se recolorent avec le token et restent nets à toutes les
   densités d'écran. */
.mz-glyphe {
  flex: none;
  display: block;
  width: 15px;
  height: 15px;
  border: 2px solid var(--brand-verdigris);
  position: relative;
}

.mz-glyphe > span {
  position: absolute;
  inset: 3px;
  background: var(--brand-verdigris);
}

/* ⚠️ LE NOM RESTE LA CHOSE LA PLUS SOBRE DE LA PAGE — c'est un logotype, pas un
   titre. Ni dégradé, ni ombre, ni contour, ni animation, jamais. Tout ce qu'il
   a le droit d'être, c'est droit, blanc et espacé. */
.mz-logo__nom {
  font-family: var(--font-marque);
  font-weight: 700;
  font-size: 20px;
  line-height: 1;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #fff;
}

/* Le sélecteur de langue : un `<select>` natif rendu transparent PAR-DESSUS
   l'étiquette. Pas de panneau maison — le natif tient le clavier, le lecteur
   d'écran et la roulette iOS sans une ligne de JavaScript. */
.mz-langue {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  padding: 0 9px;
  border: 1px solid var(--hairline-pill);
  border-radius: var(--rayon);
  font-family: var(--font-corps);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--brand-bone);
  cursor: pointer;
  transition: border-color var(--transition-couleur);
}

.mz-langue:hover,
.mz-langue:focus-within {
  border-color: var(--brand-bone);
}

.mz-langue .mz-chevron {
  font-size: 9px;
  color: var(--ink-muted);
}

/* Le repli sans script : deux liens, à la place du sélecteur. */
.mz-langue-noscript {
  display: inline-flex;
  gap: 6px;
  margin-left: 8px;
  font-size: 11px;
  letter-spacing: 0.06em;
}

.mz-langue select {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  border: 0;
  cursor: pointer;
  font: inherit;
}

/* Le corps. ⚠️ LA CHAÎNE DE FLEX DOIT ÊTRE CONTINUE de `body` jusqu'à
   `.mz-scene` : c'est elle qui donne au livre toute la hauteur restante sur un
   écran de téléphone. Un maillon qui n'est pas `display:flex` et la scène
   retombe sur sa `min-height`, laissant un blanc sous le pied de page. */
.mz-corps {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.mz-colonne-livre {
  flex: 1;
  display: flex;
  flex-direction: column;
}

/* ─────────────────────────────────────────────── accroche surlignée ─────── */

/* ⚠️ `isolation: isolate` N'EST PAS DÉCORATIF. Le surligneur est un `::before`
   en `z-index: -1` ; sans contexte d'empilement local, ce -1 le fait passer
   derrière le FOND DU `body`, et il disparaît purement et simplement — le titre
   reste alors en encre sombre sur l'anthracite, illisible, sans la moindre
   erreur nulle part. Attrapé à la première capture. */
/* ⚠️ 22 EN HAUT, PAS 30, ET C'EST MESURÉ. Le bandeau posé le 10/09 a ajouté 65 px
   au-dessus de tout : avec 30 ici, l'accroche FRANÇAISE — une ligne de plus que
   l'anglaise — poussait le bouton 4 px sous le pli d'un écran de 812, qui est le
   contexte d'usage du projet. Quatre pixels ne se voient pas sur une maquette et
   coupent le premier appel à l'action sur un vrai téléphone. */
.mz-accroche-bloc {
  position: relative;
  isolation: isolate;
  padding: 22px var(--gouttiere) 0;
}

.mz-accroche {
  position: relative;
  display: inline-block;
  margin: 0;
  font-family: var(--font-marque);
  font-weight: 700;
  font-size: 28px;
  line-height: 1.18;
  color: var(--ink-on-verdigris);
  text-wrap: balance;
}

/* Le surligneur : une bande posée DERRIÈRE le texte, légèrement de travers et
   mordue sur les bords — un coup de marqueur, pas un rectangle.
   ⚠️ LES QUATRE RETRAITS NÉGATIFS SONT MESURÉS. Ils existent pour que les
   hampes des DEUX lignes passent au-dessus du bord de la bande y compris là où
   le `clip-path` mord à gauche. Les resserrer fait ressortir un « d » ou un
   « t » hors du vert. */
.mz-accroche::before {
  content: '';
  position: absolute;
  top: -14px;
  right: -12px;
  bottom: -10px;
  left: -10px;
  z-index: -1;
  background: var(--brand-verdigris);
  transform: rotate(-1deg);
  clip-path: polygon(0 5%, 100% 0, 99% 94%, 1% 100%);
}

.mz-intro {
  margin: 13px 0 0;
  max-width: 46ch;
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink-body);
  text-wrap: pretty;
}

/* ──────────────────────────────────────────── la scène du livre ─────────── */

/* ⚠️ LA HAUTEUR MINIMALE N'EST PAS UN RÉGLAGE ESTHÉTIQUE — c'est elle qui rend
   le tracé visible. Le cadre du tracé fait 300 × 250 et il est en `meet` : pour
   qu'il occupe toute la LARGEUR de la scène, il faut hauteur ≥ largeur × 250/300,
   soit 312 à 375 px d'écran. En dessous, `meet` met à l'échelle sur la hauteur,
   le dessin se rétrécit horizontalement, et le chemin repasse derrière la
   couverture. La marge est prise à 340. */
.mz-scene {
  position: relative;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 340px;
  margin-top: 14px;
  overflow: hidden;
  /* Toute la scène est la cible du clic — le livre est un objet qu'on ouvre,
     pas une image à côté d'un lien. */
}

.mz-scene-lien {
  flex: 1;
  display: flex;
  flex-direction: column;
  width: 100%;
  text-decoration: none;
}

/* a. Le halo. La seule courbe du système, et c'est un flou. */
.mz-halo {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 240px;
  height: 240px;
  margin: -120px 0 0 -120px;
  border-radius: 50%;
  background: var(--brand-verdigris);
  filter: blur(74px);
  opacity: 0.14;
  animation: mzHalo 6s ease-in-out infinite;
  pointer-events: none;
}

/* b. La grille en brouillard de guerre.
   La grille n'est peinte que là où le tracé passe, et se referme derrière lui.
   Le masque est FAIT DU MÊME CHEMIN, épaissi à 62 et flouté, sur la MÊME
   animation — d'où la synchronisation parfaite sans une ligne de script.

   ⚠️ LE FONDU DES BORDS EST DANS LE SVG, PLUS ICI, et ce n'est pas un
   déplacement cosmétique. Posé en CSS sur cet élément, il s'appliquait au
   `<svg>` ENTIER — donc au tracé autant qu'à la grille — et éteignait le trait
   à ses deux extrémités, c'est-à-dire aux seuls endroits où il sort de derrière
   la couverture. Il vit maintenant dans un masque SVG qui n'enveloppe que la
   grille (`mzFondu`, voir page.mjs). */
.mz-grille {
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(100%, var(--mz-grille-max, 460px));
  height: 100%;
  transform: translate(-50%, -50%);
  pointer-events: none;
}

/* Le tracé et la grille qu'il révèle courent sur la MÊME animation : le masque
   est fait du même chemin, épaissi et flouté.

   ⚠️ LA RÈGLE EST ICI, ET ELLE EST VITALE — voir page.mjs. En attribut `style`
   elle serait imbattable et le bloc « mouvement réduit » ne pourrait pas
   l'arrêter. Et sans elle, RIEN NE S'AFFICHE : le `stroke-dashoffset` de départ
   vaut toute la course, donc le trait n'est pas dessiné — et la grille, qui est
   révélée par ce même trait, disparaît avec lui. Supprimée par accident en
   réécrivant ce bloc le 10/09 : les deux se sont éteints d'un coup, sans erreur. */
.mz-grille [data-mz-trace] {
  animation: mzTrace 9s ease-in-out infinite;
}

/* c. Le livre — un OBJET POSÉ, pas une image flottante.
   Deux choses l'ancrent : l'ombre au sol sous lui, et l'ombre portée qui suit sa
   silhouette découpée. Sans elles il flotte au centre d'un rectangle sombre,
   sans poids ni sol — ce que Fabien avait relevé sur la première maquette. */

/* ⚠️ 55 % DE LA LARGEUR, ET C'EST MESURÉ SUR LA MAQUETTE, PAS ESTIMÉ. Dans
   `Mazetery - acceuil.png`, le livre occupe x 83 → 288 sur un cadre de 375 :
   205 px, soit 55 %. Il a été essayé à 78 puis à 68 — aux deux, la couverture
   recouvrait le tracé d'un bord à l'autre et il ne restait qu'un moignon de
   magenta en dessous. Le tracé, lui, traverse 80 % de la largeur : c'est
   l'écart entre les deux qui laisse VOIR le chemin passer derrière le livre.
   **Élargir le livre, c'est éteindre l'animation.**

   ⚠️ ET LA TROISIÈME BORNE EST EN `vh`. Le mockup fait 640 × 800 : sa hauteur
   vaut 1,25 fois sa largeur. Borné par la seule largeur, il pousse le bouton —
   le premier appel à l'action de la page — sous la ligne de flottaison d'un
   écran de 812. */
.mz-livre {
  position: relative;
  width: min(55%, 230px, 30vh);
  margin: 0 auto;
  animation: mzFlotte 9s ease-in-out infinite;
  will-change: transform;
}

.mz-livre img {
  display: block;
  width: 100%;
  height: auto;
  /* `drop-shadow` suit la découpe alpha du PNG — le contour du livre — là où
     `box-shadow` dessinerait l'ombre du rectangle de l'image. Deux passes :
     une courte et dense pour le contact, une longue et douce pour la portée. */
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.55)) drop-shadow(10px 26px 34px rgba(0, 0, 0, 0.55));
  transition: transform var(--transition-base);
}

/* L'ombre au sol : ce qui dit que le livre POSE. Elle est sous lui, écrasée,
   et elle respire avec le flottement — plus large et plus pâle quand il monte. */
.mz-ombre-sol {
  position: absolute;
  left: 8%;
  right: 4%;
  bottom: -14px;
  height: 26px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  filter: blur(14px);
  animation: mzOmbre 9s ease-in-out infinite;
  pointer-events: none;
}

.mz-scene-lien:hover .mz-livre img {
  transform: translateY(-4px);
}

/* ⚠️ IL N'Y A PLUS DE BANDEAU DÉCHIRÉ SOUS LA SCÈNE — retiré par Fabien le
   10/09, et `public/bandeau-marque.svg` n'est plus référencé par personne. Il
   portait deux rôles : structurer la page, et donner un sol au livre. Le second
   revient entièrement à l'ombre au sol, qui suffit. Ne pas le reproposer — c'est
   la même décision que sur le site du livre, où la déchirure ne sépare plus rien
   nulle part depuis le 09/09. */

/* ─────────────────────────────────────────────── le bloc du titre ───────── */

/* ⚠️ PLUS DE SURFACE ENFONCÉE SOUS LE TITRE. Elle existait pour donner un pied
   au bandeau déchiré ; le bandeau retiré, il ne restait qu'un rectangle plus
   sombre flottant dans la page — très visible au bureau, où il s'étend sur toute
   la colonne alors que son texte est calé à gauche. La scène finit, le bloc
   commence : ça se lit sans changer de fond. */
.mz-titre-bloc {
  padding: 12px var(--gouttiere) 0;
}

.mz-eyebrow {
  margin: 0;
  font-size: 13px;
  color: var(--ink-muted);
}

.mz-titre {
  margin: 2px 0 0;
  font-family: var(--font-marque);
  font-weight: 600;
  font-size: 21px;
  line-height: 1.15;
  color: #fff;
}

.mz-fiche {
  margin: 6px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-muted);
}

.mz-relance {
  margin: 8px 0 0;
  font-size: 14px;
  color: var(--ink-body);
}

/* Le bouton. Verdigris plein — c'est l'action de la marque, pas celle du livre. */
/* ⚠️ PLEINE LARGEUR, LIBELLÉ CENTRÉ, À TOUTES LES TAILLES. Mesuré sur la
   maquette : le bouton y occupe x 24 → 351 d'un cadre de 375, c'est-à-dire toute
   la largeur moins les gouttières. Il a été essayé en `width: fit-content` calé
   à gauche au-delà de 640 px : le livre restant centré, le bouton se retrouvait
   décalé sous lui et la page paraissait de travers. */
.mz-action {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: var(--cible-bouton);
  margin: 12px 0 0;
  padding: 0 16px;
  background: var(--brand-verdigris);
  color: var(--ink-on-verdigris);
  border-radius: var(--rayon);
  font-family: var(--font-marque);
  font-weight: 600;
  font-size: 17px;
  letter-spacing: 0.02em;
  text-decoration: none;
  transition: background var(--transition-couleur);
}

.mz-action:hover {
  background: var(--brand-verdigris-hover);
  color: var(--ink-on-verdigris);
}

.mz-action .mz-fleche {
  animation: mzClignote 1.6s steps(1) infinite;
}

/* ⚠️ IL N'Y A PLUS DE LIEN « BLOQUÉ ? » sous le bouton — retiré par Fabien le
   10/09, et la maquette l'avait déjà retiré de l'écran 00. Ne pas le
   reproposer : la seule sortie de la page est le bouton « Voir le livre », et
   l'aiguillage `/help/` est à un clic de là. */

/* ────────────────────────────────────────────────────────── pied ────────── */

.mz-pied {
  margin: 14px var(--gouttiere) 0;
  padding: 16px 0 22px;
  border-top: 1px solid var(--hairline-faint);
  font-size: 12px;
  color: var(--ink-muted);
}

/* ⚠️ LES LIENS LÉGAUX SONT DANS LE PIED DES DEUX SITES, ET ILS POINTENT ICI.
   Ce sont des documents de l'ÉDITEUR : le site du livre y renvoie, il n'en a pas
   de copie. Deux copies divergeraient au premier changement, et deux politiques
   de confidentialité qui ne disent pas la même chose sont pires qu'une seule. */
.mz-pied__liens {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
}

.mz-pied__liens a {
  color: var(--ink-muted);
  text-decoration-color: rgba(140, 154, 160, 0.4);
  /* La cible tactile, pas la taille du texte : 12 px de haut ne se visent pas. */
  padding: 6px 0;
}

.mz-pied__liens a:hover {
  color: var(--brand-bone);
}

.mz-pied__mention {
  margin: 8px 0 0;
}

/* ───────────────────────────── le catalogue à plusieurs titres (00b) ─────── */

/* ⚠️ CE BLOC N'EST PAS DU CODE MORT. Il est ce qui rend vraie la phrase « la
   page accueillera trois ou quatre titres dans deux ans ». `construire.mjs`
   bascule dessus dès que `TITRES` en contient plus d'un — en-tête, accroche,
   pied et tokens ne bougent pas, seule la scène devient une liste. Le vérifier
   coûte une ligne : ajouter un titre au catalogue et reconstruire. */

.mz-catalogue {
  flex: 1;
  display: grid;
  /* Une liste, donc un `<ul>` — un lecteur d'écran annonce « trois titres ». Les
     puces, elles, n'ont rien à faire dans une grille de couvertures. */
  margin: 0;
  list-style: none;
  gap: 14px;
  padding: 14px var(--gouttiere) 0;
  grid-template-columns: 1fr;
  align-content: start;
}

.mz-ligne {
  display: flex;
  gap: 16px;
  padding: 14px;
  border: 1px solid var(--hairline);
  text-decoration: none;
  color: inherit;
  transition:
    border-color var(--transition-couleur),
    background var(--transition-couleur);
}

.mz-ligne:hover {
  border-color: rgba(79, 184, 158, 0.55);
  background: rgba(79, 184, 158, 0.08);
  color: inherit;
}

.mz-vignette {
  flex: none;
  width: 78px;
  height: 104px;
  display: grid;
  place-items: center;
  background: var(--brand-sunken);
  border: 1px solid rgba(231, 226, 214, 0.18);
  overflow: hidden;
}

.mz-vignette img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Un titre pas encore paru : un carré vide dans SA couleur, pas une fausse
   couverture. Une vignette inventée pour un livre qui n'existe pas se retrouve
   en capture d'écran ailleurs, et devient une promesse. */
.mz-vignette-vide {
  width: 26px;
  height: 26px;
  border: 2px solid var(--mz-accent, var(--ink-muted));
}

.mz-ligne-texte {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.mz-ligne-titre {
  font-family: var(--font-marque);
  font-weight: 600;
  font-size: 18px;
  line-height: 1.15;
  color: #fff;
}

.mz-ligne-meta {
  font-size: 12px;
  color: var(--ink-muted);
}

/* L'état d'un titre PARU est une action — donc verdigris, comme toute action de
   la marque. L'état d'un titre à paraître est une information, et il porte la
   couleur de ce titre-là. */
.mz-ligne-etat {
  font-size: 12px;
  color: var(--brand-verdigris);
}

.mz-ligne-etat[data-etat='a-paraitre'] {
  color: var(--mz-accent, var(--ink-muted));
}

/* ──────────────────────────────────────────────────── mouvements ────────── */

@keyframes mzHalo {
  0%,
  100% {
    opacity: 0.14;
  }
  50% {
    opacity: 0.26;
  }
}

/* Le livre respire. ⚠️ PAS DE ROTATION 3D : le mockup est un rendu photo, déjà
   vu sous un angle. Le refaire tourner en CSS ferait tourner une perspective
   dans une autre, et le livre se tordrait. Une translation et un souffle de
   rotation dans le plan, rien de plus. */
@keyframes mzFlotte {
  0%,
  100% {
    transform: translateY(0) rotate(-0.4deg);
  }
  50% {
    transform: translateY(-12px) rotate(0.4deg);
  }
}

/* L'ombre au sol contredit le livre : elle s'élargit et pâlit quand il monte. */
@keyframes mzOmbre {
  0%,
  100% {
    transform: scaleX(1);
    opacity: 0.55;
  }
  50% {
    transform: scaleX(1.1);
    opacity: 0.32;
  }
}

/* Le tracé avance de case en case, se repose entier, puis S'EFFACE — et
   l'effacement est une phase à part entière, pas une disparition.

       0 → 48 %   il se dessine        (4,3 s)
      48 → 80 %   il reste entier      (2,9 s)
      80 → 100 %  il s'efface          (1,8 s)

   ⚠️ L'EFFACEMENT PART DU DÉBUT DU TRACÉ ET FINIT PAR LA FIN — la queue rattrape
   la tête, comme un chemin qu'on remonte. Ce n'est pas un réglage à part : c'est
   ce que fait un `stroke-dashoffset` qui continue de DÉCROÎTRE après zéro.
   L'inverser — remonter de 0 vers la course — ferait reculer la TÊTE, donc
   défaire le chemin à l'envers, et le trait rentrerait d'où il vient.

   ⚠️ ET IL EST NETTEMENT PLUS VIF QUE LA MONTÉE, SANS ÊTRE UN CLIGNOTEMENT. Deux
   réglages ont été écartés par Fabien avant celui-ci : 12 % du cycle — une
   seconde pour 464 unités — ne se lisait pas comme un effacement, et 32 % se
   lisait comme une seconde montée à l'envers. À 20 % (1,8 s contre 4,3 s à la
   montée), le trait se retire vite mais on voit par où. Le temps rendu par
   l'effacement est donné au PALIER, qui passe de 1,8 à 2,9 s : c'est le moment
   où le chemin est entier, donc le seul où il dit quelque chose.

   ⚠️ LA FIN PASSE PAR `--mz-course-fin`, JAMAIS PAR UN `calc()`. Un `calc()`
   bâti sur une propriété personnalisée non typée reste un jeton non résolu à la
   valeur calculée : le navigateur ne sait pas l'interpoler et bascule en pas à
   pas. Mesuré — pendant toute la phase d'effacement la valeur calculée restait
   la chaîne « calc(-470px) », et le tracé ne s'effaçait pas : il DISPARAISSAIT
   d'un coup à la fin du cycle. Relevé à l'œil par Fabien, confirmé au
   `getComputedStyle`.

   ⚠️ LA COURSE EST UNE VARIABLE, PAS UN NOMBRE. Elle vaut la longueur du chemin,
   et le chemin a déjà changé une fois : écrite en dur dans les keyframes, elle
   se serait désynchronisée du `stroke-dasharray` sans que rien ne le dise — le
   tracé serait simplement parti trop tôt ou resté planté. `page.mjs` la pose sur
   l'élément, à côté du `dasharray` qu'elle doit suivre. */
@keyframes mzTrace {
  0% {
    stroke-dashoffset: var(--mz-course);
  }
  48% {
    stroke-dashoffset: 0;
  }
  80% {
    stroke-dashoffset: 0;
  }
  100% {
    stroke-dashoffset: var(--mz-course-fin);
  }
}

@keyframes mzClignote {
  0%,
  44% {
    opacity: 0;
  }
  50%,
  94% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

/* ⚠️ MOUVEMENT RÉDUIT : ON NE COUPE PAS, ON FIGE À L'ÉTAT UTILE. Un tracé figé
   à l'offset de départ ne montrerait RIEN — ni la grille, ni le chemin. On le
   fige donc terminé, grille révélée, livre à mi-hauteur. */
@media (prefers-reduced-motion: reduce) {
  .mz-halo,
  .mz-livre,
  .mz-ombre-sol,
  .mz-action .mz-fleche {
    animation: none;
  }

  .mz-halo {
    opacity: 0.2;
  }

  .mz-livre {
    transform: translateY(-6px);
  }

  .mz-scene-lien:hover .mz-livre img {
    transform: none;
  }

  .mz-grille [data-mz-trace] {
    animation: none;
    stroke-dashoffset: 0;
  }
}

/* ────────────────────────────────────────────────────── au-delà de 640 ──── */

/* ⚠️ UNE SEULE COLONNE, À TOUTES LES LARGEURS. Une mise en page à deux colonnes
   a été construite puis retirée par Fabien le 10/09 : elle mettait le livre à
   DROITE de l'accroche, alors que l'ordre de lecture de la maquette est
   l'inverse — on lit « …jusqu'à trouver la solution », PUIS on voit le livre
   apparaître dessous. Le mockup n'illustre pas le texte à côté de lui, il en est
   la chute. À large, la page ne se répartit donc pas : elle se centre et
   grandit.

   ⚠️ RIEN N'EST CALÉ SUR UNE LONGUEUR DE CHAÎNE : le français est plus long que
   l'anglais de près de 30 %, et l'espagnol viendra. Chaque bloc grandit en
   hauteur, aucun ne tronque. */
@media (min-width: 640px) {
  :root {
    --gouttiere: 40px;
    --gouttiere-entete: 40px;
    /* La grille déborde plus largement du livre : bornée à 460 elle ne dépassait
       que de quarante pixels de chaque côté, donc elle disparaissait derrière la
       couverture au lieu de l'entourer. */
    --mz-grille-max: 620px;
  }

  /* La colonne a une largeur de lecture, et elle est centrée. Sans borne, la
     ligne de l'intro atteindrait cent caractères sur un écran large — illisible,
     et l'accroche surlignée deviendrait une banderole. */
  .mz-corps,
  .mz-entete__barre,
  .mz-pied {
    width: 100%;
    max-width: 760px;
    margin-left: auto;
    margin-right: auto;
  }

  /* ⚠️ LA BARRE RESTE PLEINE LARGEUR, SEUL SON CONTENU SE CENTRE. La borner
     elle-même la transformerait en encart posé au milieu d'une bande vide. Le
     bord du bas et le filet doivent aller d'un bord de l'écran à l'autre. */
  .mz-entete {
    max-width: none;
  }

  /* ⚠️ 36 ET PAS 40, ET C'EST LE FRANÇAIS QUI DÉCIDE. À 40, l'accroche anglaise
     tient sur une ligne dans la colonne de 760 et la française sur deux — cette
     ligne de plus poussait « Voir le livre » sous le pli d'un écran de 800.
     C'est la langue la plus longue qui fixe la taille, comme pour la barre du
     site du livre. */
  .mz-accroche {
    font-size: 36px;
  }

  .mz-intro {
    font-size: 15px;
    line-height: 1.6;
  }

  /* ⚠️ LA HAUTEUR MINIMALE SUIT L'ÉCRAN, ELLE AUSSI. Écrite à 360 en dur, elle
     rouvrait sur un portable court (1024 × 640) exactement le défaut que la
     borne en `vh` du livre venait de fermer : la scène gardait sa hauteur de
     bureau et repoussait le bouton dehors. Une largeur d'écran ne dit rien de sa
     hauteur. */
  .mz-scene {
    min-height: min(420px, 46vh);
  }

  /* ⚠️ LA BORNE EN `vh` COMPTE ENCORE PLUS QU'AU TÉLÉPHONE. En une seule colonne,
     le livre est AU-DESSUS du bouton à toutes les largeurs : c'est lui, et lui
     seul, qui décide si « Voir le livre » tombe hors de l'écran. Un écran
     de bureau est plus large mais pas plus haut — 800 px de haut est courant, et
     40 vh y valent 320. */
  .mz-livre {
    width: min(42%, 300px, 32vh);
  }

  .mz-titre {
    font-size: 22px;
  }

  /* Les lignes du catalogue deviennent une grille dès qu'elles tiennent à deux. */
  .mz-catalogue {
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  }
}

@media (min-width: 1040px) {
  .mz-accroche {
    font-size: 48px;
  }
}

/* ─────────────────────────────────────── les documents de l'éditeur ─────── */

/* Mentions légales, confidentialité, contact. Des pages qu'on vient LIRE : pas
   de héros, pas d'animation, pas de bouton. La seule chose qui compte est la
   longueur de ligne et l'espace entre les blocs.

   ⚠️ CE SONT DES DOCUMENTS JURIDIQUES. Ne pas y « ajouter du rythme » : un
   intertitre décoratif, un encadré, une phrase de liaison, et le texte ne dit
   plus exactement ce que l'éditeur s'engage à faire. */

.mz-doc {
  flex: 1;
  /* 62 caractères : la longueur de ligne au-delà de laquelle l'œil perd le
     début de la suivante. Un document légal se lit mal ; il n'a pas besoin
     d'être long à parcourir en plus. */
  max-width: 62ch;
  margin: 0 auto;
  padding: 30px var(--gouttiere) 8px;
  width: 100%;
}

.mz-doc__titre {
  margin: 0 0 6px;
  font-family: var(--font-marque);
  font-weight: 700;
  font-size: 28px;
  line-height: 1.18;
  color: #fff;
  text-wrap: balance;
}

.mz-doc h2 {
  margin: 30px 0 10px;
  font-family: var(--font-marque);
  font-weight: 600;
  font-size: 18px;
  line-height: 1.2;
  color: #fff;
}

.mz-doc p {
  margin: 0 0 12px;
  line-height: 1.65;
  color: var(--ink-body);
  text-wrap: pretty;
}

.mz-doc strong {
  color: var(--brand-bone);
  font-weight: 600;
}

.mz-doc ul {
  margin: 0 0 12px;
  padding-left: 18px;
}

.mz-doc li {
  margin-bottom: 8px;
  line-height: 1.65;
  color: var(--ink-body);
}

/* La date d'entrée en vigueur : une note, pas un titre. */
.mz-doc__vigueur {
  margin-bottom: 22px;
  color: var(--ink-muted);
  font-size: 13px;
}

/* ⚠️ UN BLOC D'ADRESSE GARDE SES RETOURS À LA LIGNE. Raison sociale, siège,
   SIREN, TVA : c'est ce qu'on vient chercher ligne par ligne, et le recoller en
   paragraphe le rendrait illisible exactement là où il doit être lisible. */
.mz-doc__adresse {
  line-height: 1.75;
}

.mz-doc__avant {
  margin-bottom: 4px;
  color: var(--ink-muted);
}

/* L'adresse de contact est le sujet de sa page : elle a droit à la taille. */
.mz-doc__mail {
  margin-bottom: 22px;
  font-size: 19px;
}

.mz-doc__mail a {
  color: var(--brand-verdigris);
}

@media (min-width: 640px) {
  .mz-doc {
    padding-top: 40px;
  }

  .mz-doc__titre {
    font-size: 34px;
  }
}
