/* ANAELA, habillage de l'application.
 *
 * Deux typographies coexistent, et il ne faut jamais les confondre :
 *
 *   Abril Fatface + Jost              =  la marque de l'APPLICATION
 *   Comfortaa + Nunito              =  la typographie du LIVRE imprime
 *
 * Les secondes ne servent QUE dans l'apercu de page : elles sont exactement
 * celles du PDF, servies depuis moteur/fonts. Rien de ce fichier n'a le droit
 * de les toucher, changer la marque ne doit jamais changer le livre.
 *
 * Aucune cote du gabarit imprime n'apparait ici : elles arrivent de
 * GET /api/gabarit. Ce qui suit n'est que l'habillage de l'ecran.
 *
 * LA CHARTE ANAELA. Les couleurs ne sont plus ecrites ici : elles viennent de
 * /jetons.css, repris du projet de design. La charte est CARREE, aucun rayon,
 * aucune ombre : la separation se fait au filet et a l'aplat gris. Toute
 * valeur de `border-radius` ou de `box-shadow` ajoutee ici la contredit.
 */

/* --- marque de l'application, servie en local : aucun CDN --- */
/* Elles sont declarees dans /jetons.css, charge avant cette feuille.
   Bricolage et Gabarito ne servent plus : les fichiers restent en place, la
   charte ne les appelle plus. */

/* --- typographie du livre, celle qui imprime --- */
@font-face { font-family: Nunito; src: url("/polices/Nunito-400.ttf"); font-weight: 400; font-display: swap; }
@font-face { font-family: Nunito; src: url("/polices/Nunito-700.ttf"); font-weight: 700; font-display: swap; }
@font-face { font-family: Nunito; src: url("/polices/Nunito-800.ttf"); font-weight: 800; font-display: swap; }
@font-face { font-family: Comfortaa; src: url("/polices/Comfortaa-700.ttf"); font-weight: 700; font-display: swap; }

/* Les noms de l'application, les valeurs de la charte.
 *
 * La palette « Prune & peche » avait trois couleurs porteuses de sens : g1
 * l'action, g2 l'alerte, g3 le fait. La charte ANAELA n'en a aucune, elle
 * est a l'encre et aux gris, et distingue par le POIDS et le FILET, pas par
 * la teinte. Les trois se rabattent donc, et ce qui les separait se lit
 * desormais a l'encre pour ce qui est acquis, au gris pour ce qui attend.
 *
 * Les noms ne changent pas : renommer quinze variables dans 4 000 lignes de
 * JavaScript et 560 de CSS pour le meme resultat, c'est du risque sans gain.
 */
:root {
  --g0: var(--surface-page);      /* le fond de l'ecran */
  --g1: var(--ink);               /* l'action */
  --g2: var(--ink);               /* ce qui reclame, au poids, plus a la teinte */
  --g3: var(--ink);               /* ce qui est fait */
  --g1t: var(--grey-50); --g2t: var(--grey-50); --g3t: var(--grey-50);
  --encre: var(--ink);
  --texte: var(--grey-600);
  --libelle: var(--grey-600);
  --discret: var(--grey-400);
  --desactive: var(--grey-300);
  --bord: var(--grey-200);
  --champ: var(--grey-50);
}

/* --------------------------------------------------------------------------
 * DEUX CHOSES QU'ON CONFONDAIT : L'ERREUR ET LE MANQUE
 *
 * Elles partageaient une couleur. La maquette « Anaela États » les separe, et
 * c'est la seule regle de tout le systeme qui ait une couleur :
 *
 *   ERREUR   terracotta, celui des couvertures, et il ne sert a rien d'autre.
 *            Un geste a echoue, ou une ligne est illisible : quelque chose EST
 *            en faute, et tant que ce n'est pas repare, on n'avance pas.
 *
 *   MANQUE   gris. « Il manque la photo », « recette jamais relue » : rien
 *            n'est en faute, il manque seulement quelque chose. Le peindre en
 *            rouge accuse quelqu'un qui n'a rien fait de mal, et use la
 *            couleur qui doit rester rare pour rester lue.
 *
 * Ecrire une des deux valeurs ailleurs qu'ici, c'est perdre la distinction au
 * premier copier-coller.
 * -------------------------------------------------------------------------- */
:root {
  --alerte: #C0563D;        /* le terracotta, et rien d'autre ne le porte */
  --alerte-fond: #FBF4F2;   /* le fond d'une LIGNE fautive, jamais d'un bloc */
  --alerte-trait: #C0563D;  /* la regle sous un champ refuse, 1,5 px */
  --incomplet: var(--grey-400);
}

* { box-sizing: border-box; }

/* `hidden` est un `display:none` de la feuille du NAVIGATEUR : n'importe quel
   `display` d'auteur le bat, sans avertissement. Depuis que l'encart de
   dépassement est en `flex`, l'attribut ne masquait plus rien, le message
   « Le texte dépasse » s'affichait sur tous les blocs, y compris ceux qui
   tiennent largement. Cette ligne rend l'attribut plus fort que la mise en
   forme, pour tous les composants, y compris ceux qu'on écrira après. */
[hidden] { display: none !important; }
html, body { height: 100%; }
body {
  margin: 0; background: var(--grey-200); color: var(--encre);
  font-family: var(--font-text); font-size: 16px;
  -webkit-font-smoothing: antialiased;
}
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; padding: 0; }
textarea { resize: none; }

@keyframes gspin { to { transform: rotate(360deg); } }
@keyframes gpulse { 0%,100% { opacity: .35 } 50% { opacity: 1 } }
@keyframes ganneau { 0% { transform: scale(1); opacity: .35 }
  70%, 100% { transform: scale(1.9); opacity: 0 } }
@keyframes gwave { 0%,100% { transform: scaleY(.3) } 50% { transform: scaleY(1) } }

/* L'application vit a la largeur d'un telephone : la maquette est mobile.
   Au-dela on centre plutot que d'etirer, une ligne de 900 px ne se lit pas. */
.appli {
  max-width: 430px; margin: 0 auto; min-height: 100%;
  background: var(--g0); display: flex; flex-direction: column;
}
.corps { flex: 1; padding: 0 22px 30px; }

/* ---------- en-tete ---------- */
/* L'en-tete de la charte : blanche, collante, separee par un filet. Le
   bandeau prune arrondi disparait, c'etait la couleur qui portait la marque,
   c'est desormais la typographie. */
.tete { position: sticky; top: 0; z-index: 30;
  background: var(--surface-header); backdrop-filter: var(--blur-header);
  -webkit-backdrop-filter: var(--blur-header);
  color: var(--encre); border-bottom: 1px solid var(--bord);
  padding: 14px 16px; margin-bottom: 18px; }
.tete.compacte { padding: 12px 16px; }
.tete-ligne { display: flex; align-items: center; gap: 12px; min-height: 34px; }
.marque { font-family: var(--font-display); font-weight: 400; font-size: 20px;
  letter-spacing: var(--wordmark-track); text-transform: uppercase; }
.tete h1 { font-family: var(--font-display); font-weight: 400; font-size: 30px;
  line-height: 1.05; letter-spacing: 0; text-transform: uppercase; margin: 10px 0 0; }
