/* ===================================================================
   style.css — feuille de style de La Mijoteuse

   Chargée APRÈS Bootstrap dans base.html. À priorité égale, la
   dernière règle lue gagne : nos personnalisations passent donc
   devant celles de Bootstrap sans avoir à forcer avec !important.

   Principe retenu : on ne réécrit pas Bootstrap, on le colore.
   Bootstrap 5.3 expose ses propres réglages sous forme de variables
   CSS (les noms commençant par --bs-). En redéfinissant ces
   variables, on change l'apparence de tous les composants d'un coup.
   =================================================================== */

/* -------------------------------------------------------------------
   1. Palette du projet

   :root désigne l'élément racine du document (<html>). Une variable
   déclarée ici est visible partout dans la feuille de style.

   On l'écrit une fois, on la réutilise ensuite avec var(--nom).
   Changer une couleur du site se fait alors à un seul endroit.

   Univers culinaire, sobre et chaleureux : terre cuite, épice, crème.

   ⚠️ Valeurs alignées sur la maquette de-rodolphe (ADR-048). Un écart
   de couleur se corrige ICI, jamais en copiant un style en ligne de
   la maquette dans un gabarit.
   ------------------------------------------------------------------- */
:root {
  --mijoteuse-terracotta:      #c0532b;
  --mijoteuse-terracotta-fonce: #9e3f1d;
  --mijoteuse-terracotta-pale: #f6e4d8;   /* fond des états actifs et survolés */
  --mijoteuse-creme:           #faf4ea;   /* fond de page */
  --mijoteuse-carte:           #fffdf9;   /* fond des cartes et panneaux */
  --mijoteuse-bordure:         #ebe0d0;   /* filets et bordures de cartes */
  --mijoteuse-brun:            #2c2521;   /* texte principal, pied de page */
  --mijoteuse-texte-doux:      #6b615a;   /* texte secondaire */
  --mijoteuse-vert-herbe:      #556247;

  /* Redéfinition d'une variable de Bootstrap : la couleur « primary »
     de tout le site devient notre terre cuite. Les .btn-primary, les
     liens et les bordures actives suivent automatiquement. */
  --bs-primary:     #c0532b;
  --bs-primary-rgb: 192, 83, 43;   /* même couleur, forme utilisée par
                                      Bootstrap pour ses transparences */
  --bs-link-color:       var(--mijoteuse-terracotta);
  --bs-link-hover-color: var(--mijoteuse-terracotta-fonce);
}

/* -------------------------------------------------------------------
   2. Réglages généraux
   ------------------------------------------------------------------- */
body {
  background-color: var(--mijoteuse-creme);
  color: var(--mijoteuse-brun);
}

/* Bootstrap ne construit .btn-primary qu'à la compilation Sass : la
   variable --bs-primary ne suffit pas à le recolorer. On le fait ici
   explicitement.

   ⚠️ LES DEUX DERNIÈRES LIGNES NE SONT PAS UN DÉTAIL.

   Bootstrap change de variable quand le bouton est désactivé : il lit
   --bs-btn-disabled-bg, et NON --bs-btn-bg. Sans elles, un bouton
   « primary » désactivé repassait au BLEU d'origine — visible sur la
   page d'accueil, dont les deux boutons portent .disabled. La couleur
   du projet semblait ne pas s'appliquer alors qu'elle s'appliquait
   partout ailleurs. */
.btn-primary {
  --bs-btn-bg:           var(--mijoteuse-terracotta);
  --bs-btn-border-color: var(--mijoteuse-terracotta);
  --bs-btn-hover-bg:           var(--mijoteuse-terracotta-fonce);
  --bs-btn-hover-border-color: var(--mijoteuse-terracotta-fonce);
  --bs-btn-active-bg:           var(--mijoteuse-terracotta-fonce);
  --bs-btn-active-border-color: var(--mijoteuse-terracotta-fonce);
  --bs-btn-disabled-bg:           var(--mijoteuse-terracotta);
  --bs-btn-disabled-border-color: var(--mijoteuse-terracotta);
}

/* 🔴 SA VARIANTE EN CONTOUR ÉTAIT RESTÉE BLEUE — 2026-10-09.

   Même piège, sur .btn-outline-primary : trois gabarits l'emploient
   (« Ajouter » du matériel, entre autres), et tous s'affichaient en
   #0d6efd. Vu sur une capture de l'atelier mobile, où il était seul de
   sa couleur. Le texte prend la terre cuite FONCÉE : 6,5 de contraste
   sur fond clair, là où la terre cuite claire n'en a que 4,6. */
.btn-outline-primary {
  --bs-btn-color:              var(--mijoteuse-terracotta-fonce);
  --bs-btn-border-color:       var(--mijoteuse-terracotta);
  --bs-btn-hover-color:        #fff;
  --bs-btn-hover-bg:           var(--mijoteuse-terracotta);
  --bs-btn-hover-border-color: var(--mijoteuse-terracotta);
  --bs-btn-active-color:        #fff;
  --bs-btn-active-bg:           var(--mijoteuse-terracotta-fonce);
  --bs-btn-active-border-color: var(--mijoteuse-terracotta-fonce);
  --bs-btn-disabled-color:        var(--mijoteuse-terracotta);
  --bs-btn-disabled-border-color: var(--mijoteuse-terracotta);
  --bs-btn-focus-shadow-rgb: 192, 83, 43;
}

/* -------------------------------------------------------------------
   3. Lien d'évitement (accessibilité)

   Il doit être invisible tant qu'on ne s'en sert pas, MAIS rester
   présent dans le document : le masquer avec display:none le
   retirerait aussi du parcours clavier, ce qui le rendrait inutile.

   On le sort donc de l'écran par le haut, et on le ramène quand il
   reçoit le focus, c'est-à-dire à la première pression sur Tab.
   ------------------------------------------------------------------- */
.skip-link {
  position: absolute;
  top: -3rem;                 /* hors de l'écran, vers le haut */
  left: 0.5rem;
  z-index: 1080;              /* au-dessus de la barre de navigation */
  padding: 0.5rem 1rem;
  background-color: var(--mijoteuse-brun);
  color: #fff;
  border-radius: 0 0 0.375rem 0.375rem;
  text-decoration: none;
  transition: top 0.15s ease-in-out;
}

.skip-link:focus {
  top: 0;                     /* il redescend et devient visible */
  color: #fff;
  outline: 3px solid var(--mijoteuse-vert-herbe);
}

/* <main> reçoit le focus via le lien d'évitement (tabindex="-1").
   Sans cette règle, certains navigateurs dessinent un contour autour
   de toute la zone de contenu, ce qui est déroutant. */
main:focus {
  outline: none;
}

/* -------------------------------------------------------------------
   4. Navigation — la colonne latérale

   ⚠️ ELLE A CHANGÉ DE NATURE le 2026-08-16 ([ADR-048](…#ADR-048)).

   C'était une barre horizontale terre cuite. C'est désormais une
   COLONNE claire à gauche, comme la maquette de référence : à dix
   entrées, une barre horizontale déborde, alors qu'une colonne les
   montre toutes en même temps et laisse voir où l'on est.

   Le balisage n'existe toujours qu'UNE fois. Sous 992 px la colonne
   redevient une barre repliable — voir la section 9.
   ------------------------------------------------------------------- */
.navbar-mijoteuse {
  background-color: var(--mijoteuse-carte);
  color: var(--mijoteuse-brun);
}

.navbar-mijoteuse .navbar-brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0;
  color: var(--mijoteuse-brun);
  font-weight: 600;
  font-size: 1.25rem;
}

/* Le carré de marque : l'unique aplat de terre cuite de la colonne.
   flex-shrink:0 l'empêche d'être comprimé quand le nom est long. */
.nav-marque-blason {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  background-color: var(--mijoteuse-terracotta);
  color: #fff;
  border-radius: 10px;
}

/* Une entrée de navigation : icône + libellé, sur toute la largeur.
   L'état courant est porté par un fond, pas par un soulignement —
   il doit se repérer d'un coup d'œil dans une liste de dix. */
.navbar-mijoteuse .nav-link {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.55rem 0.75rem;
  border-radius: 10px;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.95rem;
  font-weight: 500;
}

.navbar-mijoteuse .nav-link:hover,
.navbar-mijoteuse .nav-link:focus {
  background-color: var(--mijoteuse-creme);
  color: var(--mijoteuse-brun);
}

.navbar-mijoteuse .nav-link.active {
  background-color: var(--mijoteuse-terracotta-pale);
  color: var(--mijoteuse-terracotta-fonce);
  font-weight: 700;
}

/* .disabled est appliqué par Bootstrap aux entrées pas encore actives. */
.navbar-mijoteuse .nav-link.disabled {
  color: #a89c92;
}

/* L'icône ne porte aucune information : le libellé est toujours écrit
   à côté. Elle aide au repérage, elle ne le remplace pas. */
.nav-icone {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
}

/* -------------------------------------------------------------------
   5. Bandeau d'accueil et cartes
   ------------------------------------------------------------------- */
.hero-mijoteuse {
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 18px;
}

.hero-mijoteuse h1 {
  color: var(--mijoteuse-brun);
}

.card {
  background-color: var(--mijoteuse-carte);
  border-color: var(--mijoteuse-bordure);
  border-radius: 18px;
}

.card-title {
  color: var(--mijoteuse-terracotta-fonce);
}

/* -------------------------------------------------------------------
   5 avant. La barre de recherche

   Elle vit dans le gabarit commun, donc en haut de chaque page :
   chercher ne doit pas obliger à revenir à l'accueil.
   ------------------------------------------------------------------- */
.barre-recherche {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  /* La même largeur maximale que le .container de Bootstrap, et les
     mêmes marges : sans cela, la barre ne s'alignerait pas avec le
     contenu qu'elle surplombe. */
  width: 100%;
  max-width: 1140px;
  /* calc() reprend les marges latérales du .container de Bootstrap
     (1,5 rem de gouttière, donc la moitié de chaque côté) : sans elles,
     la barre toucherait le bord de l'écran sur mobile. */
  margin: 1.25rem auto 0;
  padding: 0.5rem 0.5rem 0.5rem 1.1rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 16px;
  /* L'ombre portée très diffuse de la maquette : elle décolle la barre
     du fond crème sans dessiner de second trait. */
  box-shadow: 0 10px 30px -24px rgba(80, 45, 20, 0.6);
}

/* ⚠️ TERRE CUITE, ET NON GRIS. C'est le seul repère de couleur de la
   barre : il désigne le champ avant même qu'on lise le texte
   d'invite. */
.barre-recherche-loupe {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  color: var(--mijoteuse-terracotta);
}

/* Le bouton reprend l'arrondi de la barre, en un peu plus serré. Le
   rayon de Bootstrap — 0,375 rem — jurerait avec des angles à 16 px. */
.barre-recherche .btn {
  flex-shrink: 0;
  padding: 0.55rem 1.4rem;
  border-radius: 12px;
  font-weight: 700;
}

/* min-width:0 laisse le champ rétrécir sous la largeur de son
   placeholder ; sans lui, la barre déborderait sur petit écran.
   La bordure est retirée : c'est la barre entière qui en porte une. */
.barre-recherche-champ {
  flex-grow: 1;
  min-width: 0;
  padding: 0.5rem 0;
  background: none;
  border: none;
  color: inherit;
  font-family: inherit;
  font-size: 1rem;
}

/* Le texte d'invite est plus clair que la saisie : sans cela, on croit
   que le champ est déjà rempli. */
.barre-recherche-champ::placeholder {
  color: var(--mijoteuse-texte-doux);
  opacity: 1;   /* Firefox l'atténue par défaut, ce qui le rend illisible */
}

.barre-recherche-champ:focus {
  outline: none;
}

/* Le focus se dessine sur la BARRE, pas sur le champ : c'est elle
   qu'on voit, et un contour sur un champ sans bordure flotterait au
   milieu de rien. */
.barre-recherche:focus-within {
  border-color: var(--mijoteuse-terracotta);
  outline: 3px solid var(--mijoteuse-terracotta-pale);
}

/* -------------------------------------------------------------------
   5 bis. Le fil de la page d'accueil

   Des cartes larges empilées, et non une grille : le fil se parcourt
   en descendant, une recette à la fois. La grille, c'est le catalogue.
   ------------------------------------------------------------------- */
.fil {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  max-width: 34rem;
}

.fil-carte {
  overflow: hidden;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 18px;
}

/* Les onglets du fil — des liens, pas des boutons : chacun est une
   adresse, qui se partage et que le retour arrière retrouve. */
.fil-onglets {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.fil-onglet {
  padding: 0.35rem 0.9rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 999px;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.9rem;
  font-weight: 600;
  text-decoration: none;
}

.fil-onglet:hover,
.fil-onglet:focus {
  border-color: var(--mijoteuse-terracotta);
  color: var(--mijoteuse-terracotta-fonce);
}

.fil-onglet.actif {
  background-color: var(--mijoteuse-terracotta);
  border-color: var(--mijoteuse-terracotta);
  color: #fff;
}

/* La photo d'un repas. display:block supprime l'espace que la ligne de
   base réserve sous une image en ligne — un filet clair sous la photo,
   à l'intérieur de la carte. */
.fil-photo {
  display: block;
  width: 100%;
  height: auto;
}

/* --- Le profil public --------------------------------------------- */
.profil-entete {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.profil-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 64px;
  height: 64px;
  background-color: #f0d6c4;
  color: var(--mijoteuse-terracotta-fonce);
  border-radius: 50%;
  font-family: "Newsreader", Georgia, serif;
  font-size: 1.75rem;
  font-weight: 600;
}

.fil-entete {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.8rem 1rem;
}

.fil-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  background-color: #f0d6c4;
  color: var(--mijoteuse-terracotta-fonce);
  border-radius: 50%;
  font-weight: 700;
}

.fil-auteur {
  font-weight: 700;
  font-size: 0.95rem;
}

.fil-etiquette {
  margin-left: auto;
  padding: 0.15rem 0.6rem;
  background-color: var(--mijoteuse-terracotta-pale);
  color: var(--mijoteuse-terracotta-fonce);
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* ⚠️ CETTE VIGNETTE N'IMITE PAS UNE PHOTO, elle dit qu'il n'y en a
   pas — l'image principale attend son ADR. Les rayures signalent une
   place réservée ; un aplat gris se lirait comme un chargement
   échoué. Le texte est repris du gabarit, en clair. */
.fil-vignette {
  display: flex;
  align-items: flex-end;
  min-height: 170px;
  margin: 0;
  padding: 0.8rem;
  background: repeating-linear-gradient(
    135deg,
    #ead3be, #ead3be 16px,
    #f1dfcc 16px, #f1dfcc 32px
  );
}

.fil-vignette span {
  padding: 0.2rem 0.55rem;
  background-color: rgba(255, 253, 249, 0.85);
  border-radius: 8px;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.78rem;
}

.fil-corps {
  padding: 1rem;
}

.fil-titre {
  margin-bottom: 0.4rem;
  font-size: 1.25rem;
}

.fil-titre a {
  color: inherit;
  text-decoration: none;
}

.fil-titre a:hover,
.fil-titre a:focus {
  text-decoration: underline;
}

.fil-description {
  margin-bottom: 0.6rem;
  color: var(--mijoteuse-texte-doux);
}

/* Les métadonnées sont séparées par un point médian dessiné en CSS :
   l'écrire dans le gabarit obligerait à savoir, à chaque élément, s'il
   est le dernier — or ils sont tous facultatifs. */
.fil-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.85rem;
}

.fil-meta span + span::before {
  content: "· ";
}

/* -------------------------------------------------------------------
   5 ter. Listes de résumé

   Une liste de liens sans puces ni retrait, séparés par un filet.
   Employée par « Mon espace », et prévue pour les autres récapitulatifs.
   ------------------------------------------------------------------- */
.liste-nue {
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
}

.ligne-resume {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--mijoteuse-bordure);
}

