/* =====================================================================
   LA BRASA — la peau. LOT-BRASA-02, 15/08/2026.
   Ecrite d'apres le handoff decode (_design/decode/proto-template.html),
   jamais de memoire. Les couleurs sont MESUREES par outils/contraste.mjs :
   34 paires, 0 rouge. Ne pas en ajouter une sans la remesurer.

   LOI TYPO « MAN » — elle prime sur le proto :
     corps 19 px cockpit / 18 px public · AUCUN texte utile < 16 px
     interlignage 1.6 · cibles tactiles >= 48 px · boutons d'action 52-56 px
     bouton A / A+ : +15 % sur TOUT, parce que tout est en rem.

   Aucun appel reseau externe : les Playfair sont servies depuis /assets/fonts/.
   Le cockpit doit s'ouvrir meme quand la connexion du restaurant boite.
   ===================================================================== */

/* ---------------------------------------------------------------
   1. POLICES — generees par outils/polices.mjs (plages Unicode
   recopiees de Google, jamais devinees). Licence OFL : fonts/LICENCE.txt
   --------------------------------------------------------------- */
@font-face {
  font-family: 'Playfair Display';
  font-style: italic;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/playfair-600i-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Playfair Display';
  font-style: italic;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/playfair-600i-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/playfair-600-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/playfair-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/playfair-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/playfair-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('/assets/fonts/playfair-800-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('/assets/fonts/playfair-800-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------------------------------------------------------------
   2. TOKENS — lus dans le proto, puis corriges par la mesure.
   --------------------------------------------------------------- */
:root {
  --fond: #2B1F1A;
  --fond-carte: #3A2B23;
  --fond-survol: #453329;

  --braise: #D96C2F;        /* fonds de bouton, titres >= 24 px gras, gros chiffres */
  --braise-vive: #E2571B;   /* point non-lu, pastille urgente — JAMAIS de texte dessus */
  --creme: #F4E9DC;
  --creme-2: #C9B8A6;
  --azulejo: #2E5E8C;       /* liseré Portugal — decoratif, toujours double en toutes lettres */
  --morado: #5B2A6E;        /* liseré Pérou — idem */
  --ok: #4C8A4C;
  --alerte: #B8442C;

  /* Variantes nees de la MESURE (outils/contraste.mjs). Chacune existe parce
     qu'une paire est tombee, pas parce qu'elle etait jolie :
       braise/carte    3.96:1 -> --braise-texte   5.17:1  (tout texte braise < 24 px)
       fond/braise-vive 4.27:1 -> --braise-survol  4.71:1  (fond de bouton au survol)
       azulejo/fond    2.36:1 -> --azulejo-bord   5.97:1  (bords porteurs de sens)
       morado/fond     1.52:1 -> --morado-bord    5.37:1
       alerte, ok      -> bords eclaircis, >= 3:1 sur les DEUX fonds */
  --braise-texte: #E8874F;
  --braise-survol: #E6632B;
  --azulejo-bord: #6FA3D2;
  --morado-bord: #B583C9;
  --ok-bord: #7DBE7D;
  --alerte-bord: #E07A62;

  --bord-discret: rgba(244, 233, 220, .10);
  --bord-moyen: rgba(244, 233, 220, .15);
  --bord-net: rgba(244, 233, 220, .25);

  --serif: 'Playfair Display', Georgia, serif;
  --sans: system-ui, -apple-system, 'Segoe UI', sans-serif;

  --r-champ: 8px;
  --r-carte: 10px;
  --r-photo: 12px;
  --r-pilule: 99px;

  /* Cibles tactiles. Le proto etait a 44 px pour les boutons de langue :
     la loi typo « Man » monte le plancher a 48 px, partout.
     EN REM, ET C'EST TOUT L'INTERET : mesure du 15/08, avec ces trois tokens en px,
     le texte grossissait de 15 % au bouton A+ pendant que les boutons gardaient
     48 px — un texte plus gros dans une cible inchangee, donc plus serree qu'avant.
     Les valeurs ci-dessous rendent EXACTEMENT 48 / 52 / 56 px sur le socle public
     (18 px) ; le socle cockpit les redefinit pour rendre les memes 48 / 52 / 56. */
  --cible: 2.667rem;      /* 48.006 px */
  --action: 2.889rem;     /* 52.002 px */
  --action-forte: 3.112rem; /* 56.016 px — 3.111rem rendait 55.998, sous le seuil */
}

/* ---------------------------------------------------------------
   3. SOCLE — la seule vraie racine des tailles.
   Tout le reste est en rem : changer ces 4 lignes change TOUT l'ecran,
   et c'est exactement ce que fait le bouton A / A+.
   --------------------------------------------------------------- */
html { font-size: 18px; }                                   /* site public */
html[data-socle="cockpit"] {
  font-size: 19px;                                           /* cockpit /app */
  /* memes 48 / 52 / 56 px qu'en public, rapportes au socle de 19 px.
     Valeurs relevees a la mesure : 2.526rem rendait 47.994 px et 2.947rem 55.993 px
     — six millemes sous le seuil, mais sous le seuil. */
  --cible: 2.527rem;        /* 48.013 px */
  --action: 2.737rem;       /* 52.003 px */
  --action-forte: 2.948rem; /* 56.012 px */
}
html[data-taille="grand"] { font-size: 20.7px; }             /* 18 x 1.15 */
html[data-socle="cockpit"][data-taille="grand"] { font-size: 21.85px; } /* 19 x 1.15 */

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--fond);
  color: var(--creme);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
}

a { color: var(--braise-texte); }
a:hover { color: var(--braise); }

h1, h2, h3 { font-family: var(--serif); line-height: 1.25; margin: 0 0 .5em; font-weight: 700; }
h1 { font-size: 1.6rem; }
h2 { font-size: 1.35rem; }
h3 { font-size: 1.15rem; }

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }
select option { background: var(--fond-carte); color: var(--creme); }

:focus-visible { outline: 3px solid var(--braise); outline-offset: 2px; }
::selection { background: var(--braise); color: var(--fond); }

@keyframes pulse { 0% { transform: scale(1); opacity: .65; } 100% { transform: scale(1.6); opacity: 0; } }
@keyframes blink { 0%, 80%, 100% { opacity: .2; } 40% { opacity: 1; } }

/* Une animation n'est jamais indispensable a la comprehension ici :
   quand l'utilisateur demande moins de mouvement, on le lui donne. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ---------------------------------------------------------------
   4. MARQUE
   --------------------------------------------------------------- */
.marque {
  font-family: var(--serif);
  font-weight: 800;
  letter-spacing: .05em;
  color: var(--creme);
  text-decoration: none;
  background: none;
  border: none;
  padding: 0;
}
.marque-bloc { text-align: center; }
.marque-bloc .marque { font-size: 2.55rem; letter-spacing: .06em; display: block; }
.filet { height: 3px; background: var(--braise); border: 0; margin: 14px auto 10px; width: 76px; }
.baseline { color: var(--creme-2); font-size: 1rem; margin: 0; }

/* ---------------------------------------------------------------
   5. BARRES DU HAUT (cockpit et public : meme grammaire)
   --------------------------------------------------------------- */
.barre {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: .8rem; flex-wrap: wrap;
  padding: .55rem 1rem;
  background: var(--fond);
  border-bottom: 1px solid var(--bord-moyen);
}
.barre .marque { font-size: 1.2rem; }
.barre .pousse { margin-left: auto; }
.barre .qui { font-size: .95rem; font-weight: 700; }
.barre .role { font-size: .85rem; color: var(--creme-2); font-weight: 400; }