.tete h2 { font-family: var(--font-display); font-weight: 400; font-size: 17px;
  line-height: 1.1; letter-spacing: 0; text-transform: uppercase; margin: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pousse { flex: 1; }
.avatar { width: 30px; height: 30px; background: var(--grey-100);
  display: grid; place-items: center; font-weight: 400; font-size: 14px;
  letter-spacing: .06em; color: var(--libelle); flex: none; }
/* Le chevron de retour est un bouton borde, pas un caractere pose sur un
   bandeau : sur fond blanc, un « ‹ » seul ne se voyait plus. */
.retour { width: 28px; height: 28px; flex: none; border: 1px solid var(--bord);
  color: var(--libelle); font-size: 16px; font-weight: 300; line-height: 1;
  display: grid; place-items: center; padding: 0; margin: 0; }
.retour:hover, .retour:focus { border-color: var(--ink); color: var(--ink); }
.pilule { background: transparent; color: var(--libelle);
  border: 1px solid var(--bord); font-weight: 400; font-size: 14px;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  padding: 8px 12px; flex: none; white-space: nowrap; }
.pilule:hover, .pilule:focus { border-color: var(--ink); color: var(--ink); }

.compteurs { display: flex; margin-top: 14px; }
.compteur { flex: 1; padding-right: 12px; }
.compteur + .compteur { border-left: 1px solid var(--bord); padding-left: 14px; }
.compteur b { font-family: var(--font-display); font-weight: 400; font-size: 22px; display: block; }
.compteur span { font-size: 14px; letter-spacing: var(--label-nav-track);
  text-transform: uppercase; color: var(--discret); }
.compteur.alerte b { color: var(--incomplet); }

/* ---------- boutons ---------- */
.b { font-size: var(--label-cta-size); font-weight: 400; padding: 15px;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  text-align: center; display: block;
  transition: background var(--transition-hover), color var(--transition-hover); }
.b-primaire { background: var(--action-fill); color: var(--text-on-dark); }
.b-primaire:hover, .b-primaire:focus { background: var(--action-fill-hover); color: var(--text-on-dark); }
.b-contour { background: #fff; color: var(--ink); border: 1px solid var(--ink); }
.b-contour:hover, .b-contour:focus { background: var(--ink); color: var(--text-on-dark); }
.b-accent { background: var(--action-fill); color: var(--text-on-dark); }
/* Un bouton qui refuse ne se remplit pas de gris : il se VIDE. Rempli, il a
   l'air d'attendre un chargement ; vide et borde, il a l'air de manquer
   quelque chose, ce qui est le cas, et ce que la phrase au-dessus dit. */
.b[disabled] { background: #fff; color: var(--incomplet);
  border: 1px solid var(--desactive); cursor: not-allowed; }
.b-petit { font-size: 14px; padding: 10px 14px; }
/* Un lien de l'atelier : en capitales espacees, souligne d'un filet, la
   charte n'a pas de couleur pour distinguer un lien. */
.lien { color: var(--ink); font-weight: 400; font-size: 14px;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  border-bottom: 1px solid var(--ink); padding-bottom: 3px; }

/* Il n'y a plus qu'une barre d'action, construite par `barreAction()`.
   Elle est OPAQUE et séparée du contenu : en dégradé, le premier ingrédient
   se lisait à travers le bouton. */
.barre-action { position: sticky; bottom: 0; z-index: 30;
  padding: 12px 16px max(16px, env(safe-area-inset-bottom));
  background: #fff; border-top: 1px solid var(--ink); }

/* Une action principale prend toute la largeur : un <button> en display:block
   se rétrécit à son texte, ce qui la laissait calée à gauche sur la moitié. */
.barre-action .b-primaire { width: 100%; }

/* Les secondaires sont des BOUTONS, pas des liens nus : même surface tactile
   (44 px au minimum), poids visuel moindre. */
.barre-action .secondaires { display: flex; gap: 8px; margin-top: 9px; }
.b-second { flex: 1; min-height: 44px; display: flex; align-items: center;
  justify-content: center; background: #fff; color: var(--ink);
  border: 1px solid var(--bord); padding: 10px 12px;
  font-size: 14px; font-weight: 400; letter-spacing: var(--label-nav-track);
  text-transform: uppercase; text-align: center; }
.b-second:hover, .b-second:focus { border-color: var(--ink); background: #fff; }
.note-action { font-size: 14px; font-weight: 300; color: var(--discret);
  line-height: 1.5; margin-bottom: 10px; text-align: left; }
.note-action[hidden] { display: none; }
/* La mention légale d'une commande, TOUJOURS visible au-dessus du bouton,
   pas conditionnelle comme .note-action, qui explique un état passager.
   Même gabarit, plus de poids et la couleur d'encre : c'est une mention,
   pas une explication contextuelle. */
.mention-action { font-size: 14px; font-weight: 400; color: var(--encre);
  line-height: 1.5; margin-bottom: 10px; text-align: left; }

/* Le contenu ne s'arrête pas sous la barre : il respire avant elle. */
.corps { padding-bottom: 22px; }

/* ---------- 05 · l'ouverture de « Mes livres » ---------- */

/* Le titre de l'écran est descendu du bandeau dans le CORPS : la maquette
   met la marque et la navigation en haut, et ouvre la page par une adresse
   à qui la lit. */
.ouverture { padding: 24px 0 18px; border-bottom: 1px solid var(--bord); }
.surtitre { font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-section-track); text-transform: uppercase;
  color: var(--discret); margin: 0; }
.ouverture h1 { font-family: var(--font-display); font-weight: 400;
  font-size: 30px; line-height: 1.05; text-transform: uppercase; margin: 10px 0 0; }
/* Les trois temps du parcours, en une ligne. Ce n'est pas une navigation :
   on ne peut pas cliquer dessus, ça dit seulement ce qui va se passer. */
.parcours { display: flex; align-items: center; gap: 10px; margin: 14px 0 0;
  font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--libelle); }
.parcours .fleche { color: var(--desactive); }
.ouverture .sous { margin-top: 10px; }
/* Sur un téléphone, la porte vers un nouveau livre est la barre du pied :
   elle est sous le pouce, et un second bouton à côté du titre ferait deux
   fois la même action à un écran de distance. `bureau.css` intervertit. */
.ouverture-action { display: none; }

/* CE QUI N'EST PAS ENCORE ÉCRIT SE VOIT COMME TEL.
   La couleur du texte d'invite était laissée au navigateur. Dans la fonte des
   titres, en 26 px capitales, son gris par défaut se lit comme un titre déjà
   saisi, on croyait son livre nommé alors que le compteur disait « 0 / 31 ».
   La maquette la fixe : c'est le gris des choses désactivées, à pleine
   opacité, sinon Firefox l'éclaircit une seconde fois. */
::placeholder { color: var(--desactive); opacity: 1; }

/* ---------- cartes ---------- */
.carte { background: #fff; padding: 15px; }
.carte-livre { display: flex; gap: 14px; align-items: flex-start; width: 100%;
  text-align: left; padding: 16px 0; margin: 0; border-bottom: 1px solid var(--bord); }
/* La couverture miniature de la maquette : un rectangle gris borde, le titre
   en haut, le compte en bas. Sa couleur ne porte plus le livre.
 *
 * LE SELECTEUR EST SCOPE, ET C'EST LA CORRECTION D'UN DEFAUT.
 * `couverture` est aussi le nom du TYPE d'une entree de la maquette du livre :
 * `<div class="ligne-maquette couverture">`. La regle ci-dessous s'y appliquait
 * aussi, et rangeait la ligne « Couverture, imprimee a part » dans une boite
 * de 66 x 88 px : son texte debordait par-dessus la ligne suivante, a toutes
 * les largeurs. Deux sens pour un meme mot, et c'est la mise en page qui
 * tranchait. La couverture-vignette n'existe qu'a deux endroits, tous deux
 * nommes ici ; la ligne de maquette garde ses seules regles a elle
 * (`.ligne-maquette.couverture`, plus bas). */
/* LA VIGNETTE DE COUVERTURE. Elle porte la vraie composition, pas une idée
   de couverture : `container-type` fait de la boîte l'unité de la face, qui
   s'y met à l'échelle en `cqw`. La hauteur vient du FORMAT, 216 × 303, pas
   d'un chiffre choisi ici : une vignette aux mauvaises proportions ne montre
   pas le livre qu'on imprimera. */
.couverture { flex: none; container-type: inline-size;
  aspect-ratio: 216 / 303; }
.carte-livre .couverture, .livre-vide .couverture { width: 66px; }
.couverture-apercu { width: 100%; max-width: 180px; }
/* L'aplat d'attente se mesure comme une vraie couverture : en `cqw`, la part
   de SA propre largeur. Le même mot en pixels fixes tiendrait sur l'aperçu de
   180 px et déborderait d'une vignette de carte. C'est la règle de toutes les
   faces composées, celle qui fait qu'un titre garde ses proportions à toutes
   les tailles ; l'attente n'a pas de raison d'y échapper. */
.couverture-attente { background: var(--grey-200); border: 1px solid var(--bord);
  display: flex; align-items: flex-start; padding: 7cqw 6cqw; }
.couverture-sans-titre { font-family: var(--font-display); font-weight: 400;
  font-size: 8cqw; line-height: 1.15; text-transform: uppercase;
  color: var(--discret); }
.carte-livre h3 { font-family: var(--font-display); font-weight: 400;
  font-size: 18px; line-height: 1.1; text-transform: uppercase; margin: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* L'état du livre en une ligne : à l'encre quand c'est acquis, au gris quand
   ça attend. Les quatre pastilles colorées disaient la même chose en quatre
   fois, et la charte n'a pas de teinte pour les distinguer. */
.etat-livre { margin-top: 10px; font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--discret); }
.etat-livre.acquis { color: var(--ink); }
/* Deux segments, pas une barre remplie : ce qui est fait et ce qui reste,
   dans la proportion exacte. */
.jauge { display: flex; gap: 3px; height: 2px; margin-top: 9px;
  background: none; overflow: visible; }
.jauge > i { display: block; height: 2px; background: var(--ink); }
.jauge > i.reste { background: var(--bord); }
.corbeille { flex: none; width: 26px; height: 26px; border: 1px solid var(--bord);
  color: var(--discret); font-size: 14px; font-weight: 300; line-height: 1;
  display: grid; place-items: center; }
.corbeille:hover, .corbeille:focus { border-color: var(--ink); color: var(--ink); }

/* Le carré gris de la maquette : un aparté, pas une carte. */
.encart-gris { background: var(--grey-50); padding: 16px; margin-top: 24px; }
.encart-gris .sous { margin: 8px 0 0; }
.encart-gris .lien { display: inline-block; margin-top: 12px; }

.vide-titre { font-family: var(--font-display); font-weight: 400; font-size: 18px;
  line-height: 1.2; text-transform: uppercase; }
.vide p { max-width: 24em; margin: 10px auto 0; font-weight: 300;
  font-size: 14px; line-height: 1.6; color: var(--libelle); }

/* REPRENDRE OÙ VOUS EN ÉTIEZ.
   Une ligne par recette commencée, tous livres confondus : la vignette, le
   livre en surtitre, le titre, et à droite ce qu'il reste. Le filet du haut
   est à l'encre, ceux des lignes au gris, c'est ce qui fait une liste et non
   une pile de cartes. Sur un téléphone elles s'empilent ; c'est `bureau.css`
   qui les met sur deux colonnes. */
.reprendre { margin-top: 26px; }
/* Ce surtitre-là est à l'encre : il ouvre une liste, il ne commente pas une
   section. La maquette ne lui donne pas de couleur, donc il prend l'encre. */
.reprendre .surtitre { color: var(--ink); }
.reprises { border-top: 1px solid var(--ink); margin-top: 12px; }
.reprise { display: flex; align-items: center; gap: 14px; width: 100%;
  padding: 14px 0; border: 0; border-bottom: 1px solid var(--bord);
  background: transparent; text-align: left; }
.reprise:hover, .reprise:focus { background: var(--grey-50); }
.reprise-vignette { flex: none; width: 44px; height: 56px; object-fit: cover;
  background: var(--grey-50); border: 1px solid var(--bord); }
/* Une photo pas encore validée se voit : c'est une image qu'on juge à l'œil,
   pas une étiquette. Le même grisé que sur les cartes de recette. */
.reprise-vignette.brouillon { opacity: .55; }
.reprise-quoi { flex: 1; min-width: 0; }
.reprise-livre { display: block; font-size: 14px; font-weight: 400;
  line-height: 1.35; letter-spacing: var(--label-cta-track);
  text-transform: uppercase; color: var(--discret);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.reprise-titre { display: block; margin-top: 6px;
  font-family: var(--font-display); font-weight: 400; font-size: 17px;
  line-height: 1.15; text-transform: uppercase;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.reprise-reste { flex: none; font-size: 14px; font-weight: 400; line-height: 1.35;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--libelle); }

/* Le « + » et le mot sont sur UNE ligne ici, empilés sur écran large, c'est
   la seule différence entre les deux maquettes pour ce bouton, avec le mot
   « nouveau » que la case étroite de la grille ne peut pas porter. */
.zone-pointillee { width: 100%; margin-top: 18px; padding: 22px 16px;
  border: 1px dashed var(--desactive); background: transparent;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--libelle); text-align: center; }
.pointillee-plus { font-size: 14px; font-weight: 300; line-height: 1; }
.zone-pointillee:hover, .zone-pointillee:focus { border-color: var(--ink); color: var(--ink); }

/* ---------- 13 · la recette, en quatre temps ---------- */

/* Les onglets disent DEUX choses : où l'on est, l'aplat gris et l'encre, et
   ce qui est déjà passé, par le filet sous chacun. Ils ne verrouillent rien :
   une étape qu'on ne peut pas atteindre est une étape qu'on ne corrige pas. */
.onglets-recette { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  border-top: 1px solid var(--bord); margin: 8px -16px -12px; }
.onglets-recette button { padding: 8px 4px; border: 0;
  border-right: 1px solid var(--bord); background: transparent; text-align: left; }
.onglets-recette button:last-child { border-right: 0; }
.onglets-recette button.ici { background: var(--champ); }
.onglets-recette span { display: block; font-size: 14px; font-weight: 400;
  line-height: 1; letter-spacing: var(--label-nav-track); text-transform: uppercase;
  color: var(--discret); }
.onglets-recette button.ici span { color: var(--ink); }
/* LE MOT ENTIER DÈS QU'IL Y A LA PLACE, ET C'EST L'ONGLET QUI EN JUGE.
   Jamais de troncature : « INGRÉDIEN… » serait pire que « INGR. ».

   La règle était sur la largeur de l'ÉCRAN, à 900 px, et comme les onglets
   n'existent plus au-delà de 900, le mot entier ne s'écrivait JAMAIS. Sur une
   fenêtre de 500 px, où l'onglet offre 99 px, on lisait « INGR. ».

   Le seuil est mesuré, pas estimé : « 2 · Ingrédients » fait 83 px dans la
   fonte et l'approche de l'onglet. 88 px laisse de quoi ne pas toucher le
   filet du voisin, et un petit téléphone garde l'abrégé, comme il faut.
   Une requête de conteneur mesure la boîte de CONTENU : le rembourrage de
   4 px de chaque côté n'y est pas compris. */
.onglets-recette b { font-weight: inherit; }
.onglets-recette button { container-type: inline-size; }
.onglets-recette .entier { display: none; }
@container (min-width: 88px) {
  .onglets-recette .bref { display: none; }
  .onglets-recette .entier { display: inline; }
}
/* Le filet de progression a besoin d'air : collé au libellé, il se lisait
   comme un soulignement du chiffre. */
.onglets-recette i { display: block; height: 2px; margin-top: 9px; background: var(--bord); }
.onglets-recette i.passee { background: var(--ink); }

/* La gouttière de la maquette est de 16 px, comme celle du bandeau : les
   onglets, le cadre de la photo et le pied s'alignent dessus. */
.corps-recette { padding: 14px 16px 22px; }
.pan-recette { padding: 14px 0 0; }
.pan-recette .sous { margin-top: 10px; }
/* « Relire les traductions » : un lien discret, sous le bloc photo, pas une
   décision de plus, juste un chemin qui reste ouvert. */
.recette-rail [data-action="relire-langues"] { display: inline-block; margin-top: 14px; }

/* La tête d'une section : le libellé à gauche, ce qui reste à droite, sur la
   même ligne de BASE, pas centrés l'un sur l'autre. Deux tailles différentes
   alignées au milieu paraissent décalées. */
.tete-pan { display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; }
.tete-pan .reste { margin-left: auto; font-size: 14px; font-weight: 400; line-height: 1.35;
  letter-spacing: var(--label-nav-track); color: var(--discret);
  white-space: nowrap; }
.tete-pan .reste.trop { color: var(--alerte); }
/* « Resserrer » : un bouton, pas un lien, même surface tactile, poids moindre. */
.bouton-mince { flex: none; padding: 6px 10px; border: 1px solid var(--desactive);
  background: transparent; color: var(--libelle);
  font-size: 14px; font-weight: 400; line-height: 1.35;
  letter-spacing: var(--label-cta-track); text-transform: uppercase; }
.bouton-mince:hover, .bouton-mince:focus { border-color: var(--ink); color: var(--ink); }

/* Un champ sans cadre : la charte ne pose pas de boîte autour d'une saisie,
   elle pose un filet dessous. */
.saisie-nue { width: 100%; margin-top: 8px; padding: 0 0 8px;
  border: 0; border-bottom: 1px solid var(--bord); background: transparent;
  font-weight: 300; font-size: 16px; line-height: 1.5; color: var(--encre);
  outline: none; overflow-y: hidden; resize: none; }
/* LE CHAMP DONT LA HAUTEUR EST LA CAPACITÉ, l'accroche.
   Elle est volontairement figée : un champ plus grand inviterait à écrire ce
   qui ne s'imprimera pas. Mais il était aussi `overflow: hidden`, donc le
   texte se coupait net à la quatrième ligne et on ne pouvait plus relire ce
   qu'on venait d'écrire. La largeur à l'écran n'a rien à voir avec celle de
   la page : quatre lignes imprimées en font souvent cinq ici. Il défile. */
/* Le champ à hauteur fixe DÉFILE, et son texte ne doit pas déborder dans la
   marge du bas : une réserve intérieure fait partie de la zone de défilement,
   et la cinquième ligne venait s'y montrer à moitié, coupée en plein milieu
   de ses lettres. On sort la réserve du champ ; le filet suit. */
.saisie-nue.resserre { overflow-y: auto; padding-bottom: 0; margin-bottom: 8px; }
.saisie-nue:focus { border-bottom-color: var(--ink); }
/* Le titre porte le filet FORT et la fonte des titres : c'est le seul poids
   qui le distingue de ses voisins. */
.saisie-nue.titre { border-bottom-color: var(--ink);
  font-family: var(--font-display); font-weight: 400; font-size: 20px;
  line-height: 1.15; }
.saisie-nue.capitales { text-transform: uppercase; }
.pan-recette.trop .saisie-nue { border-bottom: 1.5px solid var(--alerte-trait); }

/* ---- les deux listes ---- */

/* Un INGRÉDIENT est une ligne, séparée de la précédente par un filet. Une
   ÉTAPE est un pavé gris : elle se lit d'un bloc, et sa hauteur dit qu'on y
   écrit une phrase. */
.liste-edit { display: flex; flex-direction: column; margin-top: 10px; }
.liste-edit.pavee { gap: 8px; }
.ligne-edit { border-top: 1px solid var(--bord); padding: 9px 0; }
.ligne-edit.pave { border-top: 0; background: var(--grey-50); padding: 11px 12px; }
.ligne-edit .tete-ligne { display: flex; align-items: flex-start; gap: 10px;
  min-height: 0; }
.puce-carree { flex: none; width: 4px; height: 4px; margin-top: 9px;
  background: var(--ink); }
.ligne-edit .rang { flex: none; font-family: var(--font-display); font-weight: 400;
  font-size: 16px; line-height: 1.2; color: var(--discret); }
.saisie-nue.ligne { flex: 1; min-width: 0; margin-top: 0; padding: 0;
  border-bottom: 0; font-size: 16px; line-height: 1.45; }
.ligne-edit.pave .saisie-nue.ligne { font-size: 16px; line-height: 1.5; }

/* La croix est toujours là, la maquette la dessine ainsi, et une commande
   qui n'apparaît qu'au toucher ne se découvre pas. Monter et descendre ne se
   montrent qu'en écrivant : l'ordre ne se change pas en passant. */
.outils-ligne { flex: none; display: flex; gap: 5px; }
.outils-ligne .outil, .outils-ligne .outil.retirer {
  width: 22px; height: 22px; min-height: 0; flex: none; margin: 0;
  display: grid; place-items: center; color: var(--discret);
  font-size: 14px; font-weight: 300; line-height: 1; padding: 0; }
.outils-ligne .outil:hover, .outils-ligne .outil:focus {
  border-color: var(--ink); color: var(--ink); }
.outils-ligne .outil:not(.retirer) { display: none; }
.ligne-edit:focus-within .outils-ligne .outil:not(.retirer) { display: grid; }

.ajouter-ligne { display: block; width: 100%; margin-top: 12px; padding: 12px;
  border: 1px solid var(--ink); background: transparent; color: var(--ink);
  font-size: 14px; font-weight: 400; line-height: 1.35;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  text-align: center; }
.ajouter-ligne:hover, .ajouter-ligne:focus { background: var(--ink); color: #fff; }

/* LE PANNEAU DES DÉCISIONS, ce qui a été dit, ce qui est écrit.
   Accroché sous la ligne qu'il commente, sur l'aplat gris de la charte. */
.decision { margin-top: 10px; padding: 12px 14px; background: var(--champ); }
.ligne-edit.pave .decision { background: #fff; }
.deux-versions { display: flex; flex-direction: column; gap: 9px;
  margin-bottom: 9px; }
.deux-versions .libelle { margin-bottom: 0; font-size: 14px;
  letter-spacing: var(--label-cta-track); color: var(--ink); }
/* La phrase d'origine est BARRÉE, pas grisée : grisée, elle se lit comme une
   note de bas de page ; barrée, elle dit qu'elle a été remplacée. */
.decision .dit { margin: 4px 0 0; font-size: 14px; font-weight: 300;
  line-height: 1.55; color: var(--text-secondary);
  text-decoration: line-through; text-decoration-color: var(--grey-300); }
.decision .ecrit { margin: 4px 0 0; font-size: 14px; font-weight: 300;
  line-height: 1.55; color: var(--ink); }
.decision .sous { display: block; }
.decision .deux-decisions { margin-top: 12px; }
/* Les deux issues d'une décision. Elles ont l'allure des boutons de la charte
  , plein à l'encre, filet clair, sans en être l'action principale : un
   écran n'en a qu'une, et c'est celle du pied. */
.b-garder, .b-mienne { padding: 10px 13px; border: 0; cursor: pointer;
  font-size: 14px; font-weight: 400; line-height: 1.35;
  letter-spacing: var(--label-cta-track); text-transform: uppercase; }
.b-garder { background: var(--ink); color: #fff; }
.b-garder:hover { background: var(--text-secondary); }
.b-mienne { background: transparent; border: 1px solid var(--grey-300);
  color: var(--text-secondary); }
.b-mienne:hover { border-color: var(--ink); color: var(--ink); }

/* Ce que l'IA a tranché à la place de qui dicte : le panneau gris des
   décisions, en plus petit, accroché sous la ligne qu'il commente. */
.suppose { margin: 8px 0 0; padding: 10px 12px; background: var(--grey-50);
  font-size: 14px; font-weight: 300; line-height: 1.55; color: var(--libelle); }
.ligne-edit.pave .suppose { background: #fff; }
.suppose b { font-weight: 400; color: var(--ink); }
.suppose .sous { display: block; margin-top: 4px; }

/* LE CADRE VIDE garde la hauteur de la maquette ; LA PHOTO, elle, se montre
   dans les proportions de la PAGE, A4 portrait, 0,707. Elle s'affichait en
   plein cadre, donc couchée : on jugeait un cadrage paysage une image qui
   s'imprimera debout, et ce qui déborde en haut et en bas ne se voyait pas. */
.place-photo { width: 100%; height: 250px; background: var(--champ);
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 8px; }
img.place-photo { width: 186px; height: auto; aspect-ratio: .707;
  object-fit: cover; display: block; margin: 0 auto; }
.place-photo .surtitre { color: var(--discret); }
.deux-actions { display: flex; gap: 10px; margin-top: 12px; }
.deux-actions .b { flex: 1; padding: 13px; font-size: 14px; }
/* « Importer » est un <label> : c'est le seul moyen d'ouvrir le sélecteur de
   fichiers sans un écran de plus. Il doit se poser comme un bouton. */
.deux-actions label.b { display: flex; align-items: center;
  justify-content: center; text-align: center; cursor: pointer; }

/* Le panneau gris de la maquette : celui des décisions. Il porte ce qui se
   tranche sur place, garder ce tirage, ou dire ce qui ne va pas. */
.pan-decision { background: var(--grey-50); padding: 12px 14px; margin-top: 16px; }
.pan-decision .surtitre { color: var(--ink); }
.pan-decision .sous { margin-top: 8px; }
.pan-decision .choix-carres { margin-top: 10px; }
.deux-decisions { display: flex; gap: 8px; margin-top: 12px; }
.deux-decisions .b { flex: none; min-height: 0; padding: 10px 13px;
  font-size: 14px; width: auto; }

/* Le pied de la recette : où l'on en est à gauche, ce qui reste à droite, et
   dessous DEUX boutons sur une même ligne, « Retour » étroit, l'action large.
   C'est le seul pied composé ainsi : la maquette le dessine comme un bloc,
   pas comme la barre d'action commune. */
.pied-etape { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 8px;
  font-size: 14px; font-weight: 400; line-height: 1.35;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--discret); }
/* Le titre du livre, corrigé dans la tête. Le bouton n'a AUCUNE allure de
   bouton : c'est le titre, plus un crayon. Il ne se découvre qu'en le
   regardant, et c'est ce que la maquette veut, le titre reste un titre. */
.titre-en-tete-bouton { display: flex; align-items: center; gap: 8px;
  width: 100%; padding: 0; border: 0; background: transparent;
  text-align: left; cursor: pointer; color: inherit; }
.titre-en-tete-bouton h2 { min-width: 0; }
.crayon { flex: none; font-size: 14px; font-weight: 300; line-height: 1;
  color: var(--grey-300); }
.titre-en-tete-bouton:hover .crayon { color: var(--ink); }
/* Le champ prend EXACTEMENT la place du titre : même fonte, même corps. Un
   champ plus petit ferait sauter la ligne au premier clic. */
.titre-en-tete { width: 100%; padding: 0 0 4px; border: 0;
  border-bottom: 1px solid var(--ink); background: transparent;
  font-family: var(--font-display); font-weight: 400; font-size: 17px;
  line-height: 1.15; text-transform: uppercase; color: var(--ink);
  outline: none; }


/* Pleine largeur, en CLASSE et pas en style en ligne : « width:100% » écrit
   dans le JS y fait apparaître le nombre 100, et le garde-fou qui interdit
   d'y recopier une cote du gabarit l'a pris pour la capacité de l'accroche.
   Il avait raison de le voir, c'est bien un nombre de trop dans le JS. */
.b-pleine-largeur { width: 100%; margin-top: 12px; }

/* LA PLANCHE DE COUVERTURE, telle qu'elle s'imprime.

   Elle était un SCHÉMA : trois rectangles gris, le titre dans la fonte de
   titrage de l'application, et une tranche de 14 px fixes. Elle lisait
   `livre.couleur`, un champ du générateur d'images, supprimé, donc elle ne
   pouvait plus rien dire de juste, et elle montrait une couverture que
   personne n'avait choisie.

   Tout est en `cqw` : 1 vaut 1 % de la largeur du cadre. La planche suit donc
   sa colonne, du téléphone à l'écran large, sans qu'une seule bascule de
   largeur soit écrite, et le corps du titre suit avec elle. */
.cv-planche { position: relative; width: 100%; margin-top: 12px;
  container-type: inline-size; overflow: hidden; }
.cv-planche-attente { width: 100%; aspect-ratio: 470.92 / 341.38;
  margin-top: 12px; background: var(--champ); }
.cv-panneau-planche { position: absolute; display: block; }
.cv-panneau-nom { position: absolute; left: 3cqw; bottom: 2cqw;
  font-family: var(--font-text); font-weight: 400; font-size: 1.6cqw;
  line-height: 1.4; letter-spacing: var(--label-nav-track);
  text-transform: uppercase; color: #fff; opacity: .5; z-index: 5; }
.cv-planche-face { position: absolute; display: block; }
/* Les repères de pliure, de part et d'autre de la tranche. Ils ne s'impriment
   pas, c'est l'imprimeur qui plie, mais ils disent où l'objet se replie, et
   donc pourquoi la première n'occupe pas toute la planche. */
.cv-pliure { position: absolute; top: 0; bottom: 0; width: 0;
  border-left: 1px dashed rgba(255, 255, 255, .35); z-index: 4; }

/* L'action destructrice, telle que la charte la pose : pleine largeur, filet
   clair, texte gris, tout en bas, « Supprimer ce livre » dans les réglages,
   « Supprimer cette recette » au bout du premier temps. Elle ne se remarque
   qu'en la cherchant, et c'est le but : ce qu'elle détruit ne revient pas. */
.b-discret { width: 100%; padding: 14px; border: 1px solid var(--bord);
  background: transparent; font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--discret); cursor: pointer; }
.b-discret:hover { border-color: var(--ink); color: var(--ink); }

/* LE CALQUE, l'aperçu imprimé, posé sur la recette.
 *
 * La maquette ne fait pas de l'aperçu un écran : c'est un `position:fixed`
 * par-dessus, à la largeur de l'atelier. On n'a donc jamais quitté la
 * recette, et il n'y a rien à « revenir », seulement à fermer, ou à valider.
 * `z-index: 45` le pose au-dessus de la tête (30) et sous rien d'autre. */
.calque { position: fixed; inset: 0; z-index: 45;
  width: 100%; max-width: 430px; left: 50%; transform: translateX(-50%);
  background: var(--surface-page); display: flex; flex-direction: column;
  overflow: auto; }
.calque-tete { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 14px 16px; border-bottom: 1px solid var(--bord); }
.calque-tete .libelle { margin: 0; }
.calque-corps { flex: 1; padding: 18px 16px; background: var(--champ); }
/* Le pied du calque porte un filet PLEIN, comme toutes les barres d'action de
   la charte : c'est ce qui le sépare de ce qu'on vient de lire. */
.calque-pied { position: sticky; bottom: 0; background: var(--surface-page);
  border-top: 1px solid var(--ink); padding: 12px 16px 16px; }
.note-calque { font-size: 14px; font-weight: 400; line-height: 1.4;
  letter-spacing: var(--label-nav-track); text-transform: uppercase;
  color: var(--discret); margin-bottom: 10px; }
/* Chaque compte MÈNE à ce qu'il compte. Il garde l'allure du texte qui
   l'entoure et ne se distingue qu'au soulignement : c'est une note, pas une
   rangée de boutons au-dessus de l'action principale. */
.lien-relire { border: 0; background: transparent; padding: 0;
  font: inherit; color: var(--ink); text-decoration: underline;
  text-underline-offset: 3px; cursor: pointer; }
.lien-relire:hover { color: var(--discret); }
.lien-nu { border: 0; background: transparent; padding: 0; cursor: pointer;
  font-size: 14px; font-weight: 400; line-height: 1.35;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--ink); }
.lien-nu:hover { color: var(--discret); }

/* Le compteur qui ouvre les précisions. Il garde EXACTEMENT l'allure du texte
   qu'il remplace, c'est le compteur du pied, pas un bouton de plus, et ne se
   distingue que par le soulignement, qui dit qu'on peut y aller. */
.compte-relire { border: 0; background: transparent; padding: 0;
  font: inherit; color: var(--ink); text-decoration: underline;
  text-underline-offset: 3px; cursor: pointer; }
.compte-relire:hover { color: var(--discret); }
.deux-boutons { display: flex; gap: 10px; }
.deux-boutons .b-primaire { flex: 1; width: auto; padding: 14px; }
.b-etroit { flex: none; padding: 14px 16px; font-size: 14px; }

/* ---------- attentes longues, et références de panne ---------- */

/* Passé le double de la durée annoncée, la barre change de ton et donne la
   main. Sombre, parce que ce n'est plus la même situation : on n'attend plus,
   on décide. */
.barre-action.attente-longue { background: var(--ink); border-top-color: var(--ink); }
.titre-attente { font-family: var(--font-display); font-weight: 400;
  font-size: 22px; line-height: 1.14; text-transform: uppercase; color: #fff; }
.attente-longue .sous { margin-top: 12px; color: var(--text-on-dark-muted);
  font-weight: 300; font-size: 14px; line-height: 1.65; }
.b-clair { margin-top: 18px; width: 100%; padding: 15px; text-align: center;
  background: #fff; color: var(--ink);
  font-size: 14px; font-weight: 400; letter-spacing: var(--label-cta-track);
  text-transform: uppercase; }
.b-clair:hover, .b-clair:focus { background: var(--grey-300); }
.attente-longue .barre-avance { margin-top: 16px; background: rgba(255,255,255,.25); }
.attente-longue .barre-avance i { background: #fff; }

/* La référence sort de la phrase : six caractères relevés à l'œil sur un
   écran de téléphone, c'est là qu'on se trompe. */
.reference-panne { border: 1px solid var(--bord); padding: 15px; margin-bottom: 14px; }
.reference-panne .surtitre { color: var(--discret); }
.reference-ligne { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-top: 9px; }
.reference-code { font-size: 22px; font-weight: 400; line-height: 1.1;
  letter-spacing: .22em; font-variant-numeric: tabular-nums; }
.reference-panne .sous { margin-top: 10px; }

/* ---------- 05 · aucun livre encore ---------- */

/* Deux lignes, centrées, et rien d'autre. Le décor d'avant, trois dos de
   livres vides, un titre en 30 px et son propre bouton, n'est pas dans la
   maquette : elle pose « Aucun livre », une phrase, et laisse la porte
   habituelle faire son travail. */
.aucun-livre { padding: 40px 0; text-align: center; }
.aucun-livre .sous { max-width: 24em; margin: 10px auto 0; font-size: 14px;
  line-height: 1.6; color: var(--text-secondary); }

/* ---------- 06 · nouveau livre ---------- */

/* L'APERÇU DE COUVERTURE N'EXISTE QUE SUR UN ÉCRAN LARGE.
 *
 * Il est dans le HTML à toutes les largeurs, et masqué ici. Sur un téléphone,
 * la mettre à côté du formulaire est impossible, et la mettre dessous en
 * ferait un décor qu'on ne découvre qu'après avoir tout rempli. `bureau.css`
 * le révèle et le range à droite. Pas de media query ici : cette feuille
 * décrit le téléphone, et sur un téléphone cet aperçu n'a pas lieu d'être. */
.apercu-livre { display: none; }

/* Le voile du calque, même raison : sur un téléphone le calque prend tout
   l'écran, il n'y a rien derrière lui à assombrir. */
.voile-calque { display: none; }

/* Les réglages du livre sont des SECTIONS depuis qu'un écran large les range
   en deux colonnes. Leur écart vivait auparavant dans la marge basse de la
   dernière phrase de chaque groupe ; il vit maintenant ici, une fois, entre
   deux groupes, c'est le même blanc, à un seul endroit. */
.champ-livre + .champ-livre { margin-top: 22px; }

/* Un libellé de champ et, en face, ce qui le mesure : le compte de signes,
   « facultatif ». La maquette met toujours les deux sur la même ligne. */
.tete-champ { display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; }
.compte-signes { font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-nav-track); color: var(--discret);
  font-variant-numeric: tabular-nums; }
.compte-signes.trop { color: var(--alerte); }
.mention-facultatif { font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-nav-track); text-transform: uppercase;
  color: var(--desactive); }
/* Le titre du livre s'écrit dans la fonte qui l'imprimera, sur un filet
   d'encre : on voit ce qu'on achète pendant qu'on le tape. */
.saisie-titre { width: 100%; margin-top: 10px; padding: 0 0 9px;
  border: 0; border-bottom: 1px solid var(--ink); background: transparent;
  font-family: var(--font-display); font-weight: 400; font-size: 20px;
  line-height: 1.15; text-transform: uppercase; outline: none; }
.saisie-titre.trop { border-bottom: 1.5px solid var(--alerte-trait); }

/* ---------- 18 · le tirage ---------- */

/* Ajouter une page se fait DANS la maquette, sous la liste : on ajoute en
   regardant l'endroit où la page va tomber. C'était sur l'écran d'assemblage,
   à deux navigations de la liste des pages. */
.ajouter-page { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--ink); }
.ajouter-page > .sous { margin: 8px 0 0; }
/* Les portes : trois boutons pointillés, empilés, pleine largeur. Ils étaient
   dispersés dans trois panneaux différents, la dédicace ici, les photos là,
   chacun avec son propre discours. La maquette les met côte à côte, parce que
   c'est la même question : quelle page ajouter ? */
.portes-page { display: flex; flex-direction: column; gap: 8px;
  margin-top: 12px; }
.portes-page .zone-pointillee { display: block; margin: 0; }
/* La dédicace s'écrit sur sa ligne, alignée sous le libellé, pas sous le
   folio, qui n'est pas du texte. */
.editeur-dedicace { flex: 0 0 100%; display: block; padding: 2px 0 0 54px; }
.editeur-dedicace textarea { width: 100%; padding: 10px 0; border: 0;
  border-bottom: 1px solid var(--ink); background: transparent;
  font-size: 16px; font-weight: 300; line-height: 1.6; color: var(--ink);
  outline: none; }
.editeur-dedicace .signature { width: 100%; margin-top: 8px; padding: 9px 0;
  border: 0; border-bottom: 1px solid var(--bord); background: transparent;
  font-size: 16px; font-weight: 300; line-height: 1.3; font-style: normal;
  color: var(--ink); outline: none; }
.ajouter-page .bloc { padding: 14px 0; }

/* Une ligne de la maquette : le folio à gauche, ce que c'est en Abril, ce que
   ça contient dessous, et le nombre de pages en capitales. */
.ligne-maquette { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-start;
  padding: 13px 0; border-top: 1px solid var(--bord); }
.folio-maquette { flex: none; width: 42px; font-size: 14px; font-weight: 400;
  line-height: 1.2; letter-spacing: .06em; color: var(--discret);
  font-variant-numeric: tabular-nums; }
/* Le corps de la ligne : trois lignes empilées, et rien qui flotte.
   « N pages » était un élément du flex poussé à droite par `order: 9` : sur
   une entrée au texte long il passait à la ligne, et la colonne du milieu se
   retrouvait écrasée à un tiers de sa largeur. La maquette l'empile. */
.corps-ligne { flex: 1; min-width: 0; }
.corps-ligne > b {
  display: block; font-family: var(--font-display); font-weight: 400;
  font-size: 14px; line-height: 1.2; text-transform: uppercase; }
.corps-ligne .sous { display: block; margin-top: 4px; font-size: 14px;
  font-weight: 300; line-height: 1.45; color: var(--text-secondary); }
.pages-maquette { display: block; margin-top: 5px;
  font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--discret); }

/* ---------- 07 · le livre ouvert ---------- */

/* Le titre du livre et ce qu'il contient, dans le bandeau : la maquette met
   la meta SOUS le titre plutôt que dans quatre compteurs en dessous. */
/* Le bloc titre prend la place ; le pousseur générique la lui prenait, et le
   titre du livre se coupait au tiers de la barre. */
.tete-titre { flex: 1; min-width: 0; }
.tete-titre + .pousse { display: none; }
.tete-meta { margin-top: 3px; font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-section-track); text-transform: uppercase;
  color: var(--discret); }

.tete-livre { display: flex; align-items: flex-end; justify-content: space-between;
  gap: 14px; padding: 18px 0 0; }
.compte-recettes { font-family: var(--font-display); font-weight: 400;
  font-size: 22px; line-height: 1.05; text-transform: uppercase; }
.tete-livre .etat-livre { margin-top: 7px; }
/* La même pilule que l'en-tête, mais bordée d'encre : c'est une action, pas
   un accès. */
.pilule-forte { border-color: var(--ink); color: var(--ink); }
.pilule-forte:hover, .pilule-forte:focus { background: var(--ink); color: #fff; }

.livre-vide { display: flex; gap: 16px; align-items: flex-start;
  padding: 22px 0 24px; border-bottom: 1px solid var(--bord); }
.livre-vide h1 { font-family: var(--font-display); font-weight: 400;
  font-size: 22px; line-height: 1.1; text-transform: uppercase; margin: 0; }
.livre-vide .sous { margin-top: 10px; }
.couverture-grande { width: 92px; height: auto; padding: 0; }

/* La couverture cliquable : un bouton qui ne se voit pas, pour que ce soit la
   couverture qu'on clique et non un cadre autour d'elle. Le curseur et le
   liseré au survol suffisent à dire qu'elle mène quelque part. */
.couverture-porte {
  display: block; padding: 0; margin: 0; border: 0; background: none;
  cursor: pointer; flex: none; line-height: 0;
  outline-offset: 3px; transition: opacity .12s;
}
.couverture-porte:hover { opacity: .82; }

/* ---------- recettes ---------- */

/* Le filet du chapitre porte son nom à gauche et son compte à droite : il
   sépare ET il renseigne, là où un titre seul ne faisait que séparer. */
.chapitre { display: flex; align-items: center; gap: 10px; margin: 24px 0 0; }
.chapitre-nom { font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-section-track); text-transform: uppercase;
  color: var(--ink); }
.chapitre-filet { flex: 1; height: 1px; background: var(--ink); }
.chapitre-compte { font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-nav-track); text-transform: uppercase;
  color: var(--discret); }

.carte-recette { display: flex; gap: 13px; align-items: flex-start; width: 100%;
  text-align: left; background: #fff; padding: 14px 0; margin: 0;
  border-bottom: 1px solid var(--bord); }
.vignette { width: 62px; height: 78px; flex: none; background: var(--champ);
  border: 1px solid var(--bord); display: grid; place-items: center;
  color: var(--desactive); font-size: 14px; letter-spacing: .12em;
  text-transform: uppercase; object-fit: cover; }
.titre-recette { display: block; font-family: var(--font-display);
  font-weight: 400; font-size: 16px; line-height: 1.15; text-transform: uppercase;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.carte-recette .sous { display: block; margin-top: 5px; font-weight: 300;
  font-size: 14px; line-height: 1.4; letter-spacing: .06em;
  text-transform: uppercase; color: var(--discret); }
.etat-recette { display: block; margin-top: 8px; font-size: 14px; font-weight: 400;
  line-height: 1; letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--discret); }
.etat-recette.acquis { color: var(--ink); }
.chevron { flex: none; margin-top: 2px; font-size: 16px; font-weight: 300;
  line-height: 1; color: var(--desactive); }

/* Une ligne de réglage : un libellé, un chevron, un filet. La maquette range
   ainsi tout ce qui ouvre un autre écran. */
.lignes-reglage { display: flex; flex-direction: column; margin-top: 10px; }
.ligne-reglage { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; width: 100%; text-align: left; padding: 14px 0;
  border-top: 1px solid var(--bord); border-bottom: 1px solid var(--bord);
  font-weight: 300; font-size: 16px; line-height: 1.3; }
.ligne-reglage + .ligne-reglage { border-top: none; }
.ligne-reglage .chevron { margin-top: 0; }
.sous { font-size: 14px; color: var(--libelle); }
.sous.alerte { color: var(--incomplet); }
.jalons { display: flex; gap: 5px; margin-top: 6px; }
.jalon { font-size: 14px; font-weight: 400; border-radius: 0; padding: 2px 6px; }
.jalon.ok { background: var(--g3t); color: var(--g3); }
.jalon.a-faire { background: var(--champ); color: var(--incomplet); }
.jalon.gris { background: var(--champ); color: var(--desactive); }

/* ---------- dictee ---------- */
/* Dicter et écrire ne sont pas deux réglages : ce sont deux façons d'entrer
   dans le même écran. Deux onglets soulignés, donc, et non deux pastilles
   dans un cartouche, l'un se lit comme une navigation, l'autre comme un
   interrupteur. Ils touchent les bords, sous le bandeau. */
.onglets-saisie { display: flex; border-bottom: 1px solid var(--bord); }
.onglets-saisie button { flex: 1; padding: 14px 10px;
  border-bottom: 2px solid transparent; background: transparent;
  font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-section-track); text-transform: uppercase;
  color: var(--discret); }