.ligne-resume > a {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* auto à gauche : l'étiquette est plaquée à droite, alignée d'une
   ligne à l'autre quelle que soit la longueur du titre. */
.etiquette-etat {
  flex-shrink: 0;
  margin-left: auto;
  padding: 0.1rem 0.5rem;
  background-color: var(--mijoteuse-creme);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 999px;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.72rem;
  font-weight: 700;
}

/* -------------------------------------------------------------------
   6. Pied de page
   ------------------------------------------------------------------- */
.footer-mijoteuse {
  background-color: var(--mijoteuse-brun);
  color: var(--mijoteuse-creme);
}

/* -------------------------------------------------------------------
   7. Confort de lecture et préférences système

   Certaines personnes règlent leur système pour réduire les
   animations (vertiges, troubles vestibulaires, migraines). Le
   navigateur transmet cette préférence : on la respecte en coupant
   les transitions.
   ------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .skip-link {
    transition: none;
  }
}

.counter-warning {
  color: var(--mijoteuse-terracotta);
  font-weight: 600;
}
/* ===================================================================
   style-ajouts.css — à coller À LA SUITE de style.css

   ⚠️ RIEN DE CE QUI EXISTE N'EST REDÉFINI ICI.

   Les cinq variables du projet, les surcharges --bs-* et les règles
   de .navbar-mijoteuse restent la seule source pour ce qu'elles
   couvrent. Deux endroits qui fixent la même couleur divergent
   toujours.

   Ce fichier n'ajoute que ce que le gabarit commun introduit :
   la police auto-hébergée, le menu repliable sans JavaScript, le
   compteur d'invitations, le bloc compte, les messages, et la règle
   des zones tactiles.
   =================================================================== */

/* -------------------------------------------------------------------
   8. Police auto-hébergée

   Aucun appel à un service tiers : le fichier est servi depuis static/.
   font-display:swap affiche immédiatement la police système, puis
   bascule — le texte n'est jamais invisible pendant le chargement.

   Newsreader ne sert qu'aux titres. Le corps de texte est en
   Hanken Grotesk (ADR-048), avec la pile système en secours.

   ⚠️ Hanken Grotesk est une police VARIABLE : un seul fichier couvre
   les graisses 400 à 800, le navigateur interpole entre les deux.
   D'où la plage « 400 800 » dans font-weight, là où Newsreader —
   deux fichiers figés — déclare une valeur par fichier.

   Fichiers attendus :
     static/fonts/newsreader-400.woff2
     static/fonts/newsreader-600.woff2
     static/fonts/hanken-grotesk.woff2
   ------------------------------------------------------------------- */
@font-face {
  font-family: "Newsreader";
  src: url("../fonts/newsreader-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Newsreader";
  src: url("../fonts/newsreader-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Hanken Grotesk";
  src: url("../fonts/hanken-grotesk.woff2") format("woff2");
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}

body {
  font-family: "Hanken Grotesk", system-ui, -apple-system, "Segoe UI",
    Roboto, "Helvetica Neue", Arial, sans-serif;
}

/* ⚠️ Graisse 600 imposée : la maquette titre en 500, mais Newsreader
   n'est déposée qu'en 400 et 600 (ADR-048). Sans cette règle, le 500
   par défaut de Bootstrap retomberait sur le fichier 400. */
h1, h2, h3,
.navbar-brand {
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-weight: 600;
}

/* -------------------------------------------------------------------
   9. Menu repliable — sans JavaScript

   Deux comportements, une seule liste dans le HTML :
     · sous 992 px  → barre en haut, menu dépliant
     · à partir de 992 px → COLONNE LATÉRALE, bouton masqué

   🔴 CE N'EST PLUS UN <details>, ET C'EST UNE CORRECTION DE PANNE.

   Le gabarit reposait sur un <details> auquel on appliquait
   « display: contents » au-dessus de 992 px, en comptant que ses
   enfants remonteraient dans la colonne.

   ⚠️ CELA NE MARCHE PAS. Le navigateur masque le contenu d'un <details>
   FERMÉ par sa propre feuille de style, quel que soit le « display »
   posé sur le <details>. La colonne s'affichait donc à la bonne
   largeur, ET COMPLÈTEMENT VIDE.

   🔴 AUCUN TEST NE POUVAIT LE VOIR : ils lisent le HTML, où tout était
   présent, et aucun test du projet n'exécute de CSS.

   Une case à cocher a un état que le CSS SAIT LIRE — « :checked » —,
   ce qu'un <details> ne permet pas de forcer. C'est toute la raison du
   changement, et il n'introduit aucun JavaScript.
   ------------------------------------------------------------------- */

/* ⚠️ MASQUÉE, MAIS PAS « display: none ».
   Un élément en display:none sort du parcours clavier : le menu
   deviendrait inatteignable sans souris. On la sort de l'écran en
   gardant sa boîte, comme le lien d'évitement. */
.nav-bascule {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* Le contour du focus se dessine sur le LABEL, la case étant
   invisible : sans cela, atteindre le menu au clavier ne se verrait
   nulle part. */
.nav-bascule:focus-visible + .nav-repli-bouton {
  outline: 3px solid var(--mijoteuse-terracotta);
  outline-offset: 2px;
}

/* --- Le cadre de l'application ------------------------------------
   Deux zones côte à côte sur grand écran, empilées sur mobile. Sans
   ce cadre, la colonne et le contenu ne pourraient pas se placer
   l'un à côté de l'autre. */
.app-cadre {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  min-height: 100vh;
}

/* min-width:0 est indispensable : sans lui, un élément flex refuse de
   devenir plus étroit que son contenu, et un tableau large pousserait
   la page entière en débordement horizontal. */
.app-corps {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  min-width: 0;
}

.navbar-mijoteuse .container {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* La marque est écrite après le menu dans le source — pour que le
   bouton soit atteint plus tôt au clavier — et ramenée en tête ici. */
.nav-marque {
  order: -1;
  margin-right: auto;
}

/* ⚠️ FERMÉ PAR DÉFAUT, ET SEULEMENT SOUS 992 px.
   Au-dessus, la règle du bloc @media plus bas le rouvre sans
   condition : la colonne n'a pas de bouton pour la déplier. */
.nav-repli {
  display: none;
  order: 1;
  width: 100%;
}

/* Le sélecteur « ~ » ne regarde que les frères SUIVANTS : c'est
   pourquoi l'input précède le menu dans le HTML. Les inverser
   reproduirait la panne qu'on corrige. */
.nav-bascule:checked ~ .nav-repli {
  display: block;
}

.nav-repli-bouton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  order: 1;
  width: 48px;
  height: 48px;
  cursor: pointer;
  color: var(--mijoteuse-brun);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 0.625rem;
}

/* L'icône suit l'état de la case : hamburger fermé, croix ouvert.
   ⚠️ Elle ne PORTE pas l'information — le texte masqué du label dit ce
   que fait le bouton, et il ne change pas. */
.nav-repli-icone--fermer,
.nav-bascule:checked ~ .nav-repli-bouton .nav-repli-icone--menu {
  display: none;
}

.nav-bascule:checked ~ .nav-repli-bouton .nav-repli-icone--fermer {
  display: block;
}

.nav-repli-liste {
  flex-direction: column;
  padding-top: 0.5rem;
}

@media (prefers-reduced-motion: no-preference) {
  .nav-bascule:checked ~ .nav-repli > .nav-repli-liste {
    animation: nav-deplie 0.15s ease-out;
  }
}

@keyframes nav-deplie {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

/* --- À partir de 992 px : LA COLONNE LATÉRALE ----------------------

   Le contenu est forcé visible même quand <details> est fermé. C'est
   ce qui permet de n'écrire la liste qu'une fois : le même HTML sert
   au menu dépliant du mobile et à la colonne de l'ordinateur.

   ⚠️ ON N'UTILISE PLUS « display: contents » ICI. Il était censé faire
   remonter les enfants du <details> dans la colonne ; il ne révélait
   pas leur contenu pour autant, et la colonne restait vide. Le menu
   est désormais une boîte ordinaire, simplement toujours affichée. */
@media (min-width: 992px) {
  .app-cadre {
    flex-direction: row;
  }

  .navbar-mijoteuse {
    position: sticky;
    top: 0;
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    align-self: flex-start;
    width: 264px;
    height: 100vh;
    padding: 1.25rem 0.9rem;
    border-right: 1px solid var(--mijoteuse-bordure);
    overflow-y: auto;
  }

  /* Le .container de Bootstrap impose une largeur maximale et des
     marges centrées : inadapté à une colonne, qu'il faut laisser
     occuper toute sa largeur. */
  .navbar-mijoteuse .container {
    flex-direction: column;
    align-items: stretch;
    flex-grow: 1;
    width: auto;
    max-width: none;
    padding: 0;
    gap: 0;
  }

  .nav-marque {
    margin: 0 0.25rem 1.25rem;
  }

  /* ⚠️ LE MENU EST OUVERT SANS CONDITION, et « :checked » n'est plus
     consulté : une case restée cochée sur mobile ne doit pas décider
     de l'affichage de la colonne après un simple élargissement de la
     fenêtre.

     flex + column empile la liste, le panneau du foyer et le bloc
     compte ; flex-grow permet à « margin-top: auto » du bloc compte de
     le pousser en bas de la colonne. */
  .nav-repli {
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    width: auto;
  }

  .nav-repli-bouton {
    display: none;
  }

  .nav-repli-liste {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    width: auto;
    padding-top: 0;
  }

  /* margin-top:auto pousse le bloc compte tout en bas de la colonne,
     quelle que soit la longueur de la liste. */
  .nav-compte {
    margin-top: auto;
  }
}

/* -------------------------------------------------------------------
   10. Compteur d'invitations

   Trois états, dont deux se voient ici :
     · connecté sans invitation → aucune pastille (rien à rendre)
     · connecté avec N          → la pastille porte le chiffre

   Le chiffre est écrit dans la pastille, et la phrase complète est
   lue par un texte masqué : l'information ne repose jamais sur la
   couleur seule.
   ------------------------------------------------------------------- */
.nav-compteur {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.5em;
  height: 1.5em;
  /* auto à gauche : la pastille est plaquée au bord droit de l'entrée,
     alignée avec celles des autres lignes. */
  margin-left: auto;
  padding: 0 0.4em;
  background-color: var(--mijoteuse-terracotta);
  color: #fff;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 1;
}

/* -------------------------------------------------------------------
   10 bis. Panneau du foyer

   Le vert d'herbe le distingue de la navigation : ce n'est pas une
   destination, c'est un rappel de contexte — pour qui l'on cuisine.
   ------------------------------------------------------------------- */
.nav-foyer {
  margin-top: 1rem;
  padding: 0.85rem 0.8rem 0.7rem;
  background-color: #edf0e6;
  border: 1px solid #dde4cf;
  border-radius: 14px;
}

/* Les deux intertitres sont des <h2>/<h3> pour la structure du
   document, et non des libellés décoratifs : un lecteur d'écran peut
   ainsi sauter au panneau. Leur apparence, elle, est celle d'une
   étiquette. */
.nav-foyer-titre,
.nav-foyer-soustitre {
  margin: 0 0 0.35rem;
  color: var(--mijoteuse-vert-herbe);
  font-family: inherit;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.nav-foyer-soustitre {
  margin-top: 0.8rem;
}

.nav-foyer-nom {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  padding: 0.45rem 0.6rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid #dde4cf;
  border-radius: 10px;
  font-weight: 600;
  font-size: 0.9rem;
}

.nav-foyer-autres {
  margin: 0.4rem 0 0;
  font-size: 0.78rem;
}

.nav-foyer-profils {
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav-foyer-profil > a {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.3rem;
  padding: 0.4rem 0.6rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid #dde4cf;
  border-radius: 10px;
  color: var(--mijoteuse-brun);
  font-size: 0.85rem;
  text-decoration: none;
}

.nav-foyer-profil > a:hover,
.nav-foyer-profil > a:focus {
  border-color: var(--mijoteuse-vert-herbe);
}

/* Le prénom cède la place à l'alerte plutôt que de la repousser
   hors du panneau : une contrainte alimentaire ne se tronque pas. */
.nav-foyer-prenom {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav-foyer-alerte {
  flex-shrink: 0;
  margin-left: auto;
  padding: 0.1rem 0.4rem;
  background-color: var(--mijoteuse-terracotta-pale);
  color: var(--mijoteuse-terracotta-fonce);
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
}

.nav-foyer-gerer {
  margin: 0.6rem 0 0;
  font-size: 0.8rem;
}

.nav-foyer-gerer a::after {
  content: " →";
}

/* -------------------------------------------------------------------
   11. Bloc compte

   Ni une destination de plus, ni un lien perdu dans la liste : qui
   vous êtes, et comment sortir. Un filet l'écarte de la navigation.
   ------------------------------------------------------------------- */
.nav-compte {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  margin-top: 0.75rem;
  padding: 0.4rem;
  background-color: var(--mijoteuse-creme);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 14px;
}

.nav-compte-lien {
  display: flex;
  flex-grow: 1;
  align-items: center;
  gap: 0.6rem;
  min-width: 0;
}

/* min-width:0 sur le conteneur ET overflow sur les lignes : sans le
   premier, un enfant flex refuse de rétrécir sous la largeur de son
   texte, et les points de suspension ne se déclenchent jamais. */
.nav-compte-identite {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.25;
}

.nav-compte-nom,
.nav-compte-pseudo {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav-compte-nom {
  font-size: 0.9rem;
  font-weight: 700;
}

.nav-compte-pseudo {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.78rem;
}

.nav-compte-pastille {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  background-color: #dde4cf;
  color: var(--mijoteuse-vert-herbe);
  border-radius: 50%;
  font-size: 0.9rem;
  font-weight: 700;
}

/* Le bouton de déconnexion est un vrai <button> dans un <form>. On lui
   donne l'apparence d'une icône d'action, sans en faire un lien. */
.nav-compte-sortie .nav-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  color: var(--mijoteuse-texte-doux);
  border-radius: 10px;
  text-decoration: none;
}

.nav-compte-sortie .nav-link:hover,
.nav-compte-sortie .nav-link:focus {
  background-color: var(--mijoteuse-terracotta-pale);
  color: var(--mijoteuse-terracotta-fonce);
}

/* -------------------------------------------------------------------
   12. Messages

   Le niveau est porté par un mot autant que par une couleur.
   ------------------------------------------------------------------- */
.alert-mijoteuse {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
}

.alert-mijoteuse-mot {
  flex-shrink: 0;
}

/* -------------------------------------------------------------------
   13. Zones tactiles

   ⚠️ RÈGLE UNIQUE, POSÉE AU GABARIT COMMUN.

   Sur un écran tactile, tout élément interactif fait au moins 44 px.
   Appliquée ici, elle vaut pour les 32 pages et pour celles qui
   viendront. Appliquée page par page, elle ne converge jamais —
   mesuré sur la maquette, où il a fallu cinq passes avant de la poser
   au bon endroit.

   pointer:coarse cible le doigt, pas la largeur de fenêtre : une
   fenêtre étroite sur ordinateur garde des cibles compactes, une
   tablette large les obtient.
   ------------------------------------------------------------------- */
@media (pointer: coarse) {
  .navbar-mijoteuse .nav-link,
  .navbar-mijoteuse .btn,
  main button,
  main .btn,
  main a.btn,
  main input[type="checkbox"],
  main input[type="radio"] {
    min-height: 44px;
  }

  .navbar-mijoteuse .nav-link,
  main .btn {
    display: inline-flex;
    align-items: center;
  }

  /* Une case à cocher ne s'étire pas : on agrandit sa cible en
     élargissant l'étiquette qui la précède. */
  main input[type="checkbox"],
  main input[type="radio"] {
    min-width: 24px;
    width: 24px;
    height: 24px;
  }

  main .form-check {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-height: 44px;
  }
}

/* ===================================================================
   14. Refonte de la page d'accueil — ADR-051

   ⚠️ RIEN DE CE QUI EXISTE N'EST REDÉFINI EN AMONT.

   Les variables de la palette, les surcharges --bs-* et les règles de
   .navbar-mijoteuse restent la seule source pour ce qu'elles couvrent.
   Ce fichier ne fait que passer APRÈS elles : à priorité égale, la
   dernière règle lue gagne.

   ⚠️ AUCUN TEST DU PROJET N'EXÉCUTE DE CSS. Rien ici n'est vérifié
   autrement qu'à l'œil, dans le navigateur, aux deux états de la page
   et de part et d'autre de 992 px.

   Voir ADR-051.
   =================================================================== */

/* -------------------------------------------------------------------
   14 a. LA MESURE — la correction qui compte le plus

   .fil était plafonné à 34rem dans un .container de 1140px : la moitié
   droite de la zone de contenu restait vide, et le fil semblait collé
   au bord gauche.

   Une seule mesure désormais, partagée par la barre de recherche, le
   contenu et le pied de page.

   ⚠️ LE SÉLECTEUR EST À DEUX NIVEAUX, ET C'EST NÉCESSAIRE.
   .container tient sa largeur de règles posées dans des @media de
   Bootstrap. « .app-corps .container » l'emporte par sa spécificité,
   sans avoir à rejouer chaque palier ni à forcer avec !important.
   ------------------------------------------------------------------- */
.app-corps .container {
  max-width: 41rem;
}

/* Le .container inscrit son contenu 0,75 rem à l'intérieur de ses
   bords (la moitié de la gouttière de Bootstrap). La barre, qui n'a
   pas cette gouttière, doit donc être d'autant plus étroite pour que
   les deux s'alignent bord à bord. */
.barre-recherche {
  max-width: calc(41rem - 1.5rem);
  border-radius: 14px;
}

/* Le fil n'a plus de plafond propre : il suit la mesure du conteneur.
   L'écart entre deux cartes passe de 1,25 à 1,75 rem — les cartes ont
   grandi, leur séparation doit suivre. */
.fil {
  max-width: none;
  gap: 1.75rem;
}

/* -------------------------------------------------------------------
   14 b. Newsreader 400 entre en service

   Elle est déposée et déclarée depuis l'ADR-048, et n'était employée
   nulle part : du poids téléchargé pour rien. Les titres restent en
   600, elle prend les textes de respiration.
   ------------------------------------------------------------------- */
.texte-serif {
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-weight: 400;
}

/* -------------------------------------------------------------------
   14 c. L'échelle typographique du fil
   ------------------------------------------------------------------- */
.fil-titre {
  font-size: 1.4375rem;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.fil-description {
  font-size: 0.9375rem;
  line-height: 1.6;
}

.fil-meta {
  margin-bottom: 0;
  font-size: 0.8125rem;
}

/* -------------------------------------------------------------------
   14 d. LES GRIS DE BOOTSTRAP SORTENT

   .btn-outline-secondary rend un #6c757d froid — la seule couleur
   froide du site, et elle était sur CHAQUE carte du fil par le bouton
   « Voir la recette ».

   Même méthode que .btn-primary plus haut : Bootstrap ne construit ses
   variantes qu'à la compilation Sass, ce sont donc ses variables
   --bs-btn-* qu'on redéfinit, et non la couleur directement.
   ------------------------------------------------------------------- */
.btn-outline-secondary {
  --bs-btn-color:        var(--mijoteuse-terracotta-fonce);
  --bs-btn-bg:           var(--mijoteuse-creme);
  --bs-btn-border-color: var(--mijoteuse-bordure);
  --bs-btn-hover-color:        var(--mijoteuse-terracotta-fonce);
  --bs-btn-hover-bg:           var(--mijoteuse-terracotta-pale);
  --bs-btn-hover-border-color: var(--mijoteuse-terracotta);
  --bs-btn-active-color:        var(--mijoteuse-terracotta-fonce);
  --bs-btn-active-bg:           var(--mijoteuse-terracotta-pale);
  --bs-btn-active-border-color: var(--mijoteuse-terracotta);
  --bs-btn-disabled-color:        var(--mijoteuse-texte-doux);
  --bs-btn-disabled-border-color: var(--mijoteuse-bordure);
  border-radius: 10px;
  font-weight: 600;
}

/* -------------------------------------------------------------------
   14 e. UN SEUL ÉTAT COURANT DANS TOUT LE SITE

   La colonne marquait la page courante par un fond pâle, les onglets
   par un aplat terre cuite plein. Deux transpositions faites à deux
   moments différents ; l'onglet rejoint la colonne.

   ⚠️ CETTE RÈGLE TOUCHE DEUX PAGES. .fil-onglet sert aussi à
   search/index.html (« Filtrer les résultats ») : la page de résultats
   change d'apparence dans la même livraison, et doit être vérifiée à
   l'écran. C'est voulu — la cohérence est gratuite ici.
   ------------------------------------------------------------------- */
.fil-onglets {
  gap: 0.25rem;
  margin-bottom: 2rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--mijoteuse-bordure);
}

.fil-onglet {
  padding: 0.4rem 0.85rem;
  background-color: transparent;
  border-color: transparent;
  font-weight: 500;
}

.fil-onglet:hover,
.fil-onglet:focus {
  background-color: var(--mijoteuse-creme);
  border-color: transparent;
  color: var(--mijoteuse-brun);
}

.fil-onglet.actif {
  background-color: var(--mijoteuse-terracotta-pale);
  border-color: transparent;
  color: var(--mijoteuse-terracotta-fonce);
  font-weight: 700;
}

/* -------------------------------------------------------------------
   14 f. LA COLONNE — bloc compte figé en bas

   La colonne entière défilait, bloc compte compris : sur une fenêtre
   basse, « qui je suis » et « comment sortir » disparaissaient.

   Le défilement descend d'un niveau, sur .nav-defilant (étape 3), et
   la colonne elle-même n'en a plus.

   ⚠️ SOUS 992 px RIEN NE CHANGE : la colonne est alors un menu
   dépliant dans le flux de la page, il n'y a rien à figer.
   ------------------------------------------------------------------- */
@media (min-width: 992px) {
  .navbar-mijoteuse {
    overflow: hidden;
  }

  .navbar-mijoteuse .container {
    flex-wrap: nowrap;
    min-height: 0;
  }

  /* min-height:0 est indispensable : sans lui, un enfant flex refuse
     de devenir plus court que son contenu, et c'est la colonne
     entière qui déborderait au lieu de laisser défiler l'intérieur. */
  .navbar-mijoteuse .nav-repli {
    min-height: 0;
  }

  .nav-defilant {
    flex-grow: 1;
    min-height: 0;
    overflow-y: auto;
    /* La marge négative rend au contenu la place prise par la barre
       de défilement, sans la faire chevaucher les entrées. */
    margin-right: -0.5rem;
    padding-right: 0.5rem;
  }

  /* Il n'a plus besoin de « margin-top: auto » : ce n'est plus lui
     qui pousse, c'est .nav-defilant qui occupe la place. */
  .nav-compte {
    flex-shrink: 0;
    margin-top: 0;
  }
}

/* Les intertitres de la colonne. Onze entrées à plat ne se lisent
   pas ; trois groupes se parcourent. Ce sont des <p>, pas des titres :
   ils n'ouvrent aucune section du document. */
.nav-groupe {
  margin: 1.25rem 0 0.4rem;
  padding: 0 0.7rem;
  color: #a2948a;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

/* Le premier groupe suit immédiatement la liste publique : il n'a pas
   besoin de la marge haute complète. */
.nav-repli-liste + .nav-groupe {
  margin-top: 1rem;
}

/* -------------------------------------------------------------------
   14 g. Le panneau de foyer

   ⚠️ ATTEND L'ÉTAPE 3 pour la classe du nom de foyer. La contrainte,
   elle, cesse d'être une pastille : à l'intérieur d'un panneau déjà
   coloré, une pastille de plus fait trois fonds empilés. Le mot reste
   écrit — la règle « la couleur n'est jamais le seul signal » est
   tenue par le TEXTE, comme avant.
   ------------------------------------------------------------------- */
.nav-foyer-nom {
  padding: 0;
  background: none;
  border: none;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-weight: 600;
  font-size: 1.0625rem;
}

.nav-foyer-alerte {
  padding: 0;
  background: none;
  border-radius: 0;
  font-size: 0.75rem;
  font-weight: 600;
}

.nav-foyer-profils {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.nav-foyer-profil > a {
  margin-bottom: 0;
  align-items: baseline;
  font-weight: 600;
}

/* -------------------------------------------------------------------
   14 h. Le bloc compte

   Il portait un cadre à lui dans une colonne déjà claire : un filet
   suffit à l'écarter de la navigation.
   ------------------------------------------------------------------- */
.nav-compte {
  padding: 1rem 0 0;
  background: none;
  border: none;
  border-top: 1px solid var(--mijoteuse-bordure);
  border-radius: 0;
}

.nav-compte-pseudo {
  color: #a2948a;
}

/* -------------------------------------------------------------------
   14 i. Les cartes du fil

   ⚠️ ATTEND LES CLASSES DE L'ÉTAPE 3 — .fil-categorie, .fil-pied,
   .fil-repas-texte.

   La pastille de visibilité perd la terre cuite et prend une forme
   distincte : elle ne doit pas ressembler à la catégorie, ce sont deux
   natures d'information. Le mot reste écrit dans les deux cas.
   ------------------------------------------------------------------- */
.fil-carte {
  border-radius: 16px;
}

.fil-entete {
  padding: 0.9rem 1.25rem 0.75rem;
}

.fil-avatar {
  width: 32px;
  height: 32px;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-size: 0.9375rem;
  font-weight: 600;
}

.fil-auteur a {
  color: var(--mijoteuse-brun);
  text-decoration: none;
}

.fil-auteur a:hover,
.fil-auteur a:focus {
  text-decoration: underline;
}

/* La catégorie n'est plus une pastille : du texte, à côté de
   l'auteur, précédé d'un point médian dessiné en CSS. */
.fil-categorie {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.875rem;
}

.fil-categorie::before {
  content: "· ";
  color: #d9cbba;
}

.fil-etiquette {
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 8px;
  color: var(--mijoteuse-texte-doux);
  letter-spacing: 0.06em;
}

.fil-corps {
  padding: 1.25rem;
}

/* Le texte d'un repas est un propos, pas une description de fiche :
   il prend la serif, en 400. */
.fil-repas-texte {
  margin: 0;
  color: var(--mijoteuse-brun);
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-weight: 400;
  font-size: 1.125rem;
  line-height: 1.55;
}

/* Métadonnées et bouton sur une même ligne, sous un filet. Le bouton
   pleine largeur était le geste le plus lourd de la carte, pour
   l'action la moins engageante. */
.fil-pied {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: 0.9rem;
  padding-top: 0.9rem;
  border-top: 1px solid #f2eade;
}

.fil-pied .btn {
  flex-shrink: 0;
  width: auto;
  padding: 0.45rem 0.95rem;
  font-size: 0.875rem;
}

/* La vignette d'absence de photo : rayures éclaircies, et un ratio
   fixe plutôt qu'une hauteur minimale — trois cartes à la suite
   doivent avoir la même respiration.

   ⚠️ ELLE NE DOIT TOUJOURS PAS IMITER UNE PHOTO. La mention passe en
   monospace : c'est ce qui la fait lire comme une place réservée. */
.fil-vignette {
  min-height: 0;
  aspect-ratio: 3 / 2;
  padding: 0.9rem;
  background: repeating-linear-gradient(
    135deg,
    #f2e3d3, #f2e3d3 14px,
    #f7ece0 14px, #f7ece0 28px
  );
}

.fil-vignette span {
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 7px;
  color: #8a7d72;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.6875rem;
}

/* -------------------------------------------------------------------
   14 j. L'accroche du visiteur et le pied de page

   ⚠️ ATTEND L'ÉTAPE 3 pour .principes.

   L'accroche perd son cadre : elle était une carte parmi des cartes,
   à l'endroit où la page devrait respirer. Les trois cartes
   d'argumentaire deviennent trois lignes titre/texte séparées par des
   filets — même contenu, même ordre, une hiérarchie en plus.
   ------------------------------------------------------------------- */
.hero-mijoteuse {
  padding: 4rem 0 3.5rem;
  background: none;
  border: none;
  border-bottom: 1px solid var(--mijoteuse-bordure);
  border-radius: 0;
  text-align: left;
}

.hero-mijoteuse h1 {
  max-width: 30rem;
  font-size: 3.25rem;
  line-height: 1.08;
  letter-spacing: -0.02em;
}

.hero-mijoteuse .lead {
  margin-left: 0;
  margin-right: 0;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-weight: 400;
  font-size: 1.375rem;
  line-height: 1.5;
  color: var(--mijoteuse-texte-doux);
}

.principes {
  display: grid;
  gap: 0;
}

.principes > article {
  display: grid;
  grid-template-columns: 9.5rem 1fr;
  gap: 1.5rem;
  align-items: baseline;
  padding: 1.5rem 0;
  border-bottom: 1px solid var(--mijoteuse-bordure);
}

.principes > article > h3 {
  margin: 0;
  font-size: 1.1875rem;
  line-height: 1.3;
  color: var(--mijoteuse-brun);
}

.principes > article > p {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--mijoteuse-texte-doux);
}

/* Sous 576 px, deux colonnes de 9,5 rem ne tiennent pas : le titre
   passe au-dessus de son texte. */
@media (max-width: 575.98px) {
  .principes > article {
    grid-template-columns: 1fr;
    gap: 0.5rem;
  }

  .hero-mijoteuse h1 {
    font-size: 2.25rem;
  }

  .hero-mijoteuse .lead {
    font-size: 1.125rem;
  }
}

.footer-mijoteuse {
  padding: 2rem 0;
}

.footer-mijoteuse .small {
  max-width: 34rem;
  color: #c9bba9;
  line-height: 1.6;
}

/* ===================================================================
   15. Les recettes — écrire, l'atelier, la fiche — ADR-059

   ⚠️ AUCUNE VARIABLE DE LA PALETTE NE CHANGE, sauf UNE ajoutée :
   --mijoteuse-brique, pour les actions destructrices. La palette n'avait
   rien pour cela, et le #dc3545 de Bootstrap est la seule couleur
   FROIDE du site. Voir § 15 a.

   ⚠️ AUCUN TEST DU PROJET N'EXÉCUTE DE CSS. Tout ce qui suit se vérifie
   à l'œil, aux quatre écrans et de part et d'autre de 992 px.
   =================================================================== */

/* -------------------------------------------------------------------
   15 a. Une couleur pour ce qui détruit

   🔴 LA PALETTE N'EN AVAIT PAS, et le rouge de Bootstrap était la seule
   couleur froide du site — sur « Supprimer », « Retirer », et les ✕ de
   chaque ligne d'ingrédient.

   La brique partage la famille de la terre cuite, en plus sombre et
   plus sourd : elle avertit sans jurer. Mesurée à 6,4:1 sur le fond
   crème.

   ⚠️ ELLE NE PORTE JAMAIS L'INFORMATION SEULE. Le mot est écrit, ou
   l'aria-label le dit. C'est un renfort, pas un signal.
   ------------------------------------------------------------------- */
:root {
  --mijoteuse-brique:        #a3301f;
  --mijoteuse-brique-filet:  #e8cfc6;
  /* Le filet des champs de saisie : le #dee2e6 de Bootstrap est gris
     neutre, donc froid sur un fond crème. */
  --mijoteuse-champ-filet:   #e2d6c4;
}

.btn-outline-danger {
  --bs-btn-color:        var(--mijoteuse-brique);
  --bs-btn-bg:           transparent;
  --bs-btn-border-color: var(--mijoteuse-brique-filet);
  --bs-btn-hover-color:        #fff;
  --bs-btn-hover-bg:           var(--mijoteuse-brique);
  --bs-btn-hover-border-color: var(--mijoteuse-brique);
  --bs-btn-active-bg:           var(--mijoteuse-brique);
  --bs-btn-active-border-color: var(--mijoteuse-brique);
  border-radius: 10px;
  font-weight: 600;
}

/* 🔴 PUBLIER PREND LA COULEUR PRINCIPALE, et cesse d'être verte.

   C'est l'action principale de la page : elle doit porter la couleur
   principale du site. Le vert de Bootstrap disait « validé » — un état,
   pas une action — et c'était la deuxième couleur hors palette. */
.btn-success {
  --bs-btn-bg:           var(--mijoteuse-terracotta);
  --bs-btn-border-color: var(--mijoteuse-terracotta);
  --bs-btn-hover-bg:           var(--mijoteuse-terracotta-fonce);
  --bs-btn-hover-border-color: var(--mijoteuse-terracotta-fonce);
  --bs-btn-active-bg:           var(--mijoteuse-terracotta-fonce);
  --bs-btn-active-border-color: var(--mijoteuse-terracotta-fonce);
  border-radius: 11px;
  font-weight: 600;
}

/* -------------------------------------------------------------------
   15 b. Les champs — LE POINT LE PLUS IMPORTANT DE CETTE SECTION

   🔴 L'ATELIER EST À 80 % DU TEXTE D'AIDE.

   Le § 11 du contrat impose une aide par champ, et l'atelier en compte
   douze : la page était une colonne de gris clair où les étiquettes se
   perdaient. L'aide RESTE INTÉGRALEMENT — c'est le poids visuel qui
   change de place.

     · l'étiquette prend la graisse (600) et la couleur du texte ;
     · l'aide descend à 0,8125 rem, interligne 1,55 ;
     · l'aide garde --mijoteuse-texte-doux.

   🔴 ET SURTOUT PAS PLUS CLAIR. J'avais d'abord posé un beige à
   3,9:1 — moins lisible que le .form-text de Bootstrap qu'il
   remplaçait, sur du texte que le contrat oblige à écrire. Mesurer, ne
   pas choisir à l'œil.
   ------------------------------------------------------------------- */
.form-label {
  margin-bottom: 0.4rem;
  color: var(--mijoteuse-brun);
  font-size: 0.9375rem;
  font-weight: 600;
}

.form-text {
  margin-top: 0.4rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
  line-height: 1.55;
}

.form-control,
.form-select {
  padding: 0.6rem 0.85rem;
  border-color: var(--mijoteuse-champ-filet);
  border-radius: 10px;
  color: var(--mijoteuse-brun);
}

/* Le chevron du select a besoin de sa place : Bootstrap réserve
   2,25 rem à droite, et notre padding l'écrasait. */
.form-select {
  padding-right: 2.25rem;
}

.form-control:focus,
.form-select:focus {
  border-color: var(--mijoteuse-terracotta);
  box-shadow: none;
  outline: 3px solid var(--mijoteuse-terracotta-pale);
}

.form-control::placeholder {
  color: #9c8f84;
  opacity: 1;
}

/* -------------------------------------------------------------------
   15 c. Le fil d'Ariane

   Bootstrap le rend à 1 rem, avec un « / » gris : au-dessus d'un titre
   de 2 rem, il pèse autant que lui. Il redescend, et la flèche dit le
   sens de la lecture.
   ------------------------------------------------------------------- */
.breadcrumb {
  margin-bottom: 1.25rem;
  font-size: 0.8125rem;
  --bs-breadcrumb-divider: "→";
  --bs-breadcrumb-divider-color: #c9ab93;
  --bs-breadcrumb-item-active-color: var(--mijoteuse-texte-doux);
}

.breadcrumb-item > a {
  color: var(--mijoteuse-terracotta-fonce);
  font-weight: 600;
  text-decoration: none;
}

.breadcrumb-item > a:hover {
  text-decoration: underline;
}

/* -------------------------------------------------------------------
   15 d. La mesure de l'atelier

   ⚠️ TROIS MESURES, ET CHACUNE SE JUSTIFIE.

     34 rem  un formulaire à un seul champ (écrire une recette)
     44 rem  l'atelier et la fiche — il y faut des paires de champs
     44 rem  le fil, le catalogue, la lecture

   Les colonnes de Bootstrap sont conservées dans les gabarits ; ce sont
   les conteneurs qui se resserrent.

   🔴 ET UNE LEÇON MESURÉE : à 48 rem avec des colonnes 2fr/1fr/1,2fr,
   la liste « Unité » COUPAIT « — sans unité — » et « pincée — à
   l'estime ». Les libellés viennent des tables de référence
   (FAMILY_LABELS, quinze entrées) et ne peuvent pas être raccourcis :
   c'est la colonne qui cède. « Ingrédient » passe donc seul sur sa
   ligne, « Quantité » et « Unité » se partagent la suivante.
   ------------------------------------------------------------------- */
.atelier {
  width: 100%;
  max-width: 44rem;
  margin: 0 auto;
}

.atelier-etroit {
  width: 100%;
  max-width: 34rem;
  margin: 0 auto;
}

/* Un titre de section de l'atelier, sous un filet. Cinq formulaires
   empilés sans repère se lisaient comme un seul très long formulaire. */
.atelier-section {
  margin-top: 3rem;
}

.atelier-section > h2 {
  margin-bottom: 1.25rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--mijoteuse-bordure);
  font-size: 1.375rem;
}

/* Le compte à côté du titre : « Ingrédients 3 », « Étapes aucune ».
   Il dit d'un coup d'œil ce qui manque. */
.atelier-compte {
  color: var(--mijoteuse-texte-doux);
  font-family: "Hanken Grotesk", system-ui, sans-serif;
  font-size: 0.875rem;
  font-weight: 500;
}

/* Les encadrés d'ajout. Le .border.rounded.p-3 de Bootstrap donnait un
   filet gris et un rayon de 6 px, deux fois hors système. */
.atelier-carte {
  padding: 1.25rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 14px;
}

/* ⚠️ CELUI-CI EST EN POINTILLÉS, ET C'EST UN SIGNAL.

   Créer un ingrédient remplit le référentiel COMMUN (ADR-031). Le
   formulaire ne doit pas ressembler à celui d'à côté, qui ne fait que
   choisir : le pointillé dit « autre nature de geste ». */
.atelier-carte--creation {
  padding: 1.25rem;
  background-color: var(--mijoteuse-creme);
  border: 1px dashed var(--mijoteuse-champ-filet);
  border-radius: 14px;
}

/* -------------------------------------------------------------------
   15 e. « Pour publier, il manque encore »

   🔴 C'ÉTAIT UN alert-info CYAN — #cff4fc, la couleur la plus froide
   du site, sur le message le PLUS IMPORTANT de la page.

   L'ADR-038 pose que la complétude se vérifie à la publication : ce
   bandeau est la seule chose qui empêche l'auteur de découvrir le refus
   au moment où il croit avoir fini.
   ------------------------------------------------------------------- */
.manque {
  padding: 1.1rem 1.25rem;
  background-color: var(--mijoteuse-terracotta-pale);
  border: 1px solid #ebd3c2;
  border-radius: 14px;
}

.manque-titre {
  margin-bottom: 0.5rem;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.9375rem;
  font-weight: 700;
}

.manque ul {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin: 0;
  padding: 0;
  list-style: none;
  color: #7d3b21;
  font-size: 0.9375rem;
}

/* -------------------------------------------------------------------
   15 f. Les lignes d'ingrédient et d'étape

   Le .list-group de Bootstrap rendait des lignes BLANCHES sur le fond
   crème : --bs-list-group-bg vaut --bs-body-bg, que le projet ne
   redéfinit pas (il colore body, pas la variable).

   ⚠️ LA QUANTITÉ EST EN CHIFFRES TABULAIRES, sur une colonne fixe.
   Sans cela, « 1 pièce » et « 150 g » ne s'alignent pas et la liste se
   lit ligne à ligne au lieu de se parcourir.

   ⚠️ UNE QUANTITÉ ABSENTE NE REND RIEN — « sel, poivre » sans dose est
   légitime (ADR-038). La colonne garde sa largeur, elle ne se remplit
   pas d'un tiret : le gabarit source n'écrit rien, la refonte non plus.
   ------------------------------------------------------------------- */
.lignes {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0 0 1.5rem;
  padding: 0;
  list-style: none;
}

.ligne {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0.85rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 11px;
}

.ligne-dose {
  flex-shrink: 0;
  width: 4.5rem;
  color: var(--mijoteuse-brun);
  font-size: 0.9375rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.ligne-nom {
  flex-grow: 1;
  min-width: 0;
  font-size: 0.9375rem;
}

.ligne-note {
  color: var(--mijoteuse-texte-doux);
}

/* Dans l'atelier : la durée reste sur la ligne de l'étape, le conseil
   passe dessous — il peut être long. */
.ligne-duree {
  white-space: nowrap;
  font-weight: 700;
}

.ligne-conseil,
.ligne-lies {
  display: block;
  font-size: 0.875rem;
}

/* L'en-tête d'un groupe dans l'atelier : le titre renommable en place,
   puis ses trois gestes — même rangée d'actions que les lignes. */
.groupe-entete {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1rem 0 0.5rem;
}

.groupe-renommer {
  display: flex;
  flex-grow: 1;
  min-width: 0;
  gap: 0.4rem;
}

.groupe-ajout {
  max-width: 28rem;
  margin-top: 0.5rem;
}

/* Les trois gestes d'une recette à valider, empilés — PAGE-MOD-001. La
   largeur minimale tient le motif lisible ; la charte interdit les styles
   en ligne, et un test le vérifie. */
/* La filiation d'une variante et le compteur de variantes, dans le
   bandeau de la fiche — chantier 6. */
.fiche-filiation {
  margin: 0.35rem 0 0;
  font-size: 0.9375rem;
}

/* « Créer une variante », en tête du corps de la fiche. */
.fiche-actions {
  margin: 0 0 1.25rem;
}

/* Les tags de l'auteur — ADR-089. Des pastilles sobres, comme le statut :
   ce sont des mots, pas des verdicts. */
.fiche-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0 0 1.25rem;
  padding: 0;
  list-style: none;
}

.fiche-tag {
  padding: 0.2rem 0.7rem;
  background-color: var(--mijoteuse-creme);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 999px;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
}

/* -------------------------------------------------------------------
   Mes notifications — ADR-091. « Non lue » est ÉCRIT (pastille) ; le
   fond terre cuite pâle ne fait que l'appuyer.
   ------------------------------------------------------------------- */
.notifications {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.notification {
  padding: 0.9rem 1.1rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 14px;
}

.notification--non-lue {
  background-color: var(--mijoteuse-terracotta-pale);
  border-color: #ebd3c2;
}

.notification-etat {
  display: inline-block;
  margin-right: 0.5rem;
  padding: 0.1rem 0.55rem;
  border: 1px solid #e3c3ae;
  border-radius: 999px;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.75rem;
  font-weight: 700;
}

.notification-complement {
  display: block;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.9375rem;
}

.notification-pied {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
}

.moderation-gestes {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-width: 18rem;
}

.ligne-actions {
  display: flex;
  flex-shrink: 0;
  gap: 0.2rem;
}

/* ⚠️ LES FLÈCHES ÉTAIENT « ↑ » ET « ↓ » EN CARACTÈRES NUS.
   Elles deviennent des icônes du sprite — i-haut, i-bas, i-fermer.
   Les aria-label des boutons sont INCHANGÉS : c'est eux qui portent
   l'information (« Monter farine de blé »), jamais le glyphe. */
.ligne-actions .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 8px;
}

.ligne-actions .btn > svg {
  width: 15px;
  height: 15px;
}

/* Un pas de plus entre les flèches et la croix : retirer n'est pas
   réordonner, et les deux gestes ne doivent pas se toucher. */
.ligne-actions .btn-outline-danger {
  margin-left: 0.3rem;
}

/* -------------------------------------------------------------------
   15 g. La publication

   🔴 PUBLIER ET SUPPRIMER ÉTAIENT CÔTE À CÔTE, à 8 px l'un de
   l'autre, dans le même d-flex gap-2. L'un met une recette au monde,
   l'autre l'efface avec ses ingrédients et son adresse.

   Un filet les sépare, et chacun porte sa phrase : « il manque encore
   trois choses » sous Publier, « ses ingrédients, ses étapes et son
   adresse disparaissent avec elle » sous Supprimer.
   ------------------------------------------------------------------- */
.publication-principale {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}

.publication-destructive {
  margin: 2rem 0 0;
  padding-top: 1.25rem;
  border-top: 1px solid #f2eade;
}

.publication-note {
  margin: 0.5rem 0 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
}

/* -------------------------------------------------------------------
   15 h. Le statut d'une recette

   🔴 LES BADGES DE BOOTSTRAP APPORTAIENT TROIS COULEURS HORS PALETTE —
   vert, gris, jaune. Et la couleur seule ne dit rien : le mot est déjà
   écrit dans le badge (recipe.status_label), c'est lui qui informe.

   Deux traitements suffisent : publiée en terre cuite pâle, tout le
   reste en crème. Le mot fait la différence.
   ------------------------------------------------------------------- */
.etat-recette {
  flex-shrink: 0;
  padding: 0.3rem 0.7rem;
  background-color: var(--mijoteuse-creme);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 999px;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
  font-weight: 700;
}

.etat-recette--publiee {
  background-color: var(--mijoteuse-terracotta-pale);
  border-color: #e3c3ae;
  color: var(--mijoteuse-terracotta-fonce);
}

/* -------------------------------------------------------------------
   15 h bis. La sauvegarde automatique — chantier 7 de l'ADR-086

   L'état s'écrit en texte (« Enregistré ✓ », « Sauvegarde en
   attente ») ; la couleur ne fait que l'appuyer. « data-etat » est
   posé par autosave.ts, qui ne connaît aucune couleur.

   ⚠️ L'ATTENTE ET LE CONFLIT SONT EN TERRE CUITE, comme les manques :
   c'est la même nature d'information — quelque chose à regarder.
   ------------------------------------------------------------------- */
.autosave-etat {
  display: inline-block;
  margin-left: 0.75rem;
  color: var(--mijoteuse-texte-doux);
  font-family: "Hanken Grotesk", system-ui, sans-serif;
  font-size: 0.875rem;
}

.autosave-etat[data-etat="attente"],
.autosave-etat[data-etat="conflit"],
.autosave-etat[data-etat="session"],
.autosave-etat[data-etat="echec"] {
  color: var(--mijoteuse-terracotta-fonce);
  font-weight: 600;
}

/* Le conflit sous un champ : les deux versions, et deux gestes. */
.autosave-conflit {
  margin: -0.5rem 0 1rem;
  padding: 0.85rem 1rem;
  background-color: var(--mijoteuse-terracotta-pale);
  border: 1px solid #ebd3c2;
  border-radius: 14px;
}

.autosave-conflit-texte {
  margin-bottom: 0.6rem;
  color: #7d3b21;
  font-size: 0.9375rem;
}

.autosave-conflit-gestes {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Annuler / Rétablir — chantier 7c. Sous l'en-tête, avant les sections :
   l'historique couvre tout l'atelier, pas un bloc. */
.atelier-historique {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

/* Une étape modifiable en place : le texte sur toute la largeur, la
   durée et le conseil côte à côte, le bouton et l'état en pied. */
.ligne--etape .ligne-nom {
  flex: 1 1 auto;
  min-width: 0;
}

.etape-edition .mb-3 {
  margin-bottom: 0.6rem !important;
}

.etape-edition-details {
  display: grid;
  grid-template-columns: minmax(7rem, 1fr) 3fr;
  gap: 0.75rem;
}

@media (max-width: 575.98px) {
  .etape-edition-details {
    grid-template-columns: 1fr;
  }
}

.etape-edition-pied {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  margin-bottom: 0.5rem;
}

/* -------------------------------------------------------------------
   15 i. La fiche d'une recette

   ⚠️ LE BANDEAU D'IMAGE EST DÉCRIT EN § 19, et il EXISTE désormais.

   🔴 CE RENVOI DISAIT « § 16 » ET IL ÉTAIT FAUX SUR TROIS POINTS,
   corrigé le 2026-08-19 :

     · la § 16 est « Les classes qui remplacent les styles en ligne » —
       le numéro a glissé à la renumérotation qui a résolu les DEUX § 15
       du fichier ;
     · « dans le fichier à part » : ce fichier est intégré ici même ;
     · « qui n'existe pas encore » : la Phase 9b est faite, la photo est
       en base et servie par social.upload.

   ⚠️ UN RENUMÉROTAGE DÉPLACE LES SECTIONS, PAS LES RENVOIS QUI Y
   POINTENT. Rien ne signale un renvoi devenu faux — il désigne une
   section qui existe toujours, mais qui parle d'autre chose.

   Ce qui suit s'applique à la fiche hors de son bandeau.
   ------------------------------------------------------------------- */
.fiche-surtitre {
  margin: 0 0 0.75rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.fiche-titre {
  margin: 0;
  font-size: 2.75rem;
  line-height: 1.12;
  letter-spacing: -0.02em;
}

.fiche-chapeau {
  margin: 1.25rem 0 0;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-weight: 400;
  font-size: 1.25rem;
  line-height: 1.55;
  color: var(--mijoteuse-texte-doux);
}

.fiche-auteur {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 1.5rem 0 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.9375rem;
}

.fiche-auteur > a {
  color: var(--mijoteuse-brun);
  font-weight: 700;
  text-decoration: none;
}

/* Les quatre chiffres de la recette, entre deux filets. Le <dl class="row">
   de Bootstrap les empilait en paires étiquette/valeur sur toute la
   largeur : quatre lignes pour quatre nombres. */
.fiche-chiffres {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  margin: 2rem 0 2.5rem;
  padding: 1.25rem 0;
  border-top: 1px solid var(--mijoteuse-bordure);
  border-bottom: 1px solid var(--mijoteuse-bordure);
}

.fiche-chiffres dt {
  margin: 0 0 0.2rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.fiche-chiffres dd {
  margin: 0;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-weight: 600;
  font-size: 1.25rem;
  color: var(--mijoteuse-brun);
}

/* Sous 576 px, quatre colonnes ne tiennent pas. */
@media (max-width: 575.98px) {
  .fiche-chiffres {
    grid-template-columns: repeat(2, 1fr);
    row-gap: 1rem;
  }

  .fiche-titre {
    font-size: 2rem;
  }
}

/* La liste des ingrédients de la fiche : même alignement que l'atelier,
   en plus grand — on la lit, on ne la modifie pas. */
.fiche-ingredients {
  margin: 0 0 3rem;
  padding: 0;
  list-style: none;
}

.fiche-ingredients > li {
  display: flex;
  gap: 1.25rem;
  padding: 0.65rem 0;
  border-bottom: 1px solid #f2eade;
}

.fiche-ingredients .ligne-dose {
  width: 5.5rem;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 1rem;
}

/* Les étapes : une pastille numérotée plutôt que le compteur d'un <ol>.
   On les suit les mains dans la pâte — le numéro doit se retrouver
   d'un coup d'œil. */
/* Le titre d'un groupe d'ingrédients sur la fiche — « Pour la pâte ». */
.fiche-groupe {
  margin: 1.25rem 0 0.5rem;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--mijoteuse-brun);
}

.fiche-etapes {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: etape;
}

.fiche-etapes > li {
  display: flex;
  gap: 1.25rem;
  counter-increment: etape;
}

/* ⚠️ LE NUMÉRO EST DESSINÉ PAR LE CSS, à partir du compteur : le
   gabarit n'a pas à le connaître, et une étape supprimée renumérote
   les suivantes toute seule. aria-hidden n'est pas nécessaire — un
   ::before n'est pas dans l'arbre d'accessibilité. */
.fiche-etapes > li::before {
  content: counter(etape);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  background-color: var(--mijoteuse-terracotta-pale);
  color: var(--mijoteuse-terracotta-fonce);
  border-radius: 50%;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-weight: 600;
  font-size: 1.0625rem;
}

/* Le contenu d'une étape — texte, puis durée et conseil éventuels —,
   empilé. Le <li> est la ligne (numéro + contenu) ; ceci est la colonne. */
.fiche-etapes .etape-corps {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 0;
}

.fiche-etapes .etape-corps > p {
  margin: 0;
  padding-top: 0.35rem;
  font-size: 1.0625rem;
  line-height: 1.65;
}

/* La durée et le conseil d'une étape — en retrait du texte, jamais à
   sa place : la page reste lisible sans eux (wiki, « Accessibilité »).
   ⚠️ Sélecteurs à TROIS classes, pour l'emporter sur la règle générale
   du paragraphe juste au-dessus (deux classes et un élément). */
.fiche-etapes .etape-corps > .etape-duree,
.fiche-etapes .etape-corps > .etape-conseil,
.fiche-etapes .etape-corps > .etape-ingredients {
  padding-top: 0;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--mijoteuse-texte-doux);
}

.fiche-etapes .etape-corps > .etape-duree {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--mijoteuse-brun);
}

.etape-conseil-libelle {
  font-weight: 700;
}

.etape-conseil-libelle::after {
  content: " :";
}

/* Le bandeau « brouillon » de la fiche. C'était un alert-warning
   jaune ; le mot « Brouillon » est déjà écrit, la couleur n'a qu'à ne
   pas jurer. */
.fiche-brouillon {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  margin: 0 0 2rem;
  padding: 0.9rem 1.1rem;
  background-color: var(--mijoteuse-terracotta-pale);
  border: 1px solid #ebd3c2;
  border-radius: 12px;
  color: #7d3b21;
  font-size: 0.9375rem;
  line-height: 1.55;
}

.fiche-brouillon > strong {
  flex-shrink: 0;
  color: var(--mijoteuse-terracotta-fonce);
}

/* ===================================================================
   16. Les classes qui remplacent les styles en ligne — ADR-051

   ⚠️ DIX-NEUF « style="…" » VIVAIENT DANS LES GABARITS, dont quatorze
   dans recipes/edit.html, avec des valeurs en dur — et une couleur
   #7d3b21 absente de la palette.

   🔴 C'était le signe d'alerte de l'ADR-048, mot pour mot. Un style en
   ligne ne se voit pas dans une revue de charte : chercher une couleur
   ici ne le trouve pas, et il l'emporte sur toute règle de ce fichier
   — sauf !important, qu'on finirait par écrire.

   ⚠️ CE QUI POUVAIT ÊTRE FAIT PAR BOOTSTRAP L'EST : mt-0, mt-3, mt-4,
   align-items-start. Une classe de plus ici n'aurait servi qu'à
   redire ce que le cadre dit déjà.
   =================================================================== */

/* Le titre d'une page d'écriture — « Écrire une recette ». */
.titre-page {
  font-size: 2.25rem;
}

/* Le titre d'une recette sur sa page de modification : c'est le nom de
   la recette, pas un libellé d'interface (ADR-051). line-height serré
   parce qu'un titre long passe à la ligne. */
.titre-recette {
  font-size: 2rem;
  line-height: 1.2;
}

/* Les intertitres d'une fiche — « Ingrédients », « Préparation ».
   ⚠️ Une seule marge basse, là où les gabarits en portaient deux
   (1,25 rem et 1,5 rem) : c'était un écart, pas une intention. */
.titre-section {
  margin-bottom: 1.25rem;
  font-size: 1.5rem;
}

/* Les titres de bloc dans l'atelier — « Ajouter un ingrédient ». */
.titre-bloc {
  margin-bottom: 1.25rem;
  font-size: 1.125rem;
}

/* La variante serrée : le titre est suivi d'une explication qui lui
   appartient, et non d'un formulaire. */
.titre-bloc--serre {
  margin-bottom: 0.35rem;
  font-size: 1.125rem;
}

/* Un chapeau : la phrase qui présente une section de l'atelier. Serif
   en 400, comme les propos du fil — c'est de la prose, pas une étiquette. */
.chapo {
  margin-bottom: 1.5rem;
  color: var(--mijoteuse-texte-doux);
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-size: 1.0625rem;
}

/* L'explication qui suit un titre serré. */
.chapo-serre {
  margin-top: 0;
  margin-bottom: 1.25rem;
}

/* La pastille d'initiale d'un auteur, en petit — sur une fiche. */
.avatar-mini {
  width: 30px;
  height: 30px;
  font-size: 0.9375rem;
}

/* Le numéro d'une étape. Largeur fixe : sans elle, « 9. » et « 10. »
   décalent le texte d'une étape à l'autre. */
.ligne-numero {
  width: 2rem;
  color: var(--mijoteuse-terracotta-fonce);
}

/* ⚠️ LA COULEUR VIENT DE LA PALETTE, et non d'une troisième teinte.
   Le gabarit portait #7d3b21, absent de la palette, là où
   --mijoteuse-terracotta-fonce sert déjà sur ce fond (.manque-titre).
   Une teinte de moins, et un contraste de 6,3 — largement conforme. */
.manque-texte {
  color: var(--mijoteuse-terracotta-fonce);
}

/* Une mesure de lecture courte, pour les pages qui ne portent qu'un
   paragraphe — les pages d'erreur. */
.mesure-courte {
  max-width: 34rem;
}

/* La mesure de la démonstration du compteur. */
.mesure-demo {
  max-width: 42rem;
}

/* -------------------------------------------------------------------
   17. Les photos — ADR-049

   Deux emplacements, une seule règle : l'image occupe la largeur de son
   conteneur et garde ses proportions.

   ⚠️ display:block supprime l'espace que la ligne de base réserve sous
   une image en ligne — un filet clair sous la photo, à l'intérieur de
   la carte.
   ------------------------------------------------------------------- */
.fiche-photo,
.atelier-photo {
  display: block;
  width: 100%;
  height: auto;
  margin: 1.25rem 0;
  border-radius: 14px;
}

/* Dans l'atelier, la photo est un aperçu : elle ne doit pas repousser
   le formulaire hors de l'écran. */
.atelier-photo {
  max-width: 22rem;
  margin-top: 0;
}

/* ===================================================================
   18. Mon compte — ADR-060

   ⚠️ AUCUNE VARIABLE NOUVELLE. La § 15 a introduit --mijoteuse-brique
   et --mijoteuse-champ-filet ; tout ici s'appuie dessus.

   🔴 ET AUCUN « style="…" » DANS LES GABARITS. C'est la règle posée par
   la sortie des styles en ligne : une valeur en dur dans un gabarit ne
   se voit pas dans une revue de charte, et elle l'emporte sur toute
   règle de ce fichier. Chaque valeur de cette livraison a donc sa
   classe ici, y compris les tailles de titre.

   ⚠️ AUCUN TEST DU PROJET N'EXÉCUTE DE CSS. Les passages à faire au
   navigateur sont au § 6 de HANDOFF-CLAUDE-CODE.md.
   =================================================================== */

/* -------------------------------------------------------------------
   18 a. 🔴 LES LIENS « CHANGER » ÉTAIENT BLEUS ET SOULIGNÉS

   `class="ms-2 small"` sans autre classe rendait le #0d6efd du
   navigateur sur le fond crème, trois fois dans la même liste de
   définitions. C'est la remarque qui a lancé cette refonte.

   « Changer » n'est pas une note de bas de page : c'est une ACTION, et
   elle prend la forme d'un bouton discret.
   ------------------------------------------------------------------- */
.action-discrete {
  flex-shrink: 0;
  padding: 0.35rem 0.8rem;
  background-color: var(--mijoteuse-creme);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 9px;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.8125rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.action-discrete:hover,
.action-discrete:focus-visible {
  background-color: var(--mijoteuse-terracotta-pale);
  border-color: #e3c3ae;
  color: var(--mijoteuse-terracotta-fonce);
  text-decoration: none;
}

/* -------------------------------------------------------------------
   18 b. Les blocs du compte

   ⚠️ ILS REMPLACENT .card DE BOOTSTRAP, dont le .card-header rendait un
   fond #f8f9fa et un filet #dee2e6 — deux gris neutres, donc froids sur
   un fond crème.

   ⚠️ LE TITRE DE BLOC EST EN PETITES CAPITALES, pas en h5. Cinq blocs
   dont les titres pèsent autant que le titre de la page font cinq pages
   côte à côte.
   ------------------------------------------------------------------- */
.bloc-compte {
  overflow: hidden;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 16px;
}

.bloc-compte-tete {
  padding: 0.9rem 1.5rem;
  background-color: var(--mijoteuse-creme);
  border-bottom: 1px solid var(--mijoteuse-bordure);
}

.bloc-compte-tete > h2 {
  margin: 0;
  color: var(--mijoteuse-texte-doux);
  font-family: "Hanken Grotesk", system-ui, sans-serif;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ⚠️ UN SEUL BLOC EST MIS EN AVANT, et c'est la raison d'être du
   produit : les préférences alimentaires. Si tout est souligné, rien ne
   l'est. */
.bloc-compte--phare > .bloc-compte-tete {
  background-color: var(--mijoteuse-terracotta-pale);
  border-bottom-color: #ebd3c2;
}

.bloc-compte--phare > .bloc-compte-tete > h2 {
  color: var(--mijoteuse-terracotta-fonce);
}

.bloc-compte-corps {
  padding: 1.5rem;
}

/* Le nom du profil, dans le bloc phare. */
.bloc-compte-etiquette {
  margin-bottom: 0.35rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
}

.bloc-compte-valeur {
  margin-bottom: 0;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-weight: 600;
  font-size: 1.5rem;
  line-height: 1.2;
  color: var(--mijoteuse-brun);
}

/* -------------------------------------------------------------------
   18 c. Les lignes d'identité

   🔴 LE <dl class="row"> DE BOOTSTRAP NE TENAIT PAS EN DEMI-LARGEUR.

   Mesuré : en col-lg-6, « Adresse électronique » en col-sm-4 laissait
   9 rem à une adresse plus son bouton « Changer ». L'adresse passait à
   la ligne au milieu du domaine.

   L'étiquette monte donc AU-DESSUS de la valeur. L'élément reste un
   <dl> : ce sont bien des couples terme/valeur, et un lecteur d'écran
   annonce « liste de N éléments » plutôt que « tableau ».

   ⚠️ overflow-wrap: anywhere SUR L'ADRESSE.
   « prenom.nom@sous-domaine.exemple.fr » débordait du bloc, sans césure
   possible pour le navigateur.
   ------------------------------------------------------------------- */
.lignes-identite {
  margin: 0;
  padding: 0 1.5rem;
}

.ligne-identite {
  padding: 1rem 0;
  border-bottom: 1px solid #f2eade;
}

.ligne-identite:last-child {
  border-bottom: none;
}

.ligne-identite > dt {
  margin-bottom: 0.3rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
  font-weight: 600;
}

.ligne-identite > dd {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  flex-wrap: wrap;
  margin: 0;
}

.ligne-identite-valeur {
  flex-grow: 1;
  min-width: 0;
  font-size: 1rem;
  font-weight: 600;
  color: var(--mijoteuse-brun);
  overflow-wrap: anywhere;
}

/* La précision sous la valeur — « Vérifiée le 09/08/2026 ». */
.ligne-identite-note {
  display: block;
  margin-top: 0.35rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
  font-weight: 400;
}

/* ⚠️ L'ADRESSE NON VÉRIFIÉE PREND LA BRIQUE, et garde son mot écrit. */
.ligne-identite-note--alerte {
  color: var(--mijoteuse-brique);
  font-weight: 600;
}

/* Une ligne sans action : l'étiquette et la valeur tiennent côte à
   côte, il n'y a pas de bouton à loger. */
.ligne-identite--courte {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  flex-wrap: wrap;
}

.ligne-identite--courte > dt {
  flex-shrink: 0;
  margin-bottom: 0;
}

.ligne-identite--courte > dd {
  flex-grow: 1;
  min-width: 0;
  font-size: 1rem;
  color: var(--mijoteuse-brun);
}

/* -------------------------------------------------------------------
   18 d. Les lignes de sécurité

   Même forme que l'identité, mais la valeur est une PHRASE — ce que
   fait le réglage, et ce que le changer emporte.
   ------------------------------------------------------------------- */
.lignes-securite {
  padding: 0 1.5rem;
}

.ligne-securite {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 1.1rem 0;
  border-bottom: 1px solid #f2eade;
}

.ligne-securite:last-child {
  border-bottom: none;
}

/* La variante qui porte un avertissement sur toute la largeur. */
.ligne-securite--bloc {
  display: block;
}

.ligne-securite-titre {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  color: var(--mijoteuse-brun);
}

.ligne-securite-aide {
  flex: 1 1 12rem;
  min-width: 0;
  margin: 0.35rem 0 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
  line-height: 1.55;
}

.ligne-securite-texte {
  flex: 1 1 12rem;
  min-width: 0;
}

/* -------------------------------------------------------------------
   18 e. L'avertissement du compte

   🔴 IL REMPLACE alert-warning ET alert-info — jaune et cyan, les deux
   couleurs les plus froides de Bootstrap, sur les deux messages les
   plus importants de la page : « compatibilité incertaine » et
   « changement d'adresse en attente ».

   ⚠️ LE SYMBOLE EST DÉCORATIF, aria-hidden. Le mot « incertaine » ou
   « en attente » est écrit : c'est lui qui informe.
   ------------------------------------------------------------------- */
.avis-compte {
  display: flex;
  gap: 0.75rem;
  max-width: 44rem;
  margin: 1.25rem 0 0;
  padding: 1rem 1.1rem;
  background-color: var(--mijoteuse-creme);
  border: 1px solid #ebd3c2;
  border-radius: 12px;
}

.avis-compte-signe {
  flex-shrink: 0;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 1.125rem;
  line-height: 1.4;
}

.avis-compte-corps {
  min-width: 0;
}

.avis-compte p {
  margin: 0;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.9375rem;
  line-height: 1.6;
}

.avis-compte p + p,
.avis-formulaire p + p {
  margin-top: 0.5rem;
}

.avis-compte form {
  margin: 0.85rem 0 0;
}

/* Une variante posée dans un formulaire, sans symbole ni marge haute. */
.avis-formulaire {
  margin: 0 0 1.5rem;
  padding: 1rem 1.1rem;
  background-color: var(--mijoteuse-terracotta-pale);
  border: 1px solid #ebd3c2;
  border-radius: 12px;
}

.avis-formulaire p {
  margin: 0;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.9375rem;
  line-height: 1.6;
}

/* -------------------------------------------------------------------
   18 f. Les chiffres — « Ma cuisine », « Mes relations »

   ⚠️ CHIFFRES TABULAIRES. Sans eux, « 7 » et « 23 » ne s'alignent pas
   d'une colonne à l'autre et la grille se lit de travers.

   ⚠️ auto-fit AVEC UN MINIMUM DE 7 rem : le bloc peut occuper une
   demi-largeur d'écran large comme toute la largeur d'un téléphone, et
   la grille s'adapte sans point de rupture écrit à la main.
   ------------------------------------------------------------------- */
.chiffres-compte {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
  gap: 1.25rem 1rem;
  margin: 0;
  padding: 1.35rem 1.5rem;
}

.chiffres-compte dt {
  margin: 0 0 0.2rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.chiffres-compte dd {
  margin: 0;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-weight: 600;
  font-size: 1.75rem;
  line-height: 1.1;
  color: var(--mijoteuse-brun);
  font-variant-numeric: tabular-nums;
}

/* Le lien de pied d'un bloc — « Mes recettes → ». */
.bloc-compte-pied {
  margin: 0;
  padding: 0 1.5rem 1.25rem;
}

.bloc-compte-pied > a {
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.875rem;
  font-weight: 600;
  text-decoration: none;
}

.bloc-compte-pied > a:hover {
  text-decoration: underline;
}

/* ⚠️ LA MENTION UTC DESCEND DANS LE BLOC qu'elle concerne. En pied de
   page, elle flottait sous cinq blocs dont un seul affiche des dates. */
.mention-utc {
  margin: 0;
  padding: 0.75rem 1.5rem 1.1rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
  line-height: 1.5;
}

/* -------------------------------------------------------------------
   18 g. Les rôles, en pied de page

   ⚠️ ILS DESCENDENT, ET NE DISPARAISSENT PAS.

   Une information qu'on lit une fois dans sa vie. Mais elle doit rester
   lisible : le wiki l'écrit — « sans rôle, un compte ne peut rien », et
   cette impuissance est introuvable autrement.

   🔴 LE CAS « AUCUN RÔLE » GARDE SON POIDS VISUEL, lui. C'est le
   symptôme le plus déroutant du produit, et il prend la brique.
   ------------------------------------------------------------------- */
.roles-compte {
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--mijoteuse-bordure);
}

.roles-compte > h2 {
  margin: 0 0 0.6rem;
  color: var(--mijoteuse-texte-doux);
  font-family: "Hanken Grotesk", system-ui, sans-serif;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.roles-compte ul {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.roles-compte li {
  max-width: 44rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.875rem;
  line-height: 1.6;
}

.roles-compte strong {
  color: var(--mijoteuse-brun);
  font-weight: 600;
}

.roles-compte-aucun {
  max-width: 44rem;
  margin: 0;
  padding: 1rem 1.1rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-brique-filet);
  border-radius: 12px;
  color: var(--mijoteuse-brique);
  font-size: 0.9375rem;
  line-height: 1.6;
}

/* -------------------------------------------------------------------
   18 h. 🔴 LA SEULE PAGE PLEINE LARGEUR DU SITE

   Le gabarit commun impose une mesure centrée partout — 44 rem pour la
   lecture, 34 pour un formulaire court. « Mon compte » y échappe : ce
   n'est pas de la prose, c'est un tableau de bord, et cinq blocs à
   44 rem laissaient deux tiers de l'écran vides.

   ⚠️ LA PROSE GARDE SON PLAFOND À L'INTÉRIEUR DES BLOCS. C'est le bloc
   qui prend la largeur, jamais la ligne de texte : max-width est posé
   sur .avis-compte, .roles-compte li et .compte-chapeau. À 1 870 px,
   l'avertissement de l'ADR-056 se rendait sinon sur une seule ligne de
   157 caractères.

   ⚠️ ET LE PIED DE PAGE SUIT. Laissé à la mesure centrée, son bord
   gauche tombait à 583 px de celui des blocs — mesuré. D'où le bloc
   Jinja « mesure », partagé par les trois zones du gabarit commun.
   ------------------------------------------------------------------- */
/* ⚠️ DEUX NOMS, UNE SEULE RÈGLE, ET C'EST DÉLIBÉRÉ.

   « compte-large » est cité TEL QUEL par l'ADR-060, et une décision ne
   se récrit pas après coup. « mesure-pleine » est le nom que porte la
   même classe pour toute page qui n'est pas « Mon compte » — la fiche
   d'un profil depuis l'ADR-115.

   ⛔ N'EN SUPPRIMER AUCUN : retirer le premier casse users/account.html,
   retirer le second casse profiles/show.html. Les deux sont employés. */
.compte-large,
.mesure-pleine {
  width: 100%;
  max-width: none;
  padding-right: 2.5rem;
  padding-left: 2.5rem;
}

.compte-chapeau {
  max-width: 38rem;
  margin: 0.75rem 0 0;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-weight: 400;
  font-size: 1.125rem;
  line-height: 1.55;
  color: var(--mijoteuse-texte-doux);
}

/* La valeur nommée dans un chapeau — le nom affiché, l'adresse actuelle.
   ⚠️ overflow-wrap : une adresse longue débordait de la mesure étroite,
   sans césure possible pour le navigateur. */
.chapo-valeur {
  color: var(--mijoteuse-brun);
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* Renoncer n'est pas une action : c'est une sortie. Elle ne prend donc
   pas la forme d'un bouton, et reste en texte secondaire à côté de
   l'action principale. */
.lien-renoncer {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.9375rem;
  font-weight: 600;
  text-decoration: none;
}

.lien-renoncer:hover {
  color: var(--mijoteuse-brun);
  text-decoration: underline;
}

@media (max-width: 575.98px) {
  .compte-large,
  .mesure-pleine {
    padding-right: 1.25rem;
    padding-left: 1.25rem;
  }
}

/* ===================================================================
   19. La fiche d'une recette — le bandeau et la compatibilité
   ADR-061

   Deux sujets que la Phase 9b et la Phase 6 ont rendus réels, et que
   le § 15 ne pouvait pas traiter : il a été écrit quand la photo et le
   verdict n'existaient pas encore.
   =================================================================== */

/* -------------------------------------------------------------------
   19 a. Le bandeau de la fiche

   ⚠️ LA PHOTO MONTE EN TÊTE DE PAGE, à fond perdu, et le titre se pose
   dessus. Elle était rendue entre le titre et le chapeau, à la largeur
   de la mesure de lecture : une image de recette au milieu d'une colonne
   de texte, alors que c'est la première chose qu'on regarde.

   🔴 NE PAS EMPILER LA PHOTO ET LE TITRE EN POSITION ABSOLUE. C'est
   l'erreur commise trois fois dans la maquette : l'emplacement d'image
   centre son état vide dans sa propre boîte, le bandeau de titre est
   positionné sur le bas — et les deux se recouvrent.

   Ce qui marche : une colonne flex. La photo remplit le bandeau en
   position absolue, le bloc de titre est un bloc NORMAL dans le flux,
   poussé en bas par margin-top:auto. Le chevauchement devient
   impossible par construction.
   ------------------------------------------------------------------- */
.fiche-bandeau {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  width: 100%;
  min-height: 34rem;
  height: 64vh;
  /* Le lavis chaud d'une fiche sans photo : les hachures de 16 px
     vibraient sur 30 rem de hauteur. */
  background-color: #f3e5d6;
  background-image: radial-gradient(120% 85% at 72% 8%,
                    #f9efe2 0%, #f3e5d6 46%, #e9d7c3 100%);
}

.fiche-bandeau-photo {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  border-radius: 0;
  object-fit: cover;
}

/* ⚠️ LE ZOOM EST PILOTÉ PAR LE DÉFILEMENT, PAS PAR UNE HORLOGE.

   @supports le protège des navigateurs sans « scroll-driven
   animations » : sans cette barrière, l'animation s'y jouerait une fois
   et laisserait la photo agrandie en permanence. */
@keyframes zoom-fiche {
  to { transform: scale(1.16) }
}

@supports (animation-timeline: scroll()) {
  .fiche-bandeau-photo {
    transform-origin: 50% 45%;
    will-change: transform;
    animation: zoom-fiche linear both;
    animation-timeline: scroll(root block);
    animation-range: 0 70vh;
  }
}

/* Le fil d'Ariane posé sur la photo. */
.fiche-bandeau-fil {
  position: relative;
  flex-shrink: 0;
  padding: 1.75rem 2.5rem 0;
  /* ⚠️ La bande laisse passer les clics, le lien les reprend : posée sur
     l'image, elle avalait sinon toute la zone haute. */
  pointer-events: none;
}

/* 🔴 UNE PASTILLE OPAQUE, ET NON UN VOILE DÉGRADÉ.

   Le fil d'Ariane a d'abord été rendu en terre cuite sombre sans
   protection, puis en blanc sur un voile qui s'éteignait trop vite :
   mesuré à 2,55:1 sur une photo d'assiette blanche. Son contraste ne
   doit pas dépendre de l'image que quelqu'un dépose. */
.fiche-bandeau-fil .breadcrumb {
  display: inline-flex;
  margin: 0;
  padding: 0.4rem 0.85rem;
  background-color: rgba(255, 253, 249, 0.92);
  border-radius: 999px;
}

.fiche-bandeau-fil .breadcrumb-item > a {
  pointer-events: auto;
}

/* Le voile qui porte le titre.

   ⚠️ HUIT ARRÊTS, ET AUCUN OPAQUE. À trois arrêts dont un opaque à
   62 %, il posait une dalle brune plate sur la photo ; la transition se
   voyait par bandes. Il reste translucide jusqu'en bas — 0,95 au plus
   fort — et la photo se devine derrière le texte. */
.fiche-bandeau-texte {
  position: relative;
  flex-shrink: 0;
  margin-top: auto;
  padding: 9rem 2.5rem 2.5rem;
  background: linear-gradient(to top,
    rgba(24, 17, 13, 0.95) 0%,
    rgba(25, 18, 14, 0.91) 20%,
    rgba(27, 19, 15, 0.81) 37%,
    rgba(28, 20, 15, 0.65) 53%,
    rgba(28, 20, 15, 0.45) 67%,
    rgba(27, 19, 14, 0.26) 80%,
    rgba(25, 18, 13, 0.11) 91%,
    rgba(24, 17, 13, 0) 100%);
}

.fiche-bandeau-surtitre {
  margin: 0 0 0.85rem;
  color: #f0d6c4;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.fiche-bandeau-titre {
  margin: 0;
  max-width: 32rem;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-weight: 600;
  font-size: 3.25rem;
  line-height: 1.06;
  letter-spacing: -0.02em;
  color: var(--mijoteuse-carte);
  /* Le titre reste lisible même si la partie basse de la photo est
     claire : le voile seul n'y suffit pas toujours. */
  text-shadow: 0 1px 30px rgba(24, 17, 13, 0.55);
}

.fiche-bandeau-auteur {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  flex-wrap: wrap;
  margin: 1.5rem 0 0;
}

.fiche-bandeau-auteur .fil-avatar {
  background-color: rgba(255, 253, 249, 0.16);
  border: 1px solid rgba(255, 253, 249, 0.35);
  color: var(--mijoteuse-carte);
}

.fiche-bandeau-auteur a {
  color: var(--mijoteuse-carte);
  font-size: 0.9375rem;
  font-weight: 700;
  text-decoration: none;
}

.fiche-bandeau-auteur > span {
  color: #d9c8b3;
  font-size: 0.9375rem;
}

/* Le nombre d'abonnés, collé au nom qu'il qualifie.

   ⚠️ LE « gap: 0.85rem » DU CONTENEUR L'AURAIT DÉTACHÉ, et « camille
   · 12 abonnés » se serait lu comme deux informations séparées par un
   point médian flottant. La marge négative annule l'écart, la marge
   gauche rend l'espace d'un mot.

   ⚠️ ELLE NE REDÉCLARE NI LA COULEUR NI LA TAILLE : « > span » les
   donne déjà. Les répéter ici créerait deux endroits où changer la
   teinte du bandeau — le nœud que .fil-avatar a déjà créé entre les
   §§ 4 et 14. */
.fiche-bandeau-abonnes {
  margin-left: -0.6rem;
}

/* La pastille de brouillon, posée sur le voile. */
.fiche-bandeau-etat {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
  margin: 0 0 1rem;
  padding: 0.4rem 0.8rem;
  background-color: rgba(255, 253, 249, 0.92);
  border-radius: 999px;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.8125rem;
  line-height: 1.4;
}

/* La mesure de lecture, rendue À L'INTÉRIEUR d'une page à fond perdu.
   Le bandeau prend toute la largeur, le texte de la recette non : on lit
   une recette à 44 rem, comme le fil. */
.fiche-corps {
  width: 100%;
  max-width: 44rem;
  margin: 0 auto;
  padding: 2.5rem 1.5rem 4rem;
}

/* ⚠️ LE PREMIER ÉLÉMENT DU CORPS NE PORTE PAS DE MARGE HAUTE : le
   padding du conteneur s'en charge, et l'addition des deux creusait un
   trou sous le bandeau. */
.fiche-corps > :first-child {
  margin-top: 0;
}

@media (max-width: 575.98px) {
  .fiche-bandeau {
    min-height: 24rem;
    height: 52vh;
  }

  .fiche-bandeau-titre {
    font-size: 2rem;
  }

  .fiche-bandeau-fil,
  .fiche-bandeau-texte {
    padding-right: 1.25rem;
    padding-left: 1.25rem;
  }

  .fiche-corps {
    padding-right: 1.25rem;
    padding-left: 1.25rem;
  }
}

/* -------------------------------------------------------------------
   19 b. Le verdict de compatibilité

   🔴 IL S'AFFICHAIT EN alert-success / alert-danger / alert-warning —
   le vert, le rouge et le jaune de Bootstrap, soit les trois dernières
   couleurs froides du produit, sur l'information la plus importante
   qu'il porte.

   ⚠️ LA COULEUR NE DIT RIEN TOUTE SEULE, et le gabarit le sait déjà :
   verdict.label écrit le mot. Ces règles ne font que cesser de jurer —
   elles n'ajoutent aucune information.

   ⚠️ TROIS ÉTATS, TROIS TRAITEMENTS DISTINCTS SANS COMPTER SUR LA
   TEINTE : le filet change d'épaisseur, et « incompatible » prend un
   fond plein. Vu en noir et blanc, les trois restent distincts.
   ------------------------------------------------------------------- */
.verdict {
  margin: 1.5rem 0 0;
  padding: 1.1rem 1.25rem;
  border-radius: 14px;
  font-size: 0.9375rem;
  line-height: 1.6;
}

.verdict > strong {
  display: block;
  font-size: 1.0625rem;
}

.verdict ul {
  margin: 0.6rem 0 0;
  padding-left: 1.2rem;
}

.verdict li + li {
  margin-top: 0.25rem;
}

/* Compatible — le vert herbe de la palette, discret : c'est une bonne
   nouvelle, pas une décoration. */
.verdict--compatible {
  background-color: #edf0e6;
  border: 1px solid #dde4cf;
  color: #3f4a36;
}

.verdict--compatible > strong {
  color: var(--mijoteuse-vert-herbe);
}

/* 🔴 Incompatible — la brique, en fond plein et filet épais.

   C'est le seul bloc du site à porter un aplat de couleur soutenue, et
   c'est délibéré : il annonce qu'une personne à table ne peut pas
   manger ce plat. */
.verdict--incompatible {
  background-color: #fbf1ee;
  border: 2px solid var(--mijoteuse-brique);
  color: #7c2919;
}

.verdict--incompatible > strong {
  color: var(--mijoteuse-brique);
}

/* ⚠️ Incertain — et c'est l'état LE PLUS FRÉQUENT aujourd'hui, les
   tables de rattachement étant vides. Il ne doit ni rassurer ni
   alarmer : la terre cuite pâle, comme les autres avertissements du
   site. */
.verdict--uncertain {
  background-color: var(--mijoteuse-terracotta-pale);
  border: 1px solid #ebd3c2;
  color: var(--mijoteuse-terracotta-fonce);
}

.verdict--uncertain > strong {
  color: var(--mijoteuse-terracotta-fonce);
}

/* Le motif d'une règle, sous la raison qu'elle explique.

   ⚠️ IL EST SECOND, ET DOIT LE RESTER. La raison dit CE QUI cloche —
   « Lait — lait » ; le motif dit POURQUOI le moteur l'a conclu — « au-delà
   de toute trace de lactose ». Les mettre au même poids ferait deux
   phrases concurrentes là où il en faut une, précisée. */
.verdict-motif {
  display: block;
  font-size: 0.875rem;
  /* La couleur du texte, atténuée : le motif appartient à la raison, il
     ne forme pas une seconde information. Une teinte propre le
     détacherait de la ligne qu'il complète. */
  color: color-mix(in srgb, currentcolor 70%, transparent);
}

/* Les alertes de trace, sous les raisons.

   🔴 CE NE SONT PAS DES RAISONS — ADR-052. Une trace d'un allergène
   déclaré en INTOLÉRANCE laisse la recette compatible. Un filet les
   sépare, pour qu'on ne lise pas une trace de lactose comme une
   incompatibilité. */
.verdict-alertes {
  margin-top: 0.85rem;
  padding-top: 0.75rem;
  border-top: 1px solid currentcolor;
  /* Le filet emprunte la couleur du texte, en très atténué : une teinte
     de plus par état serait trois teintes de plus. */
  border-top-color: color-mix(in srgb, currentcolor 25%, transparent);
}

/* ===================================================================
   20. La grammaire des pages de liste — maquette du 2026-08-30

   La maquette « La Mijoteuse.dc.html » (3 505 lignes, dix-sept écrans)
   a dessiné CINQ écrans à partir du code — notifications, mes recettes,
   modération, invitations, mon compte — et les autres pages du site
   restaient en Bootstrap brut : list-group, badge, alert-warning,
   text-muted. Cette section porte ce qui manquait pour les rejoindre :
   des cartes, des filtres, des listes encadrées, des pastilles, des
   tuiles d'icône, des états vides — et le cadre des pages d'entrée.

   ⚠️ AUCUNE COULEUR NOUVELLE. Deux variables sont AJOUTÉES, mais elles
   nomment des valeurs que la § 19 b écrivait déjà en dur
   (.verdict--compatible) : herbe pâle et son filet. La maquette emploie
   aussi un ambre (#f8ebd6 / #c9922f) pour « à vérifier » — il n'est PAS
   repris : la charte dit « à vérifier » en terre cuite pâle
   (.verdict--uncertain, .avis-compte), et deux teintes pour un même
   état seraient deux signaux pour une même information (ADR-051).

   ⚠️ LE STATUT D'UNE RECETTE GARDE SES DEUX TRAITEMENTS (ADR-059, § 15 h)
   là où la maquette en colore cinq. Le mot est écrit ; c'est lui qui
   informe. Rouvrir l'ADR-059 avant de changer cela.

   ⚠️ AUCUN TEST DU PROJET N'EXÉCUTE DE CSS. Tout ceci se vérifie au
   navigateur, de part et d'autre de 992 px.
   =================================================================== */
:root {
  --mijoteuse-herbe-pale:  #edf0e6;
  --mijoteuse-herbe-filet: #dde4cf;

  /* ⚠️ L'AMBRE DIT « ÇA DÉPEND », jamais « c'est bon » ni « c'est
     mauvais ». Il porte les deux troisièmes états du référentiel : la
     TRACE d'un allergène et le « dépend de la provenance » d'un régime.
     Sans une couleur à eux, ils se rangeraient de force du côté du vert
     ou du rouge — et c'est exactement ce que l'ADR-046 interdit.

     ⚠️ #8a5f22 SUR #f8ebd6 : 4,77:1, mesuré. Au-dessus des 4,5:1. */
  --mijoteuse-ambre-pale:  #f8ebd6;
  --mijoteuse-ambre-texte: #8a5f22;
  --mijoteuse-ambre-filet: #ecd8b8;

  /* 🔴 LES LIENS DU SITE ÉTAIENT RESTÉS BLEUS — mesuré le 2026-08-30 sur
     « Mon espace » et « Voir toutes les recettes ».

     La § 1 redéfinit --bs-link-color, mais Bootstrap 5.3 colore ses
     liens par « rgba(var(--bs-link-color-rgb), …) » : c'est la
     variable en composantes qu'il lit, et elle gardait le #0d6efd
     d'origine. Même piège que .btn-primary (§ 2) : une variable de
     Bootstrap ne suffit pas toujours, il faut celle qu'il lit vraiment.

     Terre cuite foncée au repos, terre cuite au survol — comme la
     maquette (« a{color:#9E3F1D} a:hover{color:#C0532B} »). */
  --bs-link-color-rgb:       158, 63, 29;
  --bs-link-hover-color-rgb: 192, 83, 43;
}

/* -------------------------------------------------------------------
   20 a. L'en-tête d'une page de liste

   Le titre et l'action principale sur une même ligne — « Mes recettes »
   et « Écrire une recette » —, puis une phrase qui dit à quoi sert la
   page. Sur un écran étroit, le bouton passe sous le titre.
   ------------------------------------------------------------------- */
.entete-page {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.875rem;
  margin-bottom: 0.25rem;
}

.entete-page > h1 {
  flex: 1 1 11rem;
  min-width: 0;
  margin: 0;
  font-size: clamp(1.625rem, 4vw, 2.25rem);
  line-height: 1.1;
}

.entete-page > .btn,
.entete-page > form {
  flex-shrink: 0;
  align-self: center;
}

.sous-titre-page {
  max-width: 52ch;
  margin: 0.35rem 0 1.125rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.9375rem;
  line-height: 1.55;
}

/* -------------------------------------------------------------------
   20 b. Les cartes

   Une carte est un bloc sur fond carte, cerné d'un filet, aux angles à
   16 px — le module de base de la maquette. « --relief » ne sert qu'aux
   cartes qui sont un lien : elles se soulèvent au survol, ce qui dit
   « cliquable » sans mot.
   ------------------------------------------------------------------- */
.carte {
  padding: 0.9375rem 1rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 16px;
}

.carte--large {
  padding: 1.0625rem;
  border-radius: 18px;
}

.carte--relief {
  transition: transform 0.18s ease, box-shadow 0.18s ease,
              border-color 0.18s ease;
}

.carte--relief:hover,
.carte--relief:focus-within {
  transform: translateY(-3px);
  border-color: #dccbb2;
  box-shadow: 0 14px 30px -18px rgba(70, 40, 20, 0.4);
}

/* ⚠️ VERTIGES ET TROUBLES VESTIBULAIRES : la § 7 coupe déjà la
   transition du lien d'évitement ; celle-ci suit la même règle. */
@media (prefers-reduced-motion: reduce) {
  .carte--relief {
    transition: none;
  }

  .carte--relief:hover,
  .carte--relief:focus-within {
    transform: none;
  }
}

/* Une carte qui ne porte que du texte — un état vide expliqué. */
.carte--texte {
  padding: 1.625rem;
}

.carte--texte > h2 {
  margin: 0 0 0.375rem;
  font-size: 1.3125rem;
}

.carte--texte > p {
  max-width: 52ch;
  margin: 0;
  color: var(--mijoteuse-texte-doux);
  line-height: 1.6;
}

.carte--texte > p + p {
  margin-top: 0.5rem;
}

/* Une pile de cartes : le fil des pages de liste. */
.pile {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}

.pile--large {
  gap: 0.875rem;
}

.carte-tete {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.carte-tete--centree {
  align-items: center;
  gap: 0.7rem;
}

.carte-tete > .etat-recette {
  margin-left: auto;
}

.carte-corps {
  flex: 1 1 11rem;
  min-width: 0;
}

/* Le titre d'une carte est un lien qui ne se distingue pas d'un titre :
   c'est la carte entière qui se lit comme une entrée. */
.carte-titre {
  margin: 0;
  font-family: "Hanken Grotesk", system-ui, sans-serif;
  font-size: 0.96875rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--mijoteuse-brun);
}

.carte-titre--grand {
  font-size: 1.03125rem;
}

.carte-titre > a {
  color: var(--mijoteuse-brun);
  text-decoration: none;
}

.carte-titre > a:hover,
.carte-titre > a:focus {
  text-decoration: underline;
}

.carte-titre > .pastille {
  margin-left: 0.4rem;
  vertical-align: 2px;
}

.carte-sous {
  margin: 0.2rem 0 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
  line-height: 1.45;
}

/* Une carte en pointillés : l'invitation à AJOUTER quelque chose — un
   foyer, un convive. Même signal que .atelier-carte--creation : le
   pointillé dit « autre nature de geste ». */
.carte-ajout {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 7.5rem;
  padding: 1.25rem 0.9375rem;
  background-color: transparent;
  border: 1.5px dashed #d9c7ae;
  border-radius: 16px;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.875rem;
  font-weight: 700;
  text-align: center;
  text-decoration: none;
}

.carte-ajout:hover,
.carte-ajout:focus {
  background-color: var(--mijoteuse-carte);
  border-color: var(--mijoteuse-terracotta);
  color: var(--mijoteuse-terracotta-fonce);
  text-decoration: none;
}

.carte-ajout > small {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.4;
}

/* Une grille de cartes, qui replie ses colonnes toute seule. */
.grille-cartes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 0.75rem;
}

/* -------------------------------------------------------------------
   20 c. Les filtres d'une page

   Des LIENS, comme les onglets du fil (§ 5 bis) : chaque vue est une
   adresse, qui se partage et que le retour arrière retrouve. L'état
   courant prend le fond pâle et le filet terre cuite — le seul état
   courant du site (§ 14 e).
   ------------------------------------------------------------------- */
.filtres {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1.125rem;
}

.filtre {
  padding: 0.5rem 0.875rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 10px;
  color: #5c534b;
  font-size: 0.8125rem;
  font-weight: 700;
  text-decoration: none;
}

.filtre:hover,
.filtre:focus {
  border-color: var(--mijoteuse-terracotta);
  color: var(--mijoteuse-terracotta-fonce);
  text-decoration: none;
}

.filtre.actif {
  background-color: var(--mijoteuse-terracotta-pale);
  border-color: var(--mijoteuse-terracotta);
  color: var(--mijoteuse-terracotta-fonce);
}

/* -------------------------------------------------------------------
   20 d. Une liste encadrée

   Une seule carte pour toute la liste, chaque ligne sous un filet
   intérieur — notifications, membres d'un foyer, ingrédients à relire.
   Une carte PAR ligne (la forme précédente des notifications) faisait
   une pile de boîtes là où l'on parcourt une liste.
   ------------------------------------------------------------------- */
.liste-cartee {
  margin: 0;
  padding: 0;
  list-style: none;
  overflow: hidden;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 18px;
}

.liste-cartee > li {
  display: flex;
  align-items: flex-start;
  gap: 0.8rem;
  padding: 0.9375rem 1rem;
  border-top: 1px solid #f2eade;
}

.liste-cartee > li:first-child {
  border-top: none;
}

.liste-cartee-corps {
  flex: 1 1 10rem;
  min-width: 0;
}

/* Le nom d'une ligne — un lien vers sa fiche. */
.ligne-nom {
  display: block;
  font-size: 0.90625rem;
  font-weight: 700;
  color: var(--mijoteuse-brun);
}

a.ligne-nom {
  color: var(--mijoteuse-terracotta-fonce);
  text-decoration: none;
}

a.ligne-nom:hover,
a.ligne-nom:focus {
  text-decoration: underline;
}

.ligne-note {
  display: block;
  margin-top: 0.15rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.78125rem;
  line-height: 1.45;
}

/* Le second lien d'une ligne — « Composition et validation ». Souligné :
   à côté du nom en gras, c'est ce qui le fait lire comme un lien. */
a.ligne-note {
  color: var(--mijoteuse-texte-doux);
  text-decoration: underline;
}

.ligne-pastilles {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  flex-shrink: 0;
}

/* -------------------------------------------------------------------
   20 e. Les tuiles d'icône et les avatars

   Un carré aux angles doux, teinté selon la NATURE de la ligne : herbe
   pour ce qui rassure ou touche au foyer, terre cuite pour une action
   attendue, brique pour un refus. L'icône vient du sprite de
   base.html ; elle est aria-hidden, le texte à côté dit tout.
   ------------------------------------------------------------------- */
.tuile-icone {
  display: inline-grid;
  place-items: center;
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background-color: var(--mijoteuse-creme);
  color: var(--mijoteuse-texte-doux);
}

.tuile-icone > svg {
  width: 18px;
  height: 18px;
}

.tuile-icone--large {
  width: 38px;
  height: 38px;
  border-radius: 12px;
}

.tuile-icone--large > svg {
  width: 20px;
  height: 20px;
}

.tuile-icone--herbe {
  background-color: var(--mijoteuse-herbe-pale);
  color: var(--mijoteuse-vert-herbe);
}

.tuile-icone--terre {
  background-color: var(--mijoteuse-terracotta-pale);
  color: var(--mijoteuse-terracotta-fonce);
}

.tuile-icone--brique {
  background-color: #fbf1ee;
  color: var(--mijoteuse-brique);
}

/* L'avatar d'une personne — une initiale dans un rond. Deux teintes :
   herbe pour un compte, sable pour un profil sans compte (un enfant, un
   invité). */
.avatar-rond {
  display: inline-grid;
  place-items: center;
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background-color: var(--mijoteuse-herbe-filet);
  color: var(--mijoteuse-vert-herbe);
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-size: 1.0625rem;
  font-weight: 600;
}

.avatar-rond--sans-compte {
  background-color: #f1e4d3;
  color: #b08a63;
}

/* -------------------------------------------------------------------
   20 f. Les pastilles

   Une pastille dit un ÉTAT, en un mot — jamais la couleur seule.
   .etat-recette (§ 15 h) en est la spécialisation pour le statut d'une
   recette ; celles-ci servent au reste.
   ------------------------------------------------------------------- */
.pastille {
  display: inline-block;
  padding: 0.25rem 0.6rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid #e4d6c1;
  border-radius: 999px;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.6875rem;
  font-weight: 700;
  white-space: nowrap;
}

/* Ce qui reste À FAIRE : fond plein, plus sombre. */
.pastille--attente {
  background-color: var(--mijoteuse-creme);
  border-color: transparent;
  color: #5c534b;
  font-weight: 800;
}

/* Un rôle, en capitales espacées : « administrateur », « membre ». */
.pastille--role {
  background-color: var(--mijoteuse-herbe-pale);
  border-color: transparent;
  color: var(--mijoteuse-vert-herbe);
  font-size: 0.65625rem;
  font-weight: 800;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.pastille--role-admin {
  background-color: var(--mijoteuse-terracotta-pale);
  color: var(--mijoteuse-terracotta-fonce);
}

/* « Le mien » : le profil qui est le vôtre, dans la liste du foyer. */
.pastille--mien {
  background-color: var(--mijoteuse-terracotta-pale);
  border-color: transparent;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.625rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* La liste des règles d'une contrainte — maquette de l'administration,
   2026-09-23. « rules.html » la faisait en « mt-2 mb-0 small » : une
   classe évite de répéter trois utilitaires, et règle l'interligne que
   Bootstrap laisse à 1,5 sur du 0,875 rem. */
.admin-regles {
  margin: 0.35rem 0 0;
  padding-left: 1.1rem;
  font-size: 0.84375rem;
  line-height: 1.5;
}

.admin-regles > li + li {
  margin-top: 0.45rem;
}

/* ⚠️ PAS DE PUCE. Mesuré au navigateur le 2026-09-23 : la plupart des
   contraintes n'ont QU'UNE règle, et un cercle vide devant une ligne
   unique ne groupe rien — il décale le texte pour rien. */
.admin-regles {
  list-style: none;
  padding-left: 0;
}

/* La traduction technique d'une règle, repliée.

   🔴 ELLE NE PEUT PAS DISPARAÎTRE — un test la fige sur la page des
   règles — et dépliée elle écrasait la liste : trois lignes de
   « relève de Triticum (genre) ou … » sous un nom qui disait déjà tout.

   ⚠️ « details » n'a besoin d'aucun script, et c'est le patron que
   l'arbre des taxons emploie déjà pour « Déplacer… ». */
.admin-regle-detail > summary {
  display: inline-block;
  margin-top: 0.15rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
  cursor: pointer;
}

/* 🔴 SANS CE CHEVRON, RIEN NE DIT QUE LA LIGNE S'OUVRE. Mesuré au
   navigateur le 2026-09-23 : « display: inline-block » sur un <summary>
   SUPPRIME le triangle natif, et le libellé se lisait comme du texte
   gris inerte. On rend le marqueur soi-même, des deux côtés — le
   sélecteur WebKit et la liste standard. */
.admin-regle-detail > summary {
  list-style: none;
}

.admin-regle-detail > summary::-webkit-details-marker {
  display: none;
}

.admin-regle-detail > summary::after {
  content: " ›";
  display: inline-block;
  margin-left: 0.25rem;
  font-weight: 700;
  transition: transform 0.15s ease;
}

.admin-regle-detail[open] > summary::after {
  transform: rotate(90deg);
}

.admin-regle-detail > summary:hover {
  color: var(--mijoteuse-terracotta-fonce);
}

.admin-regle-detail[open] > summary {
  margin-bottom: 0.15rem;
}

.admin-regles a {
  font-weight: 600;
}

/* Le formulaire d'un réglage — maquette de l'administration, 2026-09-23.

   Il reprend « .moderation-ligne » (§ 20 o) : valeur, motif et bouton sur
   une ligne, qui se replie sur un écran étroit. La valeur est plus
   étroite que le motif — un entier ou un choix d'un côté, une phrase de
   l'autre.

   🔴 CECI REMPLACE UN TABLEAU À TROIS COLONNES, et le motif était
   mesuré : « align-middle » centre CHAQUE cellule sur sa propre hauteur.
   Le champ se retrouvait en haut, son libellé au milieu, le bouton en
   bas — et rien ne disait plus quel champ allait avec quel réglage. */
.admin-reglage {
  margin-top: 0.875rem;
  padding-top: 0.875rem;
  border-top: 1px solid #f2eade;
}

.moderation-ligne.admin-reglage > label:first-of-type {
  flex: 0 1 12rem;
}

/* ⚠️ DEUX ÉTATS DE PLUS, ET C'EST UN MANQUE QUI SE VOYAIT — maquette de
   l'administration, 2026-09-23. La charte n'avait que « neutre » et « à
   faire » : sur l'écran des invitations, « utilisée », « révoquée » et
   « expirée » sortaient toutes en gris. Trois états, un seul signal.

   ⚠️ Le MOT restait écrit — l'ADR-046 était respecté — mais la couleur
   ne disait rien, et c'est elle qu'on lit en parcourant une liste. */

/* Ce qui est ACCOMPLI (« utilisée ») : herbe pâle, les teintes de ce qui
   rassure. Contraste mesuré par la maquette : 5,6:1. */
.pastille--faite {
  background-color: var(--mijoteuse-herbe-pale);
  border-color: var(--mijoteuse-herbe-filet);
  color: var(--mijoteuse-vert-herbe);
}

/* Ce qui NE SERT PLUS (« révoquée », « expirée ») : fond transparent et
   filet en POINTILLÉS — le signal de .carte-ajout pour « autre nature ».

   🔴 LE POINTILLÉ EST LÀ POUR QU'ELLE SE DISTINGUE SANS COULEUR. Une
   pastille éteinte et une pastille neutre ne se différencieraient que
   par leur gris, et c'est exactement ce que l'ADR-046 refuse.
   Contraste : 5,5:1 sur crème. */
.pastille--eteinte {
  background-color: transparent;
  border-style: dashed;
  border-color: #d9c7ae;
  color: var(--mijoteuse-texte-doux);
  font-weight: 600;
}

/* Le compte à côté d'un titre de section — « Profils 4 ». */
.compte-pastille {
  display: inline-block;
  padding: 0.2rem 0.55rem;
  background-color: var(--mijoteuse-terracotta-pale);
  border-radius: 999px;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.75rem;
  font-weight: 800;
}

.compte-pastille--herbe {
  background-color: var(--mijoteuse-herbe-pale);
  color: var(--mijoteuse-vert-herbe);
}

/* -------------------------------------------------------------------
   20 g. Les titres de section d'une page de liste

   « Profils · 4 · — les personnes pour qui l'on cuisine » : le titre,
   son compte, sa légende sur une ligne de base commune, puis une phrase
   d'aide.
   ------------------------------------------------------------------- */
.section-titre {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.625rem;
  margin: 0 0 0.2rem;
}

.section-titre > h2 {
  margin: 0;
  font-size: 1.375rem;
}

.section-legende {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.84375rem;
}

.section-aide {
  max-width: 52ch;
  margin: 0 0 0.875rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
  line-height: 1.5;
}

.section-liste {
  margin-bottom: 2rem;
}

/* -------------------------------------------------------------------
   20 h. Les encadrés

   Trois natures, trois formes — et le mot est toujours écrit :

     .info-herbe     une règle du produit, rassurante (« un foyer ne
                     porte aucune contrainte ») ;
     .avis-compte    « à vérifier », terre cuite pâle — § 18 e ;
     .avis-brique    un refus, un motif de modérateur, une mise en garde
                     qui engage la santé d'autrui.
   ------------------------------------------------------------------- */
.info-herbe {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  max-width: 38rem;
  margin: 0 0 1.5rem;
  padding: 0.75rem 0.875rem;
  background-color: var(--mijoteuse-herbe-pale);
  border: 1px solid var(--mijoteuse-herbe-filet);
  border-radius: 12px;
  color: #4a5340;
  font-size: 0.8125rem;
  line-height: 1.5;
}

.info-herbe > svg {
  flex-shrink: 0;
  width: 17px;
  height: 17px;
  margin-top: 1px;
  color: var(--mijoteuse-vert-herbe);
}

.avis-brique {
  max-width: 44rem;
  margin: 0.7rem 0 0;
  padding: 0.7rem 0.875rem;
  background-color: #fbf1ee;
  border-left: 4px solid var(--mijoteuse-brique);
  border-radius: 0 12px 12px 0;
  color: #7c2919;
  font-size: 0.84375rem;
  line-height: 1.5;
}

.avis-brique-titre {
  display: block;
  margin: 0 0 0.25rem;
  color: var(--mijoteuse-brique);
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.avis-brique p {
  margin: 0;
}

.avis-brique p + p {
  margin-top: 0.4rem;
}

/* La variante posée en tête de page, sous le chapeau : elle n'a pas la
   marge haute d'un encadré de carte. */
.avis-brique--page {
  margin: 0 0 1.125rem;
}

/* L'avis du compte, resserré, à l'intérieur d'une carte. */
.avis-compte--serre {
  max-width: none;
  margin: 0 0 0.875rem;
}

/* « Supprimer » en bouton discret : la brique de la § 15 a, pour ce
   qui détruit — et le mot est écrit. */
.action-discrete--brique {
  border-color: var(--mijoteuse-brique-filet);
  color: var(--mijoteuse-brique);
}

.action-discrete--brique:hover,
.action-discrete--brique:focus-visible {
  background-color: #fbf1ee;
  border-color: var(--mijoteuse-brique);
  color: var(--mijoteuse-brique);
}

/* -------------------------------------------------------------------
   20 i. Les notifications rejoignent la liste encadrée

   ⚠️ CETTE SOUS-SECTION REDÉFINIT LA § 15 f bis : une carte par
   notification devient une ligne dans une seule carte. Les règles
   d'ici passent APRÈS, donc gagnent. « Non lue » reste ÉCRIT.
   ------------------------------------------------------------------- */
.notifications {
  gap: 0;
}

.notification {
  padding: 0.9375rem 1rem;
  border: none;
  border-radius: 0;
}

.notification--non-lue {
  background-color: #fffbf4;
}

.notification-etat {
  margin-right: 0.45rem;
  padding: 0.1rem 0.45rem;
  border: none;
  background-color: var(--mijoteuse-terracotta);
  color: #fff;
  font-size: 0.625rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  vertical-align: 1px;
}

.notification-texte {
  font-size: 0.90625rem;
  line-height: 1.5;
}

.notification-texte > a {
  color: var(--mijoteuse-terracotta-fonce);
  font-weight: 600;
  text-decoration: none;
}

.notification-texte > a:hover,
.notification-texte > a:focus {
  text-decoration: underline;
}

.notification-complement {
  margin-top: 0.15rem;
  font-size: 0.84375rem;
}

.notification-pied {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.notification-pied .btn-link {
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.78125rem;
  font-weight: 700;
  text-decoration: none;
}

.notification-pied .btn-link:hover,
.notification-pied .btn-link:focus {
  text-decoration: underline;
}

/* -------------------------------------------------------------------
   20 j. Les états vides et les pages d'erreur

   Un vide MUET se lit comme une panne (test_an_empty_feed_explains_
   itself). La maquette lui donne une forme : un cadre en pointillés,
   un signe, un titre en serif, une phrase, une sortie.
   ------------------------------------------------------------------- */
.vide {
  padding: 3rem 1.25rem;
  background-color: var(--mijoteuse-carte);
  border: 1px dashed #e4d6c1;
  border-radius: 20px;
  text-align: center;
}

.vide-signe {
  margin: 0;
  color: #d9b98f;
  font-size: 2.75rem;
  line-height: 1;
}

.vide > h1,
.vide > h2 {
  margin: 0.625rem 0 0.375rem;
  font-size: 1.5rem;
}

.vide > p {
  max-width: 26rem;
  margin: 0 auto 1.125rem;
  color: var(--mijoteuse-texte-doux);
  line-height: 1.55;
}

.vide > p:last-child {
  margin-bottom: 0;
}

.vide > .btn {
  margin-top: 0.25rem;
}

.page-erreur {
  margin-top: 1rem;
}

.page-erreur > h1 {
  font-size: 1.75rem;
}

/* -------------------------------------------------------------------
   20 k. Les cartes de recette — catalogue, résultats, profil public

   La grille, c'est le catalogue (§ 5 bis) : une vignette, le titre en
   serif, l'auteur, les métadonnées en pied. Le titre porte le lien ; la
   carte entière le suit par .stretched-link, qui exige un parent en
   position:relative.
   ------------------------------------------------------------------- */
.grille-recettes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: 1rem;
}

.carte-recette {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 0;
  border-radius: 18px;
}

.carte-recette-photo {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

/* La vignette d'absence de photo est celle du fil ; ici elle se
   raccourcit un peu, la carte étant plus étroite. */
.carte-recette > .fil-vignette {
  aspect-ratio: 16 / 9;
}

.carte-recette-corps {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.8rem 0.9375rem 0.9375rem;
}

.carte-recette-titre {
  margin: 0;
  font-size: 1.125rem;
  line-height: 1.2;
}

.carte-recette-titre > a {
  color: var(--mijoteuse-brun);
  text-decoration: none;
}

.carte-recette-titre > a:hover,
.carte-recette-titre > a:focus {
  text-decoration: underline;
}

.carte-recette-auteur {
  margin: 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
}

/* Deux lignes de description, pas plus : la carte doit rester une
   carte. -webkit-line-clamp est compris par tous les navigateurs
   courants malgré son préfixe. */
.carte-recette-description {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  margin: 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.84375rem;
  line-height: 1.5;
}

.carte-recette-corps > .fil-meta {
  margin-top: auto;
  margin-bottom: 0;
  padding-top: 0.35rem;
}

/* -------------------------------------------------------------------
   20 l. L'en-tête d'un profil public

   L'avatar grandit, le nom prend la serif, les actions se rangent à
   droite. ⚠️ PAS DE CHIFFRES : la route plafonne ses listes à vingt,
   un compte lu dessus mentirait. Des compteurs viendront avec un
   service qui compte.
   ------------------------------------------------------------------- */
.profil-avatar--grand {
  width: 74px;
  height: 74px;
  font-size: 2rem;
}

.profil-identite {
  flex: 1 1 11rem;
  min-width: 0;
}

.profil-identite > h1 {
  margin: 0;
  font-size: clamp(1.5rem, 3.6vw, 2rem);
}

.profil-identite > p {
  margin: 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.875rem;
}

.profil-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-left: auto;
}

.profil-entete {
  flex-wrap: wrap;
}

/* -------------------------------------------------------------------
   20 m. Les blocs de « Mon espace »

   Une carte, un titre précédé d'une tuile d'icône, des lignes sous un
   filet, un lien de pied. Les lignes restent des .ligne-resume (§ 5
   ter) : test_dashboard.py les compte.
   ------------------------------------------------------------------- */
.bloc {
  height: 100%;
  padding: 1.125rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 18px;
}

.bloc-titre {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0 0 0.75rem;
  font-family: "Hanken Grotesk", system-ui, sans-serif;
  font-size: 1rem;
  font-weight: 700;
}

.bloc > .liste-nue {
  margin-bottom: 0.75rem;
}

.bloc .ligne-resume {
  padding: 0.6rem 0;
  border-bottom: none;
  border-top: 1px solid #f2eade;
  font-size: 0.9375rem;
}

.bloc-texte {
  margin: 0 0 0.75rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.875rem;
  line-height: 1.55;
}

.bloc-pied {
  margin: 0;
}

.bloc-pied > a {
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.875rem;
  font-weight: 600;
  text-decoration: none;
}

.bloc-pied > a:hover,
.bloc-pied > a:focus {
  text-decoration: underline;
}

/* -------------------------------------------------------------------
   20 n. Les cartes d'un foyer et de ses profils
   ------------------------------------------------------------------- */
.carte-foyer {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  color: var(--mijoteuse-brun);
  text-decoration: none;
}

.carte-foyer:hover,
.carte-foyer:focus {
  color: var(--mijoteuse-brun);
  text-decoration: none;
}

.carte-foyer:hover .carte-titre,
.carte-foyer:focus .carte-titre {
  text-decoration: underline;
}

.carte-foyer-tete {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  width: 100%;
}

.carte-foyer-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.78125rem;
}

/* Le profil qui est le vôtre porte un liseré terre cuite à gauche. */
.carte-profil--mien {
  box-shadow: inset 3px 0 0 var(--mijoteuse-terracotta);
}

.carte-profil-lien {
  display: block;
  margin-top: 0.1rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
}

.carte-profil-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.7rem;
}

.carte-note {
  display: flex;
  align-items: flex-start;
  gap: 0.45rem;
  margin: 0.7rem 0 0;
  padding-top: 0.625rem;
  border-top: 1px solid #f2eade;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
  line-height: 1.4;
}

.carte-note > svg {
  flex-shrink: 0;
  width: 15px;
  height: 15px;
  color: var(--mijoteuse-vert-herbe);
}

.membre-tete {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.45rem;
}

/* -------------------------------------------------------------------
   20 o. La modération

   Chaque recette dans sa carte ; sous le titre, trois formulaires en
   colonne. Le motif est un champ VISIBLE avec son étiquette — il était
   masqué (visually-hidden) au profit d'un placeholder, qui disparaît
   dès qu'on écrit.
   ------------------------------------------------------------------- */
.moderation-formulaires {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  margin-top: 0.875rem;
}

.moderation-ligne {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 0.6rem;
}

.moderation-ligne > label {
  display: block;
  flex: 1 1 13rem;
  min-width: 0;
}

.moderation-ligne > label > span {
  display: block;
  margin-bottom: 0.25rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
  font-weight: 700;
}

.moderation-ligne textarea {
  min-height: 3.6rem;
  font-size: 0.875rem;
}

.moderation-ligne > .btn {
  flex-shrink: 0;
}

/* -------------------------------------------------------------------
   20 p. Le cadre des pages d'entrée — inscription, connexion, mots de
   passe

   La maquette les dessine SANS colonne de navigation. Le gabarit commun
   la garde : le balisage n'existe qu'une fois, et test_navigation.py
   compte l'état courant sur /login. C'est donc le contenu qui prend la
   forme de la maquette — la marque, le titre en serif, la phrase
   d'accueil, les champs plus hauts, le bouton pleine largeur, la ligne
   de bascule.
   ------------------------------------------------------------------- */
.auth-cadre {
  max-width: 26.25rem;
  margin: 0.5rem auto 0;
}

.auth-marque {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin: 0 0 1.375rem;
  color: var(--mijoteuse-brun);
  font-size: 1.125rem;
  font-weight: 800;
  letter-spacing: -0.02em;
}

.auth-cadre > h1 {
  margin: 0 0 0.375rem;
  font-size: clamp(1.625rem, 4vw, 2.125rem);
  line-height: 1.1;
}

.auth-sous-titre {
  margin: 0 0 1.375rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.90625rem;
  line-height: 1.5;
}

.auth-cadre .form-control {
  padding: 0.8rem 0.875rem;
  border-radius: 12px;
  font-size: 0.9375rem;
}

.auth-bouton {
  display: block;
  width: 100%;
  margin-top: 0.5rem;
  padding: 0.9rem;
  border-radius: 13px;
  font-size: 1rem;
  font-weight: 800;
}

.auth-liens {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem 1.125rem;
  margin: 0.875rem 0 0;
  padding: 0;
  list-style: none;
}

.auth-liens a,
.auth-bascule a {
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.84375rem;
  font-weight: 600;
  text-decoration: underline;
}

.auth-bascule {
  margin: 1rem 0 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.84375rem;
  text-align: center;
}

.auth-bascule a {
  font-weight: 700;
}

/* ===================================================================
   21. L'atelier — moins de gris, plus de structure — 2026-08-30

   « Je trouve moche la partie création de recette » — Rodolphe, le
   2026-08-30, capture à l'appui. Ce qui rendait la page moche, mesuré :

     · douze champs, chacun suivi de trois ou quatre lignes d'aide
       grise — la page était à 80 % du texte d'aide (ADR-059, § 15 b) ;
     · cinq sections posées à plat sur le fond crème, sans relief ;
     · les ingrédients en mini-cartes séparées, avec une colonne de
       dose vide quand il n'y a pas de dose ;
     · le formulaire « Titre du groupe » entre la liste et le bloc
       d'ajout, qu'on prenait pour une ligne de la liste ;
     · la photo réduite à un « Choisir un fichier ».

   ⚠️ LE WIKI IMPOSE UNE PAGE UNIQUE (Création d'une recette, règle
   impérative n° 2) : l'assistant en quatre étapes de la maquette n'est
   PAS transposé. Ce qui l'est : ses champs à aide repliée, ses zones
   d'ajout en pointillés, sa zone de photo, ses étapes numérotées.

   ⚠️ AUCUN IDENTIFIANT NI data-* NE CHANGE : content-add.ts,
   autosave.ts et ingredient-search.ts lisent le gabarit, pas la charte.
   =================================================================== */

/* -------------------------------------------------------------------
   21 a. L'aide repliée — « ? Aide »

   Un <details> natif : Tab l'atteint, Entrée l'ouvre, le doigt aussi,
   sans script. L'aide garde son identifiant et son aria-describedby
   (voir la macro « champ »). Le marqueur triangle du navigateur est
   retiré : le rond « ? » le remplace, et change d'état à l'ouverture.
   ------------------------------------------------------------------- */
.aide-champ {
  margin-top: 0.4rem;
}

.aide-champ > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  list-style: none;
  cursor: pointer;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.78125rem;
  font-weight: 600;
}

.aide-champ > summary::-webkit-details-marker {
  display: none;
}

.aide-champ > summary:focus-visible {
  outline: 3px solid var(--mijoteuse-terracotta-pale);
  outline-offset: 2px;
  border-radius: 999px;
}

.aide-champ-signe {
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border: 1px solid #dccbb2;
  border-radius: 50%;
  background-color: var(--mijoteuse-carte);
  color: var(--mijoteuse-texte-doux);
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
}

.aide-champ > summary:hover .aide-champ-signe,
.aide-champ[open] > summary .aide-champ-signe {
  background-color: var(--mijoteuse-terracotta-pale);
  border-color: var(--mijoteuse-terracotta);
  color: var(--mijoteuse-terracotta-fonce);
}

.aide-champ[open] > summary {
  color: var(--mijoteuse-terracotta-fonce);
}

/* L'aide dépliée : sur fond crème, pour qu'on voie d'où elle vient. */
.aide-champ > .form-text {
  margin-top: 0.4rem;
  padding: 0.6rem 0.8rem;
  background-color: var(--mijoteuse-creme);
  border-radius: 10px;
}

/* -------------------------------------------------------------------
   21 b. Les sections numérotées, et leur corps en carte

   Le titre porte un numéro dans un rond — celui des étapes de la
   maquette —, et son filet disparaît : c'est la carte, dessous, qui
   délimite désormais. Le numéro vient d'un compteur CSS : le gabarit
   n'a pas à le connaître.
   ------------------------------------------------------------------- */
.atelier {
  counter-reset: atelier-section;
}

.atelier-section > h2 {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.9rem;
  padding-bottom: 0;
  border-bottom: none;
  counter-increment: atelier-section;
}

.atelier-section > h2::before {
  content: counter(atelier-section);
  display: inline-grid;
  place-items: center;
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background-color: var(--mijoteuse-terracotta-pale);
  color: var(--mijoteuse-terracotta-fonce);
  font-family: "Hanken Grotesk", system-ui, sans-serif;
  font-size: 0.8125rem;
  font-weight: 800;
}

.atelier-bloc {
  padding: 1.25rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 18px;
}

.atelier-bloc > .chapo {
  margin-bottom: 1rem;
  font-size: 1rem;
}

/* Dans une carte, la zone d'ajout n'est plus une carte de plus : un
   encart crème en pointillés — « autre nature de geste », comme
   .atelier-carte--creation (§ 15 d). */
.atelier-bloc .atelier-carte {
  background-color: var(--mijoteuse-creme);
  border: 1.5px dashed var(--mijoteuse-champ-filet);
  border-radius: 14px;
}

.atelier-bloc .atelier-carte > .titre-bloc {
  margin-bottom: 1rem;
  font-size: 1.0625rem;
}

/* Le pied d'un formulaire : le bouton, le lien, l'état — sur une ligne. */
.atelier-pied {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  margin-top: 0.25rem;
}

/* -------------------------------------------------------------------
   21 c. Les lignes d'ingrédient et d'étape : une carte, des filets

   Une carte par ligne (§ 15 f) faisait une pile de boîtes. Les lignes
   se rangent dans une seule carte, séparées par un filet — la liste
   encadrée de la § 20 d. La dose garde sa colonne fixe (chiffres
   tabulaires), un peu plus étroite.
   ------------------------------------------------------------------- */
.atelier-bloc .lignes {
  gap: 0;
  margin: 0 0 1rem;
  overflow: hidden;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 14px;
}

.atelier-bloc .lignes > .ligne {
  padding: 0.65rem 0.9rem;
  border: none;
  border-top: 1px solid #f2eade;
  border-radius: 0;
}

.atelier-bloc .lignes > .ligne:first-child {
  border-top: none;
}

.atelier-bloc .ligne-dose {
  width: 4rem;
  color: var(--mijoteuse-terracotta-fonce);
}

/* Les gestes d'une ligne : des boutons sans cadre, qui le prennent au
   survol — trois cadres par ligne sur dix lignes faisaient trente
   petites boîtes. Les aria-label sont inchangés. */
.atelier-bloc .ligne-actions .btn {
  border-color: transparent;
  background-color: transparent;
}

.atelier-bloc .ligne-actions .btn:hover,
.atelier-bloc .ligne-actions .btn:focus-visible {
  border-color: var(--mijoteuse-bordure);
  background-color: var(--mijoteuse-creme);
}

.atelier-bloc .ligne-actions .btn-outline-danger:hover,
.atelier-bloc .ligne-actions .btn-outline-danger:focus-visible {
  border-color: var(--mijoteuse-brique);
  background-color: var(--mijoteuse-brique);
}

/* Le numéro d'une étape : le rond des étapes de la fiche (§ 15 i). */
.atelier-bloc .ligne--etape {
  padding: 0.9rem;
}

.atelier-bloc .ligne--etape .ligne-numero {
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  margin-top: 0.2rem;
  border-radius: 50%;
  background-color: var(--mijoteuse-terracotta-pale);
  color: var(--mijoteuse-terracotta-fonce);
  font-family: "Hanken Grotesk", system-ui, sans-serif;
  font-size: 0.8125rem;
  font-weight: 800;
}

/* L'en-tête d'un groupe, dans la carte des lignes. */
.atelier-bloc .groupe-entete {
  margin: 1rem 0 0.5rem;
}

/* -------------------------------------------------------------------
   21 d. Le groupe, replié ; la photo, en zone

   « Titre du groupe » se prenait pour une ligne de la liste. Il se
   range derrière un <details> — natif, sans script — que la plupart
   des recettes n'ouvriront jamais.
   ------------------------------------------------------------------- */
.atelier-repli {
  margin: 0.25rem 0 0;
}

.atelier-repli > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  list-style: none;
  cursor: pointer;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.8125rem;
  font-weight: 700;
}

.atelier-repli > summary::-webkit-details-marker {
  display: none;
}

.atelier-repli > summary::before {
  content: "+";
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border: 1px solid #dccbb2;
  border-radius: 50%;
  font-size: 0.75rem;
  line-height: 1;
}

.atelier-repli[open] > summary::before {
  content: "–";
  background-color: var(--mijoteuse-terracotta-pale);
  border-color: var(--mijoteuse-terracotta);
}

.atelier-repli > summary:focus-visible {
  outline: 3px solid var(--mijoteuse-terracotta-pale);
  outline-offset: 2px;
  border-radius: 999px;
}

.atelier-bloc .groupe-ajout {
  max-width: none;
  margin-top: 0.6rem;
  padding: 0.9rem 1rem;
  background-color: var(--mijoteuse-creme);
  border: 1.5px dashed var(--mijoteuse-champ-filet);
  border-radius: 12px;
}

/* La zone de photo : le signe, une phrase, le champ, le bouton —
   centrés. Le champ reste le <input type=file> natif : sans script,
   c'est lui seul qui montre le nom du fichier choisi. */
.atelier-carte--photo {
  text-align: center;
}

.atelier-photo-signe {
  display: block;
  margin: 0 auto 0.5rem;
  width: 30px;
  height: 30px;
  color: #c4b7a6;
}

.atelier-carte--photo .form-label {
  display: block;
  font-size: 1rem;
}

.atelier-carte--photo .form-control {
  max-width: 24rem;
  margin: 0 auto;
}

.atelier-carte--photo .form-text {
  max-width: 30rem;
  margin: 0.5rem auto 0;
}

.atelier-carte--photo .btn {
  margin-top: 0.9rem;
}

/* La photo en place : arrondie, et retirable juste dessous. */
.atelier-bloc .atelier-photo {
  margin: 0 0 0.75rem;
}

/* ===================================================================
   22. La mesure suit la maquette — ADR-092, qui amende l'ADR-051 et
   l'ADR-060

   « Ça ne prend pas la totalité de l'écran » — Rodolphe, le 2026-08-30.
   La mesure unique de 41 rem, centrée (ADR-051, § 14 a), laissait les
   deux tiers d'un écran d'ordinateur vides, de part et d'autre d'une
   colonne qui flottait. La maquette fait l'inverse : le contenu part du
   bord gauche de la zone, derrière une gouttière de 18 à 44 px, et
   chaque page porte son propre plafond — 760 px pour l'atelier, 720 à
   900 pour les listes, aucun pour l'espace, la recherche, le catalogue.

   ⚠️ LE MÉCANISME NE CHANGE PAS : le bloc « mesure » du gabarit commun,
   partagé par les messages, le contenu et le pied (ADR-060). Une page y
   ajoute UNE classe — « container mesure-liste » — et les trois zones
   suivent ensemble. Sans classe, la page prend toute la largeur.

   ⚠️ LA § 14 a N'EST PAS RÉÉCRITE, elle est dépassée : à priorité
   égale, la dernière règle lue gagne.

   ⚠️ AUCUN TEST N'EXÉCUTE DE CSS. Se vérifie au navigateur, de part et
   d'autre de 992 px — et à 1 920 px, où une prose sans plafond ne se
   lit plus.
   =================================================================== */
:root {
  /* La gouttière de la maquette : « clamp(18px, 4vw, 44px) ». */
  --mijoteuse-gouttiere: clamp(1.125rem, 4vw, 2.75rem);
}

.app-corps .container {
  max-width: none;
  margin-left: 0;
  padding-right: var(--mijoteuse-gouttiere);
  padding-left: var(--mijoteuse-gouttiere);
}

/* La barre de recherche reste CENTRÉE au-dessus de la zone — demande de
   Rodolphe, le 2026-08-30, capture à l'appui : alignée à gauche avec le
   contenu, elle semblait collée à la colonne. Elle garde le plafond de
   la maquette (640 px) : une barre de 1 600 px serait une tranchée. Sur
   un écran étroit, elle laisse la gouttière de chaque côté. */
.barre-recherche {
  width: calc(100% - 2 * var(--mijoteuse-gouttiere));
  max-width: 40rem;
  margin: 1.25rem auto 0;
}

/* Les plafonds par page — alignés à gauche, jamais centrés. C'est la
   LISTE de l'ADR-092 : une classe qui n'y est pas est un signe d'alerte. */
.mesure-fil {
  max-width: 40rem;   /* le fil : 600 px dans la maquette */
}

.mesure-lecture {
  max-width: 44rem;   /* de la prose, un formulaire */
}

.mesure-liste {
  max-width: 54rem;   /* mes recettes, un foyer, la modération : 820–900 px */
}

.mesure-large {
  max-width: 68rem;   /* réservé — la fiche a la sienne (ADR-061) */
}

/* 🔴 LES QUATRE PLAFONDS CI-DESSUS N'ONT JAMAIS ÉTÉ APPLIQUÉS.

   ⚠️ MESURÉ LE 2026-09-01, SUR UNE CAPTURE D'ÉCRAN DE RODOLPHE — « c'est
   encore moche » —, dix jours après l'ADR-092.

   Le <main> porte « container mesure-liste », et les deux règles se
   disputent « max-width » sur le MÊME élément :

       .app-corps .container    deux classes   -> spécificité 0,2,0
       .mesure-liste            une classe     -> spécificité 0,1,0

   La plus spécifique gagne, quel que soit l'ordre de lecture. « max-width:
   none » l'emportait donc partout, et les 22 pages qui déclarent une
   mesure s'étalaient sur toute la largeur — 1 500 px de prose sur un
   écran d'ordinateur, soit exactement ce que l'ADR-092 voulait empêcher.

   🔴 « À PRIORITÉ ÉGALE, LA DERNIÈRE RÈGLE LUE GAGNE » — l'en-tête de ce
   fichier le dit, et c'est vrai. Le piège est dans « à priorité égale » :
   ajouter une classe à un sélecteur change la priorité, et l'ordre cesse
   alors de compter. Écrire la règle plus bas ne suffisait pas.

   ⚠️ AUCUN TEST N'EXÉCUTE DE CSS. Le § 22 l'écrivait déjà — « se vérifie
   au navigateur » — et personne ne l'avait fait. C'est la limite connue
   de toute cette feuille, pas un oubli isolé.

   Les pages SANS classe de mesure — l'espace, la recherche, le
   catalogue — gardent la pleine largeur : elles n'entrent dans aucune
   des règles ci-dessous. */
.app-corps .mesure-fil {
  max-width: 40rem;
}

.app-corps .mesure-lecture {
  max-width: 44rem;
}

.app-corps .mesure-liste {
  max-width: 54rem;
}

.app-corps .mesure-large {
  max-width: 68rem;
}

/* Les formulaires que la grille de Bootstrap centrait — col-lg-6 ou
   col-lg-8 dans une .row.justify-content-center — prennent toute la
   mesure de lecture : centrer deux tiers de 44 rem donnerait un
   formulaire de 29 rem posé au tiers de la page. Le gabarit n'est pas
   touché ; la règle vise exactement ce motif. */
.mesure-lecture > .row > [class*="col-"] {
  flex: 0 0 100%;
  max-width: 100%;
}

/* L'atelier : 760 px dans la maquette, à gauche. Les pages étroites —
   publier, une étape, les formulaires du compte — à 40 rem. */
.atelier {
  max-width: 48rem;
  margin: 0;
}

.atelier-etroit {
  max-width: 40rem;
  margin: 0;
}

/* « Mon compte » (ADR-060) et la fiche d'un profil (ADR-115) reprennent
   la gouttière commune : leur bord gauche doit tomber au même pixel que
   celui des autres pages. */
.compte-large,
.mesure-pleine {
  padding-right: var(--mijoteuse-gouttiere);
  padding-left: var(--mijoteuse-gouttiere);
}

/* ===================================================================
   23. La bande haute — notifications, recherche, accès réservés
       2026-08-31

   Trois fentes sur une ligne, à la hauteur de la barre de recherche :

     gauche   les notifications — ce qui vient d'arriver ;
     centre   la barre de recherche ;
     droite   la modération et l'administration, selon les rôles.

   ⚠️ LA BARRE DE RECHERCHE RESTE AU CENTRE. C'est ce que l'ADR-092 a
   retenu, capture à l'appui : alignée à gauche, elle semblait collée
   à la colonne. Les deux fentes latérales sont donc TOUJOURS rendues,
   même vides, et se partagent la place restante à parts égales.
   =================================================================== */

/* Sous 576 px, la bande ne fait rien : la barre garde les marges de la
   § 22, et les deux fentes prennent une ligne chacune. La gauche est
   alignée à gauche, la droite à droite — elles restent du même côté
   que sur grand écran, ce qui évite d'avoir à réapprendre la page.

   ⚠️ DÈS 576 px, LA BANDE EST UNE RANGÉE (ADR-096). Elle empilait
   Notifications puis la recherche jusqu'à 991 px : deux lignes
   perdues sur une tablette qui a la place d'une seule. */
.barre-haut-gauche,
.barre-haut-acces {
  display: flex;
  gap: 0.5rem;
  margin: 0 var(--mijoteuse-gouttiere);
}

.barre-haut-gauche { justify-content: flex-start; }
.barre-haut-acces  { justify-content: flex-end; }

/* 🔴 L'ÉCART EST PORTÉ PAR LE BOUTON, PAS PAR LA FENTE.

   Les fentes sont rendues même vides — c'est ce qui centre la barre.
   Une marge haute posée sur la fente laisserait donc un blanc sous la
   barre chez qui n'a ni notification ni rôle réservé, c'est-à-dire
   chez presque tout le monde.

   ⚠️ « :empty » NE RÈGLE PAS CE CAS. Il n'atteint que les éléments
   sans AUCUN enfant NI nœud de texte — et Jinja laisse des retours à
   la ligne dans la fente, qui sont des nœuds de texte. La règle ne
   s'appliquerait jamais, sans que rien ne le signale.

   Une fente vide est une boîte flex sans élément : sa hauteur vaut
   zéro, et elle ne se voit pas. */
.barre-haut-gauche > .acces-bande,
.barre-haut-acces > .acces-bande {
  margin-top: 0.75rem;
}

/* Le bouton reprend la matière de la barre de recherche — même fond,
   même filet, même ombre — et l'arrondi resserré de son bouton
   « Chercher » : c'est la même bande, pas une pièce rapportée. */
.acces-bande {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  gap: 0.45rem;
  height: 44px;              /* la zone tactile minimale de la § 13 */
  padding: 0 0.85rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 12px;
  box-shadow: 0 10px 30px -24px rgba(80, 45, 20, 0.6);
  color: var(--mijoteuse-brun);
  font-size: 0.9375rem;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
}

.acces-bande:hover,
.acces-bande:focus-visible {
  background-color: var(--mijoteuse-terracotta-pale);
  border-color: var(--mijoteuse-terracotta);
  color: var(--mijoteuse-terracotta-fonce);
}

/* ⚠️ L'ÉTAT COURANT SE VOIT, il n'est pas seulement annoncé.
   aria-current dit à un lecteur d'écran qu'on y est déjà ; sans repère
   visuel, personne d'autre ne le sait. Même fond que l'entrée active
   de la colonne : c'est la même idée, elle doit se lire pareil. */
.acces-bande.actif {
  background-color: var(--mijoteuse-terracotta-pale);
  border-color: transparent;
  color: var(--mijoteuse-terracotta-fonce);
}

/* Terre cuite au repos, comme la loupe de la barre : c'est le repère
   qui désigne le bouton avant qu'on lise son libellé. Au survol elle
   suit le texte, sans quoi elle jurerait sur le fond pâle. */
.acces-bande-icone {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  color: var(--mijoteuse-terracotta);
}

.acces-bande:hover .acces-bande-icone,
.acces-bande:focus-visible .acces-bande-icone,
.acces-bande.actif .acces-bande-icone {
  color: inherit;
}

@media (min-width: 576px) {
  .barre-haut {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0 var(--mijoteuse-gouttiere);
  }

  /* ⚠️ « flex: 1 1 0 » SUR LES DEUX FENTES, ET C'EST CE QUI CENTRE.
     Base nulle des deux côtés, même souplesse : elles se partagent la
     place restante à parts égales, et la barre tombe au milieu. Une
     fente rendue seulement quand elle a du contenu ferait sauter la
     barre d'une page à l'autre.

     ⚠️ AUCUN « min-width: 0 » ICI, et c'est délibéré. Le minimum
     automatique d'un élément flex vaut la largeur de son contenu :
     c'est lui qui empêche les boutons d'être rognés quand la place
     manque. C'est alors la barre qui rétrécit — elle sait le faire,
     eux non. */
  .barre-haut-gauche,
  .barre-haut-acces {
    flex: 1 1 0;
    margin: 0;
  }

  /* La bande est alignée sur les centres : l'écart haut du bouton
     entre dans la hauteur de sa fente, et les trois se retrouvent
     centrées sur la même ligne que la barre de recherche. */
  .barre-haut-gauche > .acces-bande,
  .barre-haut-acces > .acces-bande {
    margin-top: 1.25rem;
  }

  /* La barre perd ici la largeur et les marges de la § 22 : c'est la
     bande qui porte désormais la gouttière, et le flex qui la place. */
  .barre-haut > .barre-recherche {
    flex: 0 1 40rem;
    width: auto;
    max-width: 40rem;
    margin-right: 0;
    margin-left: 0;
  }
}

/* ===================================================================
   24. La mosaïque du fil — 2026-08-31

   🔴 LE FIL ÉTAIT UNE PILE DE CARTES DE 40 rem. Mesuré à 1 452 px : il
   occupait 640 px sur une zone de 1 188, soit 46 % — le reste vide.

   Il devient une grille de six colonnes, quatre formats de tuile, à la
   manière d'une page de magazine. L'ADR-092 disait « des cartes de fil
   de 1 000 px ne se lisent pas » : c'est toujours vrai, et c'est
   pourquoi la tuile ne s'élargit PAS — on en met plusieurs de front.
   =================================================================== */

.mosaique {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(6, 1fr);

  /* 🔴 « minmax(x, auto) », JAMAIS UNE HAUTEUR FIXE.

     Les tuiles sont en « overflow: hidden ». Avec une rangée figée,
     tout texte plus haut que « span × rangée » serait coupé en
     silence — pas de barre de défilement, pas d'erreur, juste une
     phrase qui s'arrête. « auto » laisse la rangée grandir. */
  grid-auto-rows: minmax(100px, auto);
}

/* 🔴 AUCUN « grid-auto-flow: dense » ICI, ET C'EST UNE DÉCISION.

   Dense comble les trous en REMONTANT des tuiles : l'ordre vu cesse
   alors de suivre l'ordre du document. Sur un fil dont le seul
   classement est chronologique, la quatrième publication s'afficherait
   au-dessus de la deuxième, et « les plus récentes d'abord »
   deviendrait illisible — y compris au clavier, qui suivrait le
   document pendant que l'œil suit la grille.

   On s'en passe parce que le MOTIF PAVE EXACTEMENT six colonnes :

     une        4 col × 3 rangées
     compagnon  2 col × 3 rangées      → la rangée 1-3 est pleine
     large      3 col × 2 rangées  ×2  → la rangée 4-5 est pleine
     petite     2 col × 2 rangées  ×3  → la rangée 6-7 est pleine

   ⚠️ CHANGER UN SEUL SPAN ROUVRE LES TROUS. Le motif est déclaré dans
   main/index.html ; les deux doivent rester d'accord. */
.tuile--une       { grid-column: span 4; grid-row: span 3; }
.tuile--compagnon { grid-column: span 2; grid-row: span 3; }
.tuile--large     { grid-column: span 3; grid-row: span 2; }
.tuile--petite    { grid-column: span 2; grid-row: span 2; }

/* --- La tuile elle-même -------------------------------------------- */

.tuile {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 18px;
}

/* 🔴 « flex: 1 » SANS PLANCHER ÉCRASE LA PHOTO JUSQU'À UN LISERÉ.

   La hauteur de la tuile est décidée par la grille ; le texte prend ce
   qu'il lui faut, et la photo se contente du reste. Sur une tuile dont
   le texte est long, ce reste tend vers zéro. Le plancher dépend du
   gabarit : une pièce du jour montre une photo, une petite tuile en
   montre l'idée. */
.tuile__photo {
  position: relative;
  flex: 1;
  min-height: 80px;
}

.tuile--une .tuile__photo       { min-height: 140px; }
.tuile--compagnon .tuile__photo { min-height: 100px; }
.tuile--large .tuile__photo     { min-height: 90px; }

/* 🔴 L'IMAGE EST SORTIE DU FLUX, SINON C'EST ELLE QUI FIXE LA HAUTEUR.

   « height: 100% » ne peut rien valoir ici : le cadre n'a pas de
   hauteur définie, il attend celle de son contenu. Le navigateur
   retombe alors sur la hauteur NATURELLE de l'image — une photo en
   portrait montait à 800 px et la rangée « auto » suivait.

   En absolu, l'image n'a plus de voix au chapitre : elle remplit la
   place que la grille et le plancher « min-height » donnent au cadre. */
.tuile__photo img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  /* ⚠️ « cover » ET NON « contain » : une photo de plat ne doit pas
     laisser deux bandes crème de part et d'autre. Le cadrage se perd,
     la matière se voit. */
  object-fit: cover;
}

/* ⚠️ CETTE ZONE DIT QU'IL N'Y A PAS DE PHOTO — elle n'en imite pas une.
   Un aplat gris muet se lirait comme un chargement échoué ; les rayures
   signalent une place réservée. Reprises de .fil-vignette, qu'elle
   remplace. */
.tuile__photo--vide {
  background: repeating-linear-gradient(
    135deg,
    #ead3be, #ead3be 16px,
    #f1dfcc 16px, #f1dfcc 32px
  );
}

/* L'étiquette nomme la place réservée. Monospace : c'est le seul
   endroit du site où le texte dit « ceci n'est pas du contenu ». */
.tuile__etiquette {
  position: absolute;
  bottom: 10px;
  left: 10px;
  max-width: calc(100% - 20px);
  overflow: hidden;
  padding: 3px 9px;
  background-color: rgba(255, 253, 249, 0.78);
  border-radius: 7px;
  color: var(--mijoteuse-texte-doux);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* min-width:0 : sans lui, un titre sans espace — « Bœufbourguignonaux… »
   — refuserait de se couper et élargirait la tuile hors de sa colonne. */
.tuile__texte {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  min-width: 0;
  padding: 0.85rem 1rem 1rem;
}

/* La hiérarchie ne suit pas la taille : les quatre sont des <h2>. */
.tuile__titre {
  margin: 0;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-size: 1.03rem;
  font-weight: 600;
  line-height: 1.2;
}

.tuile--une .tuile__titre {
  font-size: clamp(1.375rem, 2.6vw, 1.875rem);
  font-weight: 500;
}

.tuile--large .tuile__titre { font-size: 1.1875rem; }

.tuile__titre a {
  color: inherit;
  text-decoration: none;
}

.tuile__titre a:hover,
.tuile__titre a:focus-visible {
  color: var(--mijoteuse-terracotta-fonce);
  text-decoration: underline;
}

/* --- Qui, et depuis quand ------------------------------------------ */

.tuile__qui {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0;
  font-size: 0.8125rem;
}

.tuile__avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  background-color: var(--mijoteuse-bordure);
  border-radius: 50%;
  color: var(--mijoteuse-brun);
  font-size: 0.75rem;
  font-weight: 700;
}

/* ⚠️ L'AVATAR NE PORTE PAS L'INFORMATION, il la répète. Sa teinte suit
   la relation, mais c'est le badge écrit à côté qui la dit. */
.tuile__avatar--famille   { background-color: #dde4cf; }
.tuile__avatar--amis      { background-color: #f0e0c4; }
.tuile__avatar--createurs { background-color: #f0d6c4; }

.tuile__auteur {
  overflow: hidden;
  color: var(--mijoteuse-brun);
  font-weight: 700;
  text-decoration: none;
  text-overflow: ellipsis;
  white-space: nowrap;
}

a.tuile__auteur:hover,
a.tuile__auteur:focus-visible {
  color: var(--mijoteuse-terracotta-fonce);
  text-decoration: underline;
}

/* 🔴 LE BADGE EST LA SEULE CHOSE QUI DISE POURQUOI CETTE PUBLICATION
   EST DANS MON FIL. Le mot est écrit ; la couleur ne fait que le
   doubler. Un badge muet et coloré ne dirait rien à qui ne distingue
   pas les teintes, et rien du tout à un lecteur d'écran. */
.tuile__badge {
  flex-shrink: 0;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
}

.tuile__badge--famille {
  background-color: var(--mijoteuse-herbe-pale);
  color: var(--mijoteuse-vert-herbe);
}

/* ⚠️ #7a6b45 ET NON LE #8a6b45 DE LA MAQUETTE : mesuré à 4,13:1 sur ce
   fond, sous les 4,5:1 exigés pour un texte de cette taille. */
.tuile__badge--amis {
  background-color: #f5ead7;
  color: #7a6b45;
}

.tuile__badge--createurs {
  background-color: var(--mijoteuse-terracotta-pale);
  color: var(--mijoteuse-terracotta-fonce);
}

.tuile__quand {
  color: var(--mijoteuse-texte-doux);
  white-space: nowrap;
}

/* --- Légende et pied ------------------------------------------------ */

/* 🔴 « -webkit-line-clamp » EST LE SEUL MOYEN DE COUPER À LA LIGNE.

   Il est préfixé et il n'a pas d'équivalent standard répandu : c'est
   la seule propriété préfixée du fichier, et elle est reconnue par
   tous les navigateurs visés. Sans elle, une légende de 500 signes
   pousserait la tuile hors de sa rangée. */
.tuile__legende {
  display: -webkit-box;
  overflow: hidden;
  margin: 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.875rem;
  line-height: 1.45;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.tuile--une .tuile__legende { -webkit-line-clamp: 3; }

.tuile__pied {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: auto;
  padding-top: 0.6rem;
  border-top: 1px solid var(--mijoteuse-bordure);
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
}

.tuile__supprimer { margin-left: auto; }

/* --- Sous 992 px ----------------------------------------------------

   ⚠️ 992 px, ET NON LES 900 DE LA MAQUETTE. C'est le palier de tout le
   site — celui où la colonne latérale apparaît. Un second seuil à 900
   ouvrirait une bande de 92 px où la colonne est encore repliée et la
   mosaïque déjà réduite.

   Deux colonnes — la bande MÉDIANE, 576 à 991 px (ADR-096) : la
   pièce du jour garde toute la largeur, TOUT LE RESTE se met par
   deux. Le pavage reste exact, et le test le recalcule :

     une                       2 col × 3 rangées   → pleine
     compagnon + large         1 col × 2 chacune   → rangée pleine
     large + petite            1 col × 2 chacune   → rangée pleine
     petite + petite           1 col × 2 chacune   → rangée pleine

   ⚠️ SIX DEMI-TUILES PAR MOTIF, UN NOMBRE PAIR : c'est ce qui ferme
   le motif sans trou. En ajouter une septième rouvrirait le trou que
   ce même test avait trouvé à l'écriture de la § 24. */
@media (max-width: 991.98px) {
  .mosaique {
    grid-template-columns: repeat(2, 1fr);
    grid-auto-rows: minmax(90px, auto);
  }

  .tuile--une       { grid-column: span 2; grid-row: span 3; }
  .tuile--compagnon,
  .tuile--large,
  .tuile--petite    { grid-column: span 1; grid-row: span 2; }
}

/* 🔴 SOUS 576 px, LA PILE — c'était déjà sa disposition. Une
   demi-largeur de téléphone fait 200 px : un titre, un avatar, un nom
   et un badge écrit n'y tiennent pas. Tout reprend les deux colonnes,
   c'est-à-dire toute la largeur. */
@media (max-width: 575.98px) {
  .tuile--une       { grid-column: span 2; grid-row: span 3; }
  .tuile--compagnon,
  .tuile--large,
  .tuile--petite    { grid-column: span 2; grid-row: span 2; }
}

/* ===================================================================
   25. Le panneau déroulant des notifications — 2026-08-31

   Il s'ouvre sous le bouton de la bande haute, au clic.

   🔴 IL N'EST QU'UN RACCOURCI. Le bouton reste un lien vers
   /notifications : sans JavaScript le panneau ne s'ouvre pas, et la
   page affiche les mêmes lignes. Rien ici ne doit devenir le seul
   chemin vers quoi que ce soit.
   =================================================================== */

/* ⚠️ LE REPÈRE DE POSITIONNEMENT EST LA FENTE, PAS LA BANDE. Posé sur
   .barre-haut, le panneau se placerait par rapport à toute la ligne et
   partirait à gauche de l'écran. */
.barre-haut-gauche {
  position: relative;
}

/* ⚠️ « position: absolute » SERT ICI À SUPERPOSER, pas à bâtir une mise
   en page — la nuance de l'ADR-048. Le panneau doit recouvrir le
   contenu sans le déplacer : s'il poussait la page, ouvrir le panneau
   ferait sauter tout ce qu'on était en train de lire. */
.panneau-notifs {
  position: absolute;
  z-index: 20;
  top: calc(100% + 8px);
  left: 0;
  width: min(24rem, calc(100vw - 2 * var(--mijoteuse-gouttiere)));
  max-height: min(28rem, 70vh);
  overflow-y: auto;
  padding: 0.35rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 14px;
  /* Plus marquée que celle des cartes : le panneau flotte au-dessus du
     contenu, il doit s'en détacher. */
  box-shadow: 0 18px 40px -22px rgba(80, 45, 20, 0.55);
}

/* ⚠️ SOUS 992 px LA FENTE PREND TOUTE LA LARGEUR et son contenu est
   aligné à gauche : le panneau doit rester dans l'écran, d'où le
   « min() » de la largeur plus haut. */

.panneau-notifs-liste {
  margin: 0;
  padding: 0;
  list-style: none;
}

.panneau-notifs-ligne {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.6rem 0.7rem;
  border-radius: 10px;
  font-size: 0.875rem;
}

.panneau-notifs-ligne + .panneau-notifs-ligne {
  border-top: 1px solid var(--mijoteuse-bordure);
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

/* 🔴 « NON LUE » NE REPOSE PAS SUR CETTE COULEUR SEULE. Le fond n'est
   qu'un rappel : c'est la page qui écrit le mot « Non lue », et le
   panneau qui renvoie vers elle. Un panneau où l'état ne serait porté
   QUE par la teinte ne dirait rien à qui ne la distingue pas — d'où le
   filet de gauche, qui se voit sans couleur. */
.panneau-notifs-ligne--non-lue {
  background-color: var(--mijoteuse-terracotta-pale);
  border-left: 3px solid var(--mijoteuse-terracotta);
}

.panneau-notifs-ligne--invitation {
  background-color: var(--mijoteuse-herbe-pale);
  border-left: 3px solid var(--mijoteuse-vert-herbe);
}

.panneau-notifs-texte {
  color: var(--mijoteuse-brun);
  line-height: 1.35;
}

a.panneau-notifs-texte {
  color: var(--mijoteuse-terracotta-fonce);
  text-decoration: none;
}

a.panneau-notifs-texte:hover,
a.panneau-notifs-texte:focus-visible {
  text-decoration: underline;
}

.panneau-notifs-quand {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
}

.panneau-notifs-vide {
  margin: 0;
  padding: 1rem 0.7rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.875rem;
  text-align: center;
}

/* ⚠️ 44 px DE HAUT : c'est la zone tactile minimale de la § 13, et
   « Voir plus » est la seule sortie du panneau vers les actions. */
.panneau-notifs-plus {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  margin-top: 0.35rem;
  background-color: var(--mijoteuse-creme);
  border-radius: 10px;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.875rem;
  font-weight: 700;
  text-decoration: none;
}

.panneau-notifs-plus:hover,
.panneau-notifs-plus:focus-visible {
  background-color: var(--mijoteuse-terracotta-pale);
}

/* ===================================================================
   26. La fiche de relecture d'un ingrédient — 2026-08-31

   Maquette de Rodolphe : sur-titre, avertissement en encadré, un bloc
   par famille avec bandeau, et des PUCES à la place de listes
   déroulantes nues.

   🔴 CHAQUE PUCE PORTE TROIS ÉTATS, PAS DEUX. La maquette dessine des
   cases à cocher ; le référentiel a un troisième état de chaque côté —
   « peut en contenir des traces » et « dépend de la provenance » — et
   ce sont eux qui rendent « incertain » plutôt que de trancher à tort
   (ADR-046). L'état est ÉCRIT dans la puce ; la couleur le double.
   =================================================================== */

.fiche-retour {
  margin-bottom: 1.25rem;
  font-size: 0.9375rem;
}

.fiche-surtitre {
  margin: 0 0 0.15rem;
  color: #7a6f64;   /* mesuré 4,6:1 sur le fond crème */
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.fiche-titre {
  margin: 0 0 1.5rem;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-size: clamp(1.875rem, 4vw, 2.75rem);
  font-weight: 500;
  line-height: 1.1;
}

/* 🔴 L'AVERTISSEMENT DE LA PAGE LA PLUS DANGEREUSE DU PRODUIT.

   Il reprend la forme des avis du compte (§ 18) et non l'alert-warning
   JAUNE de Bootstrap — la couleur la plus froide, sur la phrase la plus
   importante du site. Le filet épais à gauche se voit sans couleur. */
.avis-danger {
  display: flex;
  gap: 0.85rem;
  margin-bottom: 1.5rem;
  padding: 1.1rem 1.25rem;
  background-color: #fbeae6;
  border-left: 4px solid var(--mijoteuse-brique);
  border-radius: 0 14px 14px 0;
  color: var(--mijoteuse-brique);
}

.avis-danger p {
  margin: 0;
  line-height: 1.55;
}

.avis-danger-signe {
  flex-shrink: 0;
  font-size: 1.25rem;
  line-height: 1.4;
}

.fiche-note {
  margin-bottom: 2rem;
  color: var(--mijoteuse-texte-doux);
}

/* --- Un bloc par famille -------------------------------------------- */

/* 🔴 PAS D'« overflow: hidden » — retiré le 2026-10-14. Il arrondissait
   les coins du bandeau en coupant tout ce qui dépasse… y compris les
   bulles d'aide, positionnées en absolu dans le bloc. Pleine largeur, elles
   y tenaient ; dans les colonnes du tableau de bord (§ 30 c), elles étaient
   tronquées au bord du bloc — vu par Rodolphe. Les coins du bandeau sont
   arrondis par lui-même, plus bas. */
.fiche-bloc {
  margin-bottom: 2rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 18px;
}

/* Le bandeau : un aplat un peu plus chaud que la carte, comme la
   maquette. Il porte le titre du bloc ET son état d'attestation —
   celui-ci se lit d'abord, il décide de tout le reste. */
.fiche-bloc-tete {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 1rem 1.35rem;
  background-color: #f6efe3;
  border-bottom: 1px solid var(--mijoteuse-bordure);
  /* 17 px : le rayon du bloc moins sa bordure, pour épouser le coin. */
  border-radius: 17px 17px 0 0;
}

.fiche-bloc-tete h2 {
  margin: 0;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-size: 1.375rem;
  font-weight: 600;
}

.fiche-bloc-etat {
  margin: 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
}

.fiche-bloc-corps {
  padding: 1.35rem;
}

.fiche-bloc-aide {
  margin-bottom: 1rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.9375rem;
  line-height: 1.55;
}

/* --- Les puces ------------------------------------------------------ */

.puces {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-bottom: 1.25rem;
}

/* ⚠️ « min-width » ET NON UNE GRILLE : les libellés vont de « Œufs » à
   « Anhydride sulfureux et sulfites ». Une grille à colonnes égales les
   alignerait sur le plus long, et laisserait treize puces à moitié
   vides. */
.puce {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 11rem;
  max-width: 100%;
  padding: 0.6rem 0.8rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-champ-filet);
  border-radius: 12px;
}

.puce-nom {
  font-size: 0.9375rem;
  font-weight: 700;
}

/* Le <select> perd son cadre : c'est la puce qui en porte un. Il garde
   sa flèche native — donc son affordance — et tout son comportement au
   clavier. */
.puce-choix {
  max-width: 100%;
  padding: 0.15rem 0;
  background: none;
  border: none;
  color: inherit;
  font-family: inherit;
  font-size: 0.8125rem;
}

.puce-choix:focus {
  outline: none;
}

.puce:focus-within {
  border-color: var(--mijoteuse-terracotta);
  outline: 3px solid var(--mijoteuse-terracotta-pale);
}

.puce-aide {
  max-width: 22rem;
  margin: 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
  line-height: 1.4;
}

/* 🔴 LES CINQ ÉTATS, ET LEURS COULEURS.

   Elles ne portent rien : l'état est écrit dans le <select> de la puce,
   qui reste lisible en niveaux de gris comme pour un lecteur d'écran.
   Elles font gagner le coup d'œil, pas la compréhension.

     aucun / compatible   rien ne s'oppose, ou rien n'est encore dit
     contains             composant : le cas franc
     traces               contamination possible — ambre, « ça dépend »
     incompatible         s'oppose au régime
     depends              selon la provenance — ambre aussi */
.puce--contains,
.puce--incompatible {
  background-color: #fbeae6;
  border-color: var(--mijoteuse-brique-filet);
  color: var(--mijoteuse-brique);
}

.puce--traces,
.puce--depends {
  background-color: var(--mijoteuse-ambre-pale);
  border-color: var(--mijoteuse-ambre-filet);
  color: var(--mijoteuse-ambre-texte);
}

.puce--compatible {
  background-color: var(--mijoteuse-herbe-pale);
  border-color: var(--mijoteuse-herbe-filet);
  color: var(--mijoteuse-vert-herbe);
}

/* --- Le récapitulatif et l'attestation ------------------------------ */

/* ⚠️ IL DIT CE QUE LA FICHE AFFIRME, d'un coup d'œil. Quatorze puces ne
   le montrent qu'en les parcourant — et c'est en les parcourant qu'on
   en saute une. */
.fiche-recap {
  margin-bottom: 1.25rem;
  padding: 0.75rem 1rem;
  background-color: var(--mijoteuse-creme);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 10px;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.875rem;
}

.fiche-recap-item {
  color: var(--mijoteuse-brun);
  font-weight: 700;
}

/* L'attestation est le geste le plus lourd de la page : elle se
   distingue du reste du formulaire, sans crier. */
.fiche-attestation {
  display: flex;
  gap: 0.75rem;
  margin-bottom: 1.25rem;
  padding: 1rem 1.15rem;
  background-color: var(--mijoteuse-creme);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 12px;
}

.fiche-attestation .form-check-input {
  flex-shrink: 0;
  width: 1.15rem;
  height: 1.15rem;
  margin-top: 0.15rem;
}

/* =====================================================================
   § 26 — La barre des pages de l'atelier — ADR-094

   L'atelier est découpé en pages, à navigation LIBRE : cinq pastilles,
   toujours toutes cliquables. La pastille active porte
   aria-current="page" — c'est l'ATTRIBUT qui est stylé, pas une classe :
   l'accessibilité et l'apparence ne peuvent pas diverger.

   ⚠️ .atelier-compte est réutilisé pour les compteurs ; sur la pastille
   active, il repasse en blanc translucide pour rester lisible sur la
   terre cuite. */

.atelier-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
}

.atelier-nav > a {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.9rem;
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 999px;
  background-color: var(--mijoteuse-carte);
  color: var(--mijoteuse-brun);
  font-size: 0.9rem;
  text-decoration: none;
}

.atelier-nav > a:hover,
.atelier-nav > a:focus-visible {
  background-color: var(--mijoteuse-terracotta-pale);
  border-color: var(--mijoteuse-terracotta);
  color: var(--mijoteuse-brun);
}

.atelier-nav > a[aria-current="page"] {
  background-color: var(--mijoteuse-terracotta);
  border-color: var(--mijoteuse-terracotta);
  color: #fff;
  font-weight: 600;
}

.atelier-nav > a[aria-current="page"] .atelier-compte {
  background-color: rgba(255, 255, 255, 0.25);
  border-color: transparent;
  color: #fff;
}

/* =====================================================================
   § 27 — Les transitions de l'atelier — ADR-095

   Des View Transitions INTER-DOCUMENTS : chaque page reste une vraie
   page servie par Flask (« pas une SPA », contrat § 4) ; c'est le
   navigateur qui anime le passage de l'une à l'autre. Firefox ne les
   prend pas encore en charge : il navigue comme avant, sans animation —
   amélioration progressive, rien n'en dépend.

   ⚠️ LA RACINE N'ANIME PAS. Sans cette ligne, TOUTES les navigations du
   site prendraient un fondu ; seule la zone .atelier bouge, et la barre
   (.atelier-nav) a son propre nom pour rester en place pendant que le
   contenu glisse.

   ⚠️ LE SENS VIENT DU SCRIPT (atelier-nav.ts) : data-atelier-sens sur
   <html> — « avance » vers une page plus loin dans la barre, « recule »
   vers une plus tôt. Sans lui (arrivée directe, Firefox), le fondu par
   défaut suffit. */

@view-transition {
  navigation: auto;
}

::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
}

.atelier {
  view-transition-name: atelier;
}

.atelier-nav {
  view-transition-name: atelier-nav;
}

html[data-atelier-sens="avance"] ::view-transition-old(atelier) {
  animation: 220ms ease both atelier-sort-a-gauche;
}

html[data-atelier-sens="avance"] ::view-transition-new(atelier) {
  animation: 220ms ease both atelier-entre-de-droite;
}

html[data-atelier-sens="recule"] ::view-transition-old(atelier) {
  animation: 220ms ease both atelier-sort-a-droite;
}

html[data-atelier-sens="recule"] ::view-transition-new(atelier) {
  animation: 220ms ease both atelier-entre-de-gauche;
}

@keyframes atelier-sort-a-gauche {
  to { transform: translateX(-3rem); opacity: 0; }
}

@keyframes atelier-entre-de-droite {
  from { transform: translateX(3rem); opacity: 0; }
}

@keyframes atelier-sort-a-droite {
  to { transform: translateX(3rem); opacity: 0; }
}

@keyframes atelier-entre-de-gauche {
  from { transform: translateX(-3rem); opacity: 0; }
}

/* ⚠️ LE MOUVEMENT RÉDUIT EST UN RÉGLAGE DE SANTÉ, pas une préférence
   cosmétique : le glissement peut donner la nausée. Tout s'éteint. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-image-pair(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* =====================================================================
   § 28 — L'historique d'une recette — ADR-097

   PAGE-REC-014 : une ligne par version conservée, la plus récente
   d'abord. Elle reprend la grammaire des étapes de l'atelier — un rond
   numéroté, un corps, des actions à droite — parce que c'est la même
   nature de liste : des éléments ordonnés qu'on parcourt.

   ⚠️ .ligne et .ligne-numero viennent de la § 20 d et de la § 21 c : on
   ne redéfinit ici que ce qui diffère. */

.historique .ligne--revision {
  align-items: flex-start;
  gap: 0.9rem;
}

.revision-titre {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.15rem;
  color: var(--mijoteuse-brun);
  font-weight: 700;
}

.revision-detail {
  margin-bottom: 0.15rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.9375rem;
}

/* L'état figé, en une ligne : titre, nombre d'ingrédients, d'étapes.
   Plus discret que le reste — c'est un rappel, pas l'information. */
.revision-resume {
  margin-bottom: 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.875rem;
  font-style: italic;
}

/* ⚠️ SOUS 576 px, LES ACTIONS PASSENT SOUS LE TEXTE. « Revenir à cette
   version » ne tient pas à côté d'une ligne de résumé sur un téléphone :
   le bouton serait rogné, ou le résumé coupé en plein mot. */
@media (max-width: 575.98px) {
  .historique .ligne--revision {
    flex-wrap: wrap;
  }

  .historique .ligne--revision .ligne-actions {
    width: 100%;
    margin-top: 0.5rem;
    padding-left: 2.6rem;
  }
}

/* =====================================================================
   § 29 — Les infobulles d'aide — 2026-09-01

   Un bouton « ? » à côté d'un titre ou d'un libellé ; l'explication
   s'ouvre au survol, au focus clavier et au clic.

   🔴 POURQUOI ELLES EXISTENT : PAGE-ING-003 empilait six sections
   précédées chacune de deux à quatre paragraphes gris. Les explications
   étaient justes, et elles occupaient la majorité de la hauteur — les
   formulaires, c'est-à-dire ce qu'on VIENT FAIRE, se trouvaient noyés.

   ⚠️ LA RÈGLE DE TRI TIENT EN UNE PHRASE, ET ELLE N'EST PAS
   ESTHÉTIQUE :

       ce qui EXPLIQUE se replie.   ce qui AVERTIT reste.

   « Est fait de énumère des présences » explique : dans une bulle.
   « Valider fait passer des recettes de incertain à compatible »
   avertit : cela reste écrit en clair, à côté du bouton. Une aide
   s'ouvre quand on la cherche ; un danger se lit quand on ne le
   cherche pas.

   ⚠️ TROIS DÉCLENCHEURS, PAS UN. Le survol seul serait hors contrat —
   CLAUDE.md § 11 exige une aide qui marche « à la souris, au clavier et
   sur mobile ». Le comportement vit dans infobulle.ts ; ici, seule
   l'apparence. */

/* --- Le bouton ------------------------------------------------------ */

/* Un cercle discret, de la taille d'une lettre. Il ne doit pas rivaliser
   avec le titre qu'il accompagne : c'est un recours, pas une action. */
.aide-declencheur {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.35rem;
  height: 1.35rem;
  padding: 0;
  background-color: transparent;
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 50%;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
  font-weight: 700;
  line-height: 1;
  cursor: help;
  transition: background-color 0.18s ease, border-color 0.18s ease,
              color 0.18s ease, transform 0.18s ease;
}

.aide-declencheur:hover,
.aide-declencheur[aria-expanded="true"] {
  background-color: var(--mijoteuse-terracotta-pale);
  border-color: var(--mijoteuse-terracotta);
  color: var(--mijoteuse-terracotta-fonce);
  transform: scale(1.12);
}

/* 🔴 L'ANNEAU DE FOCUS N'EST PAS NÉGOCIABLE. Sans lui, une personne qui
   navigue au clavier ne sait pas où elle est — et c'est précisément
   elle qui dépend le plus de ce bouton, faute de survol. */
.aide-declencheur:focus-visible {
  outline: 3px solid var(--mijoteuse-terracotta);
  outline-offset: 2px;
}

/* --- La bulle ------------------------------------------------------- */

/* Le conteneur porte « position: relative » pour que la bulle se place
   par rapport à LUI, et non par rapport à la page entière. */
.aide-ancre {
  position: relative;
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
}

/* ⚠️ « --aide-decalage » EST ÉCRITE PAR LE SCRIPT, pas ici. Près d'un
   bord d'écran, la bulle déborderait ; infobulle.ts mesure et pose ce
   décalage. La valeur par défaut vaut zéro — sans JavaScript, la bulle
   reste centrée, ce qui est le cas ordinaire. */
.aide-bulle {
  position: absolute;
  z-index: 1080;   /* au-dessus des cartes et des bandeaux collants */
  top: calc(100% + 0.6rem);
  left: 50%;
  width: max-content;
  max-width: min(22rem, calc(100vw - 2rem));
  padding: 0.75rem 0.9rem;
  background-color: var(--mijoteuse-brun);
  border-radius: 12px;
  box-shadow: 0 10px 28px rgb(44 37 33 / 22%);
  color: #f7f1e8;
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.5;
  text-align: left;
  text-transform: none;    /* le sur-titre est en capitales, pas l'aide */
  letter-spacing: normal;

  /* L'état FERMÉ. Le script ajoute « --ouverte » pour l'ouvrir. */
  opacity: 0;
  transform: translate(calc(-50% + var(--aide-decalage, 0px)), -0.35rem);
  transition: opacity 0.18s ease, transform 0.18s ease;

  /* ⚠️ La bulle ne doit jamais intercepter la souris : elle se place
     SOUS le pointeur qui vient de quitter le bouton, et le survol
     rebondirait entre les deux. */
  pointer-events: none;
}

.aide-bulle--ouverte {
  opacity: 1;
  transform: translate(calc(-50% + var(--aide-decalage, 0px)), 0);
}

/* La pointe. Un carré tourné de 45°, dont seule la moitié haute
   dépasse — le fond de la bulle recouvre le reste. */
.aide-bulle::before {
  content: "";
  position: absolute;
  bottom: 100%;
  left: calc(50% - var(--aide-decalage, 0px));
  width: 0.7rem;
  height: 0.7rem;
  margin-bottom: -0.35rem;
  background-color: var(--mijoteuse-brun);
  transform: translateX(-50%) rotate(45deg);
}

.aide-bulle strong {
  color: #fff;
  font-weight: 700;
}

/* 🔴 « aide-para » ET NON <p> — voir templates/ingredients/_aide.html.

   Un <p> dans un <span> est du HTML invalide : le parseur ferme le span
   et sort le paragraphe, qui s'affiche alors EN CLAIR au milieu de la
   page pendant que la bulle « hidden » reste vide. Mesuré le
   2026-09-01, et invisible pour un test qui lit le HTML source. */
.aide-para {
  display: block;
}

.aide-para + .aide-para {
  margin-top: 0.5rem;
}

/* ⚠️ SOUS 576 px, LA BULLE PREND TOUTE LA LARGEUR UTILE. Une bulle de
   22 rem centrée sur un bouton proche du bord sortirait de l'écran ; le
   script la replacerait, mais elle resterait étroite et très haute. */
@media (max-width: 575.98px) {
  .aide-bulle {
    max-width: calc(100vw - 2rem);
  }
}

/* 🔴 MOINS DE MOUVEMENT : ON COUPE L'ANIMATION, PAS L'AIDE.

   « prefers-reduced-motion » est réglé par la personne dans son système
   — souvent pour un trouble vestibulaire. On retire la transition et le
   glissement ; la bulle apparaît instantanément, et rien n'est perdu. */
@media (prefers-reduced-motion: reduce) {
  .aide-declencheur,
  .aide-bulle {
    transition: none;
  }

  .aide-declencheur:hover,
  .aide-declencheur[aria-expanded="true"] {
    transform: none;
  }

  .aide-bulle {
    transform: translate(calc(-50% + var(--aide-decalage, 0px)), 0);
  }
}

/* =====================================================================
   § 30 — La fiche d'un ingrédient — 2026-09-01

   PAGE-ING-003, devenue le point d'entrée du référentiel le même jour.
   Elle reprend la grammaire de blocs de la § 26 — bandeau, corps,
   état — et lui ajoute ce qui lui manquait : un en-tête d'état, des
   chemins lisibles, et des aides repliées (§ 29).

   🔴 CE QUE CETTE SECTION CORRIGE : la page était en Bootstrap brut,
   six sections « mt-4 » séparées par rien, chacune ouverte par deux à
   quatre paragraphes « small text-body-secondary ». Un mur gris où le
   formulaire — ce qu'on vient faire — arrivait en dernier.

   ⚠️ ELLE NE REDÉFINIT PAS .fiche-bloc, .fiche-bloc-tete NI
   .fiche-bloc-corps : ils viennent de la § 26 et servent les deux
   écrans d'ingrédient. Les deux pages doivent se ressembler — c'est ce
   qui dit qu'elles parlent du même objet. */

/* --- L'en-tête d'état ----------------------------------------------- */

/* 🔴 IL PASSE AVANT TOUT LE RESTE, ET C'EST UN CHOIX DE FOND.

   « Le moteur ignore ces mesures » décide de tout : sous le seuil, une
   composition parfaitement documentée ne sert à rien. Le lire après
   avoir saisi trois mesures, c'est l'apprendre trop tard. */
.fiche-etat {
  display: flex;
  align-items: stretch;
  gap: 1.25rem;
  margin-bottom: 2rem;
  padding: 1.15rem 1.35rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 18px;
}

/* ⚠️ LE FILET ÉPAIS À GAUCHE PORTE L'ÉTAT, PAS SEULEMENT LA COULEUR.
   Il reste visible en niveaux de gris et pour un daltonisme — et le
   texte le double de toute façon, ce qui est la vraie garantie. */
.fiche-etat--sur {
  border-left: 4px solid var(--mijoteuse-vert-herbe);
}

.fiche-etat--absent {
  border-left: 4px solid var(--mijoteuse-brique);
  background-color: #fdf6f3;
}

.fiche-etat-mesure {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  min-width: 5.5rem;
  padding-right: 1.25rem;
  border-right: 1px solid var(--mijoteuse-bordure);
}

.fiche-etat-indice {
  margin: 0;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-size: 2.25rem;
  font-weight: 600;
  line-height: 1;
}

.fiche-etat--sur .fiche-etat-indice {
  color: var(--mijoteuse-vert-herbe);
}

.fiche-etat--absent .fiche-etat-indice {
  color: var(--mijoteuse-brique);
}

.fiche-etat-legende {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  margin: 0.25rem 0 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ⚠️ « flex: 1 » ET « min-width: 0 », LES DEUX.

   Sans « flex: 1 », le corps ne prend pas la place restante et le bloc
   se remplit de vide. Sans « min-width: 0 », un enfant flex refuse de
   se réduire sous sa largeur de contenu : le texte SORT du cadre au
   lieu de passer à la ligne — c'est le défaut le plus courant des
   dispositions en flex, et il ne se voit qu'à l'écran. */
.fiche-etat-corps {
  display: flex;
  flex: 1;
  min-width: 0;
  flex-direction: column;
  justify-content: center;
}

.fiche-etat-statut {
  margin: 0 0 0.2rem;
  font-size: 1.0625rem;
  font-weight: 700;
}

/* ⚠️ LA CAPITALE EST POSÉE ICI, PAS PAR UN FILTRE JINJA. Les libellés
   viennent de INGREDIENT_STATUS_LABELS — « à valider »,
   « Validé - Modérateur ». Un « | capitalize » mettrait le reste en
   minuscules et rendrait « Validé - modérateur ». */
.fiche-etat-statut::first-letter {
  text-transform: uppercase;
}

.fiche-etat-detail,
.fiche-etat-echeance {
  margin: 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.9375rem;
  line-height: 1.5;
}

.fiche-etat-echeance {
  margin-top: 0.35rem;
  font-size: 0.875rem;
}

/* ⚠️ SOUS 576 px, L'INDICE PASSE AU-DESSUS. Une colonne de 5,5 rem plus
   trois lignes de texte ne tiennent pas côte à côte sur un téléphone :
   le texte serait réduit à deux mots par ligne. */
@media (max-width: 575.98px) {
  .fiche-etat {
    flex-direction: column;
    gap: 0.85rem;
  }

  .fiche-etat-mesure {
    flex-direction: row;
    gap: 0.6rem;
    align-items: baseline;
    justify-content: flex-start;
    padding-right: 0;
    padding-bottom: 0.85rem;
    border-right: none;
    border-bottom: 1px solid var(--mijoteuse-bordure);
  }
}

/* --- Un titre de bloc porte son bouton d'aide ------------------------ */

/* Le bouton suit le titre sans le pousser : « gap » l'écarte, et
   « baseline » sur le conteneur (§ 26) l'aligne sur la ligne du texte. */
.fiche-bloc-tete h2 {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* --- Les chemins : hiérarchie et classification ---------------------- */

/* Un fil d'ariane du générique au précis. ⚠️ Il PEUT être long — la
   classification du vivant compte sept rangs : il passe donc à la ligne
   plutôt que de déborder. */
.fiche-chemin {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0 0 1rem;
  padding: 0.7rem 0.9rem;
  background-color: #f6efe3;
  border-radius: 12px;
  font-size: 0.9375rem;
}

.fiche-chemin-fleche {
  color: var(--mijoteuse-texte-doux);
}

.fiche-chemin-rang {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
}

/* --- Listes, états vides, sous-titres -------------------------------- */

.fiche-liste {
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
}

.fiche-liste li {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.45rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--mijoteuse-bordure);
  font-size: 0.9375rem;
}

.fiche-liste li:last-child {
  border-bottom: none;
}

/* La nature d'un lien, ou la méthode d'une validation : une étiquette
   discrète qui QUALIFIE ce qui suit. ⚠️ Elle ne décide d'aucun verdict
   (ADR-082) — d'où le gris, et non une couleur d'état. */
.fiche-nature {
  padding: 0.1rem 0.5rem;
  background-color: var(--mijoteuse-terracotta-pale);
  border-radius: 999px;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

/* 🔴 UN ÉTAT VIDE DIT POURQUOI, JAMAIS RIEN. « Aucune mesure » seul
   laisserait croire à une page cassée ; la phrase dit la conséquence —
   le moteur ne peut pas conclure. */
.fiche-vide {
  margin: 0 0 1rem;
  padding: 0.85rem 1rem;
  background-color: #faf6f0;
  border: 1px dashed var(--mijoteuse-bordure);
  border-radius: 12px;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.9375rem;
  line-height: 1.55;
}

.fiche-sous-titre {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 1.5rem 0 0.6rem;
  color: var(--mijoteuse-brun);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* --- Les formulaires ------------------------------------------------- */

/* ⚠️ « max-width » ET NON UNE COLONNE : un champ pleine largeur sur un
   écran large se lit mal — l'œil perd le lien entre l'étiquette et le
   champ. La § 22 pose la même limite pour le corps de texte. */
.fiche-formulaire {
  max-width: 34rem;
  margin-top: 1rem;
  padding-top: 1.15rem;
  border-top: 1px solid var(--mijoteuse-bordure);
}

/* --- Le tableau des mesures ------------------------------------------ */

.fiche-mesures {
  margin-bottom: 0;
}

.fiche-mesures thead th {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* La valeur est ce qu'on vient lire : elle passe en chiffres tabulaires,
   qui alignent les colonnes de décimales. */
.fiche-mesure-valeur {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  white-space: nowrap;
}

.fiche-mesure-base {
  color: var(--mijoteuse-texte-doux);
  font-weight: 400;
}

.fiche-mesure-source {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.875rem;
}

/* --- La saisie d'une mesure, sur la grille du tableau — 2026-09-02 --- */

/* 🔴 LA LIGNE DE SAISIE EST LA DERNIÈRE DU TABLEAU — demande de
   Rodolphe. Un formulaire vertical posé dessous obligeait à faire
   l'aller-retour entre ce qu'on lit et ce qu'on écrit ; ici, la valeur
   qu'on tape est sous l'en-tête qui la nomme.

   ⚠️ Le <form> vit HORS du tableau : un <form> ne peut pas contenir un
   <tr>. Les champs le rejoignent par leur attribut « form » (HTML5). */
.fiche-mesure-saisie {
  background-color: #f6efe3;
}

/* ⚠️ Le filet du haut sépare ce qu'on LIT de ce qu'on ÉCRIT. Sans lui,
   la ligne de saisie se lit comme une mesure de plus, à moitié
   remplie. */
.fiche-mesure-saisie > td {
  border-top: 2px solid var(--mijoteuse-bordure);
  vertical-align: middle;
}

/* Un nombre se lit aligné à droite, et se saisit plus court que du
   texte : 7 rem suffisent à « 1234.5678 ». */
.fiche-mesure-nombre {
  max-width: 7rem;
  font-variant-numeric: tabular-nums;
}

.fiche-mesures-vide {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.9375rem;
  line-height: 1.55;
}

/* 🔴 SANS CETTE LIGNE, UNE SAISIE REFUSÉE REVIENT SANS DIRE POURQUOI.
   La macro « champ » rendait les erreurs sous chaque champ ; dans un
   tableau, elle ne sert plus. */
.fiche-mesures-erreur {
  background-color: #fbeae6;
  border-left: 3px solid var(--mijoteuse-brique);
  color: var(--mijoteuse-brique);
  font-size: 0.9375rem;
}

/* 🔴 SOUS 992 px, SIX COLONNES NE TIENNENT PAS.

   ⚠️ « table-responsive » de Bootstrap fait défiler horizontalement, ce
   qui convient pour LIRE mais pas pour SAISIR : on ne voit jamais le
   bouton d'envoi en même temps que le premier champ. La ligne de saisie
   repasse donc en blocs empilés, et chaque champ reprend une largeur
   pleine.

   ⚠️ ON NE TOUCHE PAS AUX LIGNES DE LECTURE : elles restent un tableau,
   qui défile. Les deux besoins ne sont pas les mêmes. */
@media (max-width: 991.98px) {
  .fiche-mesure-saisie {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    padding: 0.75rem;
  }

  .fiche-mesure-saisie > td {
    display: block;
    width: 100%;
    padding: 0;
    border-top: none;
  }

  .fiche-mesure-nombre {
    max-width: none;
  }
}

/* --- 🔴 La page est large, les phrases ne le sont pas — 2026-09-02 ---- */

/* PAGE-ING-003 n'a plus de plafond : un tableau à six colonnes et cinq
   formulaires ne tenaient pas dans 54 rem. Mais une PHRASE étalée sur
   1 900 px ne se lit plus — l'œil perd la ligne en revenant à la
   gauche, et c'est exactement ce que l'ADR-092 cherche à éviter.

   ⚠️ LE PLAFOND EST POSÉ SUR LA PROSE, PAS SUR LE GABARIT. L'écrire
   dans le template demanderait d'ajouter une classe à chaque
   paragraphe, et le prochain bloc l'oublierait.

   ⚠️ CE QUI N'EST PAS PLAFONNÉ, ET DÉLIBÉRÉMENT : les tableaux, les
   formulaires et les chemins de taxons. Ce sont eux qui avaient besoin
   de place. */
.fiche-note,
.fiche-bloc-aide,
.fiche-vide,
.fiche-etat-detail,
.fiche-etat-echeance,
.avis-compte-corps p,
.taxo-raisons {
  max-width: 44rem;
}

/* ⚠️ « .avis-compte » EST UN FLEX : plafonner le paragraphe seul le
   laisserait à gauche d'un cadre resté large. C'est le cadre qui doit
   se limiter. */
.fiche-bloc-corps > .avis-compte {
  max-width: 48rem;
}

/* --- Le pont vers l'écran hérité -------------------------------------- */

/* ⚠️ DISCRET, MAIS PAS CACHÉ. Il mène à un écran en sursis : le mettre
   en avant en ferait une destination normale, le supprimer rendrait les
   contraintes sans règle inatteignables. */
.fiche-pont {
  margin-top: 2.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--mijoteuse-bordure);
  color: var(--mijoteuse-texte-doux);
  font-size: 0.875rem;
}

/* --- § 30 c — La fiche en tableau de bord, sur PC — 2026-10-14 -------- */

/* Rodolphe : « rendre moins horizontal, plus en mode dashboard
   (horizontal et vertical) (pc) », puis « l'ordre des cellules n'est pas
   très logique ». Une ligne par question, dans l'ordre du travail :

     .fiche-ligne--est        nom et autres noms · place · origine
     .fiche-ligne--contient   composition et provenance · composition
     (la validation suit, sur toute la largeur)

   ⚠️ « align-items: start » : une cellule ne s'étire pas à la hauteur de
   sa voisine. Étirée, elle afficherait un grand vide sous son formulaire.

   ⚠️ SOUS 1 200 px, RIEN NE CHANGE : les lignes ne sont plus des grilles,
   et les blocs s'empilent dans l'ordre du HTML — le même ordre. */
@media (min-width: 1200px) {
  .fiche-ligne {
    display: grid;
    gap: 1.25rem;
    align-items: start;
    margin-bottom: 1.25rem;
  }

  .fiche-ligne--est {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  /* Le tableau des mesures a six colonnes : il prend les deux tiers. */
  .fiche-ligne--contient {
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  }

  .fiche-ligne .fiche-bloc,
  .fiche-colonne > .fiche-bloc:last-child {
    margin-bottom: 0;
  }

  .fiche-colonne > .fiche-bloc + .fiche-bloc {
    margin-top: 1.25rem;
  }

  .fiche-etat {
    margin-bottom: 1.25rem;
  }

  /* Dans une cellule étroite, un formulaire prend toute sa largeur : le
     plafond de 34 rem (§ 30) servait la page pleine largeur. */
  .fiche-ligne .fiche-formulaire {
    max-width: none;
  }

  /* Un bloc plus dense : le titre d'une carte de tableau de bord n'a pas
     besoin de la taille d'un titre de page. */
  .fiche-ligne .fiche-bloc-tete {
    padding: 0.8rem 1.1rem;
  }

  .fiche-ligne .fiche-bloc-tete h2 {
    font-size: 1.2rem;
  }

  .fiche-ligne .fiche-bloc-corps {
    padding: 1.1rem;
  }

  /* La validation, seule sur sa ligne : le geste à gauche, l'annulation à
     droite — sinon une carte de 1 200 px pour un bouton et une phrase. */
  .fiche-validation {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 2rem;
    align-items: start;
  }
}

/* --- Un bloc réductible — la composition ------------------------------ */

/* ⚠️ LE MARQUEUR NATIF EST RETIRÉ, PAS LE REPLI. Le triangle de <summary>
   se placerait avant le titre, hors de la mise en page du bandeau ; le
   chevron dessiné ici se range à droite, après l'état du bloc. */
.fiche-repli > summary {
  cursor: pointer;
  list-style: none;
}

.fiche-repli > summary::-webkit-details-marker {
  display: none;
}

/* ⚠️ LE BANDEAU EST UN FLEX « space-between » (§ 26) : le chevron y
   serait un troisième élément, et repousserait l'état au milieu. L'état
   se colle donc à droite, et le chevron le suit. */
.fiche-repli > summary {
  justify-content: flex-start;
}

.fiche-repli > summary .fiche-bloc-etat {
  margin-left: auto;
}

.fiche-repli > summary::after {
  content: "▾";
  margin-left: 0.5rem;
  color: var(--mijoteuse-texte-doux);
  transition: transform 0.15s ease;
}

.fiche-repli:not([open]) > summary::after {
  transform: rotate(-90deg);
}

/* Replié, le bandeau est tout le bloc : son filet bas ferait double
   bordure avec celle de la carte. */
.fiche-repli:not([open]) > summary {
  border-bottom: none;
  border-radius: 17px;
}

/* ⚠️ LE FOCUS CLAVIER DOIT SE VOIR sur le bandeau : c'est lui qu'on
   active avec Entrée. */
.fiche-repli > summary:focus-visible {
  outline: 3px solid var(--mijoteuse-brique);
  outline-offset: -3px;
}

/* ⚠️ UN FORMULAIRE EN TÊTE DE BLOC N'A PAS DE FILET AU-DESSUS : le filet
   sépare ce qu'on lit de ce qu'on écrit, et il n'y a rien à lire avant —
   il soulignait le vide (bloc « Nom »). */
.fiche-bloc-corps > .fiche-formulaire:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

/* --- Un libellé porte sa bulle d'aide — macro champ(bulle=True) ------- */

/* ⚠️ « flex » ET NON « inline » : le libellé de Bootstrap porte une marge
   basse ; c'est le conteneur qui la reprend, pour que le « ? » reste
   aligné sur la ligne du texte et non sous lui. */
.champ-tete {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.5rem;
}

.champ-tete .form-label {
  margin-bottom: 0;
}

/* --- § 30 b — La proposition de classification — ADR-098 -------------- */

/* Les raisons du score, sous le statut. ⚠️ Elles sont ÉCRITES et non
   résumées par un chiffre : « le cultivar Touchon est reconnu » se
   vérifie, « 75 points » ne se vérifie pas. */
.taxo-raisons {
  margin: 0.35rem 0 0;
  padding-left: 1.1rem;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.9375rem;
  line-height: 1.5;
}

.taxo-raisons li + li {
  margin-top: 0.2rem;
}

/* Le bouton « interroger à nouveau », sous la mention du cache — ADR-098.
   ⚠️ Il ne paraît que sur une réponse rangée : voir taxonomy_search.html. */
.taxo-oubli {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 0.75rem;
}

.taxo-oubli-note {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
}

/* =====================================================================
   § 31 — La composition qui bouge — API-ING-002 et 003, 2026-09-02

   Une mesure s'ajoute et se retire sans recharger la page. Ce qui
   change doit alors se VOIR : sans rechargement, rien ne signale qu'une
   ligne est apparue, et l'œil ne sait pas où regarder.

   🔴 CES ANIMATIONS NE SONT PAS DE L'ORNEMENT. Elles remplacent le seul
   retour que la page donnait auparavant — le rechargement lui-même.

   ⚠️ TOUT SE COUPE SOUS « prefers-reduced-motion ». Le réglage vient du
   système, souvent pour un trouble vestibulaire : la ligne apparaît
   alors d'un coup, et rien n'est perdu. */

/* --- La ligne qui arrive --------------------------------------------- */

@keyframes mesure-arrive {
  from {
    background-color: var(--mijoteuse-terracotta-pale);
    opacity: 0;
    transform: translateY(-0.35rem);
  }

  to {
    background-color: transparent;
    opacity: 1;
    transform: translateY(0);
  }
}

/* ⚠️ L'ÉCLAIRAGE DURE PLUS LONGTEMPS QUE LE GLISSEMENT — 900 ms contre
   180. C'est lui qui dit LAQUELLE des lignes vient de changer, et une
   demi-seconde ne suffit pas à le remarquer quand on regardait le
   formulaire. */
.fiche-mesure-neuve {
  animation: mesure-arrive 0.9s ease-out;
}

/* --- La ligne qui part ------------------------------------------------ */

@keyframes mesure-part {
  from {
    opacity: 1;
    transform: translateX(0);
  }

  to {
    opacity: 0;
    transform: translateX(1.5rem);
  }
}

/* ⚠️ ELLE GLISSE VERS LA DROITE, hors de la colonne d'action d'où vient
   le clic. Un fondu sur place laisserait croire à un raté d'affichage. */
.fiche-mesure-partante {
  animation: mesure-part 0.24s ease-in forwards;
}

/* --- Ce que le script annonce ---------------------------------------- */

/* 🔴 CETTE ZONE EXISTE D'ABORD POUR LES LECTEURS D'ÉCRAN. Une page qui
   change sans recharger ne s'annonce pas toute seule : « role=status »
   la fait lire, et le texte est visible pour tout le monde. */
.composition-annonce {
  margin: 0.75rem 0 0;
  padding: 0.6rem 0.9rem;
  background-color: #eef2e6;
  border-left: 3px solid var(--mijoteuse-vert-herbe);
  border-radius: 0 10px 10px 0;
  color: var(--mijoteuse-brun);
  font-size: 0.9375rem;
  animation: mesure-arrive 0.5s ease-out;
}

/* ⚠️ UN REFUS N'EST PAS UN SUCCÈS, et la couleur seule ne le dirait pas
   à qui ne la distingue pas : le texte du message porte la raison. */
.composition-annonce--erreur {
  background-color: #fbeae6;
  border-left-color: var(--mijoteuse-brique);
  color: var(--mijoteuse-brique);
}

/* --- Le bouton d'envoi qui réagit ------------------------------------ */

/* ⚠️ SANS RECHARGEMENT, RIEN NE DIT QUE LE CLIC A ÉTÉ PRIS. Un léger
   enfoncement suffit — le message d'annonce dit la suite. */
.fiche-mesure-saisie input[type="submit"]:active {
  transform: translateY(1px);
}

/* --- 🔴 Moins de mouvement : on coupe tout ---------------------------- */

@media (prefers-reduced-motion: reduce) {
  .fiche-mesure-neuve,
  .composition-annonce {
    animation: none;
  }

  /* ⚠️ « forwards » GARDE LE DERNIER ÉTAT : sans animation, la ligne
     partante resterait visible à l'écran alors qu'elle est effacée en
     base. On la masque donc directement. */
  .fiche-mesure-partante {
    animation: none;
    opacity: 0;
  }

  .fiche-mesure-saisie input[type="submit"]:active {
    transform: none;
  }
}

/* =====================================================================
   § 32 — Ce qu'une règle fait taire — ADR-103, 2026-09-06

   🔴 LA BASCULE EST PAR CONTRAINTE, PAS PAR INGRÉDIENT.

   Écrire une seule règle sur une contrainte retire à l'ancien mécanisme
   toute compétence sur elle, pour tout le catalogue. Les déclarations
   posées à la main restent en base, et plus rien ne les lit.

   ⚠️ MESURÉ LE 2026-09-06 : une règle « végétarien exclut Animalia »
   transforme en COMPATIBLE un sucre qu'un modérateur avait déclaré
   INCOMPATIBLE — la canne à sucre est une plante, et la règle répond
   « faux » avec assurance.

   🔴 RIEN NE SIGNALAIT CETTE PERTE. Ni erreur, ni message, ni trace
   dans le verdict. Cette ligne est le seul endroit où elle se voit
   avant le geste. */
.regle-tait {
  padding: 0.6rem 0.8rem;
  background-color: #fbeae6;
  /* ⚠️ LE FILET SE VOIT SANS COULEUR — même parti que « .avis-danger » :
     la couleur n'est jamais le seul moyen d'identifier un état. */
  border-left: 3px solid var(--mijoteuse-brique);
  border-radius: 0 10px 10px 0;
  color: var(--mijoteuse-brique);
}

/* =====================================================================
   § 33 — L'arbre du vivant — PAGE-ADMIN-004, 2026-09-07

   🔴 CETTE PAGE PORTAIT UNE LISTE À PUCES ET SOIXANTE-NEUF LISTES
   DÉROULANTES.

   Chaque taxon affichait un « select » de tous les autres, plus un
   bouton « Déplacer » — soixante-neuf fois. Le geste rare occupait
   tout l'écran, et l'arbre, qui est l'objet de la page, ne se lisait
   pas.

   ⚠️ UN ARBRE SE LIT PAR SES FILETS, PAS PAR SON INDENTATION SEULE.
   Au-delà de trois niveaux, l'œil perd la colonne à laquelle un enfant
   se rattache : « Bos taurus » descend-il de « Mammalia » ou de
   « Chordata » ? Les filets répondent sans qu'on compte les espaces.

   🔴 LE DÉPLACEMENT PASSE DANS UN « details » NATIF. Il fonctionne
   sans JavaScript — le contrat l'exige — et rend l'écran à l'arbre. */

.taxon-outils {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1.25rem;
  padding: 0.85rem 1rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 12px;
}

.taxon-filtre {
  flex: 1 1 14rem;
  min-width: 0;
}

/* ⚠️ « aria-live » ANNONCE LE COMPTE AUX LECTEURS D'ÉCRAN. Filtrer sans
   recharger ne se remarque pas autrement : la page ne se relit pas. */
.taxon-compte {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.875rem;
  white-space: nowrap;
}

/* --- L'arbre lui-même ------------------------------------------------ */

.arbre-taxons,
.arbre-taxons ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* 🔴 LES FILETS SONT DESSINÉS PAR LES BORDURES, PAS PAR DES IMAGES.
   Ils suivent le zoom du texte, se voient en contraste élevé, et ne
   demandent aucune requête. */
.arbre-taxons ul {
  margin-left: 0.75rem;
  padding-left: 1rem;
  border-left: 1px solid var(--mijoteuse-bordure);
}

.arbre-noeud {
  position: relative;
}

/* Le trait horizontal qui rattache un nœud au filet de sa branche. */
.arbre-taxons ul > .arbre-noeud::before {
  content: "";
  position: absolute;
  top: 1.15rem;
  left: -1rem;
  width: 0.75rem;
  border-top: 1px solid var(--mijoteuse-bordure);
}

.arbre-ligne {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.5rem;
  border-radius: 8px;
}

.arbre-ligne:hover {
  background-color: var(--mijoteuse-terracotta-pale);
}

/* ⚠️ LE NOM SCIENTIFIQUE S'ÉCRIT EN ITALIQUE — convention de
   nomenclature, au même titre que la majuscule au genre. La respecter
   ici apprend à la respecter à la saisie. */
.arbre-nom {
  font-style: italic;
  font-weight: 600;
  color: var(--mijoteuse-brun);
}

.arbre-rang {
  padding: 0.1rem 0.5rem;
  background-color: var(--mijoteuse-creme);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 999px;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
  font-style: normal;
  white-space: nowrap;
}

.arbre-compte {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
}

/* --- Le bouton de repliement ----------------------------------------- */

/* 🔴 IL EST POSÉ PAR LE SCRIPT, ET N'EXISTE PAS SANS LUI.
   Sans JavaScript l'arbre reste déplié — c'est l'état d'aujourd'hui, et
   rien n'est perdu. */
.arbre-bascule {
  flex-shrink: 0;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  background: none;
  border: 1px solid transparent;
  border-radius: 6px;
  color: var(--mijoteuse-texte-doux);
  line-height: 1;
}

.arbre-bascule:hover {
  border-color: var(--mijoteuse-bordure);
  color: var(--mijoteuse-terracotta);
}

.arbre-bascule[aria-expanded="false"] .arbre-chevron {
  transform: rotate(-90deg);
}

.arbre-chevron {
  display: inline-block;
  transition: transform 0.15s ease;
}

/* --- Le déplacement, replié par défaut ------------------------------- */

.arbre-deplacer {
  margin-left: auto;
}

.arbre-deplacer > summary {
  padding: 0.1rem 0.5rem;
  border-radius: 6px;
  color: var(--mijoteuse-texte-doux);
  cursor: pointer;
  font-size: 0.8125rem;
  list-style: none;
}

.arbre-deplacer > summary::-webkit-details-marker {
  display: none;
}

.arbre-deplacer > summary:hover,
.arbre-deplacer[open] > summary {
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  color: var(--mijoteuse-terracotta);
}

.arbre-deplacer-corps {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0.4rem 0 0.6rem;
  padding: 0.6rem 0.75rem;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 10px;
}

/* --- Ce que le filtre masque ----------------------------------------- */

/* ⚠️ « hidden » NE SUFFIT PAS SUR UN ÉLÉMENT EN « display: flex » ou
   « list-item » : la propriété d'affichage l'emporte sur l'attribut.
   D'où cette règle, sans laquelle le filtre ne masquerait rien. */
.arbre-noeud[hidden] {
  display: none;
}

/* ⚠️ LA CORRESPONDANCE SE MARQUE, elle ne se devine pas. Un arbre filtré
   qui montre aussi les ancêtres laisserait croire qu'ils correspondent. */
.arbre-noeud[data-trouve="oui"] > .arbre-ligne .arbre-nom {
  background-color: var(--mijoteuse-ambre-pale);
  box-shadow: 0 0 0 2px var(--mijoteuse-ambre-pale);
  border-radius: 3px;
}

.arbre-vide {
  margin: 1rem 0;
  color: var(--mijoteuse-texte-doux);
}

/* ⚠️ TOUT SE COUPE SOUS « prefers-reduced-motion » — le réglage vient du
   système, souvent pour un trouble vestibulaire. */
@media (prefers-reduced-motion: reduce) {
  .arbre-chevron {
    transition: none;
  }
}

/* =====================================================================
   § 34 — Le matériel d'une recette — ADR-110, 2026-09-13

   Deux endroits, deux formes, et la différence est délibérée :

     l'atelier   une LISTE à retirer, une ligne par ustensile
     la fiche    une PHRASE, « Matériel : four, fouet »

   🔴 LE MATÉRIEL NE RESSEMBLE PAS À UN TAG, et ce n'est pas un détail
   d'esthétique. Un tag est un mot de l'auteur ; un matériel vient d'un
   référentiel et servira à filtrer (« recettes sans four »). Leur donner
   la même pastille ferait croire qu'on cherche l'un comme l'autre.
   ===================================================================== */

.liste-materiel {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .35rem;
}

.liste-materiel li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .45rem .75rem;
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 0.625rem;
  background: var(--mijoteuse-carte);
}

/* ⚠️ Le formulaire de retrait ne doit pas casser la ligne : il ne porte
   qu'un bouton et un jeton caché. */
.liste-materiel form {
  margin: 0;
}

.fiche-materiel {
  margin: 0 0 1rem;
  color: var(--mijoteuse-texte-doux);
}

/* Le texte d'aide d'un bloc de l'atelier — plus discret que le corps,
   mais lisible : il porte une consigne, pas une décoration. */
.aide-bloc {
  margin: 0 0 1rem;
  color: var(--mijoteuse-texte-doux);
  font-size: .95rem;
}

/* =====================================================================
   § 35 — La prévisualisation — PAGE-REC-015, ADR-111, 2026-09-13

   🔴 UN BANDEAU QUI NE RESSEMBLE À RIEN D'AUTRE DE LA FICHE.

   La page rend le gabarit du LECTEUR : sans un cadre franchement
   distinct, l'auteur ne saurait plus s'il regarde sa recette publiée ou
   son brouillon — et l'erreur la plus coûteuse serait de croire publié
   ce qui ne l'est pas.

   ⚠️ Les deux natures de contrôle ne partagent pas leur teinte : ⛔ en
   brique, ⚠ en ambre. Le wiki l'exige — « cette distinction doit être
   visible dans l'interface ».
   ===================================================================== */

.apercu-bandeau {
  margin: 0 0 1.5rem;
  padding: 1rem 1.25rem;
  border: 2px dashed var(--mijoteuse-terracotta);
  border-radius: 0.625rem;
  background: var(--mijoteuse-terracotta-pale);
}

.apercu-titre {
  margin: 0 0 .5rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: .85rem;
  color: var(--mijoteuse-terracotta-fonce);
}

.apercu-bloquant {
  margin: .75rem 0 .25rem;
  color: var(--mijoteuse-brique);
}

.apercu-avertit {
  margin: .75rem 0 .25rem;
  color: var(--mijoteuse-ambre-texte);
}

.apercu-liste {
  margin: 0 0 .5rem;
  padding-left: 1.25rem;
}

/* § 36 — Les recettes employées — ADR-112, 2026-09-13.
   ⚠️ La VERSION s'affiche en plus petit : elle compte, mais le nom de la
   préparation compte davantage. Sans elle, le lecteur croirait consulter
   la recette d'aujourd'hui. */
.fiche-revision {
  font-size: .85em;
  color: var(--mijoteuse-texte-doux);
}


/* =====================================================================
   § 37 — Mes préférences alimentaires — PAGE-PROF-004, 2026-09-14

   Transposition de l'écran « myProfile » de la maquette de-rodolphe.

   🔴 CE QUI EST TRANSPOSÉ, ET CE QUI NE L'EST PAS.

   La maquette dessine sept blocs. Trois seulement ont des données
   derrière eux — allergies, intolérances, régimes. Les goûts (« J'aime »,
   « Je n'aime pas ») et « Ma façon de cuisiner » n'ont AUCUNE table :
   ils sont rendus en état « à venir », volontairement inertes.

   ⚠️ L'ORDRE DE LA MAQUETTE A ÉTÉ CHANGÉ, ET C'EST DÉLIBÉRÉ.

   Elle place les goûts en premier. Chez nous ils seraient deux cartes
   vides AVANT les allergies — or « ce qui peut envoyer quelqu'un à
   l'hôpital se lit en premier » (PAGE_REGISTRY, PAGE-PROF-004). Les
   contraintes passent donc devant, les goûts ferment la section.

   ⚠️ AUCUNE COULEUR N'EST ÉCRITE EN DUR DANS UN GABARIT — ADR-048.
   Les quatre nuances que la palette n'avait pas sont ajoutées ci-dessous
   comme jetons, pas recopiées d'un style en ligne de la maquette.

   ⚠️ LA COULEUR NE PORTE JAMAIS LA GRAVITÉ SEULE. Le titre de la carte
   écrit le mot — « Allergies », « Intolérances » — et chaque puce le
   répète pour les lecteurs d'écran (.visually-hidden). Le filet plus
   épais de la carte des allergies est un RENFORT, pas le signal.
   ===================================================================== */
:root {
  /* Le filet des puces « J'aime » : la terre cuite pâle sert déjà de
     fond, il lui fallait un contour un ton plus soutenu. */
  --mijoteuse-terracotta-filet: #e4c4ac;

  /* ⚠️ LE FOND DES ALLERGIES. La brique et son filet existaient depuis
     l'ADR-046 ; le fond pâle manquait, et une puce d'allergie sans fond
     se serait confondue avec une puce de goût. */
  --mijoteuse-brique-pale: #fbe7e0;

  /* Le sable : « je n'aime pas », le seul registre du jeu qui ne doit
     RIEN signaler. Ni alerte, ni approbation — le gris chaud du fond. */
  --mijoteuse-sable-pale:  #f1eade;
  --mijoteuse-sable-filet: #e4dbcb;
}


/* --- L'en-tête de la fiche ------------------------------------------- */

.prefs-entete {
  display: flex;
  align-items: center;
  gap: 1.125rem;
  flex-wrap: wrap;
  margin-bottom: 2.25rem;
}

/* ⚠️ UN ROND, PAS UNE PHOTO. Aucune colonne de la base ne porte
   d'image de profil : l'initiale est tout ce que l'on sait afficher.
   Dessiner un emplacement de photo promettrait une fonctionnalité
   absente. */
.prefs-avatar {
  width: 4.25rem;
  height: 4.25rem;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--mijoteuse-terracotta-pale);
  border: 1px solid var(--mijoteuse-bordure);
  display: grid;
  place-items: center;
  font-family: "Newsreader", Georgia, "Times New Roman", serif;
  font-size: 1.75rem;
  line-height: 1;
  color: var(--mijoteuse-terracotta-fonce);
}

.prefs-identite {
  flex: 1 1 14rem;
  min-width: 0;
}

.prefs-nom {
  margin: 0;
  font-size: clamp(1.75rem, 4vw, 2.25rem);
  line-height: 1.15;
}

.prefs-sous-titre {
  margin: .25rem 0 0;
  color: var(--mijoteuse-texte-doux);
  font-size: .9375rem;
}

.prefs-actions {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
}


/* --- Le titre d'une section ------------------------------------------ */

.prefs-section {
  margin-top: 2.75rem;
}

.prefs-section-titre {
  margin: 0 0 .35rem;
  font-size: clamp(1.375rem, 3vw, 1.625rem);
}

/* La phrase qui dit à quoi sert la section. Elle garde son plafond de
   lecture même si le bloc s'élargit. */
.prefs-section-intro {
  margin: 0 0 1.25rem;
  max-width: 44rem;
  color: var(--mijoteuse-texte-doux);
}


/* --- Une carte de préférence ----------------------------------------- */

/* ⚠️ COLONNE FLEX, ET C'EST CE QUI ÉGALISE LES HAUTEURS — ADR-115.

   Deux cartes voisines n'ont jamais le même contenu : trois allergies
   d'un côté, « Aucune intolérance déclarée » de l'autre. En bloc, la
   plus courte s'arrêterait au milieu de la plus haute et la ligne
   paraîtrait cassée. En colonne flex, le corps prend le reste. */
.carte-pref {
  display: flex;
  flex-direction: column;
  background: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 1rem;
  padding: .9375rem;
  margin-bottom: .875rem;
}

/* ⚠️ 1,5 px ET UN FILET BRIQUE — le seul écart de traitement de la
   page. Il n'informe personne à lui seul : le titre écrit « Allergies »
   juste à côté. */
.carte-pref--allergie {
  border-width: 1.5px;
  border-color: var(--mijoteuse-brique-filet);
}

.carte-pref--intolerance {
  border-color: var(--mijoteuse-ambre-filet);
}

/* 🔴 L'ÉTAT « À VENIR ». Le fond crème, et non le blanc cassé des
   cartes vivantes : la différence se voit sans qu'on ait à la lire, et
   la mention écrite la confirme. */
.carte-pref--avenir {
  background: var(--mijoteuse-creme);
  border-style: dashed;
}


/* --- La tête d'une carte : icône, titres, bouton d'ajout -------------- */

/* ⚠️ CETTE TÊTE EST UN <summary> QUAND ON PEUT ÉCRIRE, un <div>
   sinon. Les deux doivent se ressembler trait pour trait : une carte en
   lecture seule qui n'aurait pas la même tête se lirait comme une carte
   d'une autre nature.

   « display:flex » retire déjà le marqueur de <summary> dans la plupart
   des navigateurs — mais pas tous, d'où list-style et la règle WebKit
   plus bas. Un triangle oublié apparaîtrait à gauche de l'icône. */
.carte-pref-tete {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  list-style: none;
}

summary.carte-pref-tete {
  cursor: pointer;
}

summary.carte-pref-tete::-webkit-details-marker {
  display: none;
}

/* Le <details> ne dessine rien : la carte qui l'entoure porte le fond,
   le filet et le rayon. Il n'est là que pour le repli. */
.carte-pref-repli {
  margin: 0;
}

.carte-pref-icone {
  width: 2.125rem;
  height: 2.125rem;
  flex-shrink: 0;
  border-radius: .625rem;
  display: grid;
  place-items: center;
  background: var(--mijoteuse-sable-pale);
  color: var(--mijoteuse-texte-doux);
}

.carte-pref-icone svg {
  width: 1.125rem;
  height: 1.125rem;
}

.carte-pref-icone--aime {
  background: var(--mijoteuse-terracotta-pale);
  color: var(--mijoteuse-terracotta-fonce);
}

.carte-pref-icone--allergie {
  background: var(--mijoteuse-brique-pale);
  color: var(--mijoteuse-brique);
}

.carte-pref-icone--intolerance {
  background: var(--mijoteuse-ambre-pale);
  color: var(--mijoteuse-ambre-texte);
}

.carte-pref-icone--regime {
  background: var(--mijoteuse-herbe-pale);
  color: var(--mijoteuse-vert-herbe);
}

.carte-pref-titres {
  flex: 1 1 auto;
  min-width: 0;
}

.carte-pref-titre {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 700;
  font-family: inherit;   /* pas de serif ici : ce sont des étiquettes */
}

.carte-pref-aide {
  margin: .0625rem 0 0;
  font-size: .8125rem;
  color: var(--mijoteuse-texte-doux);
}


/* --- Le bouton « + », qui est un <summary> ---------------------------- */

/* ⚠️ UN <details> NATIF, PAS DU TYPESCRIPT — même choix que l'aide des
   champs (_macros.html) et le repli de l'atelier. Il fonctionne au
   clavier, sans script, et avant que la page soit interactive. */
.carte-pref-ajout {
  width: 2rem;
  height: 2rem;
  flex-shrink: 0;
  border-radius: .5625rem;
  border: 1px solid var(--mijoteuse-bordure);
  background: var(--mijoteuse-creme);
  color: var(--mijoteuse-terracotta-fonce);
  display: grid;
  place-items: center;
  cursor: pointer;
  font-size: 1.125rem;
  line-height: 1;
  list-style: none;          /* retire le triangle de <summary> */
}

.carte-pref-ajout::-webkit-details-marker {
  display: none;             /* le même triangle, côté WebKit */
}

.carte-pref-ajout:hover,
.carte-pref-ajout:focus-visible {
  background: var(--mijoteuse-terracotta-pale);
  border-color: var(--mijoteuse-terracotta);
}

/* La croix apparaît quand le volet est ouvert : le même bouton ferme. */
.carte-pref-repli[open] > .carte-pref-tete .carte-pref-ajout {
  transform: rotate(45deg);
}

.carte-pref-formulaire {
  margin-top: .875rem;
  padding-top: .875rem;
  border-top: 1px solid var(--mijoteuse-bordure);
}


/* --- Le corps : les puces, ou l'état vide ----------------------------- */

.carte-pref-corps {
  margin-top: .75rem;
  flex: 1 1 auto;   /* il occupe ce qui reste : voir .carte-pref */
}

/* ⚠️ « RIEN DÉCLARÉ » N'EST PAS « RIEN À DÉCLARER ». Le texte de cet
   état est une règle de sécurité (ADR-028), pas une tournure : il dit
   la CONSÉQUENCE, et la maquette ne la disait pas. */
.carte-pref-vide {
  margin: 0;
  font-size: .9375rem;
  color: var(--mijoteuse-texte-doux);
}

.puces-pref {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.puce-pref {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .3125rem .375rem .3125rem .6875rem;
  border-radius: .5625rem;
  font-size: .8125rem;
  font-weight: 700;
  background: var(--mijoteuse-sable-pale);
  border: 1px solid var(--mijoteuse-sable-filet);
  color: var(--mijoteuse-texte-doux);
}

.puce-pref--aime {
  background: var(--mijoteuse-terracotta-pale);
  border-color: var(--mijoteuse-terracotta-filet);
  color: var(--mijoteuse-terracotta-fonce);
}

.puce-pref--allergie {
  background: var(--mijoteuse-brique-pale);
  border-width: 1.5px;
  border-color: var(--mijoteuse-brique-filet);
  color: var(--mijoteuse-brique);
}

.puce-pref--intolerance {
  background: var(--mijoteuse-ambre-pale);
  border-color: var(--mijoteuse-ambre-filet);
  color: var(--mijoteuse-ambre-texte);
}

.puce-pref--regime {
  background: var(--mijoteuse-herbe-pale);
  border-color: var(--mijoteuse-herbe-filet);
  color: var(--mijoteuse-vert-herbe);
}

.puce-pref-icone {
  width: .875rem;
  height: .875rem;
  flex-shrink: 0;
}

/* La précision d'un régime, en poids normal : c'est le nom qui compte. */
.puce-pref-note {
  font-weight: 400;
  opacity: .85;
}

/* 🔴 LA CROIX RETIRE UNE DONNÉE DE SANTÉ, SANS CONFIRMATION.
   C'est voulu (PAGE-PROF-004 : retirer une contrainte doit rester
   réversible en trois clics), mais une croix se touche par mégarde bien
   plus qu'un lien « Retirer ». D'où la cible élargie sous 576 px, et un
   aria-label qui NOMME ce qui part. */
.puce-pref-retrait {
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
  padding: 0;
  border: none;
  border-radius: .375rem;
  background: rgba(0, 0, 0, .06);
  color: inherit;
  cursor: pointer;
  font-size: .6875rem;
  line-height: 1;
  display: grid;
  place-items: center;
}

.puce-pref-retrait:hover,
.puce-pref-retrait:focus-visible {
  background: rgba(0, 0, 0, .14);
}

/* Le formulaire d'une croix ne doit pas casser l'alignement de la puce. */
.puce-pref-forme {
  display: inline-flex;
}


/* --- L'avertissement de fin de section -------------------------------- */

/* ⚠️ IL RESTE APRÈS LES CARTES, ET IL NE S'EFFACE JAMAIS. Il dit ce que
   le produit ne garantit PAS — « l'application ne se substitue pas à un
   professionnel de santé », règle structurante du contrat. */
.prefs-avis {
  margin: 1.25rem 0 0;
  padding: .875rem 1.125rem;
  border-left: 3px solid var(--mijoteuse-brique);
  border-radius: 0 .5rem .5rem 0;
  background: var(--mijoteuse-brique-pale);
  color: var(--mijoteuse-brique);
  font-size: .9375rem;
}

.prefs-avis p {
  margin: 0;
}


/* --- « Ma façon de cuisiner » : des lignes, pas des cartes ------------ */

.prefs-ligne {
  display: flex;
  align-items: center;
  gap: .875rem;
  padding: .875rem .9375rem;
  background: var(--mijoteuse-creme);
  border: 1px dashed var(--mijoteuse-bordure);
  border-radius: .875rem;
  margin-bottom: .5rem;
}

.prefs-ligne-icone {
  width: 1.375rem;
  height: 1.375rem;
  flex-shrink: 0;
  color: var(--mijoteuse-texte-doux);
}

.prefs-ligne-texte {
  flex: 1 1 auto;
  min-width: 0;
}

.prefs-ligne-titre {
  margin: 0;
  font-weight: 700;
  font-size: .9375rem;
}

.prefs-ligne-valeur {
  margin: 0;
  font-size: .875rem;
  color: var(--mijoteuse-texte-doux);
}

/* 🔴 LA MENTION QUI SAUVE LA PAGE DU MENSONGE.

   Sans elle, quatre lignes grises ressembleraient à des réglages en
   panne. L'ADR-040 impose de dire ce qui n'est pas construit ; ici,
   c'est aussi ce qui évite qu'on attende un bouton. */
.prefs-a-venir {
  display: inline-block;
  margin-left: .5rem;
  padding: .125rem .5rem;
  border-radius: 999px;
  background: var(--mijoteuse-sable-pale);
  border: 1px solid var(--mijoteuse-sable-filet);
  color: var(--mijoteuse-texte-doux);
  font-size: .75rem;
  font-weight: 700;
  vertical-align: middle;
}


/* --- La grille : prendre toute la largeur disponible — ADR-115 ------- */

/* 🔴 LA PAGE PASSE EN PLEINE LARGEUR, et les cartes se rangent côte à
   côte plutôt que de s'empiler sur une colonne de 44 rem.

   ⚠️ « flex-wrap » N'EST PAS UN DÉTAIL : sans lui, cinq cartes sur un
   écran étroit se compresseraient jusqu'à l'illisible au lieu de passer
   à la ligne. La largeur de base — « flex-basis » — est le seuil sous
   lequel elles se replient.

   ⚠️ L'ORDRE DU DOCUMENT EST L'ORDRE À L'ÉCRAN. Aucune règle « order »
   n'est employée ici, et il ne faut pas en introduire : les allergies
   se lisent en premier, donc à gauche. Une propriété « order » les
   déplacerait visuellement SANS déplacer le document — un lecteur
   d'écran et un œil liraient alors deux ordres différents. */
.prefs-grille {
  display: flex;
  flex-wrap: wrap;
  gap: .875rem;
  align-items: stretch;
}

.prefs-grille > .carte-pref {
  flex: 1 1 20rem;
  margin-bottom: 0;
}

/* « Ma façon de cuisiner » : des lignes plus courtes, donc un seuil de
   repli plus bas — quatre tiennent de front sur un large écran. */
.prefs-grille > .prefs-ligne {
  flex: 1 1 15rem;
  margin-bottom: 0;
}

/* 🔴 UN FORMULAIRE NE S'ÉTIRE PAS SANS FIN, MÊME EN PLEINE LARGEUR.

   Les blocs du bas portent des cases à cocher, des boutons radio et des
   listes déroulantes. Seuls sur un écran de 1 500 px, ils donneraient
   une case à cocher suivie d'un mètre de vide. Ils grandissent jusqu'à
   44 rem, et pas au-delà — la même mesure que la prose du site. */
.prefs-grille--formulaires {
  align-items: flex-start;
}

.prefs-grille--formulaires > .card {
  flex: 1 1 26rem;
  max-width: 44rem;
  margin-bottom: 0;
}

/* L'avertissement reste PLEINE LARGEUR, hors de toute grille : il porte
   sur les trois cartes à la fois, pas sur l'une d'elles. */

/* --- Sous 576 px : les cibles tactiles ------------------------------- */

/* ⚠️ 44 px EST UN MINIMUM, PAS UN CONFORT. En dessous, on manque la
   croix et on touche la puce voisine — sur une liste d'allergies, on
   retire la mauvaise. La maquette pose la même valeur. */
@media (max-width: 575.98px) {

  .carte-pref-ajout {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: .6875rem;
    font-size: 1.1875rem;
  }

  .puce-pref {
    padding: .25rem .25rem .25rem .8125rem;
    border-radius: .6875rem;
  }

  .puce-pref-retrait {
    width: 2.25rem;
    height: 2.25rem;
    border-radius: .5625rem;
    font-size: .9375rem;
  }

  .prefs-actions {
    width: 100%;
  }

  .prefs-actions .btn {
    flex: 1 1 auto;
  }
}


/* --- Moins de mouvement ---------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .carte-pref-repli[open] > .carte-pref-tete .carte-pref-ajout {
    transform: none;
  }
}


/* =====================================================================
   § 38 — L'avis de phase de publication — ADR-116, 2026-09-18

   Il ne paraît que sur l'écran d'authentification, et seulement tant que
   le produit n'est pas en version publique.

   ⚠️ IL N'EST PAS UNE ALERTE. Rien n'est cassé : le produit est jeune,
   et il le dit. L'ambre du référentiel — « ça dépend » — convient mieux
   que la brique, qui annonce un risque.
   ===================================================================== */

.avis-phase {
  margin: 0 0 1.5rem;
  padding: .875rem 1.125rem;
  border-left: 3px solid var(--mijoteuse-ambre-filet);
  border-radius: 0 .5rem .5rem 0;
  background: var(--mijoteuse-ambre-pale);
  color: var(--mijoteuse-ambre-texte);
}

.avis-phase-titre {
  margin: 0;
  font-weight: 700;
  font-size: .9375rem;
  text-transform: uppercase;
  letter-spacing: .04em;
}

.avis-phase-corps {
  margin: .25rem 0 0;
  font-size: .9375rem;
}

/* 🔴 LES CASES ET LES BOUTONS RADIO COCHÉS ÉTAIENT RESTÉS BLEUS.

   Signalé par la maquette du 2026-09-25, et vérifié sur une capture
   prise la veille : la case « et tout ce qui en dérive » de la fiche
   d'une règle, et le bouton radio « Un ingrédient », s'affichaient en
   #0d6efd — le bleu d'origine de Bootstrap.

   ⚠️ CE N'EST PAS UN DÉFAUT DE L'ADMINISTRATION, IL TOUCHE TOUT LE SITE :
   « Rester connecté » à la connexion, les cases du référentiel, les
   interrupteurs. La § 1 redéfinit --bs-primary, mais Bootstrap colore
   ses cases par --bs-form-check-bg et sa propre couleur compilée — même
   piège que .btn-primary (§ 2) et que les liens (§ 20).

   ⚠️ LE HALO SUIT, sans quoi la case cochée serait terre cuite et son
   contour bleu au clavier. */
.form-check-input:checked {
  background-color: var(--mijoteuse-terracotta-fonce);
  border-color: var(--mijoteuse-terracotta-fonce);
}

.form-check-input:focus {
  border-color: var(--mijoteuse-terracotta-fonce);
  box-shadow: 0 0 0 0.25rem rgba(192, 83, 43, 0.25);
}

/* ⚠️ L'INTERRUPTEUR NON COCHÉ DESSINE SA PASTILLE EN SVG, couleur
   comprise : sans cette règle, elle reste bleue au moment du focus —
   c'est-à-dire exactement quand on la regarde. */
.form-switch .form-check-input:focus:not(:checked) {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23c0532b'/%3e%3c/svg%3e");
}

/* 🔴 LA § 13 ÉCRASAIT L'INTERRUPTEUR EN CARRÉ — 2026-10-09.

   Sur écran tactile, elle force TOUTE case de <main> à 24 × 24 px :
   c'est juste pour une case, et cela fait d'un interrupteur un rond
   dans un carré, sans piste où glisser. Celui de « Rester connecté »
   en a été le premier.

   ⚠️ LE RETRAIT DE BOOTSTRAP SAUTE AUSSI. La § 13 met le .form-check
   en flex, avec un écart : le décalage négatif de Bootstrap ferait
   alors chevaucher l'interrupteur et son libellé. C'est l'écart du
   flex qui sépare les deux.

   ⚠️ ET « min-height: 0 », SANS QUOI LA PISTE MESURE 44 PX DE HAUT. La
   § 13 donne ce minimum à toute case, en plus de la largeur : la seule
   largeur corrigée laissait un rond épais. Vu dans Chromium, règles
   tactiles forcées ; une relecture du CSS ne l'avait pas vu.

   ⚠️ L'AIDE PASSE SOUS LE LIBELLÉ. La ligne étant en flex, l'aide se
   rangeait À CÔTÉ, en troisième colonne de 150 px. Le retour
   à la ligne et la base de 100 % le renvoient dessous, aligné sur le
   libellé (3 rem de piste + 0,75 rem d'écart).

   La zone tactile reste celle de la § 13 : la ligne entière fait
   44 px, et toucher le libellé bascule l'interrupteur. */
@media (pointer: coarse) {
  main .form-switch {
    flex-wrap: wrap;
    padding-left: 0;
  }

  main .form-switch .form-check-input {
    flex-shrink: 0;
    width: 3rem;
    min-width: 3rem;
    height: 1.75rem;
    min-height: 0;
    margin: 0;
  }

  main .form-switch > .aide-champ {
    flex-basis: 100%;
    margin-top: 0;
    padding-left: 3.75rem;
  }
}

/* La pagination d'une liste d'administration — PAGE-ADMIN-007.

   ⚠️ ELLE DIT OÙ L'ON EST, pas seulement où aller : « page 2 sur 5 » se
   relit, deux flèches seules non. */
.admin-pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1rem;
}

/* Le bouton de retour, dans le pied de page — ADR-123.

   ⚠️ LE PIED EST SOMBRE (§ 6) : un « btn-outline-secondary » y serait
   illisible. On garde le contour clair de Bootstrap et on l'assouplit —
   le pied n'est pas un appel à l'action, c'est une porte discrète qu'on
   trouve quand on la cherche. */
.pied-retour {
  --bs-btn-color: rgba(255, 255, 255, 0.85);
  --bs-btn-border-color: rgba(255, 255, 255, 0.35);
  --bs-btn-hover-color: var(--mijoteuse-brun);
  --bs-btn-hover-bg: rgba(255, 255, 255, 0.92);
  --bs-btn-hover-border-color: rgba(255, 255, 255, 0.92);
}

/* =====================================================================
   27. L'administration en tableau — maquette du 2026-09-24

   PAGE-ADMIN-001 listait les CONTRAINTES et leurs règles ; elle liste
   désormais les RÈGLES, chacune portant sa contrainte en pastille
   cliquable, avec une barre de recherche et un filtre de nature.

   🔴 LE FILTRE TRAVAILLE CÔTÉ SERVEUR. La maquette le double d'un script
   qui filtre en direct ; le contrat interdit d'en dépendre, et « q »
   comme « nature » sont lus par la route.

   ⚠️ LA SECTION « CONTRAINTES SANS RÈGLE » N'EST PAS DANS LA MAQUETTE,
   et elle est CONSERVÉE : sept contraintes sur vingt et une n'ont aucune
   règle sur le référentiel réel, et une contrainte sans règle ne conclut
   rien. C'est l'information de sécurité de cet écran.

   ⚠️ AUCUN TEST N'EXÉCUTE DE CSS. Se vérifie au navigateur, de part et
   d'autre de 992 px.
   ===================================================================== */

/* .admin-tableau — PAGE-ADMIN-001 en tableau : nom, nombre de taxons, trois gestes. Posé dans une carte sans marge intérieure ; filets intérieurs #f2eade comme .liste-cartee (§ 20 d). */
.admin-tableau-carte {
  padding: 0;
  overflow: hidden;
}
.admin-tableau {
  --bs-table-bg: transparent;
  margin: 0;
}
.admin-tableau th,
.admin-tableau td {
  padding: 0.8rem 1rem;
  vertical-align: middle;
  border-bottom: 1px solid #f2eade;
}
.admin-tableau tbody tr:last-child > * {
  border-bottom: none;
}
.admin-tableau thead th {
  font-size: 0.78125rem;
  font-weight: 700;
  color: var(--mijoteuse-texte-doux);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.admin-tableau tbody th {
  font-weight: 400;
}
.admin-tableau-sous {
  display: block;
  font-size: 0.8125rem;
  color: var(--mijoteuse-texte-doux);
}
.admin-tableau-nombre {
  text-align: right;
  font-variant-numeric: tabular-nums;
  width: 1%;
  white-space: nowrap;
}
.admin-tableau-gestes {
  width: 1%;
  white-space: nowrap;
  text-align: right;
}
.admin-tableau-gestes-corps {
  display: flex;
  justify-content: flex-end;
  gap: 0.4rem;
}
.admin-tableau-gestes-corps > form {
  display: flex;
  margin: 0;
}
.admin-tableau tbody th {
  white-space: normal;
  min-width: 12rem;
}

/* .admin-recherche — barre de recherche et filtres de nature au-dessus du tableau 001. Formulaire GET : Flask filtre sur q et nature ; le script de la maquette filtre en direct. */
.admin-recherche {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin: 1.25rem 0 0.875rem;
}
.admin-recherche-champ {
  flex: 1 1 16rem;
  margin: 0;
}
.admin-filtres {
  display: flex;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  border: 0;
}
.admin-recherche-vide {
  color: var(--mijoteuse-texte-doux);
  margin: 0 0 0.875rem;
}
/* .admin-tags — la contrainte et sa nature, en pastilles cliquables : un clic filtre le tableau. */
.admin-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-top: 0.3rem;
}
.admin-tag {
  text-decoration: none;
  cursor: pointer;
}
.admin-tag:hover,
.admin-tag:focus-visible {
  border-color: var(--mijoteuse-terracotta-fonce);
  color: var(--mijoteuse-terracotta-fonce);
}
.admin-tag--nature {
  background-color: transparent;
}

/* ⚠️ L'ÉTIQUETTE SE DISTINGUE DE LA CONTRAINTE — ADR-120.

   Trois pastilles se suivent sur une ligne de tableau : ce que la règle
   VISE (la contrainte, sa nature) et ce qui la RANGE (les étiquettes).
   Sans marque, on croirait pouvoir retirer la première comme les
   autres.

   Le filet en herbe pâle suffit : le mot reste écrit, et c'est lui qui
   informe (ADR-046). */
.admin-tag--etiquette {
  background-color: var(--mijoteuse-herbe-pale);
  border-color: var(--mijoteuse-herbe-filet);
  color: var(--mijoteuse-vert-herbe);
}

.admin-tag--etiquette:hover,
.admin-tag--etiquette:focus-visible {
  border-color: var(--mijoteuse-vert-herbe);
  color: var(--mijoteuse-vert-herbe);
}

/* Un rang qui répond à la recherche — maquette du 2026-09-24.

   ⚠️ SES ANCÊTRES RESTENT AFFICHÉS, eux, sans cette marque : sans quoi
   l'espèce flotterait à la racine et la page dirait le contraire de ce
   qu'elle montre. La marque distingue donc « ce que je cherchais » de
   « ce qui le porte ». */
.arbre-noeud--trouve > .arbre-ligne > .arbre-nom {
  background-color: var(--mijoteuse-terracotta-pale);
  border-radius: 6px;
  padding: 0.05rem 0.35rem;
  font-weight: 700;
}

/* Les étiquettes d'une règle, en cases à cocher — ADR-120.

   🔴 SANS JAVASCRIPT. La maquette retire un tag par un « × » et en
   ajoute par une liste : les deux demandent un script, que le contrat
   interdit d'exiger. Une case cochée dit la même chose et s'envoie
   telle quelle.

   ⚠️ LA CASE ELLE-MÊME EST VISIBLE — on ne la masque pas au profit de
   la seule pastille. Une pastille « cochée » ne se distinguerait d'une
   « décochée » que par sa couleur, ce que l'ADR-046 refuse. */
.admin-tags-cases {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.3rem;
}

.admin-tag-case {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0;
  cursor: pointer;
}

.admin-tag-case > input {
  margin: 0;
}

.admin-tag-case > input:checked + .pastille {
  background-color: var(--mijoteuse-terracotta-pale);
  border-color: var(--mijoteuse-terracotta);
  color: var(--mijoteuse-terracotta-fonce);
}

/* =====================================================================
   28. Les onglets de l'administration — maquette du 2026-09-24

   PAGE-ADMIN-005 range ses réglages par catégorie. Les onglets sont des
   BOUTONS RADIO masqués, et la bascule est faite ici : le contrat
   interdit de dépendre de JavaScript, et une page de réglages qui ne
   s'ouvre pas sans script serait une page fermée.

   🔴 LE SÉLECTEUR NOMME LES ONGLETS UN PAR UN, et c'est le piège de
   cette section : un onglet ajouté au gabarit sans sa ligne ici reste
   INVISIBLE, sans lever la moindre erreur.

   ⚠️ tests/test_admin_settings.py le surveille — il lit les
   « data-onglet » du gabarit et exige que chacun figure dans ce fichier.

   ⚠️ La maquette en nommait neuf, dont sept pour des écrans qui ne sont
   pas transposés. Seuls les deux qui existent sont gardés : une règle
   sans appelant ne se distingue plus d'une règle fausse.
   ===================================================================== */

/* .admin-onglets — le détail d'une règle (003) en trois parties : Conditions, Historique, Actions supplémentaires. Onglets par boutons radio, sans script ; dans Flask, trois sections ou ?partie= suffisent. */
.admin-onglets {
  margin-top: 1.5rem;
}
.admin-onglets-barre {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  border-bottom: 1px solid #e8dccb;
  margin-bottom: 1.25rem;
}
.admin-onglets-barre > label {
  padding: 0.55rem 0.9rem;
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  color: var(--mijoteuse-texte-doux);
  font-weight: 600;
  cursor: pointer;
}
.admin-onglets-barre > label:hover {
  color: var(--mijoteuse-terracotta-fonce);
}
.admin-onglets-barre > input:checked + label {
  color: var(--mijoteuse-terracotta-fonce);
  border-bottom-color: var(--mijoteuse-terracotta-fonce);
  font-weight: 700;
}
.admin-onglets-barre > input:focus-visible + label {
  outline: 2px solid var(--mijoteuse-terracotta-fonce);
  outline-offset: 2px;
}
/* Compteur d'un onglet (File d'attente) : pastille terracotta pâle. */
.admin-onglet-compteur {
  display: inline-block;
  min-width: 1.4rem;
  margin-left: 0.3rem;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background-color: var(--mijoteuse-terracotta-pale);
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.75rem;
  font-weight: 700;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.admin-onglet {
  display: none;
}
.admin-onglets:has(#onglet-profil:checked) [data-onglet="profil"],
.admin-onglets:has(#onglet-recettes:checked) [data-onglet="recettes"],
.admin-onglets:has(#onglet-actions-compte:checked) [data-onglet="actions-compte"],
.admin-onglets:has(#onglet-journal:checked) [data-onglet="journal"],
.admin-onglets:has(#onglet-inscription:checked) [data-onglet="inscription"],
.admin-onglets:has(#onglet-recettes:checked) [data-onglet="recettes"],
.admin-onglets:has(#onglet-conditions:checked) [data-onglet="conditions"],
.admin-onglets:has(#onglet-label:checked) [data-onglet="label"],
.admin-onglets:has(#onglet-historique:checked) [data-onglet="historique"],
.admin-onglets:has(#onglet-actions:checked) [data-onglet="actions"] {
  display: block;
}
.admin-onglets:has(#onglet-inscription:checked) [data-onglet="inscription"].pile,
.admin-onglets:has(#onglet-recettes:checked) [data-onglet="recettes"].pile {
  display: flex;
}
.admin-onglet > .admin-suppression {
  margin-top: 0;
}

/* =====================================================================
   § 39 — La barre d'onglets du mobile — ADR-130, 2026-10-09

   Sous 992 px, la navigation d'un compte connecté quitte le menu
   dépliant du haut pour une BARRE FIXÉE EN BAS, comme la maquette
   de-rodolphe : quatre rubriques et un bouton « Menu ». Le pouce
   l'atteint sans changer de prise, et elle reste là quand on a défilé.

   Le menu, lui, ne disparaît pas : « Menu » le fait monter du bas en
   panneau, par-dessus un voile. C'est TOUJOURS la même case à cocher
   que la § 9 — aucun JavaScript, aucun second balisage de la liste.

   ⚠️ TOUT EST SOUS « .app-cadre--onglets ». Un visiteur n'a pas de
   barre, et garde exactement le menu de la § 9.

   ⚠️ AUCUN TEST N'EXÉCUTE CE CSS — c'est la mise en garde des §§ 9 et
   22. Mesuré dans Chromium à 393 × 852, le gabarit de la maquette.
   ===================================================================== */

/* Hauteur de la barre, hors encoche. Une seule valeur : la marge du
   cadre, le bas du panneau et la barre en dépendent tous les trois. */
:root {
  --onglets-hauteur: 3.75rem;
}

/* ⚠️ MASQUÉE PAR DÉFAUT, donc à partir de 992 px sans autre règle :
   la colonne montre tout, une barre en plus ferait doublon. */
.onglets,
.nav-voile {
  display: none;
}

@media (max-width: 991.98px) {

  /* 🔴 LA MARGE EST CE QUI REND LE PIED DE PAGE ATTEIGNABLE. Sans elle,
     la barre fixée recouvre sa dernière ligne — le bouton de retour de
     l'ADR-123.

     env(safe-area-inset-bottom) : la barre du geste des iPhone. Elle
     vaut 0 tant que la page n'est pas en « viewport-fit=cover », ce qui
     est le cas : la valeur ne sert qu'à ne rien casser le jour où elle
     le sera. */
  .app-cadre--onglets {
    padding-bottom: calc(var(--onglets-hauteur) + env(safe-area-inset-bottom, 0px));
  }

  .app-cadre--onglets .onglets {
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1030;
    display: flex;
    margin: 0;
    padding: 0 0.25rem env(safe-area-inset-bottom, 0px);
    list-style: none;
    /* ⚠️ OPAQUE. À 96 %, le pied de page sombre se lisait AU TRAVERS
       de la barre — « Un bug, une idée ? » sous les onglets. */
    background-color: var(--mijoteuse-carte);
    border-top: 1px solid var(--mijoteuse-bordure);
    box-shadow: 0 -8px 24px -20px rgba(80, 45, 20, 0.6);
  }

  /* Chaque onglet prend sa part : en largeur automatique, les libellés
     courts tombaient sous les 44 px de la § 13 — mesuré sur la
     maquette, à 39 px. min-width:0 laisse « Rechercher » rétrécir. */
  .onglets > li {
    flex: 1 1 0;
    min-width: 0;
  }

  .onglet {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.2rem;
    width: 100%;
    height: var(--onglets-hauteur);
    margin: 0;
    padding: 0.25rem 0.125rem;
    color: var(--mijoteuse-texte-doux);
    font-size: 0.6875rem;
    font-weight: 600;
    line-height: 1.1;
    text-decoration: none;
    cursor: pointer;
    border-radius: 12px;
  }

  .onglet > span {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .onglet-icone {
    width: 24px;
    height: 24px;
    flex-shrink: 0;
  }

  /* L'onglet courant : la couleur ET la graisse. ⚠️ Terre cuite FONCÉE,
     pas la terre cuite de la maquette. Calculé : #c0532b sur #fffdf9
     donne 4,58 pour un minimum de 4,5 — de justesse, et la barre est
     translucide : une photo qui défile dessous suffirait à passer en
     dessous. #9e3f1d donne 6,49. (La barre est devenue opaque depuis ;
     la marge reste mince, la teinte foncée reste.) */
  .onglet.active,
  .onglet:hover,
  .app-cadre--onglets .nav-bascule:checked ~ .onglets .onglet--menu {
    color: var(--mijoteuse-terracotta-fonce);
  }

  .onglet.active,
  .app-cadre--onglets .nav-bascule:checked ~ .onglets .onglet--menu {
    font-weight: 700;
  }

  /* 🔴 LE FOCUS CLAVIER DU BOUTON « MENU » EST CELUI DE LA CASE.
     Un <label> ne reçoit jamais le focus : c'est la case masquée qui
     le prend. Sans cette règle, atteindre le menu au clavier ne se
     verrait nulle part — le bouton du haut, qui le montrait (§ 9),
     est masqué ici. */
  .app-cadre--onglets .nav-bascule:focus-visible ~ .onglets .onglet--menu {
    outline: 3px solid var(--mijoteuse-terracotta);
    outline-offset: -3px;
  }

  /* La barre remplace le bouton du haut : deux commandes pour le même
     menu, l'une en haut et l'autre en bas, se contrediraient. */
  .app-cadre--onglets .nav-repli-bouton {
    display: none;
  }

  /* --- Le menu monte du bas, en panneau --------------------------- */
  .app-cadre--onglets .nav-bascule:checked ~ .nav-repli {
    position: fixed;
    right: 0;
    bottom: calc(var(--onglets-hauteur) + env(safe-area-inset-bottom, 0px));
    left: 0;
    z-index: 1031;
    max-height: calc(100vh - var(--onglets-hauteur) - 3rem);
    max-height: calc(100dvh - var(--onglets-hauteur) - 3rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0.75rem 1rem 1rem;
    background-color: var(--mijoteuse-carte);
    border-radius: 22px 22px 0 0;
    box-shadow: 0 -18px 40px -24px rgba(60, 35, 15, 0.55);
  }

  /* --- Le panneau habillé — 2026-10-09 ------------------------------

     Rodolphe : « le menu n'est pas très joli en version mobile ». C'était
     la colonne de l'ordinateur posée telle quelle dans un panneau : une
     longue liste aérée, qui répétait en tête trois entrées de la barre
     d'onglets juste en dessous.

     Le panneau devient un menu d'application :
       · une POIGNÉE en tête, qui dit « ceci est un panneau » ;
       · les doublons de la barre masqués (base.html marque leur liste) ;
       · les entrées en TUILES, deux par rangée, groupe par groupe ;
       · le bloc compte en carte, au pied.

     ⚠️ « .nav-repli-liste .nav-link », JAMAIS « .nav-repli .nav-link »
     seul : le bouton de déconnexion du bloc compte porte aussi
     .nav-link, et deviendrait une tuile.

     ⚠️ TOUT RESTE SOUS « .app-cadre--onglets » ET SOUS 992 px. Hors du
     panneau — colonne de l'ordinateur, menu du visiteur —, rien ne
     change. */
  .app-cadre--onglets .nav-repli::before {
    content: "";
    display: block;
    width: 2.5rem;
    height: 0.3rem;
    margin: 0 auto 0.75rem;
    background-color: #dccbb2;
    border-radius: 999px;
  }

  /* 🔴 LA DOUBLE CLASSE N'EST PAS UNE COQUETTERIE. Écrite avec une
     seule, cette règle pesait autant que celle des tuiles plus bas —
     « .app-cadre--onglets .nav-repli-liste { display: grid } » — et
     perdait, venant avant. Les trois doublons restaient affichés. Vu sur
     la capture, pas à la relecture. */
  .app-cadre--onglets .nav-repli-liste.nav-repli-liste--onglets {
    display: none;
  }

  /* Le même principe dans les espaces réservés : base.html marque
     « dans-la-barre » les entrées — et l'intertitre d'un groupe entier —
     que la barre d'administration ou de modération porte déjà. Classe
     posée sur le <li> et sur le <p> : aucune règle de grille ne les
     vise, une seule classe suffit ici. */
  .app-cadre--onglets .nav-repli .dans-la-barre {
    display: none;
  }

  .app-cadre--onglets .nav-repli .nav-groupe {
    margin: 0.9rem 0.25rem 0.45rem;
    padding: 0;
  }

  /* Le premier intertitre suit la poignée : la marge haute pleine
     creuserait un trou sous elle. */
  .app-cadre--onglets .nav-repli-liste--onglets + .nav-groupe {
    margin-top: 0.25rem;
  }

  .app-cadre--onglets .nav-repli-liste {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem;
    padding-top: 0;
  }

  .app-cadre--onglets .nav-repli-liste .nav-link {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    height: 100%;
    min-height: 3.5rem;
    padding: 0.6rem 0.7rem;
    background-color: var(--mijoteuse-creme);
    border: 1px solid var(--mijoteuse-bordure);
    border-radius: 14px;
    color: var(--mijoteuse-brun);
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.2;
  }

  /* L'icône dans une pastille carrée, comme les boutons de l'en-tête :
     elle se repère avant qu'on lise, sans porter seule l'information. */
  .app-cadre--onglets .nav-repli-liste .nav-icone {
    box-sizing: content-box;
    width: 18px;
    height: 18px;
    padding: 0.4rem;
    background-color: var(--mijoteuse-carte);
    border-radius: 9px;
    color: var(--mijoteuse-terracotta);
  }

  .app-cadre--onglets .nav-repli-liste .nav-link:hover,
  .app-cadre--onglets .nav-repli-liste .nav-link:focus-visible {
    background-color: var(--mijoteuse-terracotta-pale);
    border-color: var(--mijoteuse-terracotta);
    color: var(--mijoteuse-terracotta-fonce);
  }

  .app-cadre--onglets .nav-repli-liste .nav-link.active {
    background-color: var(--mijoteuse-terracotta-pale);
    border-color: transparent;
    color: var(--mijoteuse-terracotta-fonce);
    font-weight: 700;
  }

  .app-cadre--onglets .nav-repli-liste .nav-link.active .nav-icone {
    background-color: var(--mijoteuse-terracotta);
    color: #fff;
  }

  .app-cadre--onglets .nav-repli .nav-compte {
    margin-top: 1rem;
    padding: 0.5rem 0.6rem;
    background-color: var(--mijoteuse-creme);
    border: 1px solid var(--mijoteuse-bordure);
    border-radius: 14px;
  }

  /* Le voile couvre la page, mais PAS la barre (z-index inférieur) :
     « Menu » reste touchable pour refermer, comme le voile lui-même. */
  .app-cadre--onglets .nav-bascule:checked ~ .nav-voile {
    position: fixed;
    inset: 0;
    z-index: 1029;
    display: block;
    margin: 0;
    background-color: rgba(44, 37, 33, 0.38);
    cursor: pointer;
  }
}

/* --- L'en-tête mobile — ADR-130, amendement 1 ---------------------

   La maquette de Claude Design : UNE rangée — la marque en petit, puis
   des boutons-icônes. Plus de bouton « Notifications » ni de grande
   barre de recherche sous l'en-tête : ils mangeaient 130 px en haut de
   chaque page, mesuré à 393 px de large.

   ⚠️ LA MARQUE PASSE EN HANKEN GROTESK, en gras. La § 8 l'écrit en
   Newsreader, la police des titres : la maquette mobile la traite comme
   un libellé, pas comme un titre. */
.entete-actions {
  display: none;
}

@media (max-width: 991.98px) {
  .app-cadre--onglets .navbar-mijoteuse {
    border-bottom: 1px solid var(--mijoteuse-bordure);
  }

  .app-cadre--onglets .nav-marque {
    gap: 0.65rem;
    font-family: "Hanken Grotesk", system-ui, sans-serif;
    font-size: 1.0625rem;
    font-weight: 700;
    letter-spacing: -0.01em;
  }

  .app-cadre--onglets .nav-marque-blason {
    width: 30px;
    height: 30px;
    border-radius: 9px;
  }

  .app-cadre--onglets .nav-marque-blason svg {
    width: 19px;
    height: 19px;
  }

  .app-cadre--onglets .entete-actions {
    display: flex;
    gap: 0.375rem;
  }

  /* 44 px : la zone tactile de la § 13, que la maquette respecte. */
  .entete-action {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    background-color: var(--mijoteuse-carte);
    border: 1px solid var(--mijoteuse-bordure);
    border-radius: 12px;
    color: var(--mijoteuse-brun);
  }

  .entete-action:hover,
  .entete-action:focus-visible {
    background-color: var(--mijoteuse-terracotta-pale);
    border-color: var(--mijoteuse-terracotta);
    color: var(--mijoteuse-terracotta-fonce);
  }

  .entete-action > svg {
    width: 21px;
    height: 21px;
  }

  /* La pastille déborde du coin, comme dans la maquette. Le nombre est
     ÉCRIT : une pastille qui ne porterait qu'une couleur ne dirait rien
     à qui ne la distingue pas (règle de la § 10). */
  .entete-pastille {
    position: absolute;
    top: -6px;
    right: -6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 19px;
    height: 19px;
    padding: 0 5px;
    background-color: var(--mijoteuse-terracotta);
    color: #fff;
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 700;
    line-height: 1;
  }

  /* --- Les accès réservés dans l'en-tête — 2026-10-09 ---------------
     (l'écart de 6 px est posé sur .entete-actions, plus haut)

     Quatre boutons au plus — loupe, cloche, modération, administration.
     Mesuré : la marque (~150 px), quatre fois 44 px et trois écarts de
     6 px font 344 px, plus 24 px de marges. Cela tient à 393 px de
     large (iPhone), PAS à 360 px (les petits Android).

     ⚠️ D'OÙ LE NOM DE LA MARQUE QUI S'EFFACE sous 380 px, et seulement
     quand les boutons réservés sont là. Le blason reste, et le nom
     reste lu par un lecteur d'écran (visually-hidden, pas display:none).
     Un membre ordinaire, deux boutons, garde toujours le nom. */

  /* La bande haute perd ce que l'en-tête porte désormais.

     🔴 LA BARRE DE RECHERCHE RESTE SUR LA PAGE DE RECHERCHE. /search n'a
     pas de champ à elle : la masquer là aussi rendrait toute recherche
     impossible à corriger sur mobile. base.html pose le marqueur.

     ⚠️ LA FENTE DROITE PART AUSSI, mais ses boutons ne disparaissent
     pas : Modération et Administration n'ont pas d'autre porte d'entrée
     (ADR-093), et ils sont dans l'en-tête, en icônes. Sur la page de
     recherche, la bande ne garde donc que sa barre. */
  .app-cadre--onglets .barre-haut-gauche,
  .app-cadre--onglets .barre-haut-acces,
  .app-cadre--onglets .barre-haut:not(.barre-haut--recherche) > .barre-recherche {
    display: none;
  }
}

/* Le nom de la marque s'efface quand les boutons réservés manquent de
   place — voir plus haut. visually-hidden, pas display:none : le lien
   garde son nom pour un lecteur d'écran. */
@media (max-width: 379.98px) {
  .app-cadre--onglets .navbar-mijoteuse:has(.entete-action--reserve) .nav-marque > span:last-child {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

@media (max-width: 991.98px) and (prefers-reduced-motion: no-preference) {
  .app-cadre--onglets .nav-bascule:checked ~ .nav-repli {
    animation: onglets-panneau 0.22s cubic-bezier(0.2, 0.8, 0.3, 1);
  }
}

@keyframes onglets-panneau {
  from { transform: translateY(1.5rem); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

/* =====================================================================
   § 40 — L'atelier sur téléphone — 2026-10-09

   Rodolphe : « la partie création de recette, je trouve que c'est pas
   beau du tout sur mobile. rends ça plus moderne ». Mesuré à 393 px sur
   les six pages : les onglets sur deux lignes, trois boîtes imbriquées
   (section, carte, encart en pointillés), une ligne « ? Aide » sous
   chacun des sept champs, des nombres de deux chiffres sur toute la
   largeur, des boutons étroits calés à gauche.

   ⚠️ DU CSS SEULEMENT, ET SOUS 576 px SEULEMENT. Aucun formulaire ne
   change : mêmes champs, même ordre, mêmes aides — un lecteur d'écran
   entend exactement la même page. La tablette et l'ordinateur gardent
   les §§ 15, 21 et 26.

   ⚠️ AUCUN TEST N'EXÉCUTE CE CSS. Vérifié dans Chromium à 393 px, page
   par page, aide ouverte et fermée.
   ===================================================================== */
@media (max-width: 575.98px) {

  /* --- 1. Les onglets : voir la § 41 ---------------------------------
     Leur remplacement par la barre d'étapes vaut désormais à toutes les
     largeurs (ADR-131, amendement 1) : la règle a quitté ce bloc. */

  /* --- 2. Une boîte, pas trois -------------------------------------

     La carte qui enveloppait chaque section disparaît : les champs
     blancs sur le fond crème suffisent à dire « formulaire ». L'encart
     en pointillés, lui, reste — c'est un SIGNAL (§ 15 d : « autre
     nature de geste »), pas une décoration. */
  .atelier .atelier-bloc {
    padding: 0;
    background: none;
    border: none;
    border-radius: 0;
  }

  .atelier .atelier-bloc .atelier-carte,
  .atelier .atelier-carte--creation {
    padding: 1rem;
  }

  .atelier .atelier-section + .atelier-section {
    margin-top: 2rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--mijoteuse-bordure);
  }

  /* --- 3. L'aide sur la ligne du libellé ----------------------------

     Le « ? » remonte en haut à droite du champ ; ouverte, l'aide flotte
     en bulle par-dessus le champ au lieu de pousser la page.

     ⚠️ LE MOT « Aide » EST MASQUÉ À L'ŒIL, PAS RETIRÉ. Le résumé garde
     « Aide — Titre » pour un lecteur d'écran (visually-hidden de la
     macro « champ »), et l'aide reste liée au champ par
     aria-describedby : rien ne change pour lui.

     ⚠️ :has() POUR LE RETRAIT DU LIBELLÉ : seul un champ qui A une aide
     repliée le décale, sinon les libellés s'aligneraient mal. */
  .atelier .mb-3:has(> .aide-champ) {
    position: relative;
  }

  .atelier .mb-3:has(> .aide-champ) > .form-label {
    padding-right: 2.25rem;
  }

  .atelier .mb-3 > .aide-champ {
    position: absolute;
    top: -0.45rem;
    right: 0;
    margin: 0;
  }

  /* 32 px de cible autour d'un rond de 22 : le « ? » est la seule
     commande de la ligne, il doit se toucher sans viser. */
  .atelier .mb-3 > .aide-champ > summary {
    justify-content: center;
    width: 2rem;
    height: 2rem;
  }

  .atelier .mb-3 > .aide-champ > summary > span:not(.aide-champ-signe):not(.visually-hidden) {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .atelier .mb-3 > .aide-champ .aide-champ-signe {
    width: 22px;
    height: 22px;
    font-size: 0.75rem;
  }

  .atelier .mb-3 > .aide-champ[open] > .form-text {
    position: absolute;
    top: 2.1rem;
    right: 0;
    z-index: 5;
    width: min(20rem, calc(100vw - 2 * var(--mijoteuse-gouttiere)));
    margin: 0;
    background-color: var(--mijoteuse-carte);
    border: 1px solid var(--mijoteuse-bordure);
    box-shadow: 0 16px 34px -18px rgba(60, 35, 15, 0.45);
  }

  /* --- 4. Les petits nombres côte à côte ----------------------------

     Personnes, préparation, cuisson : trois nombres de deux chiffres,
     chacun sur toute la largeur. Les deux durées se mettent côte à
     côte ; la colonne pousse son champ EN BAS, pour que les deux
     entrées restent alignées quand un libellé passe sur deux lignes. */
  .atelier .row > .col-sm-4 + .col-sm-4 {
    flex: 0 0 auto;
    width: 50%;
  }

  .atelier .row > .col-sm-4 + .col-sm-4 > .mb-3 {
    display: flex;
    flex-direction: column;
    height: calc(100% - 1rem);
  }

  .atelier .row > .col-sm-4 + .col-sm-4 > .mb-3 > .form-control {
    margin-top: auto;
  }

  /* --- 5. Les boutons à la largeur du pouce --------------------------

     Un bouton plein, sur toute la largeur, est l'action de la page ;
     le lien qui l'accompagne passe dessous, centré. */
  .atelier .atelier-pied {
    flex-direction: column;
    align-items: stretch;
  }

  .atelier .atelier-pied > .btn,
  .atelier .atelier-carte > .btn,
  .atelier .atelier-carte form > .btn,
  .atelier form > .btn-primary,
  .atelier form > .btn-outline-primary {
    width: 100%;
    min-height: 48px;
    border-radius: 12px;
    font-weight: 700;
  }

  .atelier .atelier-pied > .autosave-etat {
    text-align: center;
  }

  /* La page Publication : « Publier… », « Retirer », « Supprimer… »
     sont des liens ou des boutons hors des sélecteurs ci-dessus, chacun
     dans son bloc (§ 15). Même largeur, même hauteur. */
  .atelier .publication-principale .btn,
  .atelier .publication-destructive .btn {
    width: 100%;
    min-height: 48px;
    border-radius: 12px;
    font-weight: 700;
  }

  /* Les deux liens « Prévisualiser → » et « Voir l'historique → »
     collaient à l'encadré et l'un à l'autre. */
  .atelier .manque + .publication-note {
    margin-top: 1rem;
  }

  .atelier .publication-note {
    margin-bottom: 0.75rem;
  }

  /* L'encadré « référentiel vide » touchait la carte d'ajout. */
  .atelier .manque + .atelier-carte {
    margin-top: 0.75rem;
  }

  /* --- 6. Le choix de la photo ----------------------------------------

     Le bouton du navigateur, gris et nu, au milieu de l'encart. Il prend
     les couleurs du site ; le texte « aucun fichier » reste celui du
     navigateur — il est traduit dans sa langue, et on ne le réécrit
     pas sans JavaScript. */
  .atelier input[type="file"] {
    padding: 0.4rem;
    font-size: 0.875rem;
  }

  .atelier input[type="file"]::file-selector-button {
    margin-right: 0.75rem;
    padding: 0.55rem 0.9rem;
    background-color: var(--mijoteuse-terracotta-pale);
    border: none;
    border-radius: 9px;
    color: var(--mijoteuse-terracotta-fonce);
    font-weight: 700;
  }
}

/* =====================================================================
   § 41 — Le pas à pas de l'atelier — ADR-131, 2026-10-09

   Rodolphe : « pour la création du mobile, que ce soit découpé en blocs
   et par étapes, de façon dynamique » ; puis, le 2026-10-10 : « sur la
   version PC il faudrait aussi faire le formulaire en mode étape par
   étape » (amendement 1). La barre d'étapes remplace les onglets ;
   atelier-steps.ts n'affiche qu'un bloc à la fois — À TOUTES LES
   LARGEURS : le seuil de 576 px a disparu ici et dans le script.

   ⚠️ SANS SCRIPT, LA BARRE S'AFFICHE QUAND MÊME, et c'est voulu : ses
   segments sont des liens, et mènent aux blocs par leur ancre.
   ===================================================================== */
/* Les onglets de l'atelier cèdent la place à la barre d'étapes : elle
   mène aux mêmes pages, découpées plus fin, et deux navigations l'une sur
   l'autre se contrediraient. ⚠️ Les compteurs des onglets — ingrédients,
   et ce qui manque pour publier — ne se voient donc plus ; la page
   Publication garde la liste complète. */
.atelier:has(.pas-a-pas) .atelier-nav {
  display: none;
}

.pas-a-pas {
  display: block;
  margin-bottom: 1.5rem;
}

/* « Étape 2 sur 8 », puis le nom de l'étape, en titre. Il reçoit le
   focus à chaque changement : son contour reste celui du clavier
   seulement (:focus-visible), un doigt ne le voit pas. */
.pas-a-pas-titre {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  margin: 0 0 0.75rem;
  outline: none;
}

.pas-a-pas-titre:focus-visible {
  outline: 3px solid var(--mijoteuse-terracotta-pale);
  outline-offset: 4px;
  border-radius: 6px;
}

.pas-a-pas-rang {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.pas-a-pas-titre > span:last-child {
  font-family: "Newsreader", Georgia, serif;
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.15;
}

/* --- Les segments ------------------------------------------------

   Un segment par étape, à parts égales. La barre visible fait 6 px ;
   le lien, lui, fait 32 px de haut : on vise un trait, on touche une
   bande. */
.pas-a-pas-liste {
  display: flex;
  gap: 0.3rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.pas-a-pas-liste > li {
  flex: 1 1 0;
  min-width: 0;
}

.pas-a-pas-liste a {
  display: flex;
  align-items: center;
  height: 2rem;
}

.pas-a-pas-liste a::before {
  content: "";
  display: block;
  width: 100%;
  height: 6px;
  background-color: var(--mijoteuse-bordure);
  border-radius: 999px;
  transition: background-color 0.2s ease;
}

/* Ce qui précède l'étape courante est teinté, ce qui suit reste
   neutre — un repère de position, PAS un « fait » : rien ne vérifie
   qu'une étape est remplie (ADR-131). « :has() » regarde si un
   segment SUIVANT est courant. */
.pas-a-pas-liste > li:has(~ li > a[aria-current="step"]) > a::before {
  background-color: #e6b9a1;
}

.pas-a-pas-liste a[aria-current="step"]::before {
  background-color: var(--mijoteuse-terracotta);
}

.pas-a-pas-liste a:focus-visible {
  outline: 3px solid var(--mijoteuse-terracotta-pale);
  outline-offset: 2px;
  border-radius: 6px;
}

/* --- Le mode pas à pas (posé par le script) ----------------------

   Le titre de section — « 1 La recette » — ferait doublon avec le nom
   de l'étape, juste au-dessus. */
.atelier--pas .atelier-section > h2 {
  display: none;
}

.atelier--pas .atelier-section + .atelier-section {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

/* --- « ← Précédent » et « Suivant → » ------------------------------ */
.pas-suivants {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: 1.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--mijoteuse-bordure);
}

.pas-suivants > .btn {
  flex: 1 1 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  border-radius: 12px;
  font-weight: 700;
}

.pas-suivants-precedent {
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  color: var(--mijoteuse-brun);
}

.pas-suivants-suivant {
  background-color: var(--mijoteuse-brun);
  border: 1px solid var(--mijoteuse-brun);
  color: #fff;
}

.pas-suivants-suivant:hover,
.pas-suivants-suivant:focus-visible {
  background-color: #000;
  color: #fff;
}

/* --- La navigation des étapes reste à l'écran — 2026-10-10 -----------

   Rodolphe : « il faut que les boutons d'étape soient toujours présents
   par-dessus le formulaire ». La barre d'étapes colle en HAUT de l'écran,
   « Précédent / Suivant » en BAS ; le formulaire défile entre les deux.

   ⚠️ « sticky » ET NON « fixed » : la barre reste dans le flux de
   l'atelier, et ne colle que pendant qu'on le parcourt. Elle ne recouvre
   ni le pied de page ni la colonne de l'ordinateur.

   ⚠️ UN FOND OPAQUE, sans quoi les champs se liraient au travers en
   défilant dessous. */
.pas-a-pas {
  position: sticky;
  top: 0;
  z-index: 15;
  padding: 0.75rem 0 0.35rem;
  background-color: var(--mijoteuse-creme);
  box-shadow: 0 1px 0 var(--mijoteuse-bordure);
}

.pas-suivants {
  position: sticky;
  bottom: 0;
  z-index: 15;
  padding-bottom: 0.75rem;
  background-color: var(--mijoteuse-creme);
}

/* 🔴 SUR TÉLÉPHONE, LA BARRE D'ONGLETS EST FIXÉE EN BAS (§ 39) : collé à
   « bottom: 0 », « Suivant » passerait DESSOUS, invisible et intouchable.
   Il colle donc au-dessus d'elle — la même hauteur que la marge que le
   cadre lui réserve. */
@media (max-width: 991.98px) {
  .app-cadre--onglets .pas-suivants {
    bottom: calc(var(--onglets-hauteur) + env(safe-area-inset-bottom, 0px));
  }
}

/* Sur grand écran, les deux boutons s'écartent aux deux bouts au lieu de
   s'étirer sur toute la largeur — 700 px de bouton ne se lisent plus
   comme un bouton. */
@media (min-width: 576px) {
  .pas-suivants > .btn {
    flex: 0 1 15rem;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .pas--entree {
    animation: pas-entree 0.25s cubic-bezier(0.2, 0.8, 0.3, 1);
  }
}

@keyframes pas-entree {
  from { opacity: 0; transform: translateX(0.75rem); }
  to   { opacity: 1; transform: none; }
}

/* =====================================================================
   § 42 — Les mentions obligatoires — 2026-10-09

   Deux marques, posées par la macro « champ » (mention, pour_publier) :
     *                     le formulaire refuse l'envoi sans ce champ ;
     requis pour publier   le brouillon s'enregistre sans, pas la
                           publication.
   ⚠️ ELLES NE SE RESSEMBLENT PAS, et c'est voulu : l'une bloque
   maintenant, l'autre plus tard. Une même étoile pour les deux ferait
   croire qu'on ne peut pas enregistrer sans le nombre de personnes.

   ⚠️ PAS DE LÉGENDE — retirée à la demande de Rodolphe : l'astérisque
   est une convention connue, et la pastille dit ce qu'elle veut dire.
   ===================================================================== */
.mention-obligatoire {
  color: var(--mijoteuse-terracotta-fonce);
  font-weight: 700;
}

.mention-publier {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0.05rem 0.45rem;
  background-color: var(--mijoteuse-terracotta-pale);
  border-radius: 999px;
  color: var(--mijoteuse-terracotta-fonce);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  vertical-align: 0.1em;
  white-space: nowrap;
}

/* La pastille peut faire passer un libellé sur deux lignes dans une
   rangée de colonnes — « Nombre de personnes », sur ordinateur. Son champ
   descendait alors sous ceux de la même rangée. Chaque colonne pousse son
   champ EN BAS : les champs restent alignés, quelle que soit la hauteur
   des libellés. L'aide suit son champ. */
.atelier .row > [class*="col-"] > .mb-3 {
  display: flex;
  flex-direction: column;
  height: calc(100% - 1rem);
}

.atelier .row > [class*="col-"] > .mb-3 > .form-label + * {
  margin-top: auto;
}

/* =====================================================================
   § 43 — La modération sur téléphone — 2026-10-09

   Rodolphe, après la barre de l'administration : « fais de même pour la
   partie modération ». La barre de modération existait déjà (ADR-130,
   amendement 2) ; ce sont les PAGES qui ne se lisaient pas au doigt.
   Mesuré à 393 px, avec deux recettes en attente et quatre ingrédients :

     · « Refuser » se rangeait à côté de son motif et l'écrasait à
       230 px ; les boutons, étroits, se visaient mal au doigt ;
     · les onglets « Recettes à valider / Ingrédients à relire » doublaient
       la barre du bas ;
     · le chapeau, en 1,25 rem, prenait le premier écran ;
     · dans la file des ingrédients, le nom, le lien « écran hérité » et
       deux pastilles se disputaient une ligne de 330 px.

   ⚠️ DU CSS SEULEMENT. Les formulaires ne changent pas : les trois
   décisions restent là, avec leurs motifs obligatoires.

   ⚠️ « :has(.onglets[data-barre="moderation"]) » : ces règles ne valent
   que dans l'espace de modération — .fil-onglets et .lead servent aussi
   au fil de l'accueil et à la recherche, qui ne doivent pas changer.
   ===================================================================== */
@media (max-width: 991.98px) {
  /* La barre du bas porte les deux files : les onglets de la page les
     répétaient juste au-dessus. Sur ordinateur, sans barre, ils restent
     le seul passage de l'une à l'autre hors de la colonne. */
  .app-cadre--onglets:has(.onglets[data-barre="moderation"]) .fil-onglets {
    display: none;
  }
}

@media (max-width: 575.98px) {

  .app-cadre--onglets:has(.onglets[data-barre="moderation"]) main .lead {
    font-size: 1rem;
    line-height: 1.55;
  }

  /* --- La file des recettes ---------------------------------------- */

  /* Le motif passe SOUS son libellé, le bouton sous le motif : côte à
     côte, « Refuser » écrasait le champ à 230 px. */
  .moderation-ligne {
    flex-direction: column;
    align-items: stretch;
  }

  /* 🔴 LA SECONDE LIGNE N'EST PAS UNE COQUETTERIE. En colonne, la base
     flexible devient une HAUTEUR : celle des Réglages — « 12rem », plus
     spécifique que la première ligne — creusait 140 px de vide sous
     « Nouvelle valeur ». Vu sur une capture de PAGE-ADMIN-005, qui
     partage .moderation-ligne avec la file des recettes. */
  .moderation-ligne > label,
  .moderation-ligne.admin-reglage > label:first-of-type {
    flex: 0 0 auto;
  }

  .moderation-formulaires .btn,
  .moderation-ligne > .btn {
    width: 100%;
    min-height: 48px;
    border-radius: 12px;
    font-weight: 700;
  }

  /* UN MOTIF VIDE TIENT SUR UNE LIGNE, et s'agrandit dès qu'on y entre
     ou qu'il contient du texte. « :placeholder-shown » est vrai tant que
     le champ est vide — l'invite s'affiche.

     ⚠️ MESURÉ : UNE RECETTE N'EN DEVIENT PAS PLUS COURTE (430 px environ,
     comme avant). Ce que les motifs perdent, les boutons pleine largeur
     le reprennent. Le gain est la LISIBILITÉ, pas la hauteur — replier
     « corriger » et « refuser » derrière un geste serait le seul moyen
     de raccourcir, et c'est une décision de produit, pas de style.

     ⚠️ LE CHAMP RESTE LÀ, ET OBLIGATOIRE : on le réduit, on ne le cache
     pas. Un motif qu'il faudrait découvrir serait un motif qu'on oublie
     — et la route le refuse vide. */
  .moderation-ligne textarea:placeholder-shown:not(:focus) {
    height: 2.75rem;
    min-height: 0;
    resize: none;
  }

  /* --- La file des ingrédients -------------------------------------- */

  /* Deux étages : le nom et son lien, puis les pastilles. Côte à côte,
     le nom passait sur deux lignes et « Allergènes et régimes — écran
     hérité » sur trois. */
  .app-cadre--onglets:has(.onglets[data-barre="moderation"]) .liste-cartee > li {
    flex-direction: column;
    gap: 0.5rem;
  }

  .app-cadre--onglets:has(.onglets[data-barre="moderation"]) .liste-cartee-corps {
    flex: 0 0 auto;
    width: 100%;
  }
}

/* =====================================================================
   § 44 — La base des quantités — ADR-132, 2026-10-10

   Trois bases, une liste déroulante : « pour des personnes », « pour une
   quantité produite », « pour la quantité d'un ingrédient ». Les champs
   des trois sont toujours dans le HTML ; on masque ceux qui ne sont pas
   choisis.

   🔴 ON MASQUE LES AUTRES, ON NE MONTRE PAS CELUI-CI. Écrit à l'envers —
   tout masqué, puis montré quand :has() reconnaît le choix —, un
   navigateur qui ignore :has() n'afficherait AUCUN champ, et la base
   serait impossible à remplir. Écrit ainsi, il les affiche tous : la page
   est plus longue, rien n'est perdu.

   ⚠️ « option:checked » SUIT LE CHOIX EN DIRECT, sans JavaScript : c'est
   l'option sélectionnée, et la règle se réévalue à chaque changement.
   ===================================================================== */
.base-recette:has(select[name="basis"] option[value="servings"]:checked)
  .base-champ:not(.base-champ--servings),
.base-recette:has(select[name="basis"] option[value="yield"]:checked)
  .base-champ:not(.base-champ--yield),
.base-recette:has(select[name="basis"] option[value="ingredient"]:checked)
  .base-champ:not(.base-champ--ingredient) {
  display: none;
}

/* Les champs de la base choisie sont rattachés à la liste qui les commande :
   un retrait et un filet à gauche disent « ceci dépend de ce choix ». */
.base-champ {
  margin: -0.25rem 0 1rem;
  padding-left: 0.9rem;
  border-left: 2px solid var(--mijoteuse-terracotta-pale);
}

.base-note {
  margin: 0;
  padding: 0.35rem 0;
  color: var(--mijoteuse-texte-doux);
  font-size: 0.875rem;
}

/* =====================================================================
   § 45 — Les propositions d'ingrédients — 2026-10-10

   Rodolphe : « la proposition d'ingrédient n'est vraiment pas jolie. Il
   faudrait faire comme une datalist aux dimensions de l'input, et surtout
   faire en sorte que le premier mot soit en capitale ». La liste native
   était dessinée par le navigateur, étroite dans Safari, impossible à
   styler ; ingredient-search.ts la remplace par celle-ci.

   ⚠️ « top » EST POSÉ PAR LE SCRIPT, au bas mesuré du champ. Sans lui, la
   liste prendrait sa place naturelle — sauf dans un conteneur FLEX, où un
   élément absolu se range en haut, par-dessus le libellé et le champ :
   c'est ce qu'a montré la page Ingrédients. Le conteneur du champ (.mb-3
   de la macro « champ ») sert de repère pour la position et la largeur.
   ===================================================================== */
.mb-3:has(> .propositions) {
  position: relative;
}

.propositions {
  position: absolute;
  right: 0;
  left: 0;
  z-index: 20;
  max-height: 18rem;
  margin: 0.3rem 0 0;
  padding: 0.35rem;
  overflow-y: auto;
  list-style: none;
  background-color: var(--mijoteuse-carte);
  border: 1px solid var(--mijoteuse-bordure);
  border-radius: 14px;
  box-shadow: 0 18px 36px -20px rgba(60, 35, 15, 0.45);
}

/* ⚠️ « display: block », PAS flex : ::first-letter ne s'applique qu'à un
   conteneur de BLOC. Un flex l'ignore en silence — écrit d'abord ainsi,
   la capitale ne prenait pas. La hauteur vient donc du padding. */
.proposition {
  display: block;
  padding: 0.6rem 0.75rem;
  line-height: 1.3;
  border-radius: 10px;
  color: var(--mijoteuse-brun);
  font-size: 0.95rem;
  cursor: pointer;
}

/* 🔴 LA CAPITALE N'EST QU'À L'ÉCRAN. « œuf » s'affiche « Œuf », mais c'est
   « œuf » que le choix écrit dans le champ, et le nom enregistré ne change
   pas. ::first-letter ne s'applique qu'à un BLOC — voir plus haut.

   ⚠️ « Œ » ET LES LETTRES ACCENTUÉES suivent : text-transform applique
   les règles de casse de l'Unicode, « é » devient « É ». */
.proposition::first-letter {
  text-transform: uppercase;
}

.proposition:hover,
.proposition[aria-selected="true"] {
  background-color: var(--mijoteuse-terracotta-pale);
  color: var(--mijoteuse-terracotta-fonce);
}

/* Au doigt, 44 px de cible — la règle de la § 13. */
@media (pointer: coarse) {
  .proposition {
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
  }
}

/* =====================================================================
   § 46 — Les boutons d'envoi, quand la sauvegarde est automatique —
   2026-10-10

   « Créer le brouillon » (Nouvelle recette), « Enregistrer » (La recette,
   et chaque étape) : avec autosave.ts, ils ne servent à rien — le script
   enregistre au fil de la frappe et crée le brouillon à la première
   modification. Avec le pas à pas, ils laissaient croire qu'il fallait
   cliquer avant « Suivant ». Reste l'indication d'état : « Enregistré ✓ ».

   🔴 SEULEMENT SOUS LA MARQUE QUE POSE LE SCRIPT (html[data-autosave]).
   Sans JavaScript, ce sont ces boutons qui enregistrent : ils doivent
   rester. Une règle sans la marque rendrait la page impossible à
   enregistrer pour qui n'a pas de script.

   ⚠️ « Voir la fiche » et « Annuler » restent : ce sont des liens, pas
   des envois.
   ===================================================================== */
html[data-autosave="actif"] form:is([data-autosave], [data-autosave-create])
  :is(.atelier-pied, .etape-edition-pied) > [type="submit"] {
  display: none;
}

/* =====================================================================
   § 47 — Supprimer un brouillon depuis Mes recettes — 2026-10-11

   Un lien discret au pied de la carte : il ouvre la confirmation, il ne
   supprime rien. ⚠️ PAS UN BOUTON ROUGE PAR CARTE : dix brouillons
   feraient dix alarmes, et la page se lirait comme une liste de choses à
   détruire. La couleur ne vient qu'au survol et au focus.
   ===================================================================== */
.carte-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 0.5rem;
}

.lien-suppression {
  color: var(--mijoteuse-texte-doux);
  font-size: 0.8125rem;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.lien-suppression:hover,
.lien-suppression:focus-visible {
  color: var(--mijoteuse-brique);
}

/* Au doigt, 44 px de cible — la règle de la § 13. */
@media (pointer: coarse) {
  .lien-suppression {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 0.25rem;
  }
}