.nav-pub {
  background: none; border: none; text-decoration: none;
  font-size: 1rem; color: var(--creme-2); padding: .55rem .15rem;
  min-height: var(--cible); display: inline-flex; align-items: center;
}
.nav-pub.actif { color: var(--creme); font-weight: 700; }

/* Selecteur de langue : 3 boutons, pas un menu deroulant. Le proto etait
   a 44 px de haut ; la loi typo impose 48 px. */
.langues { display: flex; gap: 2px; }
.langues button {
  background: none; border: none;
  padding: .4rem .55rem; min-height: var(--cible); min-width: 44px;
  font-size: .95rem; color: var(--creme-2); font-weight: 400;
  border-bottom: 3px solid transparent;
}
.langues button.actif { color: var(--creme); font-weight: 800; border-bottom-color: var(--braise); }

/* Bouton A / A+ : le seul reglage de confort de l'ecran. */
.taille-texte {
  background: none; border: 1.5px solid var(--creme-2); border-radius: var(--r-champ);
  color: var(--creme-2); min-height: var(--cible); padding: .35rem .8rem;
  font-family: var(--serif); font-weight: 700; line-height: 1;
}
.taille-texte:hover { border-color: var(--creme); color: var(--creme); }
.taille-texte .a-petit { font-size: .85rem; }
.taille-texte .a-grand { font-size: 1.15rem; }

.enveloppe { max-width: 1060px; margin: 0 auto; padding: 1.4rem 1.1rem 5rem; }
.enveloppe.etroite { max-width: 720px; }

/* ---------------------------------------------------------------
   6. BOUTONS
   --------------------------------------------------------------- */
.bouton, button.principal {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  background: var(--braise); color: var(--fond);
  border: none; border-radius: var(--r-champ);
  min-height: var(--cible); padding: 0 1.2rem;
  font-size: 1.05rem; font-weight: 700; text-decoration: none;
}
.bouton:hover, button.principal:hover { background: var(--braise-survol); color: var(--fond); }
.bouton.grand, button.principal.grand { min-height: var(--action); font-size: 1.1rem; padding: 0 1.4rem; }
.bouton.pleine, button.principal.pleine { width: 100%; min-height: var(--action-forte); font-size: 1.15rem; }

.bouton.doux, button.doux {
  background: none; color: var(--creme-2);
  border: 1.5px solid var(--creme-2); border-radius: var(--r-champ);
  min-height: var(--cible); padding: 0 1rem; font-size: .95rem; font-weight: 600;
}
.bouton.doux:hover, button.doux:hover { border-color: var(--creme); color: var(--creme); background: none; }

/* gap explicite : en flex, l'espace blanc du HTML entre « ← » et le libelle
   disparait, et le lien se lit « ←Nos recettes ». Vu a l'oeil le 15/08. */
.lien-retour {
  display: inline-flex; align-items: center; gap: .35rem; min-height: var(--cible);
  background: none; border: none; padding: .4rem 0;
  color: var(--braise-texte); font-size: 1rem; text-decoration: none;
}
button:disabled, .bouton:disabled { opacity: .45; cursor: not-allowed; }

/* Choix a 3 branches (langue de dictee, gestes de specialites) : jamais
   moins de 52 px de haut, ce sont des cibles de pouce. */
.choix-fort { display: flex; gap: .55rem; flex-wrap: wrap; }
.choix-fort button {
  flex: 1 1 6rem; min-height: var(--action);
  background: var(--fond-carte); color: var(--creme-2);
  border: 1.5px solid var(--bord-net); border-radius: var(--r-champ);
  font-size: 1.05rem; font-weight: 500;
}
.choix-fort button:hover { border-color: var(--braise); }
.choix-fort button.actif { background: var(--braise); color: var(--fond); border-color: var(--braise); font-weight: 800; }

/* ---------------------------------------------------------------
   7. CHAMPS
   --------------------------------------------------------------- */
label { display: block; margin: 1rem 0 .35rem; font-size: .95rem; color: var(--creme-2); }

input[type="text"], input[type="password"], input[type="number"], input[type="date"],
input[type="search"], select, textarea {
  width: 100%;
  background: var(--fond-carte); color: var(--creme);
  border: 1.5px solid var(--bord-net); border-radius: var(--r-champ);
  min-height: var(--action); padding: .6rem .85rem;
  font-size: 1rem;
}
textarea { min-height: 150px; resize: vertical; line-height: 1.6; }
textarea::placeholder, input::placeholder { color: var(--creme-2); opacity: .7; }

.champ-dictee {
  background: var(--fond-carte); border: 1px solid var(--bord-moyen);
  border-radius: var(--r-champ); padding: 6px 6px 10px;
}
.champ-dictee textarea {
  background: none; border: none; outline: none;
  padding: .6rem .7rem; min-height: 150px;
}
/* Le provisoire de la dictee : italique creme-2, il n'est pas encore acquis. */
.interim { padding: 0 .7rem; font-size: 1rem; color: var(--creme-2); font-style: italic; }

/* Cases a cocher 28 px du proto : une case de 14 px ne se vise pas au pouce. */
.cases { display: flex; gap: .7rem; flex-wrap: wrap; }
.cases label {
  display: flex; align-items: center; gap: .7rem; margin: 0;
  background: var(--fond-carte); border: 1.5px solid var(--bord-net);
  border-radius: var(--r-champ); padding: .5rem 1rem; min-height: var(--action);
  color: var(--creme); font-size: 1.05rem; font-weight: 600; cursor: pointer;
}
.cases label:hover { border-color: var(--braise); }
.cases label.coche { border-color: var(--braise); }
.cases input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  /* 28 px du proto, en rem : une case qui ne grandit pas avec le texte redevient
     petite des qu'on agrandit l'ecran. */
  width: 1.474rem; height: 1.474rem; min-height: 0; padding: 0; flex: 0 0 1.474rem;
  border: 2px solid var(--creme-2); border-radius: 6px; background: none;
  display: grid; place-content: center;
}
.cases input[type="checkbox"]:checked { background: var(--braise); border-color: var(--braise); }
.cases input[type="checkbox"]:checked::after {
  content: '✓'; color: var(--fond); font-weight: 800; font-size: 1.05rem; line-height: 1;
}

/* ---------------------------------------------------------------
   8. CARTES, TUILES, COMPTEURS
   --------------------------------------------------------------- */
.carte {
  background: var(--fond-carte);
  border: 1px solid var(--bord-discret);
  border-radius: var(--r-carte);
  padding: 1rem 1.1rem;
  margin-bottom: 1rem;
}
a.carte, button.carte {
  display: block; width: 100%; text-align: left; color: inherit; text-decoration: none;
  font: inherit;
}
a.carte:hover, button.carte:hover { border-color: var(--braise); background: var(--fond-survol); }

.tuiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: .9rem; }
.tuile {
  background: var(--fond-carte);
  border: 1px solid var(--bord-discret); border-radius: var(--r-carte);
  min-height: 132px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .7rem;
  padding: 1rem; text-decoration: none; color: var(--creme);
}
.tuile:hover { border-color: var(--braise); background: var(--fond-survol); }
.tuile .icone { color: var(--braise); }
.tuile .nom { display: flex; align-items: center; gap: .5rem; font-size: 1.05rem; font-weight: 700; text-align: center; }
.point {
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--braise-vive); display: inline-block; flex: 0 0 12px;
}

.compteurs { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: .9rem; margin-bottom: 1.6rem; }
.compteur { background: var(--fond-carte); border-radius: var(--r-carte); padding: 1rem 1.1rem; }
.compteur .n { font-family: var(--serif); font-weight: 800; font-size: 2.3rem; color: var(--braise); line-height: 1.1; }
.compteur .quoi { font-size: .95rem; color: var(--creme-2); }