.onglets-saisie button.actif { border-bottom-color: var(--ink); color: var(--ink); }

/* « J'ai déjà la recette quelque part » : la porte vers Photographier et
   Depuis un lien, qui ne pèsent plus comme les deux onglets. Un lien, pas un
   bouton, elle ouvre une ligne, elle ne fait rien elle-même. */

.corps-saisie { display: flex; flex-direction: column; padding-top: 18px; }

/* La dictée se lit du bas : le texte monte au fur et à mesure, comme une
   conversation. `justify-content: flex-end` tient la dernière phrase sous
   l'œil au lieu de la laisser filer vers le bas de l'écran. */
.scene-dictee { display: flex; flex-direction: column; }
.transcription-cadre { min-height: 250px; display: flex;
  flex-direction: column; justify-content: flex-end; }
.ecoute { display: flex; align-items: center; gap: 8px; margin-bottom: 14px;
  font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-section-track); text-transform: uppercase;
  color: var(--ink); }
.puce { width: 6px; height: 6px; background: var(--ink);
  animation: gpulse 1.2s infinite; flex: none; }
.transcription { margin: 0; font-weight: 300; font-size: 16px; line-height: 1.75;
  white-space: pre-wrap; text-wrap: pretty; }
.transcription.vide { font-size: 16px; line-height: 1.7; color: var(--desactive); }
.transcription .provisoire { color: var(--discret); }
/* Le même texte, devenu corrigible. Il garde EXACTEMENT l'allure du
   paragraphe qu'il remplace : même corps, même interligne, aucun cadre. Un
   champ qui se signale comme un champ ferait de la relecture un formulaire,
   alors que c'est encore la dictée qu'on regarde. */
.transcription.corrigible { width: 100%; border: 0; padding: 0;
  background: transparent; color: var(--ink); resize: none; outline: none;
  font-family: inherit; }
.transcription.corrigible:focus { border-bottom: 1px solid var(--ink); }
.indice-correction { margin: 10px 0 0; }
.compteurs-dictee { display: flex; align-items: baseline;
  justify-content: space-between; gap: 12px; margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--bord);
  font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--discret); }
.compteurs-dictee .actif { color: var(--ink); }

.scene-micro { padding-top: 22px; display: flex; flex-direction: column;
  align-items: center; }
.onde { display: flex; align-items: center; justify-content: center; gap: 4px;
  height: 34px; margin-bottom: 18px; }
.onde i { width: 2px; height: 100%; background: var(--ink); animation: gwave .9s infinite; }
/* Le halo bat AUTOUR du bouton, il ne le remplace pas : un anneau qui grandit
   et s'efface, pendant que le bouton reste immobile sous le pouce. */
.halo { position: relative; width: 78px; height: 78px; display: flex;
  align-items: center; justify-content: center; }
.halo.bat::before { content: ""; position: absolute; inset: 0;
  border: 1px solid var(--ink); border-radius: 50%;
  animation: ganneau 1.8s ease-out infinite; }
.bouton-micro { position: relative; width: 78px; height: 78px; border-radius: 50%;
  border: 1px solid var(--ink); background: transparent;
  display: grid; place-items: center; }
.bouton-micro i { width: 13px; height: 13px; border-radius: 50%;
  background: var(--ink); display: block; }
/* En écoute, le bouton s'inverse et sa pastille devient carrée : rond pour
   commencer, carré pour arrêter, c'est le vocabulaire de tous les appareils
   qui enregistrent, et il n'a pas besoin d'être appris. */
.bouton-micro.ecoute { background: var(--ink); }
.bouton-micro.ecoute i { width: 18px; height: 18px; border-radius: 0; background: #fff; }
.indice-micro { margin-top: 12px; font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--libelle); }

/* CE QUE LA MAQUETTE BUREAU AJOUTE, ET QUE LE TÉLÉPHONE NE PORTE PAS.
   Deux blocs masqués ici, révélés par `bureau.css` : l'en-tête de l'écran et
   la phrase qui présente le micro. La maquette mobile n'en dessine aucun,
   390 px n'ont pas la place, et les empiler ferait descendre le micro sous
   la ligne de flottaison. */
.entete-saisie, .mot-micro { display: none; }

/* Le brouillon retrouvé, sous la barre d'erreur. Pas de cadre : c'est une
   ligne, comme l'indice de correction juste en dessous. */
.brouillon-repris { margin: 4px 0 14px; }
.brouillon-repris .lien { margin-left: 6px; }

.scene-ecriture { display: flex; flex-direction: column; }
.scene-ecriture .sous { margin-bottom: 12px; }
.zone-ecriture { width: 100%; min-height: 300px; padding: 12px 0;
  background: transparent; border: 0;
  border-top: 1px solid var(--bord); border-bottom: 1px solid var(--bord);
  font-weight: 300; font-size: 16px; line-height: 1.7; outline: none; }