.titre-ecran { font-family: var(--serif); font-weight: 700; font-size: 1.5rem; margin: .3rem 0 1.2rem; }
.entete-ecran { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.2rem; }
.entete-ecran .titre-ecran { margin: 0; }
.entete-ecran .pousse { margin-left: auto; }

/* ---------------------------------------------------------------
   9. PASTILLES — le mapping vient de la BASE, pas du proto.
   Le repli rgba est declare AVANT color-mix : un navigateur qui ignore
   color-mix garde une pastille lisible au lieu d'un fond transparent.
   Les valeurs de repli sont celles calculees par outils/contraste.mjs.
   --------------------------------------------------------------- */
.pastille {
  display: inline-flex; align-items: center;
  padding: .15rem .7rem; border-radius: var(--r-pilule);
  font-size: .9rem; font-weight: 700; white-space: nowrap;
  color: var(--creme);
  background: #5A4D44;
  border: 1.5px solid var(--creme-2);
}

/* fils : ouvert · repondu · clos */
.pastille.ouvert  { background: #5F3620; background: color-mix(in srgb, var(--braise) 30%, var(--fond)); border-color: var(--braise); }
.pastille.repondu { background: #3F4751; background: color-mix(in srgb, var(--azulejo-bord) 30%, var(--fond)); border-color: var(--azulejo-bord); }
.pastille.clos    { background: #444F38; background: color-mix(in srgb, var(--ok-bord) 30%, var(--fond)); border-color: var(--ok-bord); }

/* travaux et taches : a faire · en cours · fait */
.pastille.a_faire  { background: #5A4D44; background: color-mix(in srgb, var(--creme-2) 30%, var(--fond)); border-color: var(--creme-2); }
.pastille.en_cours { background: #5F3620; background: color-mix(in srgb, var(--braise) 30%, var(--fond)); border-color: var(--braise); }
.pastille.fait     { background: #444F38; background: color-mix(in srgb, var(--ok-bord) 30%, var(--fond)); border-color: var(--ok-bord); }

/* priorites : QUATRE en base, pas deux. Le proto n'en montrait que 2. */
.pastille.urgente { background: #62301A; background: color-mix(in srgb, var(--braise-vive) 30%, var(--fond)); border-color: var(--braise-vive); }
.pastille.haute   { background: #5F3620; background: color-mix(in srgb, var(--braise) 30%, var(--fond)); border-color: var(--braise); }
.pastille.normale { background: #5A4D44; background: color-mix(in srgb, var(--creme-2) 30%, var(--fond)); border-color: var(--creme-2); }
.pastille.basse   { background: #3F4751; background: color-mix(in srgb, var(--azulejo-bord) 30%, var(--fond)); border-color: var(--azulejo-bord); }

/* recettes : publiee · retenu · a discuter · ecarte */
.pastille.publie     { background: #444F38; background: color-mix(in srgb, var(--ok-bord) 30%, var(--fond)); border-color: var(--ok-bord); }
/* « Direction » : une section de la spec que l'exploitation ne recoit pas. Le violet
   du Perou est la seule couleur porteuse encore libre — elle ne dit ni un statut,
   ni une priorite, ni un choix de carte, donc elle ne peut pas se confondre. */
.pastille.direction  { background: #543D4F; background: color-mix(in srgb, var(--morado-bord) 30%, var(--fond)); border-color: var(--morado-bord); }
.pastille.retenu     { background: #5F3620; background: color-mix(in srgb, var(--braise) 30%, var(--fond)); border-color: var(--braise); }
.pastille.a_discuter { background: #3F4751; background: color-mix(in srgb, var(--azulejo-bord) 30%, var(--fond)); border-color: var(--azulejo-bord); }
.pastille.ecarte     { background: #613A30; background: color-mix(in srgb, var(--alerte-bord) 30%, var(--fond)); border-color: var(--alerte-bord); }

/* Une pastille EDITABLE : le tableau des travaux se corrige en place, mais une
   liste deroulante nue casserait la lecture du tableau. Le select PORTE la pastille
   au lieu de s'y substituer — meme couleur, meme forme, et il s'ouvre au clic. */
/* La fleche reste celle du navigateur (appearance non touchee) : dessinee par le
   systeme, elle dit « ceci s'ouvre » sans qu'on ait a la peindre — et une fleche
   peinte en background-image serait de toute facon effacee par le raccourci
   `background` des regles .pastille.<valeur>, plus specifiques que celle-ci. */
select.pastille {
  width: auto; min-height: 0;
  padding: .2rem .5rem;
  cursor: pointer;
}
select.pastille option { font-size: 1rem; }

/* etiquette de pays : contour seul, et le pays est TOUJOURS ecrit en toutes lettres */
.pays {
  display: inline-flex; align-items: center;
  padding: .15rem .8rem; border-radius: var(--r-pilule);
  font-size: .9rem; font-weight: 600; color: var(--creme);
  border: 1.5px solid var(--creme-2); background: none;
}
.pays.pt { border-color: var(--azulejo-bord); }
.pays.pe { border-color: var(--morado-bord); }

/* ---------------------------------------------------------------
   10. LISTES ET FILS
   --------------------------------------------------------------- */
.liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .7rem; }

.ligne-fil {
  display: flex; align-items: center; gap: .8rem;
  background: var(--fond-carte); border: 1px solid var(--bord-discret);
  border-radius: var(--r-carte); padding: .9rem 1rem; min-height: 72px;
  text-align: left; text-decoration: none; color: var(--creme); width: 100%;
}
.ligne-fil:hover { border-color: var(--braise); background: var(--fond-survol); }
.ligne-fil .corps { display: flex; flex-direction: column; gap: .15rem; min-width: 0; flex: 1; }
.ligne-fil .sujet { font-size: 1.05rem; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ligne-fil .apercu { font-size: .9rem; color: var(--creme-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ligne-fil .droite { display: flex; flex-direction: column; align-items: flex-end; gap: .4rem; flex-shrink: 0; }
.ligne-fil .heure { font-size: .9rem; color: var(--creme-2); }
.ligne-fil .puce { width: 12px; height: 12px; border-radius: 50%; flex: 0 0 12px; background: transparent; }
.ligne-fil .puce.nonlu { background: var(--braise-vive); }

/* bulles : moi a droite, les autres a gauche. La couleur dit qui parle. */
.bulles { display: flex; flex-direction: column; gap: .7rem; margin-bottom: 1.6rem; }
.bulle-rang { display: flex; justify-content: flex-start; }
.bulle-rang.moi { justify-content: flex-end; }
.bulle {
  max-width: min(560px, 84%);
  background: var(--fond-carte); border: 1px solid var(--bord-discret);
  border-radius: var(--r-photo); padding: .7rem 1rem;
}
.bulle-rang.moi .bulle {
  background: #573725;
  background: color-mix(in srgb, var(--braise) 18%, var(--fond-carte));
  border-color: rgba(217, 108, 47, .5);
}
.bulle .qui { font-size: .9rem; color: var(--creme-2); margin-bottom: .25rem; }
.bulle .texte { font-size: 1rem; white-space: pre-wrap; word-wrap: break-word; }

/* ---------------------------------------------------------------
   11. MICRO DE DICTEE — le plus gros element de l'ecran.
   Le mecanisme (app.js) ne bouge pas : seul l'habit change.
   --------------------------------------------------------------- */
.bloc-micro { display: flex; flex-direction: column; align-items: center; gap: .6rem; margin-bottom: 1.1rem; }
/* 88 px et 76 px sur le socle cockpit, mais EN REM : le micro est la plus grosse
   cible de l'ecran, c'est la premiere qui doit grandir quand on demande A+. */
.micro-hote { position: relative; width: 4.632rem; height: 4.632rem; }
.micro {
  position: absolute; inset: .316rem;
  width: 4rem; height: 4rem; border-radius: 50%;
  background: var(--braise); border: none; padding: 0;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 18px rgba(0, 0, 0, .35);
  color: #fff;
}
.micro:hover { background: var(--braise-survol); }
.micro.ecoute { background: var(--braise-vive); }
/* Le halo ne se dessine QUE pendant l'ecoute — et il est purement decoratif :
   le texte sous le bouton dit la meme chose, en toutes lettres. */
.micro-halo { position: absolute; inset: 0; border-radius: 50%; background: var(--braise); animation: pulse 1.5s ease-out infinite; }
.micro-mot { font-size: 1rem; color: var(--creme-2); font-weight: 600; text-align: center; }
.micro-mot.ecoute { color: var(--braise-texte); }
.micro:disabled { opacity: .45; }

/* LE MICRO COMPACT (LOT-BRASA-04) — le meme bouton, au bord d'un champ d'une ligne.
   /app/specialites en pose un par carte : 121 micros de 76 px auraient mange l'ecran.

   ⚠ CORRECTION MESUREE LE 16/08 (LOT-BRASA-07). Le commentaire d'origine disait
   « 44 px de rond dans une cible de 48 px : le rond est plus petit, LA CIBLE NON ».
   La mesure au navigateur dit le contraire : `.micro-hote` est un simple <div> sans
   geste, et c'est le BOUTON qui recoit le clic — il rendait 44 px de haut. La cible
   etait donc bien de 44 px, sur les 121 cartes des specialites comme sur le fil.
   `inset: 0` : le rond remplit sa boite, et la cible fait les 48 px annonces. */
.bloc-micro.compact { flex-direction: row; align-items: center; gap: .5rem; margin: 0; flex: 0 0 auto; }
.bloc-micro.compact .micro-hote { width: var(--cible); height: var(--cible); }
.bloc-micro.compact .micro { inset: 0; width: auto; height: auto; box-shadow: none; }
.bloc-micro.compact .micro svg { width: 22px; height: 22px; }

/* Les trois boutons FR/PT/ES de la barre de session : la langue de dictee de TOUT
   l'ecran, choisie une fois. Plus petits que .choix-fort (ce n'est pas un geste de
   decision), mais jamais sous la cible de 48 px. */
.langue-dictee { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.choix-langue { display: flex; gap: .3rem; }
.choix-langue button {
  min-height: var(--cible); min-width: 3rem;
  background: var(--fond-carte); color: var(--creme-2);
  border: 1.5px solid var(--bord-net); border-radius: var(--r-champ);
  font-size: .95rem; font-weight: 700;
}
.choix-langue button:hover { border-color: var(--braise); }
.choix-langue button.actif { background: var(--braise); color: var(--fond); border-color: var(--braise); }

/* Repli quand la dictee du navigateur n'existe pas : un mot doux, pas une erreur. */
.bandeau-micro {
  background: var(--fond-carte); border: 1.5px solid var(--braise);
  border-radius: var(--r-carte); padding: .8rem 1.1rem;
  font-size: 1rem; text-align: center; margin-bottom: 1.1rem;
}

/* ---------------------------------------------------------------
   12. TABLEAUX — ils defilent DANS leur boite, jamais la page.
   --------------------------------------------------------------- */
.tableau-boite { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table { width: 100%; border-collapse: collapse; min-width: 560px; }
th {
  text-align: left; font-size: .9rem; color: var(--creme-2); font-weight: 600;
  padding: .6rem .7rem; border-bottom: 1px solid rgba(244, 233, 220, .2);
}
th.droite, td.droite { text-align: right; }
td { padding: .8rem .7rem; font-size: 1rem; vertical-align: middle; }
/* Zebrures a coins arrondis : le premier et le dernier td portent le rayon. */
tbody tr:nth-child(odd) { background: var(--fond-carte); }
tbody tr td:first-child { border-radius: var(--r-champ) 0 0 var(--r-champ); }
tbody tr td:last-child { border-radius: 0 var(--r-champ) var(--r-champ) 0; }
td.montant { font-weight: 700; white-space: nowrap; }
tfoot td { padding: 1rem .7rem; font-size: 1.05rem; font-weight: 700; border-top: 2px solid var(--braise); }
.total { font-family: var(--serif); font-weight: 800; font-size: 1.55rem; color: var(--braise); white-space: nowrap; }

/* ---------------------------------------------------------------
   13. RECETTES
   --------------------------------------------------------------- */
.grille-recettes { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); gap: .9rem; }
.carte-recette {
  background: var(--fond-carte);
  border: 1px solid var(--bord-discret);
  border-left: 4px solid var(--creme-2);
  border-radius: var(--r-carte);
  padding: 1rem; min-height: 120px;
  display: flex; flex-direction: column; gap: .6rem;
  text-align: left; text-decoration: none; color: var(--creme); width: 100%;
}
.carte-recette:hover { border-color: var(--braise); background: var(--fond-survol); }
.carte-recette.pt { border-left-color: var(--azulejo); }
.carte-recette.pe { border-left-color: var(--morado); }
.carte-recette:hover.pt { border-left-color: var(--azulejo); }
.carte-recette:hover.pe { border-left-color: var(--morado); }
.carte-recette .nom { font-family: var(--serif); font-weight: 700; font-size: 1.15rem; line-height: 1.25; }
.carte-recette .marques { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin-top: auto; }

/* Photo : tant que recettes.photo_url est vide, un degrade assume — pas un trou gris.
   Le jour ou une photo arrive, l'image prend exactement la meme place. */
.photo {
  aspect-ratio: 4 / 3; border-radius: var(--r-photo);
  background: linear-gradient(140deg, var(--braise) 0%, #8a4420 55%, var(--fond-carte) 100%);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; margin-bottom: 1.4rem;
}
.photo img { width: 100%; height: 100%; object-fit: cover; }
.photo .bientot {
  color: var(--creme); font-size: 1rem; font-weight: 600;
  background: rgba(43, 31, 26, .45); padding: .4rem 1rem; border-radius: var(--r-pilule);
}
.carte-recette .photo { border-radius: 0; margin: 0; }

/* LE CREDIT DE LA PHOTO. Il n'est pas decoratif : les licences CC BY et CC BY-SA
   EXIGENT l'attribution. Une photo sans son credit affiche est une photo volee.
   .9rem = 16,2 px sur le socle public — exactement le plancher mesure au LOT-02,
   pas un pixel en dessous. Il remonte sous la photo, colle a elle : -1rem de marge
   haute contre le 1,4rem que la photo pousse dessous. */
.credit-photo {
  margin: -1rem 0 1.4rem; font-size: .9rem; color: var(--creme-2);
  line-height: 1.45; word-break: break-word;
}
.credit-photo a { color: var(--braise-texte); }
.carte-recette .credit-photo { margin: .35rem 0 0; font-size: .9rem; }

.preparation { display: flex; flex-direction: column; gap: .9rem; margin-bottom: 1.6rem; }
.etape { display: flex; gap: .9rem; align-items: baseline; }
.etape .n { font-family: var(--serif); font-weight: 800; font-size: 1.5rem; color: var(--braise); min-width: 2rem; }
.etape .quoi { font-size: 1rem; }
.ingredients { margin: 0 0 1.6rem; padding-left: 1.4rem; display: flex; flex-direction: column; gap: .35rem; }
.ingredients li { font-size: 1rem; }

.encadre-variante { border: 2px solid var(--braise); border-radius: var(--r-carte); padding: .9rem 1.2rem; margin-bottom: 1.6rem; }
.encadre-variante .titre { font-size: .95rem; font-weight: 700; color: var(--braise-texte); margin-bottom: .3rem; }

/* colonnes par pays, site public */
/* La piste est BORNEE a 460 px, et non a 1fr comme au proto. Mesure du 15/08, a
   l'oeil, avec une seule recette publiee : une colonne unique en 1fr prenait toute
   la largeur, et la photo 4/3 montait a 750 px de haut. Le proto ne montrait ce
   bloc qu'avec deux colonnes bien remplies — il ne pouvait pas voir ce cas. */
.colonnes-pays {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 460px));
  /* start, et non center : centrer la grille decalait la colonne unique par rapport
     au titre « Nos recettes », qui reste, lui, cale a gauche. Vu a l'oeil le 15/08. */
  justify-content: start;
  gap: 3rem;
}
.colonne-pays .titre { font-family: var(--serif); font-weight: 700; font-size: 1.4rem; margin-bottom: .3rem; }
.colonne-pays .filet-pays { width: 56px; height: 3px; margin-bottom: 1.4rem; }
.colonne-pays .filet-pays.pt { background: var(--azulejo); }
.colonne-pays .filet-pays.pe { background: var(--morado); }
.colonne-pays .liste { gap: .9rem; }

/* ---------------------------------------------------------------
   13 bis. LA SPEC V1 — sommaire + accordeon
   Meme charte que le reste : Playfair pour les titres, corps a 1rem
   (19 px au cockpit), cibles a --cible. Rien de nouveau n'est invente ici,
   tout est repris des composants existants.
   --------------------------------------------------------------- */
.spec-sommaire {
  background: var(--fond-carte); border-radius: var(--r-carte);
  padding: 1rem 1.2rem; margin-bottom: 1.6rem;
}
.spec-sommaire .titre { font-family: var(--serif); font-weight: 700; font-size: 1.15rem; margin-bottom: .6rem; }
.spec-sommaire ol { margin: 0; padding-left: 1.5rem; display: flex; flex-direction: column; gap: .45rem; }
.spec-sommaire li { font-size: 1rem; }
.spec-sommaire a { text-decoration: none; }
.spec-sommaire a:hover { text-decoration: underline; }
.spec-sommaire .pastille { margin-left: .5rem; }

.spec-section {
  background: var(--fond-carte); border: 1px solid var(--bord-discret);
  border-radius: var(--r-carte); margin-bottom: .7rem; overflow: hidden;
}
.spec-section summary {
  display: flex; align-items: center; gap: .8rem; flex-wrap: wrap;
  padding: .85rem 1.1rem; min-height: var(--cible); cursor: pointer; list-style: none;
}
/* Le triangle par defaut de <details> n'est pas a la charte : le numero en Playfair
   braise tient ce role, et il se voit de plus loin. */
.spec-section summary::-webkit-details-marker { display: none; }
.spec-section summary:hover { background: var(--fond-survol); }
.spec-section summary .n {
  font-family: var(--serif); font-weight: 800; font-size: 1.35rem;
  color: var(--braise); min-width: 1.9rem;
}
.spec-section summary .quoi { font-family: var(--serif); font-weight: 700; font-size: 1.2rem; flex: 1; min-width: 8rem; }
.spec-section[open] summary { border-bottom: 1px solid var(--bord-discret); }
.spec-section .corps { padding: 1rem 1.2rem 1.1rem 3.8rem; }
.spec-section .corps p { margin: 0 0 .6rem; font-size: 1rem; }
@media (max-width: 520px) { .spec-section .corps { padding-left: 1.2rem; } }

/* ---------------------------------------------------------------
   14. AVIS, MENTION, CHARGEMENT
   --------------------------------------------------------------- */
.avis {
  background: var(--fond-carte); border-left: 4px solid var(--azulejo-bord);
  border-radius: var(--r-champ); padding: .7rem 1rem; font-size: .95rem;
}
.avis.alerte { border-left-color: var(--alerte-bord); }

/* La mention du devis : bandeau NON fermable, AVANT le tableau, jamais apres. */
.mention {
  background: rgba(184, 68, 44, .25);
  border: 2px solid var(--alerte); border-radius: var(--r-champ);
  padding: .8rem 1.1rem; font-size: 1rem; font-weight: 700;
  margin-bottom: 1.2rem; display: block;
}
.doux { color: var(--creme-2); }
.centre { text-align: center; }
.vide { color: var(--creme-2); padding: 1.6rem 0; text-align: center; }
.petit { font-size: .9rem; }

.rangee { display: flex; gap: .6rem; flex-wrap: wrap; align-items: center; }

.points { display: flex; align-items: center; gap: .6rem; color: var(--creme-2); font-size: 1rem; padding: 1.2rem 0; }
.points i { width: 12px; height: 12px; border-radius: 50%; background: var(--braise); animation: blink 1.2s infinite; }
.points i:nth-child(2) { animation-delay: .2s; }
.points i:nth-child(3) { animation-delay: .4s; }

/* ---------------------------------------------------------------
   15. SITE PUBLIC — le heros
   --------------------------------------------------------------- */
.heros { max-width: 860px; margin: 0 auto; padding: 5.5rem 1.2rem 4.5rem; text-align: center; }
.heros .marque { font-size: clamp(52px, 9vw, 88px); letter-spacing: .05em; line-height: 1.05; display: block; }
.heros .filet { width: 90px; margin: 26px auto 20px; }
.heros .baseline { font-size: 1.2rem; }
.heros .badge {
  display: inline-block; margin-top: 2rem;
  border: 2px solid var(--braise); border-radius: var(--r-pilule);
  padding: .55rem 1.4rem; font-size: 1.05rem; font-weight: 700; color: var(--braise-texte);
}
.heros .intro { max-width: 560px; margin: 3rem auto 0; font-size: 1.1rem; line-height: 1.65; color: var(--creme-2); }
.heros .bouton { margin-top: 2.4rem; }

.pied { text-align: center; color: var(--creme-2); font-size: .9rem; padding: 3rem 1rem 2rem; }

/* ---------------------------------------------------------------
   16. LA LOUPE — une photo en plein ecran, et rien d'autre. (LOT-04)

   Le fond est un noir a 90 % POSE SUR --fond : la couleur reellement obtenue est
   #040302, et c'est CELLE-LA que outils/contraste.mjs mesure. Mesurer le credit
   contre « rgba(0,0,0,.9) » n'aurait rien mesure du tout.
   --------------------------------------------------------------- */
.loupe {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(0, 0, 0, .9);
  display: flex; align-items: center; justify-content: center;
  padding: 1.2rem;
}
.loupe-boite {
  max-width: min(1200px, 100%); max-height: 100%;
  display: flex; flex-direction: column; gap: .7rem; align-items: center;
}
/* La photo prend tout ce qu'elle peut SANS jamais pousser le credit hors de l'ecran :
   c'est le credit qui garde sa place, pas l'inverse. */
.loupe-boite img {
  max-width: 100%; max-height: calc(100vh - 8rem);
  width: auto; height: auto; object-fit: contain;
  border-radius: var(--r-photo);
}
.loupe-boite .credit-photo { margin: 0; text-align: center; max-width: 60rem; }
.loupe-croix {
  position: absolute; top: .8rem; right: .8rem;
  width: var(--cible); height: var(--cible); min-height: var(--cible);
  display: flex; align-items: center; justify-content: center;
  background: rgba(43, 31, 26, .8); color: var(--creme);
  border: 1.5px solid var(--bord-net); border-radius: 50%;
}
.loupe-croix:hover { background: var(--fond-carte); border-color: var(--braise); }

/* Une photo qu'on peut agrandir le DIT : le curseur change, et le bord s'allume. */
.photo.zoomable { cursor: zoom-in; }
.photo.zoomable:hover, .photo.zoomable:focus-visible { outline: 3px solid var(--braise); outline-offset: 2px; }

/* ---------------------------------------------------------------
   17. SPECIALITES — la barre de session et la carte qui se deplie. (LOT-04)
   --------------------------------------------------------------- */

/* La barre de session colle SOUS la barre du haut. --haut-barre est MESUREE par
   app.js (mesurerBarre) et non ecrite en dur : la barre passe sur deux lignes des
   390 px, et un nombre fige serait faux exactement la ou il compte. */
.barre-session {
  position: sticky; top: var(--haut-barre, 4rem); z-index: 15;
  background: var(--fond);
  border-bottom: 1px solid var(--bord-moyen);
  margin: 0 -1.1rem 1rem; padding: .7rem 1.1rem .8rem;
  display: flex; flex-direction: column; gap: .6rem;
}
.barre-session .compteurs-session { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }
.barre-session .filtres { display: flex; gap: .6rem; flex-wrap: wrap; align-items: center; }
.barre-session .filtres input[type="search"] { flex: 1 1 12rem; min-width: 9rem; }
.barre-session .filtres select { flex: 0 1 11rem; }

/* Une pastille de compteur CLIQUABLE filtre la liste. Elle garde la forme d'une
   pastille : c'est le meme objet, avec un geste en plus. */
button.pastille { min-height: var(--cible); cursor: pointer; }
button.pastille.choisie { outline: 2px solid var(--braise); outline-offset: 1px; }

/* scroll-margin-top : DEUX barres collent en haut (celle du cockpit, celle de la
   session). Sans cette marge, une ancre #plat-xx amene la carte SOUS elles — on
   arrive au bon endroit et on ne voit rien. Mesure a l'oeil du 16/08. */
.carte-plat {
  padding: 0; overflow: visible;
  scroll-margin-top: calc(var(--haut-barre, 4rem) + var(--haut-session, 0px) + .5rem);
}
/* L'en-tete deborde la carte de sa propre gouttiere : colle en haut, il doit couvrir
   toute la largeur, sinon on voit passer le fond de la carte sur les cotes. */
.carte-plat .entete {
  display: flex; align-items: center; gap: .8rem;
  padding: .8rem 1.1rem; background: var(--fond-carte);
  border-radius: var(--r-carte) var(--r-carte) 0 0;
}
.carte-plat.deplie .entete {
  position: sticky; top: calc(var(--haut-barre, 4rem) + var(--haut-session, 0px)); z-index: 10;
  border-bottom: 1px solid var(--bord-moyen);
  cursor: pointer;
}
.carte-plat .vignette {
  flex: 0 0 4.632rem; width: 4.632rem; height: 4.632rem;   /* 88 px au socle cockpit */
  aspect-ratio: auto; margin: 0; border-radius: var(--r-photo);
}
/* Mesure a l'oeil du 16/08 : « Photo à venir » tient sur trois lignes serrees dans
   88 px et se lit mal. Le degrade braise suffit a dire « pas de photo » — le nom du
   plat est juste a cote, et la grande photo de la fiche, elle, garde son libelle. */
.carte-plat .vignette .bientot { display: none; }
.carte-plat .titre-plat {
  flex: 1 1 8rem; min-width: 0; text-align: left;
  background: none; border: none; padding: .2rem 0; color: inherit;
  display: flex; flex-direction: column; gap: .3rem; min-height: var(--cible);
}
.carte-plat .titre-plat .nom { font-family: var(--serif); font-weight: 700; font-size: 1.15rem; line-height: 1.25; }
.carte-plat .titre-plat .marques { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }
.carte-plat .titre-plat:hover .nom { color: var(--braise-texte); }

.chevron {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: .4rem;
  min-height: var(--cible); padding: 0 .8rem;
  background: none; border: 1.5px solid var(--bord-net); border-radius: var(--r-champ);
  color: var(--creme-2); font-size: .95rem; font-weight: 600;
}
.chevron:hover { border-color: var(--braise); color: var(--creme); }
.chevron svg { transition: transform .18s ease; }
.chevron[aria-expanded="true"] svg { transform: rotate(180deg); }
@media (max-width: 560px) { .chevron .mot { display: none; } }

.carte-plat .corps { padding: .2rem 1.1rem 1rem; display: flex; flex-direction: column; gap: .7rem; }
.carte-plat .ligne-annotation { display: flex; gap: .6rem; align-items: center; }
.carte-plat .ligne-annotation input { flex: 1 1 auto; }
.carte-plat .signe { font-size: .9rem; color: var(--creme-2); min-height: 1.4rem; }
.carte-plat .signe.ok { color: var(--braise-texte); }

/* La fiche depliee : meme rendu que le module Recettes, dans la carte. */
.carte-plat .fiche { padding: 0 1.1rem 1.2rem; border-top: 1px solid var(--bord-discret); }
.carte-plat .fiche .photo { margin-top: 1rem; }
.carte-plat .fiche h3 { margin: 1.2rem 0 .5rem; }
.carte-plat .fiche .preparation, .carte-plat .fiche .ingredients { margin-bottom: 1rem; }
.carte-plat .fiche .encadre-variante { margin-bottom: .4rem; }
.carte-plat .fiche .sans-fiche {
  margin-top: 1rem; background: var(--fond); border-radius: var(--r-champ);
  padding: .8rem 1rem; color: var(--creme-2); font-size: 1rem;
}
/* La carte visee par une ancre (#plat-xx) s'allume une seconde : arriver au bon
   endroit ne sert a rien si on ne voit pas ou on est arrive. */
.carte-plat.visee { border-color: var(--braise); }

/* ---------------------------------------------------------------
   18. LA SALLE DES MACHINES — 16 cartes, un halo commun, une animation par robot.
   Tout est CSS et SVG : aucune bibliotheque, aucun GIF, aucun actif externe.
   prefers-reduced-motion fige l'ensemble (regle globale du §3).
   --------------------------------------------------------------- */
.regle-robots {
  border: 2px solid var(--braise); border-radius: var(--r-carte);
  padding: .9rem 1.2rem; margin-bottom: 1.2rem;
}
.regle-robots .titre { font-weight: 800; color: var(--braise-texte); margin-bottom: .3rem; }
.regle-robots p { margin: 0; font-size: 1rem; }

.grille-robots { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: .9rem; }
.carte-robot {
  background: var(--fond-carte); border: 1px solid var(--bord-discret);
  border-radius: var(--r-carte); padding: 1rem 1.1rem;
  display: flex; flex-direction: column; gap: .55rem;
}
.carte-robot .haut { display: flex; align-items: center; gap: .9rem; }
.carte-robot .nom { font-family: var(--serif); font-weight: 700; font-size: 1.15rem; line-height: 1.25; }
.carte-robot .mission { font-size: 1rem; color: var(--creme-2); }
.carte-robot .bas { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-top: auto; }
/* --braise-texte, et non --braise : ce numero fait 1,1 rem, donc moins de 24 px.
   La regle du LOT-02 vaut ici comme ailleurs — braise sur fond-carte tombe a 3,96:1. */
.carte-robot .no { font-family: var(--serif); font-weight: 800; color: var(--braise-texte); font-size: 1.1rem; }

/* LE HALO COMMUN — il respire, il ne clignote pas. Purement decoratif : la pastille
   de statut dit la meme chose en toutes lettres, juste a cote. */
.picto-robot { position: relative; width: 3.4rem; height: 3.4rem; flex: 0 0 3.4rem; color: var(--braise); }
.picto-robot::before {
  content: ''; position: absolute; inset: -.25rem; border-radius: 50%;
  background: radial-gradient(circle, var(--braise) 0%, transparent 68%);
  opacity: .22; animation: rob-respire 3.6s ease-in-out infinite;
}
.picto-robot svg { position: relative; width: 100%; height: 100%; }

@keyframes rob-respire { 0%, 100% { opacity: .16; transform: scale(.94); } 50% { opacity: .40; transform: scale(1.06); } }
@keyframes rob-tourne  { to { transform: rotate(360deg); } }
@keyframes rob-onde    { 0% { opacity: 0; transform: scale(.55); } 35% { opacity: .95; } 100% { opacity: 0; transform: scale(1.3); } }
@keyframes rob-cligne  { 0%, 88%, 100% { transform: scaleY(1); } 94% { transform: scaleY(.06); } }
@keyframes rob-balaie  { 0%, 100% { transform: translateX(-2.2px); } 50% { transform: translateX(2.2px); } }
@keyframes rob-trace   { 0% { stroke-dashoffset: 30; } 55%, 100% { stroke-dashoffset: 0; } }
@keyframes rob-monte   { 0%, 100% { transform: translateY(1.5px); } 50% { transform: translateY(-1.5px); } }
@keyframes rob-bat     { 0%, 100% { transform: rotate(-8deg); } 50% { transform: rotate(8deg); } }
@keyframes rob-defile  { 0% { transform: translateX(-1.6px); opacity: .4; } 50% { opacity: 1; } 100% { transform: translateX(1.6px); opacity: .4; } }
@keyframes rob-pulse   { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
@keyframes rob-alterne { 0%, 45% { opacity: .28; } 55%, 100% { opacity: 1; } }

/* transform-box: view-box — sans lui, une rotation dans un SVG tourne autour de la
   boite de l'element (sa propre bounding box), pas autour du centre du dessin. */
.picto-robot [class^="anim-"] { transform-box: view-box; transform-origin: 12px 12px; }
.anim-tourne   { animation: rob-tourne 4.5s linear infinite; }
.anim-onde     { transform-origin: 6px 12px; animation: rob-onde 2.8s ease-out infinite; }
.anim-onde2    { transform-origin: 6px 12px; animation: rob-onde 2.8s ease-out .7s infinite; }
.anim-cligne   { animation: rob-cligne 4.2s ease-in-out infinite; }
.anim-balaie   { animation: rob-balaie 3.4s ease-in-out infinite; }
.anim-trace    { stroke-dasharray: 30; animation: rob-trace 3.4s ease-in-out infinite; }
.anim-monte    { animation: rob-monte 3.4s ease-in-out infinite; }
.anim-bat      { transform-origin: 12px 4.4px; animation: rob-bat 2.6s ease-in-out infinite; }
.anim-defile   { animation: rob-defile 3.2s ease-in-out infinite; }
.anim-pulse    { animation: rob-pulse 3s ease-in-out infinite; }
.anim-alterne  { animation: rob-alterne 3.6s ease-in-out infinite; }
.anim-alterne2 { animation: rob-alterne 3.6s ease-in-out 1.8s infinite; }

/* Statuts des robots. 'prepare' emprunte le gris-creme de « a faire » : ecrit,
   pas branche. 'arme' prend la braise, 'pause' le bleu — aucun n'existe encore
   en base, mais la peau est prete le jour ou la direction en armera un. */
.pastille.prepare { background: #5A4D44; background: color-mix(in srgb, var(--creme-2) 30%, var(--fond)); border-color: var(--creme-2); }
.pastille.arme    { background: #5F3620; background: color-mix(in srgb, var(--braise) 30%, var(--fond)); border-color: var(--braise); }
.pastille.pause   { background: #3F4751; background: color-mix(in srgb, var(--azulejo-bord) 30%, var(--fond)); border-color: var(--azulejo-bord); }

/* ---------------------------------------------------------------
   19. PORTE ET PAGES DE SERVICE (403 du middleware, 404)
   --------------------------------------------------------------- */
.porte { max-width: 26rem; margin: 3rem auto; }
.porte .marque-bloc { margin-bottom: 2rem; }
.porte input {
  font-size: 1.4rem; letter-spacing: .25em; text-align: center; text-transform: uppercase;
  min-height: var(--action-forte);
}
.porte .bouton { width: 100%; margin-top: 1rem; }
.page-service { max-width: 34rem; margin: 4rem auto; text-align: center; }
.page-service .code { font-family: var(--serif); font-weight: 800; font-size: 4rem; color: var(--braise); line-height: 1; }

/* ---------------------------------------------------------------
   20. LA JOURNEE DU RESEAU — la scene qui ouvre la salle des machines. (LOT-07)

   Tout est SVG + CSS : aucune bibliotheque, aucun GIF, aucun actif exterieur.
   Les seize pictogrammes sont ceux du LOT-04 (assets/robots.js), reutilises
   tels quels — pas une copie, pas une variante.

   ⚠ LA SCENE NE PORTE AUCUN TEXTE, et c'est une decision mesuree. A 390 px de
   large, un texte SVG de 13 unites sur une scene de 390 unites rend 13 px : sous
   le plancher de la loi typo « Man », et hors de portee du bouton A/A+, qui ne
   touche que le rem. Tout ce qui se lit vit donc en HTML, sous la scene.
   --------------------------------------------------------------- */
.reseau { margin-bottom: 2rem; }
.reseau-titre { font-family: var(--serif); font-weight: 700; font-size: 1.35rem; margin: 0 0 1rem; }

.reseau-scene {
  display: block;
  width: 100%;
  max-width: 34rem;      /* ~560 px au socle cockpit : au-dela, le dessin s'etire pour rien */
  height: auto;
  margin: 0 auto;
}

.reseau-liens line { stroke: var(--bord-moyen); stroke-width: 1; }

/* Le trajet SORTANT. Il descend du feu et s'arrete EN POINTANT la porte, qui est
   juste dessous. Aucun trait ne la traverse : il n'y a pas de chemin au-dela. */
.reseau-sortie, .reseau-sortie-pointe {
  fill: none; stroke: var(--bord-net); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.reseau-sortie.actif, .reseau-sortie-pointe.actif { stroke: var(--braise); stroke-width: 2.6; }

.reseau-feu .halo {
  fill: var(--braise); opacity: .2;
  transform-box: view-box; transform-origin: 195px 142px;
  animation: rob-respire 3.6s ease-in-out infinite;
}
.reseau-feu .rond { fill: var(--fond-carte); stroke: var(--braise); stroke-width: 2; }
.reseau-feu .flamme path {
  fill: none; stroke: var(--braise); stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}

/* Un noeud : un rond au bord de sa FAMILLE, et le pictogramme du robot dedans.
   --famille est posee par reseau.js. La couleur n'est jamais le seul signal :
   la legende des familles, sous la scene, ecrit les noms en toutes lettres. */
.reseau-noeud { color: var(--creme-2); }
.reseau-noeud .rond { fill: var(--fond-carte); stroke: var(--famille, var(--creme-2)); stroke-width: 1.6; }
.reseau-noeud.actif { color: var(--braise-texte); }
.reseau-noeud.actif .rond { fill: var(--fond-survol); stroke: var(--braise); stroke-width: 2.6; }

/* LES MICRO-ANIMATIONS DU LOT-04, MAIS A L'ARRET. Elles ne partent QUE sur le
   robot que l'etape allume : seize dessins qui s'agitent ensemble ne se
   regardent pas, ils se fuient (deja dit au LOT-04, toujours vrai ici).
   Meme regle de repere que dans la salle des machines — d'ou le <svg> imbrique
   dans reseau.js, qui rend un viewBox 0-24 a `transform-box: view-box`. */
.picto-noeud [class^="anim-"] {
  transform-box: view-box; transform-origin: 12px 12px;
  animation-play-state: paused;
}
.reseau-noeud.actif .picto-noeud [class^="anim-"] { animation-play-state: running; }

/* Les points braise qui circulent le long des liens. Un keyframe, deux variables :
   le trajet est ecrit par reseau.js en coordonnees de la scene. */
.reseau-point { fill: var(--braise); transform-box: view-box; transform-origin: 0 0; animation: reseau-file 1.9s linear infinite; }
@keyframes reseau-file {
  0%   { transform: translate(var(--x0), var(--y0)); opacity: 0; }
  14%  { opacity: 1; }
  86%  { opacity: 1; }
  100% { transform: translate(var(--x1), var(--y1)); opacity: 0; }
}

/* ⛔ LE POSTE DE CONTROLE. Il est POSE SUR LE TRAJET SORTANT, entre le feu et le
   dehors, et le dessin s'arrete dessus : rien ne sort sans le franchir. C'est la
   regle absolue du projet, rendue visible plutot qu'ecrite en note de bas de page. */
.reseau-porte {
  max-width: 34rem; margin: -.2rem auto 0;
  border: 2px solid var(--braise); border-radius: var(--r-carte);
  background: var(--fond-carte);
  padding: .8rem 1.1rem;
  display: flex; flex-direction: column; gap: .2rem; align-items: center; text-align: center;
}
.reseau-porte .titre { font-weight: 800; color: var(--braise-texte); }
.reseau-porte .regle { font-size: 1rem; }
/* La porte s'allume quand quelque chose la franchit. Le fond est celui, deja
   mesure, de la bulle « moi » du fil : color-mix(braise 18 %, fond-carte). */
.reseau-porte.allume { background: color-mix(in srgb, var(--braise) 18%, var(--fond-carte)); }
.reseau-dehors { text-align: center; color: var(--creme-2); font-size: 1rem; margin: .4rem 0 1rem; }

/* La legende de l'etape. Sa hauteur est RESERVEE : sans ce min-height, la page
   sautait de trois lignes a une entre l'etape 8 et l'etape 4. */
.reseau-legende { font-size: 1.05rem; margin: 0 0 1rem; min-height: 4.2em; }

.reseau-commandes { display: flex; gap: .6rem; flex-wrap: wrap; align-items: center; }

.reseau-etapes { list-style: none; margin: .9rem 0; padding: 0; display: flex; gap: .5rem; flex-wrap: wrap; }
.reseau-puce {
  width: var(--cible); height: var(--cible); min-height: var(--cible);
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%; background: none; color: var(--creme-2);
  border: 1.5px solid var(--bord-net); font-weight: 800; font-size: 1rem; padding: 0;
}
.reseau-puce:hover { border-color: var(--braise); color: var(--creme); }
.reseau-puce.actif { background: var(--braise); color: var(--fond); border-color: var(--braise); }

/* LES HUIT ETAPES EN CLAIR. Elles existent toujours — huit puces numerotees ne
   disent pas ce qu'elles contiennent —, et sous prefers-reduced-motion elles
   deviennent le seul pilote de la scene. */
.reseau-liste { list-style: none; margin: 0 0 1.2rem; padding: 0; display: flex; flex-direction: column; gap: .35rem; }
.reseau-ligne {
  width: 100%; text-align: left; min-height: var(--cible);
  background: none; border: 1.5px solid transparent; border-radius: var(--r-champ);
  padding: .55rem .8rem; color: var(--creme-2); font-size: 1rem; line-height: 1.5;
}
.reseau-ligne:hover { border-color: var(--bord-net); color: var(--creme); }
.reseau-ligne.actif { border-color: var(--braise); background: var(--fond-carte); color: var(--creme); }

.reseau-familles { display: flex; flex-wrap: wrap; gap: .6rem; margin-bottom: 1.2rem; }
.reseau-famille {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  background: var(--fond-carte); border-radius: var(--r-carte); padding: .5rem .85rem; font-size: 1rem;
}
.reseau-famille .puce-famille { width: 12px; height: 12px; border-radius: 50%; background: var(--famille, var(--creme-2)); flex: 0 0 12px; }
.reseau-famille .nom { font-weight: 700; }
.reseau-famille .qui { color: var(--creme-2); font-size: .95rem; }

.reseau-honnete {
  border: 2px solid var(--braise); border-radius: var(--r-carte);
  padding: .8rem 1.1rem; font-size: 1rem; margin: 0 0 1.6rem;
}

/* MOINS DE MOUVEMENT : la regle globale du §3 fige deja tout (halo, points,
   micro-animations). reseau.js va plus loin et NE CREE PAS les points, ne lance
   pas la boucle et retire le bouton lecture/pause — un bouton qui ne fait rien
   est pire qu'un bouton absent. La liste des huit etapes reste, cliquable. */
@media (prefers-reduced-motion: reduce) {
  .reseau-point { display: none; }
}

/* ---------------------------------------------------------------
   LOT-BRASA-08 — LA PORTE DE CONFIANCE : /app/appareils et la preuve.

   ⛔ AUCUNE COULEUR NOUVELLE, ET C'EST VOLONTAIRE. Tout ce bloc est peint avec
   des paires DEJA mesurees par outils/contraste.mjs : creme/fond-carte pour le
   corps, creme-2/fond-carte pour les details, braise/fond-carte pour le code a
   six chiffres (>= 24 px gras, donc seuil « ui »), et les pastilles existantes
   pour les verdicts. Le tableau des contrastes ne bouge donc pas — l'y faire
   grossir sans mesurer quoi que ce soit de neuf serait un faux progres.
   --------------------------------------------------------------- */

.titre-bloc {
  font-family: var(--serif); font-weight: 700; font-size: 1.2rem;
  margin: 2rem 0 .8rem; display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
}
.titre-bloc:first-child { margin-top: 0; }

.appareil, .connexion, .remise { display: flex; flex-direction: column; gap: .6rem; }
.nom-appareil { font-weight: 700; font-size: 1.05rem; }
.details-appareil { display: flex; flex-direction: column; gap: .15rem; }

/* ⚠ « Ce n'etait pas moi » est une CIBLE TACTILE, pas un lien de bas de page :
   il se clique dans l'urgence, souvent sur un telephone, souvent par quelqu'un
   qui n'est pas a l'aise. Il tient donc la hauteur d'action de la maison, et il
   ne se serre pas contre le bord de la carte. */
.appareil .bouton.doux { align-self: flex-start; min-height: var(--action); }

/* LE CODE A SIX CHIFFRES — il sera LU A HAUTE VOIX ou recopie dans WhatsApp.
   Chiffres espaces, gros, et en chasse fixe : « 0 » et « O », « 1 » et « l » ne
   doivent pas se discuter au telephone. */
.code-preuve {
  font-family: ui-monospace, 'SFMono-Regular', Consolas, monospace;
  font-weight: 800; font-size: 2.1rem; letter-spacing: .22em;
  color: var(--braise); background: var(--fond); border-radius: var(--r-champ);
  padding: .5rem .9rem; text-align: center;
}

/* Le champ du code de preuve, dans le panneau du fil : meme regle que le code
   ci-dessus, parce qu'on y retape exactement ce qu'on vient de lire. */
.fil-preuve input {
  font-family: ui-monospace, 'SFMono-Regular', Consolas, monospace;
  font-size: 1.3rem; letter-spacing: .18em; text-align: center;
}