/* ---------- blocs de recette ---------- */
.bloc { background: #fff; padding: 14px; margin-bottom: 12px; }
/* Un bloc qui déborde EST en faute : le texte ne rentre pas dans la page, et
   tant qu'il n'est pas raccourci, le livre ne s'assemble pas. Il prend donc le
   fond de ligne fautive et sa règle, les deux seules choses que la charte
   accorde au terracotta, avec la phrase qui l'accompagne. */
/* UN BLOC QUI BLOQUE RESTE GRIS. Le jeton le disait déjà : `--alerte-fond`
   est « le fond d'une LIGNE fautive, jamais d'un bloc ». Il habillait pourtant
   des panneaux entiers, « Ce qui bloque », « Supprimer ce livre ? », en rose
   pâle souligné de terre cuite. La charte ne sépare ni ne hiérarchise par la
   couleur : elle le fait au filet et à l'aplat gris, et le titre du bloc dit
   déjà ce qu'il est. */
.bloc.trop { background: var(--champ); }
.bloc-tete { display: flex; align-items: baseline; gap: 10px; margin-bottom: 9px; }
.bloc-tete .nom { font-size: 14px; font-weight: 400; text-transform: uppercase; letter-spacing: .07em; color: var(--discret); }
.remplissage { margin-left: auto; font-size: 14px; font-weight: 400;
  letter-spacing: var(--label-nav-track); text-transform: uppercase;
  color: var(--discret); font-variant-numeric: tabular-nums; }
.remplissage.trop { color: var(--alerte); }
/* Un etat acquis, « tout est pret », « fermé », « sans filigrane ». Meme
   place que `trop`, couleur inverse : ce qui va bien se lit du meme coup d'oeil
   que ce qui bloque. */
.remplissage.ok { color: var(--discret); }
/* `overflow-y: hidden` et pas de `resize` : la hauteur est posée en JS depuis
   `scrollHeight`, et une barre de défilement interne la fausserait. Le champ
   suit son texte, ce que la PAGE accepte, c'est la jauge qui le dit. */
.champ { width: 100%; border: none; outline: none; background: none; font-size: 16px; line-height: 1.5; color: var(--encre); font-family: inherit; overflow-y: hidden; resize: none; }
/* « On ne vide jamais un champ en erreur » : le texte reste, seule la règle
   change. C'est la première ligne de l'anatomie du message en ligne. */
.saisie.trop { border-bottom: 1.5px solid var(--alerte-trait); }
.ligne-liste { display: flex; gap: 9px; align-items: baseline; padding: 3px 0; }
/* Le nom sur une ligne, ce qui lui manque en dessous. Ils se suivaient dans le
   même paragraphe : « pâtes au beurre et parmesan texte anglais incomplet ·
   texte espagnol incomplet » se lisait comme une seule phrase, et le titre s'y
   perdait. */
.ligne-liste .sous { display: block; margin-top: 4px; }
/* Un outil de ligne, monter, descendre, retirer. Il sert aux chapitres, à la
   maquette et aux pages libres, où il porte parfois du TEXTE : sa hauteur est
   celle d'une cible tactile, pas celle d'un glyphe. La recette, elle, le
   resserre en carré de 22 px, c'est la forme de la maquette. */
.outil { min-height: 34px; padding: 0 10px; color: var(--libelle);
  font-size: 14px; font-weight: 400; line-height: 1; display: inline-flex;
  align-items: center; gap: 3px; background: #fff; border: 1px solid var(--bord); }
.outil:hover, .outil:focus { border-color: var(--ink); color: var(--ink); }
.outil[disabled] { opacity: .35; }
.outil.retirer { margin-left: auto; }
.ligne-liste .rang { color: var(--g1); font-weight: 400; font-size: 14px; min-width: 16px; flex: none; }
.encart { display: flex; gap: 8px; margin-top: 10px;
  font-weight: 300; font-size: 14px; line-height: 1.5; color: var(--alerte); }
.encart::before { content: ""; flex: none; width: 9px; height: 1.5px;
  margin-top: 8px; background: var(--alerte); }
.encart.info { background: var(--g1t); color: var(--g1); }
.nutri { display: flex; gap: 20px; }
.nutri b { font-family: var(--font-display); font-weight: 400; font-size: 17px; display: block; }
.nutri span { font-size: 14px; color: var(--libelle); }

/* ---------- attente, erreurs ---------- */
.attente { display: flex; align-items: center; gap: 10px; padding: 10px 0;
  font-size: 14px; font-weight: 400; letter-spacing: var(--label-cta-track);
  text-transform: uppercase; color: var(--ink); }
.anneau { width: 18px; height: 18px; border: 2.5px solid var(--bord); border-top-color: var(--g1); border-radius: 999px; animation: gspin 1s linear infinite; flex: none; }
.anneau.grand { width: 62px; height: 62px; border-width: 3px; margin: 0 auto; }
.centre { text-align: center; padding: 60px 22px; }
.centre h2 { font-family: var(--font-display); font-weight: 400; font-size: 22px;
  letter-spacing: var(--wordmark-track); text-transform: uppercase; margin: 20px 0 8px; }
/* L'anatomie du message en ligne, telle que la maquette la fixe : un tiret de
   9 px, la phrase, et rien d'autre. Pas de fond, pas d'icone, pas de cadre,
   un bloc teinte se lit comme une note, et l'ecran ne doit pas bouger. */
.erreur { display: flex; gap: 8px; margin-bottom: 14px;
  font-weight: 300; font-size: 14px; line-height: 1.5; color: var(--alerte); }
.erreur::before { content: ""; flex: none; width: 9px; height: 1.5px;
  margin-top: 8px; background: var(--alerte); }
.erreur > ul { margin: 6px 0 0; padding-left: 18px; }
.vide { text-align: center; color: var(--libelle); font-size: 14px; line-height: 1.6; padding: 26px 10px; }

/* ---------- connexion ---------- */
.connexion { min-height: 100vh; display: flex; flex-direction: column; justify-content: center; padding: 30px 26px; gap: 16px; }
.connexion .marque { color: var(--g1); font-size: 26px; }
.baseline { font-size: 16px; color: var(--libelle); line-height: 1.5; margin-bottom: 10px; }
.libelle { font-size: 14px; font-weight: 400; text-transform: uppercase; letter-spacing: .06em; color: var(--libelle); margin-bottom: 6px; }
.saisie { width: 100%; background: #fff; border: 1.5px solid var(--bord); border-radius: 0; padding: 14px; font-size: 16px; outline: none; }
.saisie:focus { border-color: var(--g1); }

/* ==================================================================
   Écrans 06, 11, 12, 14, 15, 16, 17, 18, 22
   Mêmes jetons que ci-dessus : aucune couleur nouvelle, aucun rayon
   inventé. Ce qui s'ajoute, ce sont des agencements.
   ================================================================== */

/* 06 · Nouveau livre */
.libelle-section { font-size: 14px; font-weight: 400; text-transform: uppercase;
  letter-spacing: .07em; color: var(--discret); margin: 0 0 9px; }
.saisie.trop { border-color: var(--alerte-trait); }
.ligne-choix { display: flex; align-items: center; gap: 11px; width: 100%; background: #fff;
  border: 1.5px solid var(--bord); border-radius: 0; padding: 12px 13px; margin-bottom: 8px;
  font-size: 16px; text-align: left; }
.ligne-choix.choisi { background: var(--g1t); border-color: var(--g1); }
.ligne-choix .case { width: 22px; height: 22px; border-radius: 0; flex: none;
  border: 1.5px solid var(--bord); background: #fff; display: grid; place-items: center;
  color: #fff; font-size: 14px; }
.ligne-choix.choisi .case { background: var(--g1); border-color: var(--g1); }
.ligne-choix .mention { font-size: 14px; color: var(--libelle); }
.ligne-choix[disabled] { opacity: 1; }

/* 11 · Mise en forme */
.etapes { text-align: left; max-width: 250px; margin: 22px auto 0; }
.etape { display: flex; align-items: center; gap: 10px; font-size: 14px;
  color: var(--discret); padding: 5px 0; }
.etape .puce { width: 16px; height: 16px; background: var(--champ);
  animation: none; display: grid; place-items: center; font-size: 14px; color: #fff; }
.etape.faite { color: var(--g3); }
.etape.faite .puce { background: var(--g3); }
.etape.encours { color: var(--g1); font-weight: 400; }
.etape.encours .puce { background: var(--g1); animation: gpulse 1.2s infinite; }

/* ---------- LE choix, et le seul ----------

   Il y avait deux composants pour le même geste : une pastille ARRONDIE de
   13,5 px sur cinq écrans, et le carré de la maquette sur celui de la recette.
   La charte n'a pas de rayon, « la separation se fait au filet et a l'aplat
   gris », donc c'est le carré qui reste, partout.

   Une seule forme, deux registres, et la maquette les distingue :

     VALEUR   ce qu'on prend tel quel et qui s'écrira dans le livre,
              « 20 cl », « Un petit pot ». Bas de casse, 13 px : c'est du
              texte, on doit pouvoir le lire comme tel.
     LIBELLÉ  ce qui nomme une catégorie ou une échappatoire, « 4 pers. »,
              « Trop sombre », « Je ne sais pas ». Capitales espacées, comme
              tous les libellés de la charte.

   Choisi = rempli à l'encre. Pas choisi = un filet. */
.choix-carres { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.choix-carre { border: 1px solid var(--desactive); background: transparent;
  color: var(--encre); padding: 13px 18px;
  font-size: 14px; font-weight: 400; line-height: 1; letter-spacing: .04em; }
.choix-carre:hover, .choix-carre:focus { border-color: var(--ink); }
.choix-carre.choisi { border-color: var(--ink); background: var(--ink); color: #fff; }

.choix-carre.libelle { border-color: var(--bord); color: var(--libelle);
  padding: 9px 13px; font-size: 14px;
  letter-spacing: var(--label-nav-track); text-transform: uppercase; }
.choix-carre.libelle:hover, .choix-carre.libelle:focus { color: var(--ink); }
.choix-carre.libelle.choisi { color: #fff; }
.encart.bandeau { display: block; width: 100%; text-align: left; }

/* 14 · Raccourcir */
.encart-primaire { background: var(--g1t); color: var(--g1); border-radius: 0;
  padding: 12px 14px; font-size: 14px; line-height: 1.5; margin-bottom: 14px; }
.encart-vert { background: var(--g3t); color: var(--g3); border-radius: 0;
  padding: 12px 14px; font-size: 14px; line-height: 1.55; margin-top: 14px; }
.diff { margin-bottom: 12px; }
.diff .avant { font-size: 14px; color: var(--discret); text-decoration: line-through;
  line-height: 1.5; margin-bottom: 5px; }
.diff .apres { font-size: 16px; color: var(--encre); line-height: 1.5; background: #fff;
  border-left: 2.5px solid var(--g3); border-radius: 0; padding: 9px 12px; }

/* 15 · Trois langues */
.onglets { display: flex; gap: 4px; margin-top: 12px; }
/* Blancs, ils l'étaient, sur le bandeau sombre d'avant. Sur la tête blanche
   de la charte, les trois langues étaient invisibles : on changeait de langue
   à l'aveugle, en visant l'endroit où le mot aurait dû être. */
.onglet { flex: 1; padding: 9px 6px; font-size: 14px; font-weight: 400;
  color: var(--discret); background: transparent; border: 0;
  border-bottom: 2px solid transparent; cursor: pointer; }
.onglet.actif { color: var(--ink); border-bottom-color: var(--ink); }
.onglet .point { width: 6px; height: 6px; background: var(--incomplet);
  display: inline-block; margin-left: 5px; vertical-align: middle; }

/* 16 · Photo */

/* 17 · Aperçu imprimé */
.corps.bureau { background: #eceae6; padding-top: 4px; }
.page-imprimee { margin-bottom: 18px; }
.page-imprimee .intitule { font-size: 14px; font-weight: 400; letter-spacing: .07em;
  color: var(--libelle); margin-bottom: 6px; }
.page-imprimee img { width: 100%; display: block; }

.lien.clair { color: #fff; }
/* La consigne, elle, se redimensionne a la main : elle garde donc son
   defilement interne. */
.champ.consigne { min-height: 76px; resize: vertical; overflow-y: auto; }

.b[disabled] { background: var(--champ); color: var(--desactive);
  border-color: transparent; }

/* Aucun élément interactif sous 44 px de hauteur effective. Les liens de
   contenu gardent leur discrétion mais pas leur cible minuscule. */
.lien { min-height: 44px; display: inline-flex; align-items: center; padding: 0 2px; }

/* Les alertes respirent comme les cartes : elles ne touchent plus ni
   l'en-tête ni le bloc suivant. */
.encart { margin: 14px 0 0; }
.encart:first-child { margin-top: 16px; }
.encart-primaire, .encart-vert { margin: 14px 0; }

/* Une attente avance au lieu de décompter. Tout est en CSS : aucun rendu
   par seconde, donc aucun curseur reposé. */
.barre-avance { height: 2px; background: var(--bord);
  overflow: hidden; margin: 2px 0 12px; }
.barre-avance i { display: block; height: 100%; width: 40%;
  background: var(--ink); animation: gavance 1.4s ease-in-out infinite; }
@keyframes gavance {
  0% { margin-left: -40%; } 100% { margin-left: 100%; }
}

/* Écran 12, où en est-on dans la file */
/* La file des précisions. Les jalons étaient BLANCS, un reste du bandeau
   sombre d'avant : sur la tête blanche de la charte, la file entière était
   invisible, et l'écran ne disait plus où l'on en était. */
.file-questions { margin-top: 12px; }
.jalons-file { display: flex; gap: 4px; }
.jalons-file i { flex: 1; height: 2px; background: var(--bord); }
.jalons-file i.faite { background: var(--ink); }
.jalons-file i.ici { background: var(--discret); }
/* « Question 3 sur 6 » d'un côté, « 2 répondues » de l'autre : deux faits
   différents, tenus aux deux bords. Réunis par un point médian, on les lisait
   comme une seule phrase et le second se perdait. */
.compte-file { display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-top: 8px;
  font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--discret); }
.compte-file .ici { color: var(--ink); }
/* La question est le seul texte de l'écran : elle se pose en display, comme
   un titre de recette, pas en gras d'interface. */
.question { margin: 26px 0 0; font-family: var(--font-display); font-weight: 400;
  font-size: 23px; line-height: 1.3; text-wrap: pretty; }
/* La réponse libre : un libellé en capitales, un filet dessous, rien autour.
   C'était un champ encadré, la seule boîte de tout l'écran, et la charte n'en
   pose aucune. Le filet du haut la sépare des propositions : ce sont deux
   façons de répondre, pas une liste qui continue. */
.reponse-libre { margin-top: 20px; padding-top: 16px;
  border-top: 1px solid var(--bord); }
.reponse-libre .libelle { display: block; margin-bottom: 10px;
  letter-spacing: var(--label-section-track); color: var(--discret); }
.reponse-libre .saisie-nue { width: 100%; padding: 10px 0; border: 0;
  border-bottom: 1px solid var(--grey-300); background: transparent;
  font-size: 16px; font-weight: 300; line-height: 1.6; color: var(--ink);
  outline: none; }

/* « Je ne sais pas » n'est PAS une réponse : il est seul sur sa ligne, après
   le champ libre, à gauche. Rangé avec les propositions, il en devenait une
   quatrième, et c'est exactement le contraire d'une réponse. */
.b-ignorer { margin-top: 22px; padding: 12px 16px;
  border: 1px solid var(--bord); background: transparent; cursor: pointer;
  font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--text-secondary); }
.b-ignorer:hover { border-color: var(--ink); color: var(--ink); }
.b-ignorer.choisi { background: var(--ink); border-color: var(--ink);
  color: #fff; }

.astuce { margin-top: 28px; padding-top: 16px;
  border-top: 1px solid var(--bord); font-size: 14px; font-weight: 300;
  line-height: 1.65; color: var(--discret); }

/* Une photo de brouillon se voit : elle existe, mais elle n'est pas tirée. */
.vignette.brouillon { opacity: .82; }

/* Le parcours d'une recette : écriture → validation → photo → finalisée.
   Visible sur tous ses écrans, parce que « où j'en suis » et « ce qui reste »
   ne se déduisent pas d'un bouton. */
.parcours { display: flex; align-items: flex-start; margin: 0 0 16px; }
.jalon-parcours { flex: 1; text-align: center; position: relative; }
.jalon-parcours::before { content: ''; position: absolute; top: 10px; left: -50%;
  width: 100%; height: 2px; background: var(--bord); z-index: 0; }
.jalon-parcours:first-child::before { display: none; }
.jalon-parcours.faite::before, .jalon-parcours.encours::before { background: var(--g3); }
.jalon-parcours .jalon { position: relative; z-index: 1; width: 22px; height: 22px;
  background: var(--champ); color: #fff; font-size: 14px;
  display: inline-grid; place-items: center; }
.jalon-parcours .nom { display: block; font-size: 14px; font-weight: 400;
  color: var(--discret); margin-top: 5px; letter-spacing: .01em; }
.jalon-parcours.faite .jalon { background: var(--g3); }
.jalon-parcours.faite .nom { color: var(--g3); }
.jalon-parcours.encours .jalon { background: var(--g1); }
.jalon-parcours.encours .nom { color: var(--g1); }

/* Le travail en cours vit DANS la barre : collée en bas, elle est toujours
   visible. En haut du contenu, on ne la voyait pas sur une page défilée, et
   on cliquait une deuxième fois sur « Générer ». */
/* CE LIBELLÉ EST UN LIBELLÉ D'ÉTAT, ET IL S'ÉCRIT COMME LES AUTRES.
   Il était en 14 px, graisse 500, bas-de-casse et sans approche : le seul
   texte de l'atelier composé ainsi. À côté d'une interface entièrement en
   capitales espacées de 9,5 px, il ne se lisait pas comme du Jost, on y
   voyait une autre police, et c'en était bien une autre, au sens qui compte :
   une autre écriture. « ÉCOUTE… », « APPUYEZ POUR DICTER » et l'attente du
   corps de page disent tous la même chose de la même façon. */
.barre-action .travail { display: flex; align-items: center; justify-content: center;
  gap: 10px; min-height: 52px;
  font-size: 14px; font-weight: 400; line-height: 1;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--ink); }
.barre-action .barre-avance { margin: 0; }

/* Une seule photo, en grand : c'est elle qu'on juge. */
.photo-unique { border-radius: 0; overflow: hidden; background: var(--champ);
  aspect-ratio: 2/3; max-height: 420px; margin: 0 auto; display: grid;
  place-items: center; color: var(--discret); font-size: 30px; }
.photo-unique img { width: 100%; height: 100%; object-fit: cover; display: block; }
.photo-unique.vide { flex-direction: column; gap: 10px; }
.photo-unique.vide span { font-size: 14px; }

/* Les réglages d'un livre : trois actions courtes qui tiennent sur la largeur.
   En liens dans une rangée sans retour, « Supprimer le livre » sortait de
   l'écran, le bouton n'était pas cassé, il était hors d'atteinte. */
.reglages-livre { display: flex; gap: 8px; margin: 0 0 16px; }
.reglages-livre .b-second { flex: 1; padding: 10px 6px; font-size: 14px; }
.b-second.retirer { color: var(--incomplet); }
.b-second.retirer:hover, .b-second.retirer:focus { border-color: var(--ink);
  background: #fff; color: var(--ink); }

/* La corbeille est hors de la zone qui ouvre le livre : sur un écran tactile,
   un bouton posé dans la cible principale se déclenche au pouce.
   Elle était posée en absolu dans le coin ; la maquette la met DANS la ligne,
   en haut à droite, l'absolu la faisait chevaucher la jauge, et la zone qui
   ouvre le livre s'étendait dessous. */
.carte-livre .ouvrir-livre { flex: 1; min-width: 0; display: flex; gap: 14px;
  align-items: flex-start; text-align: left; }

/* Le logo ramène à l'accueil. C'est un bouton : il doit s'annoncer comme tel
   au clavier et aux lecteurs d'écran, même s'il garde l'allure d'un titre. */
button.marque { cursor: pointer; text-align: left; }

/* Ce qui manque, dit à côté du champ concerné. Un bouton gris est une énigme ;
   une phrase se lit et se répare. */
.manque { font-size: 14px; color: var(--incomplet); background: var(--champ);
  border-radius: 0; padding: 8px 11px; margin: 7px 0 0; line-height: 1.45; }

/* Feuilleter en double page : c'est ainsi qu'un livre s'ouvre. Une page seule
   ne dit pas ce que le lecteur verra, un intercalaire et la photo d'en face
   n'ont de sens qu'en regard. */
.double-page { display: flex; gap: 2px; margin-bottom: 20px; background: #d9d5d0; }
.page-cote { position: relative; flex: 1; background: #fff; min-height: 40px; }
.page-cote img { width: 100%; display: block; }
/* La pliure : une ombre portée vers l'intérieur, comme au creux d'un livre. */
.page-cote.gauche { }
.page-cote.droite { }
.page-cote.absente { background: transparent; }
.folio-cote { position: absolute; bottom: 4px; width: 100%; text-align: center;
  font-size: 14px; color: var(--discret); }

/* La maquette : la suite des pages, telle qu'elle s'imprimera. La FORME de la
   ligne est posée plus haut, avec le reste du tirage ; ici ne restent que les
   nuances de type, que la charte distingue par l'aplat et non par la teinte. */
.ligne-maquette.intercalaire, .ligne-maquette.photo_libre { background: var(--champ); }
.ligne-maquette.index, .ligne-maquette.couverture { color: var(--libelle); }

/* « De… » : ce qui s'imprimera, dans chaque langue du livre. La formule se
   traduit, le nom non. */
.attribution-rendue { margin-top: 12px; background: var(--champ); border-radius: 0;
  padding: 10px 12px; }
.attribution-rendue div { display: flex; gap: 10px; align-items: baseline;
  padding: 2px 0; }
.attribution-rendue .sous { min-width: 62px; }
.attribution-rendue b { font-size: 14px; letter-spacing: .03em; }

/* Le pied legal, sur tous les ecrans de l'application.
   Discret : il n'est pas une destination, il doit seulement etre la. Mais il
   doit y etre PARTOUT, y compris dans le tunnel de paiement, c'est une
   obligation, et c'est la seule facon que les conditions soient lues avant
   l'achat plutot qu'apres. */
.pied-appli { display: flex; flex-wrap: wrap; gap: 10px 18px;
  padding: 24px 16px 20px; }
.pied-appli a { font-size: 14px; font-weight: 400; line-height: 1.4;
  letter-spacing: var(--label-nav-track); text-transform: uppercase;
  color: var(--discret); text-decoration: none; }
.pied-appli a:hover { color: var(--ink); }

/* La planche de couverture : on la voit en entier, jamais recadree, c'est
   l'objet qu'on juge. */
.planche-couverture { max-height: none; aspect-ratio: auto; background: var(--champ);
  padding: 10px; }
.planche-couverture img { width: 100%; height: auto; object-fit: contain; }

/* Une traduction perimee : le francais a change depuis qu'elle a ete ecrite.
   Meme registre visuel qu'un bon a tirer qui ne vaut plus, c'est le meme
   mecanisme, et il doit se reconnaitre. */
.encart.bandeau.perime { display: flex; flex-wrap: wrap; align-items: baseline;
  gap: .4rem .6rem; text-align: left; }
.encart.bandeau.perime .sous { flex-basis: 100%; opacity: .7; font-size: .82em; }
.encart.bandeau.perime .lien { text-decoration: underline; }

/* La derniere question est ouverte : le champ invite a ecrire, pas a repondre
   d'un mot. Sa hauteur ne cite aucune cote du gabarit, ce n'est pas un bloc
   imprime, il n'a pas de capacite. */
.champ-ouvert { min-height: 7.5em; }

/* La couverture dans la maquette : posee AVANT la premiere page, sans folio.
   Elle s'imprime a part, sur un autre papier, la compter decalerait tous les
   folios, et la maquette mentirait sur ce qui sort. */
/* La couverture s'aligne comme toutes les autres entrées : elle n'a plus de
   vignette à centrer. */
.ligne-maquette.couverture, .ligne-maquette.calage { background: var(--off-white); }

/* Une image refusee reste SOUS LES YEUX, avec le constat a cote. La faire
   disparaitre laissait un cadre vide : on ne savait plus de quelle photo on
   parlait, ni laquelle reprendre. */
.refus-cote { display: flex; gap: 12px; align-items: flex-start; }
.apercu-refuse { width: 96px; height: 96px; object-fit: cover; border-radius: 0;
  flex: none; opacity: .85; }
.refus-dire { flex: 1; min-width: 0; }
.refus-dire p { margin: 0 0 6px; }
@media (max-width: 30rem) { .refus-cote { flex-direction: column; }
  .apercu-refuse { width: 100%; height: 160px; } }

/* ---------- commencer sans compte ---------- */

/* La troisieme porte de l'ecran d'entree. Elle est separee des deux autres par
   un filet et par du blanc : ce n'est pas une variante de « se connecter »,
   c'est un autre chemin, celui qui ne demande rien. */
.sans-compte { margin-top: 22px; padding-top: 20px; border-top: 1px solid var(--bord); }
.sans-compte .b { width: 100%; }
.sans-compte .sous { margin-top: 10px; text-align: center; }

/* Le rappel, tant que le travail n'est rattache a rien. Il porte l'aplat gris
   des apartes, pas une couleur d'alerte : il ne s'est rien passe de mal, il
   manque seulement quelque chose. */
.bandeau-invite { margin-top: 0; margin-bottom: 4px; }
.bandeau-invite .b { width: 100%; }

/* ==========================================================================
   18 quater · LA COUVERTURE
   Maquette « Anaela Couverture Atelier », la colonne de 390 px.
   L'écran large est dans `bureau.css`, d'après « Anaela Couverture Bureau ».

   LES NEUF CARACTÈRES DE TITRAGE SONT CEUX DU LIVRE, ET C'EST VOULU.

   Ils viennent de /polices, c'est-à-dire de `moteur/fonts`, les fichiers
   mêmes que WeasyPrint pose dans le PDF. Ailleurs, la typographie de la marque
   et celle du livre ne se touchent jamais ; ici elles DOIVENT coïncider, parce
   que l'aperçu mesure ses lignes dans le navigateur et que le serveur les
   mesure dans le fichier de police. Deux fichiers différents donneraient deux
   découpes, et l'écart ne se verrait qu'imprimé.
   ========================================================================== */

/* WOFF2 D'ABORD, TTF EN REPLI, et ce n'est pas le meme fichier deux fois.

   Le SERVEUR imprime avec le `.ttf`, par fontconfig. Le NAVIGATEUR, lui,
   telecharge ce qu'on lui sert, et un `.ttf` n'est pas compresse : les neuf
   faisaient 835 Ko bruts sur la ligne du client, panneau « La police » ouvert.
   Le WOFF2 est le MEME fichier dans un conteneur Brotli, memes glyphes, memes
   chasses, et pese 282 Ko. `test_couverture.py` fait mesurer au navigateur les
   fichiers que le client telecharge vraiment, et compare a ce que le PDF
   imprime : la mise en page ne peut pas diverger d'un format a l'autre.

   `font-display: block` : le texte reste invisible le temps du chargement, il
   ne s'affiche PAS dans une police de secours. C'est voulu. Une couverture
   composee dans la mauvaise police n'est pas la meme couverture, corps et
   decoupe en lignes changent, et la montrer une seconde puis la voir sauter
   ferait douter de ce qu'on regarde. Mieux vaut un blanc court. */
@font-face { font-family: "Sorts Mill Goudy"; src: url("/polices/SortsMillGoudy-400.woff2") format("woff2"),
  url("/polices/SortsMillGoudy-400.ttf") format("truetype"); font-weight: 400; font-display: block; }
@font-face { font-family: Archivo; src: url("/polices/ArchivoExpanded-900.woff2") format("woff2"),
  url("/polices/ArchivoExpanded-900.ttf") format("truetype"); font-weight: 900; font-display: block; }
@font-face { font-family: "Bodoni Moda"; src: url("/polices/BodoniModa-700.woff2") format("woff2"),
  url("/polices/BodoniModa-700.ttf") format("truetype"); font-weight: 700; font-display: block; }
@font-face { font-family: Cinzel; src: url("/polices/Cinzel-700.woff2") format("woff2"),
  url("/polices/Cinzel-700.ttf") format("truetype"); font-weight: 700; font-display: block; }
@font-face { font-family: Anton; src: url("/polices/Anton-400.woff2") format("woff2"),
  url("/polices/Anton-400.ttf") format("truetype"); font-weight: 400; font-display: block; }
@font-face { font-family: "Abril Fatface"; src: url("/polices/AbrilFatface-400.woff2") format("woff2"),
  url("/polices/AbrilFatface-400.ttf") format("truetype"); font-weight: 400; font-display: block; }
@font-face { font-family: "Instrument Serif"; src: url("/polices/InstrumentSerif-400.woff2") format("woff2"),
  url("/polices/InstrumentSerif-400.ttf") format("truetype"); font-weight: 400; font-display: block; }
@font-face { font-family: "Alfa Slab One"; src: url("/polices/AlfaSlabOne-400.woff2") format("woff2"),
  url("/polices/AlfaSlabOne-400.ttf") format("truetype"); font-weight: 400; font-display: block; }
@font-face { font-family: Syne; src: url("/polices/Syne-800.woff2") format("woff2"),
  url("/polices/Syne-800.ttf") format("truetype"); font-weight: 800; font-display: block; }

.corps-couverture { padding: 0 0 8px; }

/* ---------- la face ----------
   Tout y est posé en absolu, en pixels calculés par le moteur. C'est le seul
   endroit de la feuille où une position ne vient pas d'ici : elle vient d'un
   millimètre multiplié par une échelle, et la changer ici mentirait sur ce
   qui s'imprime. */
/* AUCUNE REGLE FOURRE-TOUT SUR LES ENFANTS DE `.cv-face`.

   `.cv-face > span { display: block }` pesait plus lourd qu'une simple classe :
   il ecrasait le `display: flex` de l'embleme, qui perdait son centrage, et
   le `display: none` du trait de rogne, qui se montrait sur les sept
   couvertures de l'ecran. Chaque part se nomme donc elle-meme, et rien ne peut
   plus en ecraser une autre par accident. */
.cv-face { position: relative; overflow: hidden; display: block; }
.cv-titre, .cv-surtitre, .cv-sous-titre, .cv-marque {
  position: absolute; display: block; z-index: 3; }
.cv-titre { white-space: pre-line; }
.cv-surtitre { letter-spacing: .19em; white-space: nowrap; }
.cv-sous-titre { letter-spacing: .2em; white-space: nowrap; }
.cv-marque { white-space: nowrap; }
.cv-embleme { position: absolute; left: 0; right: 0; display: flex;
  align-items: center; justify-content: center; }
/* Le trait de rogne ne se montre pas : il ne sert qu'a la fabrication, et
   quelqu'un qui compose une couverture n'a pas a voir ses reperes d'atelier.
   Il reste dans le balisage, c'est la meme face que celle du controle. */
.cv-rogne { position: absolute; border: 1px dashed rgba(255,255,255,.45);
  pointer-events: none; z-index: 4; display: none; }

/* ---------- les six propositions ---------- */
.cv-propositions { padding: 16px 0 0; }
.cv-legende { font-family: var(--font-text); font-weight: 400; font-size: 14px;
  line-height: 1.35; letter-spacing: .16em; text-transform: uppercase;
  color: var(--encre); }
.cv-legende-ligne { display: flex; align-items: baseline;
  justify-content: space-between; gap: 12px; padding: 0 16px; }
.cv-autre, .cv-reparer, .cv-recommande {
  padding: 0; border: 0; background: transparent; font-family: var(--font-text);
  font-weight: 400; font-size: 14px; line-height: 1.35; letter-spacing: .14em;
  text-transform: uppercase; white-space: nowrap; cursor: pointer; }
.cv-autre { letter-spacing: .16em; color: var(--discret);
  border-bottom: 1px solid var(--desactive); }
.cv-autre:hover { color: var(--encre); border-color: var(--encre); }
.cv-reparer { color: var(--encre); border-bottom: 1px solid var(--encre); }
.cv-recommande { padding: 8px 12px; border: 1px solid var(--encre); color: var(--encre); }
.cv-recommande:hover { background: var(--encre); color: #fff; }

.cv-rail { margin-top: 10px; padding: 0 16px 4px; display: flex; gap: 10px;
  overflow-x: auto; }
.cv-vignette { flex: none; border: 1px solid var(--bord);
  background: transparent; padding: 5px; display: flex; flex-direction: column;
  gap: 6px; text-align: left; cursor: pointer; }
.cv-vignette.choisie { border-color: var(--encre); background: var(--champ); }
.cv-axe { display: block; max-width: 128px; font-family: var(--font-text);
  font-weight: 400; font-size: 14px; line-height: 1.35; letter-spacing: .12em;
  text-transform: uppercase; color: var(--texte);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- l'aperçu, les alertes, les onglets ----------
   Collants sous l'en-tête : on règle en bas de l'écran et on regarde en haut.
   Les perdre de vue en faisant défiler les réglages rendrait l'écran aveugle. */
.cv-collant { position: sticky; top: 57px; z-index: 20; background: var(--g0); }
.cv-scene { padding: 14px 16px 0; }
.cv-legende-apercu { display: none; }
.cv-cadre { background: var(--champ); padding: 12px; display: flex;
  justify-content: center; overflow: hidden;
  height: calc(var(--cv-h) * var(--cv-reduit) * 1px + 24px); }
.cv-zoom { transform: scale(var(--cv-reduit)); transform-origin: top center; }
.cv-zoom .cv-face { box-shadow: 0 2px 10px rgba(0,0,0,.16); }

.cv-alertes { display: flex; flex-direction: column; gap: 8px; }
.cv-alertes:not(:empty) { margin-top: 12px; }
.cv-alerte { display: flex; align-items: flex-start; gap: 12px;
  background: var(--champ); border-left: 2px solid var(--encre);
  padding: 11px 13px; }
.cv-alerte > span { flex: 1; font-family: var(--font-text); font-weight: 300;
  font-size: 14px; line-height: 1.5; color: var(--encre); }
.cv-alerte .cv-reparer { flex: none; }

.cv-onglets { display: flex; margin: 14px 16px 0; border: 1px solid var(--encre); }
.cv-onglets button { flex: 1; padding: 10px 3px; border: 0;
  border-right: 1px solid var(--bord); background: transparent;
  color: var(--texte); font-family: var(--font-text); font-weight: 400;
  font-size: 14px; line-height: 1.35; letter-spacing: .1em;
  text-transform: uppercase; cursor: pointer; }
.cv-onglets button:last-child { border-right: 0; }
.cv-onglets button.choisi { background: var(--encre); color: #fff; }

/* ---------- les panneaux ---------- */
.cv-panneau { padding: 18px 16px 0; }
.cv-panneau .cv-legende-ligne { padding: 0; }
.cv-compteur { margin: 10px 0 0; font-family: var(--font-text); font-weight: 300;
  font-size: 14px; line-height: 1.55; color: var(--discret); }
.cv-compteur.alerte { color: var(--encre); }

.cv-champ { width: 100%; border: 0; background: transparent;
  border-bottom: 1px solid var(--bord); color: var(--encre);
  outline: none; font-family: var(--font-text); }
.cv-champ-surtitre { margin-top: 12px; padding: 0 0 8px; font-weight: 400;
  font-size: 14px; line-height: 1.35; letter-spacing: .18em;
  text-transform: uppercase; }
.cv-champ-titre { margin-top: 14px; padding: 0 0 9px;
  border-bottom-color: var(--encre); font-family: var(--font-display);
  font-weight: 400; font-size: 19px; line-height: 1.15; text-transform: uppercase; }
.cv-champ-sous-titre { margin-top: 12px; padding: 0 0 8px; font-weight: 300;
  font-size: 16px; line-height: 1.3; }

/* LES MOTS PROPOSÉS, SOUS LEUR CHAMP.
 *
 * Ils s'enroulent au lieu de défiler : le rail horizontal des vignettes marche
 * pour des images, qu'on reconnaît du coin de l'œil, mais un titre se LIT, et
 * la moitié d'un titre qui sort du cadre ne se lit pas. On accepte donc que la
 * rangée prenne deux lignes.
 *
 * Le contour reste clair et le texte discret tant que rien n'est choisi : ce
 * sont des suggestions posées sous un champ, pas la décision de l'écran. Celle
 * qui est prise s'encre, comme la police et l'aplat le font au-dessus. */
.cv-mots { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.cv-mot { border: 1px solid var(--bord); background: transparent;
  padding: 6px 10px; cursor: pointer; color: var(--discret);
  font-family: var(--font-text); font-weight: 400; font-size: 14px;
  line-height: 1.3; text-align: left; }
.cv-mot:hover { background: var(--champ); color: var(--encre); }
.cv-mot.choisi { border-color: var(--encre); background: var(--encre);
  color: var(--text-on-dark); }

.cv-polices { display: flex; flex-direction: column; margin-top: 10px; }
.cv-police { border: 0; border-top: 1px solid var(--bord);
  padding: 13px 0; display: flex; align-items: center; gap: 12px;
  background: transparent; text-align: left; cursor: pointer; }
.cv-police:hover { background: var(--champ); }
.cv-police.choisie { background: var(--champ); }
.cv-coche { flex: none; width: 14px; text-align: center; font-family: var(--font-text);
  font-size: 14px; line-height: 1; color: var(--encre); }
.cv-echantillon { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap;
  text-overflow: ellipsis; line-height: 1.15; color: var(--encre); }
.cv-tag { flex: none; font-family: var(--font-text); font-weight: 400;
  font-size: 14px; line-height: 1.35; letter-spacing: .14em;
  text-transform: uppercase; color: var(--discret); white-space: nowrap; }

/* ---------- la couleur ----------
   La palette montre l'emblème DANS son encre : ce qu'on choisit est un couple,
   pas une couleur. Une pastille nue ne dit pas ce que ça donnera. */
.cv-familles { display: flex; flex-direction: column; gap: 14px; margin-top: 12px; }
.cv-famille-nom { font-family: var(--font-text); font-weight: 300; font-size: 14px;
  line-height: 1.4; color: var(--discret); }
.cv-aplats { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 8px; }
.cv-aplat { width: 50px; height: 50px; border: 0; outline-offset: 2px;
  display: flex; align-items: center; justify-content: center; cursor: pointer; }
.cv-aplat.choisi { outline: 2px solid var(--encre); }

.cv-ligne { display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 13px 0; border: 0; border-top: 1px solid var(--bord);
  background: transparent; text-align: left; cursor: pointer; }
.cv-familles + .cv-ligne { margin-top: 16px; }
.cv-ligne-nom { flex: 1; font-family: var(--font-text); font-weight: 300;
  font-size: 16px; line-height: 1.3; color: var(--encre); }
.cv-ligne-nom.sous { font-size: 14px; color: var(--texte); }
.cv-ligne input[type=color] { flex: none; width: 44px; height: 28px;
  padding: 0; border: 1px solid var(--bord);
  background: var(--g0); cursor: pointer; }
.cv-etat { flex: none; font-family: var(--font-text); font-weight: 400;
  font-size: 14px; line-height: 1.35; letter-spacing: .14em;
  text-transform: uppercase; color: var(--discret); }
.cv-etat.reprise { color: var(--encre); }
.cv-echantillon-raye { flex: none; width: 44px; height: 26px;
  border: 1px solid var(--bord); }

.cv-interrupteur { flex: none; position: relative; width: 38px; height: 20px;
  background: var(--bord); display: block; }
.cv-interrupteur > span { position: absolute; top: 2px; left: 2px; width: 17px;
  height: 16px; background: var(--encre); display: block; }
.cv-interrupteur.actif > span { left: 19px; }

/* ---------- l'emblème ---------- */
.cv-emblemes { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.cv-choix-embleme { width: 74px; height: 74px; border: 1px solid var(--bord);
  background: transparent; display: flex; align-items: center;
  justify-content: center; color: var(--encre); cursor: pointer; }
.cv-choix-embleme:hover, .cv-choix-embleme.choisi { border-color: var(--encre); }
.cv-choix-embleme.choisi { background: var(--champ); }
.cv-sans { padding: 6px; font-family: var(--font-text); font-weight: 400;
  font-size: 14px; line-height: 1.4; letter-spacing: .12em;
  text-transform: uppercase; color: var(--texte); text-align: center; }

/* ---------- les réglages ----------
   Chaque valeur dit si elle est CALCULÉE ou REPRISE, et toute valeur reprise
   porte le bouton qui la rend au calcul. C'est ce qui permet de tout essayer
   sans jamais rester coincé. */
.cv-mesures { display: flex; flex-wrap: wrap; gap: 6px 14px;
  font-family: var(--font-text); font-weight: 400; font-size: 14px;
  line-height: 1.35; letter-spacing: .12em; text-transform: uppercase;
  color: var(--discret); }
.cv-mesures-apercu { display: none; }
.cv-mesures-reglages { margin-bottom: 16px; }

.cv-segment { margin-top: 16px; }
.cv-groupe { margin-top: 20px; }
.cv-groupe-nom { padding-top: 12px; border-top: 1px solid var(--bord);
  font-family: var(--font-text); font-weight: 400; font-size: 14px;
  line-height: 1.35; letter-spacing: .16em; text-transform: uppercase;
  color: var(--desactive); }
.cv-curseur { margin-top: 14px; }
.cv-curseur-tete { display: flex; align-items: baseline;
  justify-content: space-between; gap: 10px; }
.cv-curseur-nom { font-family: var(--font-text); font-weight: 300; font-size: 14px;
  line-height: 1.4; color: var(--encre); }
.cv-curseur-droite { display: flex; align-items: baseline; gap: 10px; }
.cv-valeur { font-family: var(--font-text); font-weight: 300; font-size: 14px;
  line-height: 1.4; color: var(--discret); font-variant-numeric: tabular-nums; }
.cv-valeur.reprise { color: var(--encre); }
.cv-curseur input[type=range] { width: 100%; margin-top: 6px;
  accent-color: var(--encre); }
.cv-choix-segment { display: flex; margin-top: 8px;
  border: 1px solid var(--bord); }
.cv-choix-segment button { flex: 1; padding: 9px 4px; border: 0;
  border-right: 1px solid var(--bord); background: transparent;
  color: var(--texte); font-family: var(--font-text); font-weight: 400;
  font-size: 14px; line-height: 1.35; letter-spacing: .12em;
  text-transform: uppercase; cursor: pointer; }
.cv-choix-segment button:last-child { border-right: 0; }
.cv-choix-segment button.choisi { background: var(--encre); color: #fff; }

/* « Première · dos · quatrième » : un repère de fabrication. Il n'a pas de
   place sur un téléphone, où l'aperçu occupe déjà le haut de l'écran. */
.cv-faces { display: none; }

/* ==========================================================================
   L'ÉDITEUR DE RECETTE, les quatre temps du téléphone

   Les quatre sont RENDUS, un seul se voit. C'est ce qui permet à l'écran large
   de les mettre tous à plat sans qu'un second balisage existe : voir la fin de
   `bureau.css`, « L'éditeur bureau n'a pas d'onglets ».

   Le rail, la photo, puis la page du livre, n'est pas un rail ici : c'est le
   quatrième temps, et il s'affiche à sa place dans la suite.
   ========================================================================== */
.corps-recette .temps { display: none; }
.corps-recette[data-rang="1"] .temps[data-temps="1"],
.corps-recette[data-rang="2"] .temps[data-temps="2"] { display: block; }
/* Le titre du rail double le nom de l'onglet : « 4 · PHOTO » est déjà au-dessus. */
.corps-recette .rail-titre { display: none; }
/* L'action est dans le pied, sur un téléphone : c'est là que la maquette
   mobile la pose, avec « Retour » à côté. */
.recette-tete { display: none; }
/* L'esquisse de la page imprimée n'est pas sur la maquette mobile, il n'y a
   pas la place, et une page de livre réduite à 358 px ne se lit pas. */
.rail-page { display: none; }

/* ==========================================================================
   19 · LA CAISSE, « Anaela Checkout Bureau », à la largeur d'un téléphone

   La maquette de caisse est dessinée à 1440 px. Elle ne pose pourtant qu'UNE
   mise en page : une colonne étroite, centrée, dont tout le reste découle,
   l'en-tête de tunnel, les sections au filet, le récapitulatif en lignes, le
   total en Abril, les accords dans un cadre. Sur un téléphone cette colonne
   occupe l'écran ; sur un ordinateur elle se pose au milieu, à 760 px. C'est
   la SEULE différence, et c'est pour cela que la caisse tient en deux feuilles
   au lieu de deux écrans : voir la fin de `bureau.css`.

   Les corps écrits ici sont ceux du téléphone. Ceux de la maquette, 52 px de
   titre, 17 px de chapô, 40 px de total, sont dans `bureau.css`, à leur
   bascule. Écrire les grands ici et les rapetisser ensuite aurait fait un
   écran large déguisé en téléphone.
   ========================================================================== */

/* ---------- l'en-tête d'un tunnel ---------- */
/* Ni chevron ni avatar : la marque, un point, l'étape, et une sortie nommée à
   l'autre bout. Les quatre tiennent sur une ligne à 1440 px, pas à 390 : le
   nom de l'étape passe donc SOUS la marque, et la sortie garde la première
   ligne. C'est la sortie qu'on cherche en hésitant devant un paiement, la
   couper en « … » ou la réduire à un chevron rendrait la caisse sans porte. */
.tete.tunnel .tete-ligne { flex-wrap: wrap; gap: 10px; }
.tete.tunnel .marque { font-size: 18px; letter-spacing: .12em; }
.tete.tunnel .tete-point { display: none; }
.tete.tunnel .tete-etape { order: 3; flex: 0 0 100%; }
.tete-point { flex: none; width: 3px; height: 3px; background: var(--grey-300); }
.tete-etape { font-family: var(--font-text); font-weight: 500; font-size: 14px;
  letter-spacing: var(--label-cta-track); text-transform: uppercase;
  color: var(--encre); min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.vt-sortie { flex: none; background: transparent; border: 0; padding: 6px 0;
  font-family: var(--font-text); font-weight: 400; font-size: 14px;
  letter-spacing: var(--label-nav-track); text-transform: uppercase;
  color: var(--libelle); white-space: nowrap; }
.vt-sortie:hover, .vt-sortie:focus { color: var(--encre); }

/* ---------- la colonne ---------- */
.vt-corps { padding: 0 22px 28px; }

/* ---------- l'ouverture ---------- */
.vt-ouverture { padding: 26px 0 24px; border-bottom: 1px solid var(--bord);
  text-align: center; }
.vt-ouverture .surtitre { letter-spacing: var(--label-track); }
.vt-titre { font-family: var(--font-display); font-weight: 400;
  font-size: clamp(26px, 8vw, 34px); line-height: 1.06; text-transform: uppercase;
  text-wrap: balance; margin: 16px 0 0; }
.vt-lead { max-width: 30em; margin: 14px auto 0; font-family: var(--font-text);
  font-weight: 300; font-size: 16px; line-height: 1.7; color: var(--texte);
  text-wrap: pretty; }

/* ---------- ce qui empêche ---------- */
/* La maquette n'a pas cet état, elle ne connaît que la caisse qui aboutit.
   Elle a en revanche l'aplat gris, qu'elle réserve à ce qui se règle sur
   place. C'est ce vocabulaire-là qui est repris, et pas une couleur d'alerte
   que la charte n'a pas. */
.vt-avis { background: var(--champ); padding: 18px 18px 20px; margin-top: 24px; }
.vt-avis-nom { display: flex; align-items: baseline; gap: 10px;
  font-family: var(--font-text); font-weight: 400; font-size: 14px;
  letter-spacing: var(--label-nav-track); text-transform: uppercase;
  color: var(--encre); }
.vt-avis-compte { margin-left: auto; font-size: 14px; color: var(--discret); }
.vt-avis-texte { margin: 9px 0 0; font-family: var(--font-text); font-weight: 300;
  font-size: 14px; line-height: 1.65; color: var(--texte); }
.vt-bloquante { display: flex; align-items: center; gap: 12px;
  padding: 12px 0 0; margin-top: 12px; border-top: 1px solid var(--bord); }
.vt-bloquante-nom { flex: 1; min-width: 0; font-family: var(--font-text);
  font-weight: 300; font-size: 16px; line-height: 1.4; }
.vt-bloquante-nom .sous { display: block; margin-top: 4px; }

/* ---------- l'article ---------- */
/* La vignette et le texte côte à côte, comme la maquette : empilés, la
   couverture devient une illustration de haut de page et cesse d'être ce
   qu'on achète. C'est la PREMIÈRE seule, comme sur la maquette et comme sur
   les cartes de « Mes livres », la planche à trois faces est l'objet de
   l'atelier de couverture, pas la vignette d'un article.

   Pas de filet en bas : la section suivante ouvre par le sien, et deux filets
   à soixante pixels l'un de l'autre avec du blanc entre les deux se lisent
   comme une case vide. La maquette les a tous les deux parce qu'elle glisse
   son compteur d'exemplaires dans cet intervalle. */
.vt-article { display: flex; gap: 16px; align-items: flex-start;
  padding: 24px 0 0; }
.vt-vignette { width: 104px; }
.vt-article-corps { min-width: 0; }
.vt-article-nom { font-family: var(--font-text); font-weight: 400; font-size: 16px;
  line-height: 1.3; }
.vt-article-texte { margin: 8px 0 0; font-family: var(--font-text);
  font-weight: 300; font-size: 16px; line-height: 1.65; color: var(--texte);
  text-wrap: pretty; }
.vt-prix { display: flex; align-items: baseline; gap: 10px; margin-top: 14px; }
.vt-prix-valeur { font-family: var(--font-display); font-weight: 400;
  font-size: 22px; line-height: 1; }
.vt-prix-mention { font-family: var(--font-text); font-weight: 400; font-size: 14px;
  letter-spacing: var(--label-nav-track); text-transform: uppercase;
  color: var(--discret); }
.vt-lien { display: inline-block; margin-top: 14px; }

/* ---------- le compteur d'exemplaires ---------- */
/* L'aplat gris de la maquette : ce qui se RÈGLE, par opposition à ce qui se
   lit. C'est le seul réglage de la caisse, et le seul endroit de l'écran qui
   ne soit ni blanc ni bordé.

   Le nombre est en Abril, comme le total : c'est le même chiffre, vu à deux
   moments, celui qu'on choisit, et celui qu'on paie. */
.vt-compteur { display: flex; align-items: center; justify-content: space-between;
  gap: 18px; margin-top: 26px; padding: 16px 16px; background: var(--champ); }
.vt-compteur-mots { min-width: 0; }
.vt-compteur-nom { font-family: var(--font-text); font-weight: 400; font-size: 14px;
  letter-spacing: var(--label-nav-track); text-transform: uppercase;
  color: var(--texte); }
/* La remise du deuxième exemplaire (chantier 014, amendement du 13 septembre) :
   à l'encre et au poids, comme le reste de ce que la charte met en avant,
   elle n'a pas de couleur pour distinguer, seulement le poids. */
.vt-remise { margin-top: 6px; font-family: var(--font-text); font-weight: 600;
  font-size: 14px; line-height: 1.4; color: var(--ink); }
.vt-compteur-sous { margin-top: 6px; font-family: var(--font-text);
  font-weight: 300; font-size: 14px; line-height: 1.5; color: var(--discret); }
.vt-pas { flex: none; display: flex; align-items: center;
  border: 1px solid var(--desactive); background: #fff; }
.vt-pas-b { width: 42px; height: 42px; border: 0; background: transparent;
  font-family: var(--font-text); font-weight: 300; font-size: 18px; line-height: 1;
  color: var(--texte); }
.vt-pas-b:hover:not([disabled]), .vt-pas-b:focus:not([disabled]) { color: var(--ink); }
/* Une borne atteinte se voit, elle ne se devine pas au clic sans effet. */
.vt-pas-b[disabled] { color: var(--desactive); cursor: not-allowed; }
.vt-pas-valeur { width: 44px; text-align: center; font-family: var(--font-display);
  font-weight: 400; font-size: 18px; line-height: 1; }

/* ---------- l'adresse ---------- */
/* Deux colonnes dès le téléphone : « Code postal » et « Ville » vont ensemble,
   et les empiler ferait six champs pleine largeur là où l'on remplit une
   étiquette. L'adresse et le courriel, eux, traversent, ce sont les deux qui
   se coupent mal. */
.vt-formulaire { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px; margin-top: 16px; }
.vt-champ { display: block; min-width: 0; }
.vt-champ.pleine { grid-column: 1 / -1; }
.vt-champ-nom { display: block; font-family: var(--font-text); font-weight: 400;
  font-size: 14px; letter-spacing: var(--label-nav-track);
  text-transform: uppercase; color: var(--discret); }
/* Sans cadre, sur un aplat : la charte ne pose pas de boîte autour d'une
   saisie, elle pose un fond. Le liseré n'apparaît qu'au focus. */
.vt-saisie { width: 100%; margin-top: 9px; padding: 13px 14px; border: 0;
  background: var(--champ); font-family: var(--font-text); font-weight: 300;
  font-size: 16px; line-height: 1.3; color: var(--encre); }
.vt-saisie:focus { outline: 1px solid var(--encre); outline-offset: -1px; }
.vt-saisie::placeholder { color: var(--desactive); opacity: 1; }

/* ---------- le délai annoncé ---------- */
.vt-delai { display: flex; align-items: flex-start; gap: 12px; margin-top: 18px; }
.vt-puce { flex: none; width: 3px; height: 3px; margin-top: 9px;
  background: var(--desactive); }
.vt-delai p { margin: 0; font-family: var(--font-text); font-weight: 300;
  font-size: 14px; line-height: 1.7; color: var(--texte); text-wrap: pretty; }
.vt-delai p + p { margin-top: 6px; }
.vt-encre { color: var(--encre); }

/* ---------- une section ---------- */
/* Le filet est EN HAUT, pas en bas : c'est lui qui ouvre la section, et le
   surtitre se pose dessous. Une section qui se ferme par un filet laisse la
   dernière de la page ouverte. */
.vt-section { margin-top: 30px; padding-top: 24px; border-top: 1px solid var(--bord); }
.vt-section .surtitre { letter-spacing: var(--label-track); }

.vt-lignes { margin-top: 12px; }
.vt-ligne { display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; padding: 12px 0; border-bottom: 1px solid var(--bord); }
/* Sauf la dernière d'une section qui se termine par sa liste : son filet
   doublerait celui de la section suivante. Là où la liste est suivie du total
  , le prix, le filet reste, et c'est lui qui porte le total. */
.vt-section > .vt-lignes:last-child > .vt-ligne:last-child { border-bottom: 0; }
.vt-ligne-nom { font-family: var(--font-text); font-weight: 300; font-size: 16px;
  line-height: 1.5; color: var(--texte); }
.vt-ligne-valeur { flex: none; max-width: 55%; font-family: var(--font-text);
  font-weight: 300; font-size: 16px; line-height: 1.5; text-align: right;
  color: var(--encre); }

.vt-total { display: flex; align-items: flex-end; justify-content: space-between;
  gap: 16px; padding-top: 18px; }
.vt-total-nom { font-family: var(--font-text); font-weight: 500; font-size: 14px;
  letter-spacing: var(--label-cta-track); text-transform: uppercase; }
.vt-total-valeur { white-space: nowrap; font-family: var(--font-display);
  font-weight: 400; font-size: 30px; line-height: 1; }

.vt-note { margin: 14px 0 0; font-family: var(--font-text); font-weight: 300;
  font-size: 14px; line-height: 1.65; color: var(--texte); text-wrap: pretty; }
.vt-note b { font-weight: 400; color: var(--encre); }
.vt-note-alerte { color: var(--encre); }

/* ---------- le code de parrainage (chantier 014, ticket F) ---------- */
/* Un champ discret, entre le détail et le Total TTC : ni cadre ni couleur
   d'appel, la charte réserve ça au bouton principal de la barre d'action. */
.vt-code-parrainage { display: flex; align-items: flex-end; gap: 10px;
  margin-top: 14px; }
.vt-code-parrainage .vt-champ { flex: 1; min-width: 0; }
.vt-code-parrainage .vt-note { flex-basis: 100%; margin-top: 8px; }
.vt-code-parrainage-actif { display: flex; align-items: center;
  justify-content: space-between; gap: 12px; margin-top: 14px;
  font-family: var(--font-text); font-weight: 300; font-size: 16px;
  color: var(--encre); }

/* ---------- le code du parrain, sur « Ma commande » (lot 2) ---------- */
/* Le seul endroit où ce code est montré à son propriétaire : assez grand
   pour se lire et se dicter au téléphone, sans le poids du titre d'écran. */
.parrainage-code { margin-top: 6px; font-family: var(--font-display);
  font-weight: 400; font-size: 22px; letter-spacing: .02em; color: var(--encre); }

/* ---------- les deux accords ---------- */
/* Dans un cadre, et ensemble : ce sont les deux seules cases de toute
   l'application, et la loi demande qu'on les ait vues. Un <button> plutôt
   qu'une <input>, la surface entière se coche, une case de 16 px se rate. */
.vt-accords { display: grid; gap: 16px; margin-top: 16px;
  padding: 18px 16px; border: 1px solid var(--bord); }
.vt-accord { display: flex; align-items: flex-start; gap: 12px; width: 100%;
  background: transparent; border: 0; padding: 0; text-align: left;
  font-family: var(--font-text); font-weight: 300; font-size: 16px;
  line-height: 1.6; color: var(--texte); cursor: pointer; }
.vt-accord > span { flex: 1; min-width: 0; }
.vt-accord .sous { display: block; margin-top: 5px; }
.vt-case { flex: none; width: 16px; height: 16px; margin-top: 3px;
  border: 1px solid var(--desactive); background: #fff; font-style: normal;
  font-size: 14px; line-height: 14px; text-align: center; color: transparent; }
.vt-accord.choisi { color: var(--encre); }
.vt-accord.choisi .vt-case { background: var(--encre); border-color: var(--encre);
  color: #fff; }

/* ---------- « c'est parti » ---------- */
/* L'état d'après, celui que la maquette appelle « C'est parti à l'impression » :
   un carré, un titre, une phrase, le reçu. Ici c'est « ce livre est acheté »,
   et c'est la même page, il n'y a plus rien à décider. */
.vt-fait { text-align: center; padding-top: 40px; }
.vt-carre { width: 8px; height: 8px; margin: 0 auto; background: var(--encre); }
.vt-fait .vt-titre { margin-top: 20px; }
.vt-recu { margin-top: 30px; border-top: 1px solid var(--bord); text-align: left; }

/* ==========================================================================
   22 · MON COMPTE, « Anaela Compte Bureau », à la largeur d'un téléphone

   La maquette est une page d'administration à deux colonnes : un rail de
   sections collé au défilement, et les sections à droite. Sur un téléphone il
   n'y a pas deux colonnes, le rail passerait à 100 % de la largeur et
   deviendrait un sommaire de neuf lignes avant la première information.

   Il est donc REPLIÉ ici : les liens disparaissent, la déconnexion descend en
   fin de page, et les sections s'enchaînent. Elles gardent leur titre et leur
   filet à l'encre, qui sont ce qui les sépare. Le rail se déplie dans
   `bureau.css`, où il a la place que la maquette lui donne.
   ========================================================================== */

/* Qui l'on est, à côté de la marque. Sur un téléphone, la ligne passe SOUS
   elle : « Camille Berthier · 6 livres », « ANAELA », un bouton et un rond de
   30 px ne tiennent pas sur 390 px, et le nom du compte coupé en « CAMILLE
   BERTHIER · 6 … » est précisément ce qu'on venait lire. */
.tete.avec-qui .tete-ligne { flex-wrap: wrap; }
.tete-qui { order: 3; flex: 0 0 100%; font-family: var(--font-text);
  font-weight: 400; font-size: 14px; letter-spacing: var(--label-nav-track);
  text-transform: uppercase; color: var(--discret); }

.cp-corps { padding: 0 22px 40px; }

/* ---------- l'ouverture ---------- */
.cp-ouverture { max-width: 44em; padding: 24px 0 0; }
.cp-ouverture .surtitre { letter-spacing: var(--label-section-track); }
.cp-ouverture h1 { margin: 10px 0 0; font-family: var(--font-display);
  font-weight: 400; font-size: clamp(28px, 8vw, 34px); line-height: 1.05;
  text-transform: uppercase; }
.cp-lead { margin: 12px 0 0; font-family: var(--font-text); font-weight: 300;
  font-size: 16px; line-height: 1.65; color: var(--texte); text-wrap: pretty; }

/* ---------- le rail, replié ---------- */
.cp-grille { display: grid; }
.cp-rail { order: 2; margin-top: 34px; }
.cp-liens { display: none; }
.cp-panneaux { order: 1; min-width: 0; }
.cp-deconnexion { background: transparent; border: 1px solid var(--bord);
  padding: 13px 18px; font-family: var(--font-text); font-weight: 400;
  font-size: 14px; letter-spacing: var(--label-cta-track);
  text-transform: uppercase; color: var(--libelle); }
.cp-deconnexion:hover, .cp-deconnexion:focus { border-color: var(--ink);
  color: var(--ink); }

/* ---------- une section ---------- */
/* Le filet du titre est à l'ENCRE, celui des lignes au gris : c'est ce qui
   distingue « ici commence autre chose » de « ligne suivante ». */
.cp-section { margin-top: 40px; scroll-margin-top: 80px; }
.cp-tete { display: flex; align-items: flex-end; justify-content: space-between;
  gap: 18px; padding-bottom: 12px; border-bottom: 1px solid var(--encre); }
.cp-tete h2 { margin: 0; font-family: var(--font-display); font-weight: 400;
  font-size: 21px; line-height: 1.1; text-transform: uppercase; }
.cp-tete-droite { flex: none; font-family: var(--font-text); font-weight: 400;
  font-size: 14px; letter-spacing: var(--label-nav-track);
  text-transform: uppercase; color: var(--discret); text-align: right; }

.cp-note { margin: 14px 0 0; font-family: var(--font-text); font-weight: 300;
  font-size: 14px; line-height: 1.65; color: var(--texte); text-wrap: pretty; }
.cp-note-tete { margin-top: 16px; }
.cp-note-alerte { color: var(--encre); }

/* ---------- l'identité ---------- */
.cp-paire { display: grid; }
.cp-champ { padding: 16px 0; border-bottom: 1px solid var(--bord); }
.cp-champ-nom { font-family: var(--font-text); font-weight: 400; font-size: 14px;
  letter-spacing: var(--label-nav-track); text-transform: uppercase;
  color: var(--discret); }
.cp-champ-valeur { margin-top: 8px; font-family: var(--font-text);
  font-weight: 300; font-size: 16px; line-height: 1.4; word-break: break-word; }

/* ---------- une ligne « nom → valeur » ---------- */
.cp-lignes { margin-top: 6px; }
.cp-ligne { display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; padding: 13px 0; border-bottom: 1px solid var(--bord); }
.cp-ligne-nom { font-family: var(--font-text); font-weight: 300; font-size: 16px;
  line-height: 1.4; }
.cp-ligne-valeur { flex: none; max-width: 60%; text-align: right;
  font-family: var(--font-text); font-weight: 300; font-size: 14px;
  line-height: 1.4; color: var(--texte); }

/* ---------- les commandes ---------- */
/* Cinq colonnes sur la maquette. Sur un téléphone, trois rangs : la date, puis
   le livre et son montant, puis l'état et la sortie. C'est le même ordre de
   lecture, plié. */
.cp-commande { display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline; gap: 6px 14px; padding: 16px 0;
  border-bottom: 1px solid var(--bord); }
.cp-cmd-date { grid-area: 1 / 1 / 2 / 3; font-family: var(--font-text);
  font-weight: 300; font-size: 14px; color: var(--discret); }
.cp-cmd-livre { grid-area: 2 / 1 / 3 / 2; min-width: 0; }
.cp-cmd-titre { display: block; font-family: var(--font-display); font-weight: 400;
  font-size: 16px; line-height: 1.25; text-transform: uppercase; }
.cp-cmd-detail { display: block; margin-top: 5px; font-family: var(--font-text);
  font-weight: 300; font-size: 14px; line-height: 1.4; color: var(--texte); }
.cp-cmd-montant { grid-area: 2 / 2 / 3 / 3; text-align: right; white-space: nowrap;
  font-family: var(--font-text); font-weight: 300; font-size: 16px; }
.cp-cmd-etat { grid-area: 3 / 1 / 4 / 2; display: flex; align-items: center;
  gap: 9px; font-family: var(--font-text); font-weight: 400; font-size: 14px;
  line-height: 1.3; letter-spacing: var(--label-nav-track);
  text-transform: uppercase; color: var(--discret); }
.cp-cmd-etat.acquis { color: var(--encre); }
.cp-point { flex: none; width: 6px; height: 6px; background: var(--grey-300); }
.cp-cmd-etat.acquis .cp-point { background: var(--encre); }
.cp-cmd-action { grid-area: 3 / 2 / 4 / 3; background: transparent; border: 0;
  padding: 0; text-align: right; font-family: var(--font-text); font-weight: 400;
  font-size: 14px; line-height: 1.3; letter-spacing: var(--label-nav-track);
  text-transform: uppercase; color: var(--libelle); }
.cp-cmd-action:hover, .cp-cmd-action:focus { color: var(--ink); }

/* ---------- les fichiers ---------- */
.cp-fichiers { display: grid; gap: 14px; margin-top: 18px; }
.cp-fichier { display: flex; gap: 16px; align-items: flex-start; padding: 16px;
  border: 1px solid var(--bord); }
.cp-vignette { width: 56px; }
.cp-fichier-corps { min-width: 0; }
.cp-fichier-titre { font-family: var(--font-display); font-weight: 400;
  font-size: 16px; line-height: 1.2; text-transform: uppercase; }
.cp-fichier-meta { margin-top: 7px; font-family: var(--font-text);
  font-weight: 300; font-size: 14px; line-height: 1.5; color: var(--texte); }
.cp-fichier-liens { display: flex; flex-wrap: wrap; gap: 8px 16px; margin-top: 13px; }
.cp-fichier-lien { font-family: var(--font-text); font-weight: 400; font-size: 14px;
  line-height: 1.3; letter-spacing: var(--label-nav-track);
  text-transform: uppercase; color: var(--ink); text-decoration: none;
  border-bottom: 1px solid var(--ink); padding-bottom: 3px; }
.cp-fichier-lien:hover, .cp-fichier-lien:focus { color: var(--libelle);
  border-color: var(--libelle); }

/* ---------- les chiffres ---------- */
.cp-chiffres { display: flex; flex-wrap: wrap; gap: 18px 26px; margin-top: 18px; }
.cp-chiffres b { display: block; font-family: var(--font-display);
  font-weight: 400; font-size: 21px; line-height: 1; }
.cp-chiffres span { display: block; margin-top: 7px; font-family: var(--font-text);
  font-weight: 400; font-size: 14px; letter-spacing: var(--label-nav-track);
  text-transform: uppercase; color: var(--discret); }

/* ---------- par tâche ---------- */
.cp-tache { margin-top: 14px; }
.cp-tache-ligne { display: flex; align-items: baseline; gap: 10px;
  font-family: var(--font-text); font-size: 14px; }
.cp-tache-nom { flex: 1; min-width: 0; font-weight: 300; }
.cp-tache-appels { font-weight: 300; font-size: 14px; color: var(--discret); }
.cp-tache-ligne b { font-weight: 400; }
.cp-tache .jauge { margin-top: 6px; }

/* ---------- le pavé noir ---------- */
/* Ce qui fait disparaître un compte ne se range pas entre deux réglages : la
   maquette le sort du blanc et le pose sur l'encre, en fin de page. */
.cp-section-donnees { margin-top: 46px; }
.cp-pave { background: var(--encre); color: #fff; padding: 26px 22px; }
.cp-pave-surtitre { margin: 0; font-family: var(--font-text); font-weight: 400;
  font-size: 14px; letter-spacing: var(--label-track); text-transform: uppercase;
  color: var(--text-on-dark-muted); }
.cp-pave h2 { margin: 14px 0 0; max-width: 24em; font-family: var(--font-display);
  font-weight: 400; font-size: 21px; line-height: 1.15; text-transform: uppercase;
  color: #fff; text-wrap: balance; }
.cp-pave-texte { margin: 12px 0 0; max-width: 40em; font-family: var(--font-text);
  font-weight: 300; font-size: 16px; line-height: 1.7;
  color: var(--text-on-dark-muted); text-wrap: pretty; }
.cp-pave-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 22px; }
.cp-pave-b { padding: 15px 22px; border: 0; font-family: var(--font-text);
  font-weight: 500; font-size: 14px; letter-spacing: var(--label-cta-track);
  text-transform: uppercase; text-align: center; white-space: nowrap;
  transition: background var(--transition-hover), color var(--transition-hover); }
.cp-pave-b-fort { background: #fff; color: var(--encre); }
.cp-pave-b-fort:hover, .cp-pave-b-fort:focus { background: var(--grey-300); }
.cp-pave-b-vide { background: transparent; color: var(--text-on-dark-muted);
  border: 1px solid rgba(255,255,255,.35); }
.cp-pave-b-vide:hover, .cp-pave-b-vide:focus { color: #fff; border-color: #fff; }

/* Jamais d'italique dans ce qui est servi (consigne de Chloé, 7 octobre 2026). */
em, i, cite, address { font-style: normal; }

/* ==========================================================================
 * LOT 1 DES CORRECTIONS DU 7 OCTOBRE 2026 : la mise en page, d'un seul tenant.
 *
 * Ce bloc est volontairement le DERNIER de la feuille : il se lit d'un trait
 * et il l'emporte sur ce qui précède, à égalité de poids. Il porte six
 * décisions, une par ligne de la consigne de Chloé :
 *   a) aucun défilement horizontal ;
 *   b) l'écran est rempli en hauteur, zones sûres comprises, sans bande grise ;
 *   c) une seule gouttière, partout ;
 *   d) des boutons de 48 px au moins ;
 *   e) les liens légaux tiennent sur une ligne ;
 *   f) un titre ne se coupe jamais par des points de suspension.
 * ========================================================================== */
:root { --gout: 20px; }

html, body { height: auto; min-height: 100%; max-width: 100%; overflow-x: hidden; }
body { background: var(--g0); }

.appli { width: 100%; max-width: 430px; min-height: 100vh; min-height: 100dvh;
  padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right);
  overflow-x: clip; }
/* Le contenu pousse la barre d'action vers le bas de l'écran, et la barre
   garde sous elle la zone sûre de l'iPhone : jamais sous la barre de Safari. */
.appli > .corps { flex: 1 0 auto; }
.barre-action { margin-top: auto; padding-bottom: max(16px, env(safe-area-inset-bottom)); }

.tete, .tete.compacte, .barre-action { padding-left: var(--gout); padding-right: var(--gout); }
.corps { padding-left: var(--gout); padding-right: var(--gout); }
.pied-appli { padding-left: var(--gout); padding-right: var(--gout); }
.connexion { padding-left: var(--gout); padding-right: var(--gout); }
.appli * { min-width: 0; overflow-wrap: anywhere; }
.appli img, .appli textarea, .appli input, .appli select { max-width: 100%; }

/* d) des cibles de 48 px */
.b, .b-second, .b-petit, .pilule, .lien { min-height: 48px; }
.b, .b-second, .pilule { display: flex; align-items: center; justify-content: center; }
.b-petit { display: flex; align-items: center; justify-content: center; }
.retour { width: 48px; height: 48px; font-size: 24px; margin-left: -12px; }
.barre-action .secondaires { flex-wrap: wrap; }

/* e) les liens légaux : une ligne, petits, discrets */
.pied-appli { flex-wrap: nowrap; justify-content: space-between; gap: 8px;
  padding-top: 20px; padding-bottom: max(20px, env(safe-area-inset-bottom)); }
.pied-appli a { font-size: 14px; text-transform: none; letter-spacing: 0;
  white-space: nowrap; color: var(--discret); overflow-wrap: normal; }

/* f) un titre se replie sur deux lignes, il ne se coupe pas */
.tete h1, .tete h2, .tete-titre, .tete-etape, .carte-livre h3, .reprise-titre,
.titre-recette, .reprise-livre, .ouverture h1 {
  overflow: visible; text-overflow: clip; white-space: normal; }

/* g) le retour est toujours à gauche : l'action principale reste à droite */
.barre-action .secondaires { flex-direction: row; }
.barre-action .secondaires .b-retour { order: -1; }

/* i) aucun italique dans ce qui est servi */
em, i, cite, address, dfn { font-style: normal; }
.calque { padding-top: env(safe-area-inset-top); }
.calque-tete, .calque-corps, .calque-pied { padding-left: var(--gout); padding-right: var(--gout); }
.calque-pied { padding-bottom: max(16px, env(safe-area-inset-bottom)); }
.calque-tete { justify-content: flex-start; }
.deux-boutons .b-etroit { flex: none; }

/* Lot 2 : un titre d'écran d'attente en casse normale, lisible. */
.centre h2.titre-normal { text-transform: none; letter-spacing: 0; font-size: 26px; line-height: 1.15; }
.etape { font-size: 16px; }

/* ==========================================================================
 * LOT 3 : la liste des recettes. Un statut = une couleur + un mot court, et
 * un menu à trois points (Modifier, Supprimer) sur chaque ligne.
 * Les trois couleurs sont des aides de lecture ; le MOT les accompagne
 * toujours. Contraste de chaque texte sur blanc : au moins 4,5 pour 1.
 * ========================================================================== */
:root {
  --statut-completer: #8A5A00;  /* ambre : il reste à relire le texte */
  --statut-en-cours: #1F4F8F;   /* bleu : le texte est relu, la photo attend */
  --statut-prete: #1F6B3F;      /* vert : acquis */
}
.ligne-recette { position: relative; display: flex; align-items: flex-start;
  border-bottom: 1px solid var(--bord); }
.ligne-recette .carte-recette { flex: 1; border-bottom: 0; }
.statut { display: flex; align-items: center; gap: 8px; margin-top: 8px;
  font-size: 16px; font-weight: 500; line-height: 1.2; }
.statut .pastille { flex: none; width: 12px; height: 12px; border-radius: 50%;
  background: currentColor; }
.statut-completer { color: var(--statut-completer); }
.statut-en-cours { color: var(--statut-en-cours); }
.statut-prete { color: var(--statut-prete); }
.menu-points { flex: none; width: 48px; height: 48px; margin-top: 6px; margin-right: -12px;
  font-size: 24px; line-height: 1; letter-spacing: 0; color: var(--ink);
  display: grid; place-items: center; }
.menu-recette { position: absolute; right: 0; top: 52px; z-index: 40; min-width: 180px;
  background: #fff; border: var(--border-strong); display: flex; flex-direction: column; }
.menu-recette button { min-height: 48px; padding: 0 16px; text-align: left; font-size: 16px; }
.menu-recette button + button { border-top: 1px solid var(--bord); }
.menu-recette .danger { color: var(--alerte); }

/* ==========================================================================
 * LOT 4 : le parcours d'une recette en trois étapes.
 * ========================================================================== */
/* Étape 1 : quatre entrées de même niveau et de même taille. */
.entrees-saisie { display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  padding: 0 var(--gout) 4px; }
.entree { min-height: 56px; padding: 8px 12px; border: 1px solid var(--bord);
  background: #fff; font-size: 16px; font-weight: 500; text-align: center;
  display: flex; align-items: center; justify-content: center; }
.entree.actif { border-color: var(--ink); background: var(--ink); color: #fff; }

/* Étape 2 : une seule page, trois sortes de contenu. */
.corps-recette .temps[data-temps="1"] .voir-la-page { width: 100%; margin: 0 0 14px; }
.repli-entete { margin: 0 0 14px; border-top: 1px solid var(--bord); }
.repli-entete > summary { min-height: 48px; display: flex; align-items: center;
  font-size: 16px; font-weight: 500; cursor: pointer; }
.manques .manque { padding: 12px 0; border-top: 1px solid var(--bord); }
.manques .manque-question { margin: 0 0 8px; font-size: 16px; font-weight: 500; }
.choix-carre.choisi, .deux-actions .b.choisi { background: var(--ink); color: #fff; border-color: var(--ink); }

/* Étape 3 : l'image en pleine largeur, deux actions. */
.place-photo.pleine { width: 100%; height: auto; aspect-ratio: 1 / 1; object-fit: cover; }
img.place-photo.pleine { width: 100%; height: auto; aspect-ratio: auto; }
.place-photo.chargement { display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 14px; text-align: center; }
.deux-actions .b { min-height: 48px; font-size: 16px; padding: 12px; }

/* ==========================================================================
 * LOT 5 : l'assemblage en parcours guidé, et le bouton qui paraissait grisé.
 *
 * LA CAUSE DU « COMMANDER CE LIVRE » GRISÉ, lue dans cette feuille : le
 * survol et le focus d'un bouton principal le peignent en gris
 * (`--action-fill-hover`, #6E6E6E). Sur un iPhone, le survol COLLE au doigt :
 * on touche « Assembler le livre », le bouton « Commander ce livre » apparaît
 * à la même place, et il hérite du survol du toucher précédent, gris, jusqu'à
 * ce qu'on touche ailleurs ou qu'on revienne sur l'écran. Rien n'était grisé
 * (aucun `disabled`) : c'était un gris de survol. Sur un appareil tactile, le
 * survol n'existe plus.
 * ========================================================================== */
@media (hover: none) {
  .b-primaire:hover, .b-primaire:focus, .b-accent:hover, .b-accent:focus {
    background: var(--action-fill); color: var(--text-on-dark); }
  .b-contour:hover, .b-contour:focus, .b-second:hover, .b-second:focus {
    background: #fff; color: var(--ink); border-color: var(--bord); }
  .b-contour:hover, .b-contour:focus { border-color: var(--ink); }
}
.b-primaire:focus-visible, .b-contour:focus-visible, .b-second:focus-visible {
  outline: 2px solid var(--ink); outline-offset: 2px; }

/* Étapes de l'assemblage. */
.assemblage-etape { padding-top: 8px; }
.assemblage-etape h2 { font-family: var(--font-display); font-weight: 400;
  font-size: 26px; line-height: 1.15; margin: 6px 0 12px; }
.assemblage-etape p { font-size: 16px; line-height: 1.5; margin: 0 0 14px; }
.liste-chapitres { list-style: none; margin: 0 0 14px; padding: 0; }
.liste-chapitres li { padding: 12px 0; border-top: 1px solid var(--bord); font-size: 16px; }
.preparation { display: flex; align-items: center; gap: 12px; padding: 16px 0;
  font-size: 16px; font-weight: 500; }
.barre-action .secondaires .b-second { flex: 1; }
