/*
  STOVO — feuille de style de la PWA (lot 9a)
  =============================================
  Ce fichier reprend EXACTEMENT le <style> du dashboard actuel
  (livrables/sites-web/stovo/index.html), sans aucune modification de regle
  existante. Les regles ajoutees pour la coquille (barre de navigation,
  ecran "Parler", bascule d'onglets) sont regroupees a la fin, sous
  "Coquille PWA (lot 9a)", pour qu'on distingue clairement ce qui vient du
  dashboard de ce qui est nouveau.

  Monde clair « établi » depuis le 23/08/2026, aligné sur la vitrine
  (../DESIGN.md). Une retouche de jeton se fait aux deux endroits.
*/

/* DM Sans, variable, auto-hebergee (graisses 400 a 700), meme fichier que la
   vitrine (fonts/dm-sans-latin.woff2, copie dans app/fonts/). Pas d'Instrument
   Serif ici : le serif ne sert qu'au h1 de la vitrine, un h2 en serif dans
   l'app serait un deuxieme monde (DESIGN.md). */
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('fonts/dm-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --brand: #0F766E;
  --brand-dark: #0F766E;
  --bg: #FFF8F1;
  --card: #FFFFFF;
  --border: #E3D6C5;
  --text: #1D1E1C;
  --muted: #615F5C;
  --muted-light: #8E8B87;

  --danger: #DC2626;
  --danger-bg: #fef2f2;
  --danger-border: #fecaca;
  --danger-text: #B91C1C;
  --warn: #A16207;
  --warn-bg: #FEF9C3;
  --warn-border: #FDE68A;
  --warn-text: #A16207;
  --ok: #0F766E;
  --ok-bg: #F0FDFA;
  --brand-light: #99F6E4;
  --brand-darker: #115E59;
  --muted-dark: #615F5C;

  --flamme: #FA5D00;
  --flamme-sombre: #C94A00;
  --fond-chaud: #FFF1E4;

  /* Lot A15 (R-2, 25/08/2026) : la couleur d'action au choix, cinq
     teintes (regle 10 de DESIGN.md, teal et vert exclus). --action et
     --action-sombre remplacent --flamme/--flamme-sombre sur tout ce qui
     est TOUCHABLE (boutons, liens, micro, onglet actif) ; --flamme reste
     reserve a l'identite (logotype "Stovo") et au decor (--fond-chaud,
     --shadow-chaude, INCHANGES par ce lot). Valeur par defaut = flamme,
     comme si aucun choix n'avait ete fait. */
  --action: #FA5D00;
  --action-sombre: #C94A00;

  --shadow-sm: 0 1px 2px rgba(29,30,28,.06);
  --shadow: 0 1px 2px rgba(29,30,28,.06);
  --shadow-chaude: rgba(250,166,0,.22) 6px 4px 24px, rgba(29,30,28,.05) 0 1px 2px;
  --radius: 20px;
}

/* Les cinq teintes de --action (lot A15, R-2). Un attribut data-couleur
   sur <html>, pose par reglages.js (choix immediat, memorise dans
   localStorage) ou par le script en tete d'index.html (avant le premier
   rendu, pour eviter le clignotement en flamme). "flamme" est explicite
   ici bien qu'identique au defaut de :root : un choix EXPLICITE de
   l'utilisateur doit pouvoir se relire dans la feuille de style, meme
   s'il ne change rien visuellement. */
html[data-couleur="flamme"] { --action: #FA5D00; --action-sombre: #C94A00; }
html[data-couleur="bleu"] { --action: #1D4ED8; --action-sombre: #1E40AF; }
html[data-couleur="prune"] { --action: #7E22CE; --action-sombre: #6B21A8; }
html[data-couleur="framboise"] { --action: #BE185D; --action-sombre: #9D174D; }
html[data-couleur="encre"] { --action: #1D1E1C; --action-sombre: #000000; }

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  font-family: 'DM Sans', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  padding-bottom: 40px;
}

.wrap { max-width: 1120px; margin: 0 auto; padding: 0 20px; }

/* ---------- En-tête ----------
   Monde clair (23/08/2026) : plus de bande teal, le header prend le fond de
   page. Le logotype "Stovo" en flamme fait office de marque (plus de boîte
   .logo ni de sous-titre dans le header, retirés de index.html). La classe
   .logo elle-même a disparu au lot "monde clair, suite" (23/08/2026) : son
   dernier usage (.login-brand .logo, l'écran de connexion) a été retiré en
   même temps que le pictogramme "S" (DESIGN.md, écran de connexion). */
header {
  background: var(--bg);
  padding: 18px 0 6px;
}
.header-row { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 16px; }
.brand { display: flex; align-items: center; gap: 13px; }
/* Lot A15 (R-2, 25/08/2026) : le logotype reste en --flamme, JAMAIS en
   --action. C'est l'identite de Stovo (comme le mot "Stovo" en tete de la
   vitrine), pas un element touchable, il ne suit pas le choix de couleur. */
.brand h1 { font-size: 22px; font-weight: 700; letter-spacing: -.02em; line-height: 44px; color: var(--flamme); }
.brand p { font-size: 13.5px; opacity: .88; }
.header-actions { display: flex; align-items: center; gap: 8px; }
.updated { font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Deux boutons a contour (Rafraichir, Deconnexion) : meme gabarit, meme
   comportement responsive. Mobile-first : icone seule (carre 44x44), le
   libelle (span.btn-label.sr-only) redevient visible a partir de 560px,
   l'aria-label reste pose dans les deux etats (nom accessible constant). */
.btn-refresh, .btn-reglages {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  width: 44px; height: 44px; padding: 0;
  font-family: inherit; font-size: 14px; font-weight: 600; color: var(--text);
  background: var(--card); border: 1.5px solid var(--border); border-radius: 14px;
  cursor: pointer; transition: background .15s, transform .1s;
}
.btn-refresh svg, .btn-reglages svg { display: block; flex: 0 0 auto; }
.btn-refresh:hover, .btn-reglages:hover { background: var(--fond-chaud); }
.btn-refresh:active, .btn-reglages:active { transform: translateY(1px); }
@media (min-width: 560px) {
  .btn-refresh, .btn-reglages { width: auto; padding: 0 14px; justify-content: flex-start; }
  .btn-refresh .btn-label, .btn-reglages .btn-label {
    position: static; width: auto; height: auto; padding: 0; margin: 0;
    overflow: visible; clip: auto; white-space: nowrap; border: 0;
  }
}

/* ---------- KPI ---------- */
.kpis {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
  margin-top: 16px; margin-bottom: 8px;
}
.kpi {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 16px 18px; box-shadow: var(--shadow);
}
.kpi .k-label { font-size: 12px; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: .08em; }
.kpi .k-value { font-size: 34px; font-weight: 700; line-height: 1.1; letter-spacing: -.03em; font-variant-numeric: tabular-nums; margin-top: 6px; color: var(--text); }
.kpi.danger .k-value { color: var(--danger); }
.kpi.warn .k-value { color: var(--warn); } /* --warn = --warn-text = #A16207 (4,9:1), reprise du 23/08 : l'ambre clair #CA8A04 essaye plus tot ne faisait que 2,9:1 */
.kpi .k-sub { font-size: 12.5px; color: var(--muted); margin-top: 2px; }

/* ---------- Bandeau valeur du stock (ROI) ---------- */
.stock-value {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 16px 20px; margin: 12px 0 0;
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 16px;
}
.stock-value .sv-label { font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); }
.stock-value .sv-amount { font-size: 30px; font-weight: 700; color: var(--text); line-height: 1.1; font-variant-numeric: tabular-nums; }
.stock-value .sv-sub { font-size: 12.5px; color: var(--muted); margin-left: auto; }
@media (max-width: 560px) { .stock-value .sv-sub { margin-left: 0; flex-basis: 100%; } }

/* ---------- Phrase de verdict (la réponse en un coup d'œil, avant tout scroll) ---------- */
.verdict { font-size: 15.5px; font-weight: 700; margin: 16px 2px 0; }
.verdict.v-ok { color: var(--brand-dark); }
.verdict.v-warn { color: var(--warn-text); }
.verdict.v-crit { color: var(--danger-text); }
/* LOT D30-L3bis (27/09/2026, plan §2.1) : etat neutre -- rien a commander,
   mais des produits jamais comptes (Stovo ne sait pas si la situation est
   bonne, --brand-dark mentirait). --muted, PAS --text : c'est deja la
   couleur de toute la famille "jamais compte" (badge.neutre, .h-muted du
   hero de carte, .inv-sym-pasencorecompte plus bas), --text ferait une
   quatrieme teinte pour la meme idee. */
.verdict.v-neutre { color: var(--muted); }

/* ---------- Titres de section ---------- */
.section-title { font-size: 17px; font-weight: 700; letter-spacing: -.01em; margin: 30px 0 14px; display: flex; align-items: center; gap: 10px; }
.section-title .count {
  font-size: 12.5px; font-weight: 600; color: var(--muted);
  background: var(--card); border: 1px solid var(--border); padding: 2px 10px; border-radius: 999px;
}

/* ---------- Bloc réappro (priorité action) ---------- */
.reorder {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); overflow: hidden;
}
.reorder-item {
  display: grid; grid-template-columns: 1fr auto; gap: 8px 16px; align-items: center;
  padding: 15px 20px; border-top: 1px solid var(--border);
}
.reorder-item:first-child { border-top: none; }
.reorder-item .ri-main { min-width: 0; }
.reorder-item .ri-name { font-weight: 700; font-size: 15px; }
.reorder-item .ri-detail { font-size: 13px; color: var(--muted); margin-top: 2px; }
.reorder-item .ri-right { text-align: right; white-space: nowrap; }
.reorder-item .ri-cover { font-size: 19px; font-weight: 700; }
.reorder-item .ri-cover.c-crit { color: var(--danger); }
.reorder-item .ri-cover.c-warn { color: var(--warn); }
.reorder-item .ri-coverlabel { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .08em; }
.reorder-item .ri-qty { font-size: 22px; font-weight: 700; color: var(--danger-text); font-variant-numeric: tabular-nums; cursor: help; }
.reorder-item .ri-warning { font-size: 12.5px; font-weight: 600; color: var(--danger-text); margin-top: 6px; }

/* ---------- Cartes produits ---------- */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(248px, 1fr)); gap: 16px; }
.card {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 18px; box-shadow: var(--shadow-sm);
}
.card .c-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.card .c-name { font-size: 15px; font-weight: 700; }
/* Héros de la carte : l'autonomie, l'info qui fait agir. Couleur selon l'urgence. */
.card .c-hero { font-size: 20px; font-weight: 700; line-height: 1.15; margin: 13px 0 2px; color: var(--text); }
.card .c-hero.h-crit { color: var(--danger); }
.card .c-hero.h-warn { color: var(--warn-text); }
.card .c-hero.h-ok { color: var(--ok); }
.card .c-hero.h-muted { color: var(--muted); font-weight: 700; font-size: 16px; }
/* Stock brut, rétrogradé en information secondaire */
.card .c-stockline { font-size: 13.5px; color: var(--muted); margin-bottom: 12px; }
.card .c-stockline b { color: var(--text); font-size: 15px; font-weight: 700; }
/* Détail (prix, valeur, conso, point de commande) : petit, gris, en pied de carte */
.card .c-detail { font-size: 12px; color: var(--muted); margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border); line-height: 1.7; }
.card .c-detail b { color: var(--muted); font-weight: 700; }

/* jauge de niveau : repère du seuil au milieu (50%) */
.jauge { position: relative; height: 8px; background: var(--fond-chaud); border-radius: 999px; overflow: hidden; }
.jauge-fill { height: 100%; border-radius: 999px; background: var(--brand); }
.jauge-fill.is-low { background: var(--danger); }
.jauge-seuil { position: absolute; top: -2px; bottom: -2px; width: 2px; background: rgba(29,30,28,.35); }

/* badges / pills */
.badge { font-size: 12px; font-weight: 700; padding: 4px 10px; border-radius: 999px; white-space: nowrap; }
.badge.ok { color: var(--ok); background: var(--ok-bg); border: 1px solid var(--brand-light); }
.badge.danger { color: var(--danger-text); background: var(--danger-bg); border: 1px solid var(--danger-border); }
.badge.warn { color: var(--warn-text); background: var(--warn-bg); border: 1px solid var(--warn-border); }
/* LOT D30-L3 (27/09/2026) : pastille "Pas encore compté", NEUTRE (sans
   couleur d'alerte ni de succès, plan §2.1 -- ni rouge ni vert), meme
   famille visuelle que .tag-fixe (teinte --fond-chaud, texte --muted). */
.badge.neutre { color: var(--muted); background: var(--fond-chaud); border: 1px solid var(--border); }

/* ---------- Tableau des mouvements ---------- */
.table-wrap { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-sm); overflow: hidden; }
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 12px 18px; font-size: 14px; }
th { font-size: 11.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); background: var(--bg); font-weight: 700; }
/* Colonne "Mouvement" (3e colonne) : alignee a droite, jamais de retour a la ligne. */
th:nth-child(3), td:nth-child(3) { text-align: right; white-space: nowrap; }
tbody tr { border-top: 1px solid var(--border); }
tbody tr:hover { background: var(--fond-chaud); }
.pill { font-weight: 700; font-size: 13.5px; }
.pill.entree { color: var(--brand-dark); }
.pill.sortie { color: var(--text); } /* une sortie n'est pas une alerte, le signe moins suffit */
.src { font-size: 12px; color: var(--muted); }
/* Icone SVG en trait devant "vocal"/"manuel" (lot "monde clair, suite",
   23/08/2026), remplace les emoji 🎙️/⌨️ (dashboard.js, colonne Source). */
.src-ligne { display: inline-flex; align-items: center; gap: 5px; }
.src-ligne svg { width: 13px; height: 13px; flex: 0 0 auto; display: block; }
/* étiquette des mouvements de régularisation (motif), pour les distinguer d'une vente */
.tag-motif { font-size: 11px; font-weight: 700; color: var(--muted); background: var(--fond-chaud); border: 1px solid var(--border); padding: 1px 8px; border-radius: 999px; margin-left: 7px; vertical-align: middle; }
.tag-auto { font-size: 10.5px; font-weight: 700; color: var(--brand-dark); background: var(--ok-bg); border: 1px solid var(--brand-light); padding: 0 7px; border-radius: 999px; vertical-align: middle; cursor: help; }
.tag-fixe { font-size: 10.5px; font-weight: 700; color: var(--muted); background: var(--fond-chaud); border: 1px solid var(--border); padding: 0 7px; border-radius: 999px; vertical-align: middle; cursor: help; }

/* ---------- États ---------- */
.state { padding: 38px; text-align: center; color: var(--muted); }
.state.error { color: var(--danger); }

footer { margin-top: 36px; font-size: 12.5px; color: var(--muted); text-align: center; line-height: 1.6; }

/* ---------- Mobile ---------- */
@media (max-width: 900px) { .kpis { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) {
  .kpi .k-value { font-size: 26px; }
  .brand h1 { font-size: 21px; }
  th:nth-child(4), td:nth-child(4) { display: none; }
  th, td { padding: 11px 12px; }
  td:first-child { font-size: 13px; }
  /* D47 (25/09/2026) : le tableau "Derniers mouvements" débordait à 390px et
     se faisait couper par .table-wrap (overflow:hidden) — la colonne
     "Mouvement" imposait sa largeur en white-space:nowrap (quantité + pilule
     de motif), et l'agencement "auto" du tableau pouvait dépasser 100% dès
     que le contenu minimal des colonnes le demandait. table-layout:fixed
     répartit les 3 colonnes visibles sur 100% de la largeur, jamais plus ;
     le retour à la ligne (overflow-wrap) remplace la troncature : aucune
     information perdue, aucun défilement horizontal. */
  table { table-layout: fixed; }
  th:nth-child(1), td:nth-child(1) { width: 22%; overflow-wrap: anywhere; }
  th:nth-child(2), td:nth-child(2) { width: 42%; overflow-wrap: anywhere; }
  th:nth-child(3), td:nth-child(3) { width: 36%; white-space: normal; overflow-wrap: anywhere; }
  /* Pastille D47 (29/09/2026) : .tag-motif est un <span> inline (dashboard.js
     l.925). Des que la colonne "Mouvement" passe en white-space:normal
     ci-dessus, un motif long ("inventaire") peut couper sur deux lignes --
     et un span inline coupe alors son fond/bordure en deux blocs distincts.
     inline-block garde un seul bloc dont le texte peut passer sur deux
     lignes a l'interieur de son propre fond ; max-width l'empeche de
     depasser la cellule. */
  .tag-motif { display: inline-block; max-width: 100%; }
}

/* =====================================================================
   Coquille PWA (lot 9a) — tout ce qui suit est nouveau, rien ci-dessus
   n'a ete modifie par rapport au dashboard actuel.
   ===================================================================== */

/* Laisse de la place en bas pour la barre de navigation fixe (+ l'encoche
   iPhone via env(safe-area-inset-bottom), actif grace a viewport-fit=cover). */
body { padding-bottom: calc(78px + env(safe-area-inset-bottom)); }

/* Bascule d'ecran : un seul des deux ecrans visible a la fois. */
.ecran { display: none; }
.ecran.ecran-actif { display: block; }

/* Ecran "Parler" (placeholder, lot 9a) : centre verticalement et horizontalement. */
.parler-page {
  min-height: calc(100vh - 78px - env(safe-area-inset-bottom));
  min-height: calc(100dvh - 78px - env(safe-area-inset-bottom));
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.parler-centre { text-align: center; max-width: 340px; width: 100%; }
/* A-6 (audit accessibilité 31/07) : sur grand écran, 340px bride tout le
   panneau de réception/sortie et l'inventaire (noms de produits tronqués). */
@media (min-width: 700px) { .parler-centre { max-width: 640px; } }
/* Repos (disabled) : décor seulement (icône --muted-light, §1 de DESIGN.md).
   L'icône SVG (index.html) remplace l'emoji 🎙️ ; sa taille est fixée par
   .btn-micro svg ci-dessous, indépendamment du reste du bouton. */
.btn-micro {
  width: 90px; height: 90px; border-radius: 999px;
  background: var(--card); border: 2px solid var(--border); color: var(--muted-light);
  display: grid; place-items: center; margin: 24px auto 8px;
  cursor: not-allowed;
}
.btn-micro svg { width: 36px; height: 36px; display: block; }
.parler-texte { color: var(--muted); font-size: 12.5px; }

/* =====================================================================
   Micro on-device (lot 11a) — activé par parler.js seulement si l'API
   SpeechRecognition existe (le style "grisé" ci-dessus reste tant qu'il
   est disabled : progressive enhancement, additif seulement).
   ===================================================================== */

/* Actif : disque flamme (audit --brand §2bis, monde clair 23/08/2026) —
   c'est l'action de l'écran, au même titre que .matin-copier ou
   .btn-reception-primaire. */
.btn-micro:not(:disabled) {
  background: var(--action); border-color: var(--action); color: #fff;
  box-shadow: 0 1px 4px rgba(250,93,0,.25);
  cursor: pointer; transition: background .15s, transform .1s, box-shadow .15s;
}
.btn-micro:not(:disabled):hover { background: var(--action-sombre); border-color: var(--action-sombre); }
.btn-micro:not(:disabled):active { transform: translateY(1px); }

/* État "en écoute" : pulsation discrète pour montrer que le micro capte.
   Correctif contraste du 01/08 : --danger-text donne ~5,9:1, au moins aussi
   visible que le repos. Fond et pulsation inchangés par ce lot : c'est un
   ÉTAT (pas une action), il ne suit pas le passage à la flamme ci-dessus. */
.btn-micro.ecoute {
  background: var(--danger-bg); border-color: var(--danger-text); color: var(--danger-text);
  box-shadow: none;
  animation: pulse-micro 1.4s ease-in-out infinite;
}
@keyframes pulse-micro {
  0%, 100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, .25); }
  50% { box-shadow: 0 0 0 12px rgba(220, 38, 38, 0); }
}

/* Zone d'état du micro (écoute / erreur / indisponibilité), sous le bouton. */
.parler-etat { font-size: 12.5px; color: var(--muted); margin-top: 6px; min-height: 16px; }

/* =====================================================================
   Écran « Parler » au clavier (lot 10b) — message du bot, formulaire de
   déclaration, boutons Oui/Non de confirmation.
   ===================================================================== */

/* Dernière réponse renvoyée par pwa-api (ou message d'accueil par défaut). */
.parler-reponse {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); padding: 18px 20px; margin-bottom: 16px;
  font-size: 15px; color: var(--text); text-align: left; line-height: 1.45;
}

/* Boutons Oui/Non (monde clair, 23/08/2026) : le couple flamme/contour de la
   démo jouable de la vitrine (index.html racine, section du compteur). Oui
   = bouton flamme avec coche SVG (c'est le "Oui" de tout Stovo) ; Non =
   bouton à contour, texte seul (refuser n'est pas une erreur, plus de rouge). */
.parler-confirmation { display: flex; gap: 12px; margin-bottom: 16px; }
.btn-confirmation {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: inherit; font-size: 19px; font-weight: 700; white-space: nowrap;
  min-height: 46px; padding: 0 16px; border-radius: 14px; cursor: pointer;
  transition: background .15s, border-color .15s, transform .1s;
}
.btn-confirmation svg { flex: 0 0 auto; }
.btn-confirmation:active { transform: translateY(1px); }
.btn-confirmation:disabled { opacity: .6; cursor: wait; }
.btn-oui { background: var(--action); border: none; color: #fff; box-shadow: 0 1px 4px rgba(250,93,0,.25); }
.btn-oui:hover { background: var(--action-sombre); }
.btn-non { background: var(--card); border: 1.5px solid var(--border); color: var(--text); font-size: 17px; }
.btn-non:hover { background: var(--fond-chaud); }

/* Choix numéroté (lot A10-6, 23/08/2026 ; poli au lot A10-6b, 23/08/2026,
   après critique Impeccable) : « Tu veux dire 1) A ou 2) B ? » Un bouton par
   candidat (pastille numéro + nom), un dernier bouton « Aucun de ceux-là »,
   empilés (colonne), toute la largeur, 4 candidats maximum. Style à contour
   comme .btn-non : un choix n'écrit rien en base (§6 du plan A10, c'est
   toujours le "oui" qui écrit), ce n'est pas l'action pleine en flamme.
   Aucun jeton neuf, uniquement ceux déjà posés ailleurs dans ce fichier. */
.parler-choix { display: flex; flex-direction: column; gap: 12px; margin-bottom: 16px; }
.btn-choix {
  /* align-items:flex-start (pas center) : un nom de produit long peut passer
     sur deux lignes (ex. « Coca zéro sucre 33 cl bouteille verre » à 320 px),
     et la pastille doit rester collée à la PREMIÈRE ligne, jamais flotter au
     milieu du bloc (constaté à la capture 320 px du lot A10-6). */
  display: flex; align-items: flex-start; gap: 10px; width: 100%;
  min-height: 44px; padding: 7.5px 16px 7.5px 12px; border-radius: 14px;
  font-family: inherit; font-size: 15px; font-weight: 600; text-align: left;
  color: var(--text); background: var(--card); border: 1.5px solid var(--border);
  cursor: pointer; transition: background .15s, border-color .15s, transform .1s;
}
/* Pastille numéro (lot A10-6b) : disque encre, chiffre blanc (16,4:1 sur
   --text, comme --encre sur blanc, balayage à zéro échec), remplace l'ancien
   « 1) » en tête de texte. Hauteur totale du bouton : 7,5 (padding) + 28
   (pastille) + 7,5 (padding) + 3 (les deux filets de 1,5px) = 46px, la même
   hauteur que #btn-oui/#btn-non (corrigé après relecture du Jarvis : les
   9px d'origine donnaient 48px, l'arithmétique de la consigne n'incluait
   pas les 3px de filet). */
.btn-choix__num {
  flex: 0 0 auto; width: 28px; height: 28px; border-radius: 999px;
  background: var(--text); color: #fff; font-size: 15px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  display: inline-flex; align-items: center; justify-content: center;
}
/* padding-top:4px fait tomber le centre de la PREMIÈRE ligne du nom (20px
   d'interligne) sur le centre de la pastille de 28px : le padding-top du
   bouton s'ajoute de façon identique aux deux (pastille et nom), il
   s'annule dans l'écart entre leurs centres, donc ce padding-top:4px reste
   correct même après le changement de padding du bouton (9px -> 7,5px).
   Mesuré à la capture, écart 0px (voir le compte rendu du lot A10-6b). */
.btn-choix__nom { font-size: 15px; font-weight: 600; line-height: 20px; padding-top: 4px; }
.btn-choix:hover { background: var(--fond-chaud); }
.btn-choix:active { transform: translateY(1px); }
.btn-choix:disabled { opacity: .6; }
/* État pressé pendant l'appel (lot A10-6b, §1.2) : « en train d'être dite »,
   même dessin que la démo jouable de la vitrine (DESIGN.md, « La carte du
   compteur »). Posé/retiré par gererClicChoix (parler.js), jamais figé dans
   le HTML de base. */
.btn-choix.est-choisi { background: var(--fond-chaud); border-color: var(--text); }

/* « Aucun de ceux-là » (lot A10-6b, §1.4) : refuser n'est pas une erreur, pas
   de rouge, texte seul sans contour, dernier bouton de la zone, se cache
   avec elle. Se désactive comme les candidats quand un AUTRE bouton de la
   zone est en cours d'appel (même mécanique dans gererClicChoix). Rendu
   seulement si l'appelant fournit un vrai rappel `surAucun` (parler.js). */
.btn-choix-aucun {
  width: 100%; min-height: 44px; background: transparent; border: none;
  color: var(--muted); font-family: inherit; font-size: 14px; font-weight: 600;
  text-align: center; cursor: pointer; border-radius: 14px;
}
.btn-choix-aucun:hover { background: var(--fond-chaud); }
.btn-choix-aucun:disabled { opacity: .6; }

/* Champ texte (lot saisie multiligne, 23/08/2026) : un <textarea> qui montre
   toute la phrase, au lieu d'un <input> qui la fait defiler hors du cadre.
   Bouton Envoyer cale en bas (align-items: flex-end) pour rester sur la
   ligne de base de la derniere ligne du texte. */
.parler-form { display: flex; align-items: flex-end; gap: 10px; }
.parler-form textarea {
  display: block; flex: 1; min-width: 0; font-family: inherit; font-size: 15px;
  line-height: 1.4; padding: 11px 13px; resize: none; overflow-y: auto;
  /* 2 lignes au repos, 5 lignes maximum : au-dela, defilement interne.
     ajusterHauteurChamp() (parler.js) fait foi partout (Safari iOS ne gere
     pas encore field-sizing), field-sizing est une amelioration progressive
     pour les navigateurs qui le supportent deja (Chrome). */
  min-height: calc(2 * 1.4em + 22px + 2px);
  max-height: calc(5 * 1.4em + 22px + 2px);
  field-sizing: content;
  border: 1px solid var(--border); border-radius: 10px; background: var(--card); color: var(--text);
  transition: border-color .15s;
}
.parler-form textarea:focus { border-color: var(--text); }
.parler-form textarea:disabled { opacity: .7; }
/* Bouton à contour (action secondaire, audit --brand §2bis) : Envoyer n'est
   plus la seule action de l'écran depuis le micro et les modes réception/
   sortie/inventaire, il redevient un bouton comme les autres. */
.btn-envoyer {
  font-family: inherit; font-size: 15px; font-weight: 700; white-space: nowrap;
  min-height: 44px; padding: 0 18px; border: 1.5px solid var(--border); border-radius: 14px;
  background: var(--card); color: var(--text); cursor: pointer;
  transition: background .15s, transform .1s;
}
.btn-envoyer:hover { background: var(--fond-chaud); }
.btn-envoyer:active { transform: translateY(1px); }
.btn-envoyer:disabled { opacity: .7; cursor: wait; }

/* =====================================================================
   Import catalogue .xlsx (lot 12a) — bouton secondaire sous le formulaire
   de déclaration, sobre (l'action principale reste "Envoyer").
   ===================================================================== */
.btn-import {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; margin-top: 12px; min-height: 44px;
  font-family: inherit; font-size: 14px; font-weight: 600;
  padding: 11px 16px; border: 1px dashed var(--border); border-radius: 14px;
  background: var(--card); color: var(--muted); cursor: pointer;
  transition: background .15s, border-color .15s, transform .1s;
}
.btn-import svg { flex: 0 0 auto; }
.btn-import:hover { background: var(--fond-chaud); border-color: var(--border); color: var(--text); }
.btn-import:active { transform: translateY(1px); }
.btn-import:disabled { opacity: .7; cursor: wait; }

/* =====================================================================
   Photo du bon de livraison (lot P-3) — dans le panneau de réception.
   Même sobriété que le bouton d'import : l'action principale de l'écran
   reste "Ajouter" (dicter une ligne), la photo est une autre façon de
   remplir la même liste, pas un geste concurrent.
   ===================================================================== */
.btn-photo-bl {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; margin-top: 12px; min-height: 44px;
  font-family: inherit; font-size: 14px; font-weight: 600;
  padding: 11px 16px; border: 1px dashed var(--border); border-radius: 14px;
  background: var(--card); color: var(--muted); cursor: pointer;
  transition: background .15s, border-color .15s, transform .1s;
}
.btn-photo-bl svg { flex: 0 0 auto; }
.btn-photo-bl:hover { background: var(--fond-chaud); border-color: var(--border); color: var(--text); }
.btn-photo-bl:active { transform: translateY(1px); }
.btn-photo-bl:disabled { opacity: .7; cursor: wait; }

/* Journal de lecture de la photo : le libellé du papier en face du produit
   retenu. Volontairement discret mais lisible : c'est un outil de contrôle,
   pas une décoration. Monde clair (23/08/2026) : la bande teal à gauche
   disparaît, fond --bg (plus de #fafafa). */
.reception-lecture {
  margin-top: 12px; padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px; background: var(--bg);
}
.lecture-titre {
  margin: 0 0 8px; font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .03em; color: var(--muted);
}
.lecture-item {
  margin: 0 0 4px; font-size: 13px; line-height: 1.45;
  display: flex; flex-wrap: wrap; align-items: baseline;
}
.lecture-item:last-child { margin-bottom: 0; }
.lecture-source { color: var(--muted); word-break: break-word; }
.lecture-fleche { color: var(--muted); }
/* La cible est une VALEUR (le nom + la quantité retenus), pas un état :
   passe en encre (audit --brand §2bis), comme .ri-qte/.reception-total
   ci-dessous. */
.lecture-cible { font-weight: 700; color: var(--text); }

/* Zone « À préciser » (lot D48-L6, 17/09/2026 ; finition 17/09/2026 après
   critique du Jarvis validée par Corentin) : une ligne du bon dont le
   libellé correspond à plusieurs produits du catalogue, avec un bouton par
   candidat (classe .btn-choix réutilisée, ajustée ICI SEULEMENT pour
   l'absence de pastille numérotée). Même filet et même fond que
   .reception-lecture ci-dessus, aucune couleur neuve : tout sélecteur ajouté
   par la finition est scopé sous `.reception-ambigus`, aucune règle globale
   (dont `.btn-choix` de base) n'est touchée. */
.reception-ambigus {
  display: flex; flex-direction: column; gap: 14px;
  margin-top: 12px; padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px; background: var(--bg);
}
/* Titre : même gabarit que les lignes de la liste (.ri-nom/.ri-qte plus bas),
   pas la graisse d'un paragraphe de la bulle de réponse. `margin: 0` : sans
   ça, la marge par défaut du navigateur (1em) s'ajoutait au `gap` du flex
   parent, d'où les grands vides visibles à 320 px. */
.reception-ambigus .ambigus-titre {
  margin: 0; font-size: 14.5px; font-weight: 600; line-height: 1.4; color: var(--text);
}
.reception-ambigus .ambigu-ligne { display: flex; flex-direction: column; gap: 8px; }
/* Phrase source : ce que dit le papier, même traitement que .lecture-source
   du journal de lecture ci-dessus (13px, --muted). `margin: 0`, même raison
   que le titre. */
.reception-ambigus .ambigu-source {
  margin: 0; font-size: 13px; color: var(--muted); word-break: break-word;
}
/* Boutons de CETTE zone seulement : pas de pastille numérotée, donc pas de
   raison de caler le nom sur sa hauteur (align-items:flex-start + padding
   asymétrique de .btn-choix de base) ni de garder le padding-top du nom. */
.reception-ambigus .btn-choix { align-items: center; padding-left: 16px; }
.reception-ambigus .btn-choix__nom { padding-top: 0; }
/* La quantité à droite, comme .ri-qte de la liste : le bouton se lit alors
   comme la ligne qui va la rejoindre. */
.reception-ambigus .ambigu-qte { margin-left: auto; font-weight: 700; white-space: nowrap; }

/* =====================================================================
   Mode réception multi-produits (N1, lots FR-4 + FR-5) — écran de
   contrôle : bouton d'entrée, liste vivante, actions de clôture,
   bannière de reprise. Reprend les tokens existants (--brand, --border…).
   ===================================================================== */

/* Bouton d'entrée en réception : à contour (audit --brand §2bis, monde
   clair 23/08/2026), icône SVG (carton/cercle-moins/liste cochée selon le
   mode, index.html) devant le libellé. Survol --fond-chaud, plus de
   #ccfbf1. */
.btn-reception-demarrer {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; margin-top: 12px; min-height: 44px;
  font-family: inherit; font-size: 14.5px; font-weight: 700;
  padding: 12px 16px; border: 1.5px solid var(--border); border-radius: 14px;
  background: var(--card); color: var(--text); cursor: pointer;
  transition: background .15s, border-color .15s, transform .1s;
}
.btn-reception-demarrer svg { flex: 0 0 auto; }
.btn-reception-demarrer:hover { background: var(--fond-chaud); }
.btn-reception-demarrer:active { transform: translateY(1px); }

/* Panneau de la réception en cours (la liste vivante). */
.reception-panneau {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); padding: 14px 16px; margin-bottom: 16px; text-align: left;
}
.reception-entete { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.reception-titre { font-size: 16px; font-weight: 700; color: var(--text); }
/* Un compteur de lignes est une VALEUR, pas un état (audit --brand §2bis). */
.reception-total { font-size: 13px; font-weight: 700; color: var(--text); white-space: nowrap; }

.reception-liste { display: flex; flex-direction: column; gap: 6px; }
.reception-vide { color: var(--muted); font-size: 13.5px; padding: 8px 2px; }

/* Une ligne : nom à gauche, quantité, croix de suppression à droite. */
.reception-item {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 11px; border: 1px solid var(--border); border-radius: 10px; background: var(--card);
}
.ri-nom { flex: 1; min-width: 0; font-size: 14.5px; font-weight: 600; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ri-qte { font-size: 14.5px; font-weight: 700; color: var(--text); white-space: nowrap; }
.ri-retirer {
  position: relative;
  flex: none; width: 28px; height: 28px; border-radius: 8px; cursor: pointer;
  border: 1px solid var(--danger-border); background: var(--danger-bg); color: var(--danger-text);
  font-size: 14px; line-height: 1; display: grid; place-items: center;
  transition: background .12s, transform .1s;
}
.ri-retirer:hover { background: #fee2e2; }
.ri-retirer:active { transform: translateY(1px); }
/* Zone tactile agrandie à 44x44 px (A-5, audit accessibilité 31/07) : ce
   bouton supprime une ligne de réception/sortie en cours, usage réel debout
   une main. Le pseudo-élément agrandit la cible sans changer la taille
   visible du bouton (28x28 px). */
.ri-retirer::after {
  content: ""; position: absolute;
  top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 44px; height: 44px;
}

/* Flash bref quand une ligne vient d'être fusionnée (dictée à nouveau). */
.reception-item.fusionnee { animation: flash-fusion 1s ease-out 1; }
@keyframes flash-fusion {
  0% { background: var(--ok-bg); border-color: var(--brand-light); }
  100% { background: var(--card); border-color: var(--border); }
}

/* Lot S-5 (chantier mode sortie) : ligne dont la sortie dictée dépasse le
   stock connu (stockApres < 0). Avertissement NON BLOQUANT (§Q1 du plan) :
   la ligne reste valide et validable, elle est juste signalée. Mêmes
   variables que .reception-inconnus juste en dessous, aucune couleur neuve. */
.reception-item.alerte { border-color: var(--warn-border); background: var(--warn-bg); }

/* Produits dictés hors catalogue : signalés en orange, exclus du lot. */
.reception-inconnus {
  margin-top: 10px; padding: 9px 11px; border-radius: 10px;
  background: var(--warn-bg); border: 1px solid var(--warn-border); color: var(--warn-text);
  font-size: 13px; line-height: 1.4;
}

/* Actions de clôture : Valider (bouton flamme, c'est le "Oui" du mode) +
   Abandonner (contour, survol rouge gardé : abandonner une saisie est
   destructif, audit --brand §2bis). */
.reception-actions { display: flex; gap: 12px; margin-top: 14px; }
.btn-reception-primaire {
  flex: 1; display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: 19px; font-weight: 700; white-space: nowrap;
  min-height: 46px; padding: 0 16px; border: none; border-radius: 14px;
  background: var(--action); color: #fff; cursor: pointer;
  box-shadow: 0 1px 4px rgba(250,93,0,.25);
  transition: background .15s, transform .1s, opacity .15s;
}
.btn-reception-primaire:hover { background: var(--action-sombre); }
.btn-reception-primaire:active { transform: translateY(1px); }
.btn-reception-primaire:disabled { opacity: .5; cursor: not-allowed; }
.btn-reception-secondaire {
  font-family: inherit; font-size: 14px; font-weight: 600; min-height: 44px;
  padding: 12px 16px; border: 1.5px solid var(--border); border-radius: 14px;
  background: var(--card); color: var(--muted); cursor: pointer;
  transition: background .15s, color .15s, border-color .15s, transform .1s;
}
.btn-reception-secondaire:hover { background: var(--danger-bg); border-color: var(--danger-border); color: var(--danger-text); }
.btn-reception-secondaire:active { transform: translateY(1px); }
.btn-reception-secondaire:disabled { opacity: .6; cursor: wait; }

/* Bannière de reprise (une réception oubliée remonte au chargement). */
.reception-reprise {
  background: var(--warn-bg); border: 1px solid var(--warn-border); border-radius: var(--radius);
  padding: 14px 16px; margin-bottom: 16px; text-align: left;
}
.reception-reprise-texte { font-size: 14px; font-weight: 600; color: var(--warn-text); margin-bottom: 10px; }
.reception-reprise-actions { display: flex; gap: 12px; }
.reception-reprise-actions .btn-reception-primaire { flex: 1; }

/* Barre de navigation, fixee en bas (style app mobile).
   Passee a 4 onglets le 25/07 (ajout de « Aide ») : les colonnes sont
   resserrees (max-width, padding, taille du libelle) et les libelles ne se
   coupent plus sur deux lignes, pour tenir sur la largeur d'un telephone. */
.nav-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
  display: flex; justify-content: space-around;
  background: var(--card); border-top: 1px solid var(--border);
  padding: 6px 4px calc(6px + env(safe-area-inset-bottom));
  box-shadow: 0 -2px 10px rgba(29,30,28,.05);
}
.nav-item {
  flex: 1; max-width: 130px; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  background: none; border: none; padding: 8px 2px; border-radius: 12px;
  font-family: inherit; color: var(--muted); cursor: pointer;
  transition: color .15s;
}
.nav-item .nav-icone { display: flex; align-items: center; justify-content: center; }
.nav-item .nav-label {
  font-size: 11px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
/* Reprise du 23/08 : la couleur d'action reste sur l'icone (decorative, hors
   seuil de contraste) ; le libelle actif passe en encre pour rester lisible
   (la flamme sur blanc a 11px gras ne fait que ~3,17:1, sous le seuil AA).
   Lot A15 (R-2, 25/08) : --flamme -> --action, c'est "l'onglet qu'on peut
   toucher" au sens du brief, donc suit le choix de couleur. */
.nav-item.actif .nav-icone { color: var(--action); }
.nav-item.actif .nav-label { color: var(--text); font-weight: 700; }
.nav-item:active { transform: translateY(1px); }

/* Bannière « nouvelle version prête » (lot A6, 25/08/2026). Choix n°5 de
   l'Architecte : jamais automatique, jamais en pleine session sans ce
   bandeau. Fixée juste AU-DESSUS de la nav (même 78px que body
   padding-bottom ci-dessus, ligne 254 : la nav mesure cette hauteur), pour
   ne jamais recouvrir une saisie en cours (le champ de "Parler" est plus
   haut dans le flux, jamais coincé contre la nav). Bouton réutilise
   .btn-reception-primaire (flamme + blanc déjà audité, §2bis) : .maj-bouton
   ne fait qu'ajuster sa taille dans ce contexte plus étroit. */
.maj-bandeau {
  position: fixed; left: 0; right: 0; z-index: 55;
  bottom: calc(78px + env(safe-area-inset-bottom));
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  background: var(--card); border-top: 1px solid var(--border);
  padding: 12px 16px;
  box-shadow: 0 -2px 10px rgba(29,30,28,.08);
}
.maj-texte { font-size: 14px; font-weight: 600; color: var(--text); margin: 0; }
/* Cible tactile : le gabarit de .btn-reception-primaire (46px, deja >= 44px,
   regle des lots A1/A2) n'est PAS retaille ici, seule sa largeur est
   contrainte pour cohabiter avec le texte dans la banniere. */
.maj-bandeau .maj-bouton { flex: 0 0 auto; }

/* =====================================================================
   Connexion (lot 9b) — écran de login.
   Le bouton d'engrenage de l'en-tête (.btn-reglages, ouvre l'écran Réglages
   depuis le lot A4, 24/08/2026 — la déconnexion a quitté l'en-tête pour ce
   nouvel écran) est stylé avec .btn-refresh plus haut (section En-tête,
   monde clair) : une seule règle pour les deux boutons à contour de
   l'en-tête, pas de redéfinition ici.
   ===================================================================== */

/* Correctif d'affichage (11/07) : l'attribut `hidden` doit TOUJOURS
   l'emporter. Sans ce !important, la regle .ecran-login { display:flex }
   ci-dessous annulait le hidden -> l'ecran de connexion restait visible
   apres login et le dashboard s'empilait en dessous (il fallait defiler). */
[hidden] { display: none !important; }

/* Écran de connexion (monde clair, 23/08/2026) : centré, sobre, plein écran
   sur --bg (le dégradé teal disparaît). Référence : maquettes/compte-et-
   reglages/apercu-Connexion.png (DESIGN.md, "L'app"). */
.ecran-login {
  min-height: 100vh; min-height: 100dvh;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 24px; background: var(--bg);
}
/* Le mot Stovo, logotype flamme, posé AU-DESSUS de la carte (pas de
   pictogramme) : même gabarit que .brand h1 de l'en-tête et .logo de la
   vitrine (DM Sans 700, 22px, -.02em). Lot A15 (R-2, 25/08/2026) : reste en
   --flamme comme .brand h1 ci-dessus, c'est l'identité, pas --action. */
.login-logo {
  font-size: 22px; font-weight: 700; letter-spacing: -.02em; line-height: 44px;
  color: var(--flamme); margin-bottom: 4px;
}
.login-carte {
  width: 100%; max-width: 380px;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-sm);
  padding: 32px 28px;
}
/* Titre et sous-titre alignés à gauche comme la carte (maquettes/compte-et-
   reglages/apercu-Connexion.png), à l'inverse de l'ancien centrage teal. */
.login-carte h1 { font-size: 26px; font-weight: 700; letter-spacing: -.02em; color: var(--text); }
.login-soustitre { font-size: 15px; color: var(--muted); margin: 6px 0 26px; }

/* Lot A4 (24/08/2026) : le sélecteur était ID-spécifique à #form-login (lot
   9b), donc IGNORAIT les 3 nouveaux formulaires du mot de passe perdu
   (#form-code-demande, #form-code-saisie) et de son changement connecté
   (#form-changer-mdp) — repéré à la relecture des premières captures
   (champs rendus avec le style par défaut du navigateur). `.login-carte`
   est le conteneur COMMUN à toutes ces cartes (voir index.html), qu'elles
   vivent dans un `.ecran-login` (avant connexion) ou dans un `.ecran`
   classique (#ecran-changer-mdp, connecté) : un seul sélecteur suffit. */
.login-carte form { display: flex; flex-direction: column; gap: 6px; }
.login-carte form label { font-size: 13.5px; font-weight: 600; color: var(--muted); margin-top: 10px; }
.login-carte form input {
  font-family: inherit; font-size: 15px; padding: 11px 13px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--card); color: var(--text);
  transition: border-color .15s;
}
.login-carte form input:focus { border-color: var(--text); }
/* Champ du code reçu (planche Code2Saisie) : grand, centré, chiffres
   alignés (tabular-nums), pour qu'un code à 6 chiffres se lise d'un coup
   d'œil — reprend l'esprit de la maquette sans copier ses valeurs exactes. */
#recup-code {
  font-size: 26px; font-weight: 700; letter-spacing: .14em; text-align: center;
  font-variant-numeric: tabular-nums;
}

/* Bouton flamme, pleine largeur : c'est le "Oui" de cet écran (audit --brand,
   §2bis, comme .matin-copier et .btn-reception-primaire). */
.btn-login {
  margin-top: 20px; width: 100%;
  font-family: inherit; font-size: 19px; font-weight: 700;
  min-height: 46px; padding: 0 16px; border: none; border-radius: 14px;
  background: var(--action); color: #fff; cursor: pointer;
  box-shadow: 0 1px 4px rgba(250,93,0,.25);
  transition: background .15s, transform .1s;
}
.btn-login:hover { background: var(--action-sombre); }
.btn-login:active { transform: translateY(1px); }
.btn-login:disabled { opacity: .7; cursor: wait; }

.login-erreur {
  margin-top: 14px; padding: 10px 14px; border-radius: 10px;
  font-size: 13.5px; font-weight: 600;
  color: var(--danger-text); background: var(--danger-bg); border: 1px solid var(--danger-border);
}

@media (max-width: 420px) {
  .login-carte { padding: 26px 20px; }
}

/* =====================================================================
   Écran du matin (brique 1) — bandeau de brief en tête du tableau de
   bord, construit à partir de chiffres DEJA calcules par dashboard.js
   (lecture seule). Il chevauche le bas de l'en-tete comme le faisaient
   les KPI ; ceux-ci passent donc SOUS lui (.matin + .kpis) et ne
   remontent plus dans l'en-tete. Additif : aucune regle ci-dessus n'est
   modifiee.
   ===================================================================== */
/* Reprise du 23/08/2026 : grille nommee pour placer "Copier la liste" en
   haut a droite (bureau) / pleine largeur SOUS la liste (telephone), sans
   changer l'ordre du DOM (accessibilite, voir index.html). */
.matin {
  position: relative; z-index: 2;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-chaude); padding: 18px 20px 8px; margin-top: 10px;
}
/* Plus de bande de couleur a gauche (monde clair, 23/08/2026) : l'etat se lit
   dans la couleur de .matin-resume et son symbole (● ▲ ■), pas la bordure. */

/* Wrapper qui porte la grille (voir le commentaire de index.html) : #matin
   lui-meme reste un simple conteneur visuel, dashboard.js pose un
   style.display inline dessus pour le montrer/le masquer sans jamais
   toucher a sa mise en page interne. */
.matin-corps {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "head bouton" "resume resume" "liste liste";
  column-gap: 12px;
}

.matin-head { grid-area: head; display: flex; align-items: center; }
/* Correctif du 01/08/2026 (mesure Playwright) : "Ce matin" devient un <h2>
   (voir index.html) pour rendre a la section son titre de niveau. Le <h2>
   ne fait qu'envelopper le bouton, il ne doit imposer ni marge ni taille de
   police a lui : c'est toujours .matin-titre (le <span> a l'interieur) qui
   pilote l'apparence. */
.matin-titre-h2 { margin: 0; font-size: inherit; font-weight: inherit; line-height: inherit; }
.matin-titre { font-size: 18px; font-weight: 700; white-space: nowrap; }
/* Bouton flamme : la seule action de l'ecran Pilotage (audit --brand, §2bis).
   19px/46px, meme regime que les boutons flamme de la vitrine (DESIGN.md :
   "texte large au sens WCAG, 3,2:1 suffit") : a 14px (premiere version du
   23/08), le blanc sur --flamme ne faisait que 3,17:1, sous le seuil AA. */
.matin-copier {
  grid-area: bouton; align-self: start;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: 19px; font-weight: 700; white-space: nowrap;
  padding: 0 18px; border-radius: 14px; border: none;
  background: var(--action); color: #fff; cursor: pointer;
  box-shadow: 0 1px 4px rgba(250,93,0,.25);
  transition: background .15s, transform .1s;
  min-height: 46px;
}
.matin-copier:hover { background: var(--action-sombre); }
.matin-copier:active { transform: translateY(1px); }

.matin-resume { grid-area: resume; font-size: 14.5px; font-weight: 600; margin-top: 5px; }
.matin.matin-ok .matin-resume { color: var(--brand-dark); }
.matin.matin-warn .matin-resume { color: var(--warn-text); }
.matin.matin-crit .matin-resume { color: var(--danger-text); }
/* LOT D30-L3bis (27/09/2026, plan §2.1) : meme etat neutre que .verdict.v-neutre
   ci-dessus, meme raison (--muted, deja la couleur de la famille "jamais
   compte"). */
.matin.matin-neutre .matin-resume { color: var(--muted); }

/* Correctif du 01/08/2026 : #matin-liste devient une vraie <ul> (voir
   index.html) pour qu'un lecteur d'ecran annonce "liste de N elements" au
   lieu d'un simple bloc. list-style retire les puces (les <li> heritent de
   "none") ; margin/padding remis a zero explicitement en plus du reset
   global "* { margin:0; padding:0; }" deja present en tete de fichier, par
   robustesse si ce reset venait a changer. Le reste (grid-template-columns,
   grid-column, le bloc @media plus bas) n'est PAS touche : .matin-item
   garde exactement le meme rendu, seule sa balise change (div -> li). */
.matin-liste { grid-area: liste; list-style: none; margin: 13px 0 0; padding: 0; }
/* Monde clair (23/08/2026) : la couverture (.mi-cov) passe sur sa propre
   ligne A TOUTES LES LARGEURS (grid-column:1/-1 ci-dessous), comme sur la
   planche bureau. La grille ne garde donc que 2 colonnes (nom, quantite) ;
   l'ancienne 3e colonne "auto" ne servait qu'a l'etat replie mobile, deplace
   ici a demeure. Le correctif du 01/08/2026 (nom qui se compresse, cf.
   min-width:0 sur .mi-nom) reste inchange. */
.matin-item {
  display: grid; grid-template-columns: 1fr auto; gap: 4px 14px; align-items: baseline;
  padding: 11px 0; border-top: 1px solid var(--border);
}
.matin-item:first-child { border-top: none; }
.mi-nom { font-weight: 700; font-size: 15px; color: var(--text); min-width: 0; overflow-wrap: break-word; }
.mi-qte { font-weight: 700; font-size: 15px; color: var(--danger-text); white-space: nowrap; font-variant-numeric: tabular-nums; }
.mi-qte-label { font-weight: 600; font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
.mi-cov { font-size: 13px; color: var(--muted); white-space: normal; grid-column: 1 / -1; }
.mi-cov.urgent { color: var(--danger-text); font-weight: 700; }

/* Bandeau repliable : le chevron + le titre forment un bouton qui plie/deplie
   la liste. L'etat est memorise (localStorage) entre les sessions. */
.matin-toggle {
  display: flex; align-items: center; gap: 8px;
  background: none; border: none; padding: 0; margin: 0;
  font-family: inherit; color: inherit; cursor: pointer; text-align: left;
  /* Cible tactile 44px (mesure Playwright du 01/08/2026, le bouton mesurait
     103x22px). min-height agit directement sur le bouton, pas sur la ligne :
     align-items:center (deja present) garde le titre centre dans cette
     hauteur, sans changer sa largeur ni son texte. */
  min-height: 44px;
}
/* Une compensation en marge negative a ete essayee ici sur l'etat "rien a
   commander", puis retiree apres mesure (01/08/2026) : elle partait de l'idee
   qu'il fallait annuler la croissance de la ligne, alors que min-height:44px
   s'applique au bouton dans TOUS les etats et que cette hauteur est
   precisement ce qui rend la cible tactile conforme. Mesure a l'appui : avec
   la compensation, le titre remontait a 18px du haut du bandeau contre 29px
   dans l'etat normal, et la zone cliquable empietait de 11px dans le padding
   de la carte. Sans elle, les deux etats sont alignes au pixel pres. */
.matin-chevron { display: inline-flex; color: var(--muted); transition: transform .15s; }
.matin-chevron svg { display: block; }
.matin.replie .matin-chevron { transform: rotate(-90deg); }
.matin.replie .matin-liste { display: none; }

/* Sous 560px (reprise du 23/08/2026) : une seule colonne, le bouton "Copier
   la liste" redescend sur sa propre ligne pleine largeur, sous la liste (on
   lit, puis on copie). [hidden] reste "display:none !important" (regle
   globale plus bas) : si rien n'est a commander, la ligne "bouton" ne
   reserve aucun espace, la grille se referme normalement. */
@media (max-width: 560px) {
  .matin-corps { grid-template-columns: 1fr; grid-template-areas: "head" "resume" "liste" "bouton"; }
  .matin-copier { width: 100%; justify-content: center; margin: 4px 0 10px; }
}

/* Inventaire regroupe par etat, en sections depliables (element <details>
   natif : accessible, pas de JS pour le pli lui-meme ; l'etat ouvert est juste
   memorise cote JS pour survivre au rafraichissement). */
.inv-groupes { display: flex; flex-direction: column; gap: 12px; }
.inv-sommaire {
  cursor: pointer; list-style: none; -webkit-user-select: none; user-select: none;
  display: flex; align-items: center; gap: 9px;
  font-size: 15px; font-weight: 700; padding: 8px 2px; min-height: 44px;
}
.inv-sommaire::-webkit-details-marker { display: none; }
/* Chevron dessine en CSS (monde clair, 23/08/2026) : un carre de 8px, deux
   bordures visibles, tourne a 45deg au repos (pointe a droite, comme ▸) puis
   encore 90deg de plus une fois ouvert (pointe vers le bas, comme ▾). */
.inv-sommaire::before {
  content: ''; width: 8px; height: 8px; flex: 0 0 auto;
  border-right: 1.8px solid var(--muted); border-bottom: 1.8px solid var(--muted);
  transform: rotate(-45deg); transition: transform .15s;
}
.inv-groupe[open] > .inv-sommaire::before { transform: rotate(45deg); }
.inv-sym-commander { color: var(--danger); }
/* LOT D30-L3 (27/09/2026) : symbole du panier "Pas encore compté", neutre. */
.inv-sym-pasencorecompte { color: var(--muted); }
.inv-sym-surveiller { color: var(--warn); }
.inv-sym-stock { color: var(--brand-dark); }
.inv-groupe > .grid { margin-top: 12px; }

/* LOT D30-L3bis (27/09/2026, plan §2.3) : contenu du panier "Pas encore
   compté", liste compacte plutot que des cartes repetees (critique
   impeccable du 27/09, 22/36 -- 250 references jamais comptees feraient
   plus de 100 000px de cartes avant "En stock"). Meme modele visuel que les
   lignes de l'onglet Stock (.stock-sommaire : grille 1fr auto auto, meme
   typographie via .sl-nom/.sl-stock reutilisees plus bas), sans le pli
   <details> : il n'y a rien de plus a deplier qu'un tiret. */
.inv-groupe > .pec-entete { margin-top: 12px; font-size: 13.5px; color: var(--muted); padding: 0 2px 8px; line-height: 1.5; }
.pec-liste { border-top: 1px solid var(--border); }
.pec-ligne {
  display: grid; grid-template-columns: 1fr auto auto;
  gap: 12px; align-items: center; padding: 11px 2px;
  border-top: 1px solid var(--border);
}
.pec-ligne:first-child { border-top: none; }
.pec-nom { font-weight: 700; font-size: 14.5px; }
.pec-valeur { font-size: 13.5px; color: var(--muted); white-space: nowrap; }

/* ---------- Onglet « Stock » (QW-C, 18/07/2026) ----------
   Liste compacte (des lignes, pas des cartes) + recherche a la frappe.
   Chaque ligne est un <details> natif : sommaire = ligne compacte,
   contenu = detail replie (chiffres deja calcules par dashboard.js). */
.stock-page { padding-top: 22px; }
.stock-recherche {
  width: 100%; padding: 12px 15px; font-size: 15px;
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--card); color: var(--text);
  box-shadow: var(--shadow-sm);
  margin-bottom: 14px;
}
.stock-recherche:focus { border-color: var(--text); }
.stock-liste {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
  padding: 2px 14px;
}
.stock-ligne { border-top: 1px solid var(--border); }
.stock-ligne:first-child { border-top: none; }
.stock-sommaire {
  cursor: pointer; list-style: none; -webkit-user-select: none; user-select: none;
  display: grid; grid-template-columns: 1fr auto auto;
  gap: 12px; align-items: center; padding: 11px 2px;
}
.stock-sommaire::-webkit-details-marker { display: none; }
.sl-nom { font-weight: 700; font-size: 14.5px; }
.sl-stock { font-size: 13.5px; color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.sl-stock b { color: var(--text); }
.stock-detail { padding: 0 2px 12px; font-size: 12.5px; color: var(--muted); line-height: 1.7; }

/* ---------- Onglet « Aide » (25/07/2026) ----------
   Le mode d'emploi dans l'app. Trois sections depliables (<details> natif,
   comme l'inventaire du dashboard et les lignes de l'onglet Stock), avec des
   exemples cliquables qui recopient la phrase dans l'ecran « Parler ».
   Aucune couleur nouvelle : on reutilise les variables de la charte. */
.aide-page { padding-top: 22px; padding-bottom: 30px; }
.aide-intro { font-size: 14px; color: var(--muted); margin: -6px 0 16px; }

.aide-section {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
  margin-bottom: 12px; overflow: hidden;
}
.aide-sommaire {
  cursor: pointer; list-style: none; -webkit-user-select: none; user-select: none;
  display: flex; align-items: center; gap: 11px;
  padding: 15px 16px; font-weight: 700; font-size: 15.5px;
}
.aide-sommaire::-webkit-details-marker { display: none; }
/* Icone SVG en trait (lot "monde clair, suite", 23/08/2026) : remplace
   l'emoji. Decorative (aria-hidden dans aide.js), couleur --muted-light
   comme .aide-geste-icone ci-dessous (regle 3 de DESIGN.md : le titre en
   gras a cote porte deja le sens, l'icone n'est qu'un repere visuel). */
.aide-icone { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; color: var(--muted-light); }
.aide-icone svg { width: 22px; height: 22px; display: block; }
/* Chevron a droite, tourne quand la section est ouverte. */
.aide-titre { flex: 1; }
.aide-sommaire::after {
  content: '▾'; color: var(--muted); font-size: 13px;
  transition: transform .15s;
}
.aide-section[open] > .aide-sommaire::after { transform: rotate(180deg); }
.aide-section[open] > .aide-sommaire { border-bottom: 1px solid var(--border); }
.aide-contenu { padding: 4px 16px 16px; }

.aide-texte { font-size: 14px; color: var(--text); line-height: 1.65; margin: 12px 0; }
.aide-texte b { font-weight: 700; }

.aide-defs { margin: 12px 0; }
/* display:flex ajoutee (lot "monde clair, suite") : seules les 4 defs de
   "Comprendre Stovo" portent une icone (aide.js), les autres <dt> n'ont
   simplement rien a aligner et le flex ne change rien pour eux. */
.aide-defs dt { display: flex; align-items: center; gap: 7px; font-weight: 700; font-size: 13.5px; margin-top: 12px; }
.aide-defs dt:first-child { margin-top: 0; }
.aide-defs dd { font-size: 13.5px; color: var(--muted); line-height: 1.6; margin: 2px 0 0; }

/* Listes a puces DANS une section. Classe volontairement distincte du
   conteneur #aide-liste : sinon tout l'ecran heriterait du retrait. */
.aide-puces { margin: 12px 0; padding-left: 20px; font-size: 14px; line-height: 1.7; }

/* Un geste = un bloc encadre : ce qu'il fait, des exemples, une note. */
.aide-geste {
  border-top: 1px solid var(--border);
  padding: 16px 0 4px;
}
.aide-geste:first-of-type { border-top: none; }
.aide-geste-titre { display: flex; align-items: center; gap: 8px; font-size: 14.5px; font-weight: 700; margin-bottom: 5px; }
.aide-geste-quoi { font-size: 13.5px; color: var(--muted); line-height: 1.6; margin-bottom: 10px; }
/* Icone decorative devant le titre d'un geste ou d'une astuce (couleur
   --muted-light, regle 3 de DESIGN.md : le titre en gras a cote porte deja
   le sens). Reutilisee aussi devant les 4 defs "Comprendre Stovo" (aide.js),
   d'ou une classe generique plutot que ".aide-geste-titre .icone". */
.aide-geste-icone { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; color: var(--muted-light); }
.aide-geste-icone svg { width: 20px; height: 20px; display: block; }

.aide-exemples { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 9px; }
/* L'exemple est un BOUTON : le taper recopie la phrase dans l'ecran Parler
   (aide.js), il doit donc se voir comme cliquable. Reprise du 23/08/2026
   (audit --brand §2bis) : bouton a contour, sur le modele des trois phrases
   proposees de la demo jouable de la vitrine (.compteur__phrase) — plus de
   teal, l'italique et les guillemets restent. */
.aide-exemple {
  font-family: inherit; font-size: 13px; font-style: italic;
  color: var(--text); background: var(--card);
  border: 1.5px solid var(--border); border-radius: 14px;
  min-height: 44px; padding: 12px 16px; cursor: pointer; text-align: left;
  transition: background .15s, border-color .15s;
}
.aide-exemple::before { content: '« '; font-style: normal; }
.aide-exemple::after { content: ' »'; font-style: normal; }
.aide-exemple:hover { background: var(--fond-chaud); border-color: var(--text); }
.aide-exemple:active { transform: translateY(1px); }

.aide-note {
  font-size: 12.5px; color: var(--muted); line-height: 1.6;
  border-left: 2px solid var(--border); padding-left: 10px;
}

/* Une astuce = un encadre plein, pour trancher visuellement avec les gestes. */
.aide-astuce {
  background: var(--bg); border-radius: 12px;
  padding: 13px 14px; margin-bottom: 11px;
}
.aide-astuce-titre { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 700; margin-bottom: 2px; }
.aide-astuce .aide-texte { margin: 4px 0 0; font-size: 13.5px; }

/* ===================== Inventaire complet guidé (CM-C, 25/07/2026) =====================
   Réutilise volontairement les classes de la réception (.reception-panneau,
   .reception-actions, .btn-reception-*) : même mécanique, même langage visuel.
   Seuls les éléments propres au parcours produit-par-produit sont stylés ici. */

.inventaire-panneau {
  margin-top: 14px;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--card);
}

/* Le nom du produit à compter : c'est LE point d'attention de l'écran, donc
   l'élément le plus gros. C'est lui qui dispense de répéter le nom à la voix. */
.inventaire-nom {
  margin: 10px 0 4px;
  font-size: 1.6rem;
  font-weight: 700;
  line-height: 1.2;
}

.inventaire-stock,
.inventaire-deja,
.inventaire-total {
  margin: 2px 0;
  font-size: 0.92rem;
  opacity: 0.75;
}

.inventaire-deja:empty { display: none; }

.inventaire-aveugle {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px 0 6px;
  font-size: 0.9rem;
  opacity: 0.85;
  cursor: pointer;
}

.inventaire-recap {
  margin: 8px 0 14px;
  line-height: 1.5;
}

/* Lot P-3 (chantier PILOTAGE, 26/07/2026) : bandeau "pilotage en pause",
   affiche sous le verdict quand aucune sortie n'est declaree depuis
   GESTE_VIVANT_JOURS. Reutilise .card pour la boite (deja stylee). */
.bandeau-pilotage { margin: 10px 0 2px; }
.bandeau-pilotage .bp-titre { font-size: 16px; font-weight: 700; margin-bottom: 6px; }
.bandeau-pilotage .bp-texte { font-size: 13.5px; color: var(--muted); margin-bottom: 8px; line-height: 1.5; }
/* Bouton a contour (action secondaire, audit --brand §2bis). */
.bandeau-pilotage .bp-bouton {
  font-family: inherit; font-size: 13px; font-weight: 600; min-height: 44px;
  padding: 0 16px; border-radius: 14px; border: 1.5px solid var(--border);
  background: var(--card); color: var(--text); cursor: pointer;
  transition: background .15s, transform .1s;
}
.bandeau-pilotage .bp-bouton:hover { background: var(--fond-chaud); }
.bandeau-pilotage .bp-bouton:active { transform: translateY(1px); }

/* Lot P-5 (chantier PILOTAGE, 26/07/2026) : phrase de synthese du stock
   dormant, sous le bloc "Valeur du stock". */
.dormant-resume {
  font-size: 12.5px;
  color: var(--muted);
  margin: -2px 0 8px;
  padding: 0 2px;
}

/* ---------- Chantier C1 (26/07/2026) : demarque valorisee "Ce que tu as
   jete" ---------- Rendu par app/pertes.js (calculerDemarque + rendreDemarque),
   injecte dans #pertes-contenu, lui-meme a l'interieur du <details
   class="inv-groupe"> dedie (voir index.html) : le chevron et le style du
   sommaire sont deja herites de .inv-groupe/.inv-sommaire, rien a refaire ici.
   Marge propre a CE <details> (id, pas la classe .inv-groupe partagee) : il
   vit hors de #inv-grid/.inv-groupes (qui donne le gap de 12px entre les 3
   groupes d'inventaire), donc sans cette marge il serait colle au bloc du
   dessus (reappro, souvent masque) et au dessous. */
#pertes-groupe { margin: 18px 0 6px; }
.pertes-vide { padding: 10px 2px 4px; color: var(--muted); font-size: 14px; }

.pertes-total { font-size: 26px; font-weight: 700; color: var(--text); margin: 10px 0 8px; line-height: 1.15; }
.pertes-total .pertes-partiel { font-size: 13px; font-weight: 600; color: var(--muted); margin-left: 4px; }

.pertes-motifs { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.pertes-motif {
  display: flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600;
  background: var(--warn-bg); border: 1px solid var(--warn-border); color: var(--warn-text);
  padding: 5px 12px; border-radius: 999px;
}
.pertes-motif .pm-nom { text-transform: capitalize; }
.pertes-motif .pm-montant { font-weight: 700; }

.pertes-liste { margin-top: 2px; }
.pertes-ligne {
  display: grid; grid-template-columns: 1fr auto; gap: 8px 16px; align-items: center;
  padding: 12px 2px; border-top: 1px solid var(--border);
}
.pertes-ligne:first-child { border-top: none; }
.pertes-ligne .pp-main { min-width: 0; }
.pertes-ligne .pp-nom { font-weight: 700; font-size: 14.5px; }
.pertes-ligne .pp-detail { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.pertes-ligne .pp-right { text-align: right; white-space: nowrap; font-size: 15px; font-weight: 700; }
.pertes-ligne .pp-sansprix { font-size: 12.5px; color: var(--muted); font-weight: 500; font-style: italic; }

.pertes-note { font-size: 12.5px; color: var(--muted); margin-top: 10px; }
.pertes-methode { font-size: 11.5px; color: var(--muted); margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }

/* ---------- Chantier C2 « les exports » (lot C2-3, 22/08/2026) ----------
   Même famille que #pertes-groupe juste au-dessus : un <details
   class="inv-groupe"> qui vit hors de #inv-grid/.inv-groupes, donc la même
   marge propre est nécessaire (sinon collé au tableau des mouvements et au
   pied de page). Le chevron et le style du sommaire sont déjà hérités de
   .inv-groupe/.inv-sommaire, rien à refaire ici. */
#export-groupe { margin: 18px 0 6px; }
.export-contenu { padding-top: 4px; }
.export-intro { font-size: 13.5px; color: var(--muted); margin: 4px 0 12px; }
.export-actions { display: flex; flex-direction: column; gap: 10px; }

/* Bouton a contour (action secondaire, audit --brand §2bis, 23/08/2026) : un
   export est un geste rare, pas l'action principale de l'écran. Hauteur mini
   44 px (cible tactile, règle A1-A4). */
.btn-export {
  font-family: inherit; font-size: 14.5px; font-weight: 600;
  min-height: 44px; padding: 12px 16px; border: 1.5px solid var(--border); border-radius: 14px;
  background: var(--card); color: var(--text); cursor: pointer;
  transition: background .15s, border-color .15s, transform .1s;
}
.btn-export:hover { background: var(--fond-chaud); }
.btn-export:active { transform: translateY(1px); }
.btn-export:disabled { opacity: .6; cursor: wait; }

/* Message d'état sous les boutons (aria-live="polite" dans index.html) :
   "Préparation du fichier…", puis le compte de lignes, ou une erreur. */
.export-etat { font-size: 13px; color: var(--muted); margin: 10px 0 0; }
.export-etat.est-erreur { color: var(--danger); font-weight: 600; }

/* Mention légale répétée à l'écran (règle C1 : la méthode s'affiche avec le
   chiffre), même style que .pertes-methode juste au-dessus. */
.export-mention { font-size: 11.5px; color: var(--muted); margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }

/* =====================================================================
   Accessibilité (lot A1, audit Impeccable du 31/07/2026).
   ===================================================================== */

/* A-9 : l'avertissement "prix d'achat, pas une valorisation comptable"
   sortait du `title` (invisible sur mobile) vers un paragraphe statique,
   sous le bandeau "Valeur du stock". Discret : ce n'est pas l'info
   principale de l'écran, juste le garde-fou qui évite un contresens. */
.sv-avertissement {
  font-size: 12.5px; color: var(--muted);
  margin: -4px 0 8px; padding: 0 2px;
}

/* A-7 : aucune règle prefers-reduced-motion n'existait alors que la
   pulsation du micro en écoute (pulse-micro) tourne en boucle infinie.
   Le micro reste reconnaissable sans le mouvement (fond --danger-bg et
   bordure --danger-border déjà posés par .btn-micro.ecoute ci-dessus) :
   seule l'animation disparaît, jamais le changement de couleur.
   Correctif A-7 bis (31/07/2026) : la première version neutralisait TOUTES
   les transitions du site (`* { transition-duration: 0.01ms !important; }`),
   un motif explicitement dénoncé par le référentiel Impeccable car il
   détruit aussi le retour d'information utile (un bouton qui change de
   couleur au clic, par exemple). Un utilisateur qui demande moins de
   mouvement veut supprimer le DÉPLACEMENT et les boucles, pas les fondus.
   La règle ci-dessous cible donc uniquement : les deux animations en
   boucle, et le tassement `translateY(1px)` au clic des boutons (état
   `:active`) + le survol `.card:hover` (`translateY(-1px)`). Les
   transitions de `background`, `border-color`, `color`, `opacity` et
   `box-shadow` restent actives partout, aucune n'est touchée ici. */
@media (prefers-reduced-motion: reduce) {
  .btn-micro.ecoute { animation: none; }
  .reception-item.fusionnee { animation: none; }
  .btn-refresh:active,
  .btn-envoyer:active,
  .btn-login:active,
  .btn-import:active,
  .btn-photo-bl:active,
  .btn-confirmation:active,
  .btn-choix:active,
  .btn-reception-primaire:active,
  .btn-reception-secondaire:active,
  .btn-reception-demarrer:active,
  .ri-retirer:active,
  .matin-copier:active,
  .aide-exemple:active,
  .nav-item:active,
  .btn-micro:not(:disabled):active,
  .btn-reglages:active,
  .reglages-btn-mailto:active,
  .reglages-pastille:active {
    transform: none;
  }
}

/* =====================================================================
   Accessibilité (lot A2, seconde passe du 31/07/2026).
   ===================================================================== */

/* A2-7 : le fichier ne posait aucun style de focus clavier, et trois champs
   supprimaient activement l'anneau du navigateur (`outline: none`, retire
   ci-dessus sur .parler-form textarea, #form-login input, .stock-recherche).
   Cette regle unique le remplace pour TOUT element focusable au clavier,
   sans reintroduire d'anneau au clic souris (`:focus-visible` ne se
   declenche pas dans ce cas dans les navigateurs modernes). */
:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 2px;
}

/* A2-8 : titre <h1> reserve aux technologies d'assistance sur l'ecran
   « Parler », qui n'a aucun titre visible (son message d'accueil dans
   .parler-reponse en tient lieu a l'ecran). Retire visuellement mais reste
   lisible au clavier/lecteur d'ecran. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* =====================================================================
   Lot A4 (24/08/2026) : mot de passe perdu (écrans avant connexion) et
   écran Réglages (compte, contact, version). Aucun jeton neuf : uniquement
   ceux déjà posés ailleurs dans ce fichier. Le teal n'apparaît qu'une fois
   (.pastille-validee, l'écran "Fait") : règle 10 de DESIGN.md, il reste
   réservé aux états, jamais à un bouton ou un lien.
   ===================================================================== */

/* Lien centré sous un formulaire de .ecran-login ("Mot de passe oublié ?",
   "Renvoyer un code") : même couleur d'action que le reste de l'app, cible
   tactile 44px. */
.login-lien-centre { display: flex; justify-content: center; margin-top: 14px; }
.login-lien-centre a {
  display: inline-flex; align-items: center; min-height: 44px;
  font-size: 15px; font-weight: 600; color: var(--text);
  text-decoration: underline; text-underline-offset: 3px;
}
.login-lien-centre a:hover { color: var(--muted); }
/* Grisé pendant le compte à rebours des 60 s de "Renvoyer un code"
   (recuperation.js, Supabase refuse un 2e envoi avant une minute) : plus de
   couleur d'action tant que le clic ne fait rien, curseur par défaut. */
.login-lien-centre a.lien-recup-inactif {
  color: var(--muted); text-decoration: none; cursor: default;
}

/* Lien de retour ("← Connexion", "← Réglages"...), au-dessus d'une carte de
   .ecran-login ou de .reglages-page. Cible tactile 44px comme les autres
   liens/boutons de navigation de l'app. */
.login-retour { padding: 12px 12px 0; }
.lien-retour {
  display: inline-flex; align-items: center; gap: 4px; min-height: 44px;
  padding: 0 8px; color: var(--text); text-decoration: none;
  font-size: 15px; font-weight: 600;
}
.lien-retour svg { flex: 0 0 auto; }
.lien-retour:hover { color: var(--muted); }

/* Note sous le formulaire de "Recevoir un code" (planche Code1Demande). */
.login-note { font-size: 14px; color: var(--muted); margin-top: 16px; line-height: 1.5; text-align: center; }

/* Champ en état d'erreur (planche Code2Erreur, écran "Nouveau mot de passe") :
   bordure en encre plutôt qu'un rouge d'alerte classique, le bloc d'alerte
   juste en dessous (.login-erreur, déjà stylé) porte la couleur du message. */
#form-code-saisie input.champ-erreur { border-color: var(--text); }

/* Pastille "validé" de l'écran "Fait" (planche Code3Fait) : blanc sur --ok
   mesuré à 5,47:1 (balayage-contrastes.mjs), largement au-dessus du seuil
   même à 15px — pas besoin d'un texte large ici, contrairement à la flamme. */
.pastille-validee {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 36px; padding: 6px 14px; margin-bottom: 4px;
  border-radius: 999px; background: var(--ok); color: #fff;
  font-size: 15px; font-weight: 600;
}

/* ---------- Écran Réglages ---------- */
.reglages-page { padding-top: 8px; padding-bottom: 30px; max-width: 480px; }
.reglages-page-etroite { max-width: 420px; }
.reglages-page .section-title { margin-top: 4px; }

.reglages-carte { display: flex; flex-direction: column; gap: 4px; margin-top: 18px; }
.reglages-soustitre { font-size: 13px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.reglages-email { font-size: 15px; font-weight: 600; color: var(--text); margin: 6px 0 10px; }
.reglages-separateur { height: 1px; background: var(--border); margin: 4px 0; }

/* Une ligne de compte = un bouton pleine largeur (icône, texte, chevron
   optionnel) : même esprit que .aide-geste-titre mais cliquable. */
.reglages-ligne {
  display: flex; align-items: center; gap: 12px; width: 100%;
  min-height: 52px; padding: 4px 0; border: none; background: none;
  font-family: inherit; font-size: 17px; font-weight: 600; color: var(--text);
  text-align: left; cursor: pointer;
}
.reglages-ligne-icone {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 999px;
  background: var(--fond-chaud); color: var(--action);
}
.reglages-ligne-texte { flex: 1 1 auto; }
.reglages-chevron { flex: 0 0 auto; color: var(--muted-light); }

/* Carte "Une question, un souci ?" : fond chaud plein (comme la planche
   Main), pas de bordure — se distingue visuellement de la carte "Mon compte"
   juste au-dessus. */
.reglages-contact {
  background: var(--fond-chaud); border-radius: var(--radius);
  padding: 22px 20px; margin-top: 16px;
  display: flex; flex-direction: column; gap: 14px;
}
.reglages-contact-texte { font-size: 16px; color: var(--text); line-height: 1.5; margin: 0; }
/* Bouton flamme pleine largeur pour "Écrire à Corentin" : c'est un <a> (lien
   mailto, pas un bouton de formulaire), donc son style est écrit ici plutôt
   que de réutiliser .btn-login (qui suppose display:block via un <button>
   natif — un <a> reste "inline" par défaut et ignorerait sa largeur/hauteur
   sans ce display explicite). */
.reglages-btn-mailto {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; min-height: 50px; padding: 12px 20px;
  background: var(--action); color: #fff; text-decoration: none;
  font-family: inherit; font-size: 19px; font-weight: 700; border-radius: 14px;
  box-shadow: 0 1px 4px rgba(250,93,0,.25);
  transition: background .15s, transform .1s;
}
.reglages-btn-mailto:hover { background: var(--action-sombre); }
.reglages-btn-mailto:active { transform: translateY(1px); }
.reglages-adresse-ligne { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.reglages-adresse { font-size: 15px; color: var(--text); word-break: break-all; }

.reglages-version { font-size: 13px; color: var(--muted); margin-top: 22px; line-height: 1.5; }
.reglages-version a { color: var(--muted); }

/* Carte "Diagnostic micro" (lot D28, 05/09/2026) : même gabarit que
   .reglages-carte (padding 22px 20px, marge du haut 18px), un peu plus
   d'espace vertical entre ses blocs (soustitre, texte, journal, actions). */
.reglages-diagnostic { padding: 22px 20px; display: flex; flex-direction: column; gap: 10px; margin-top: 18px; }
.reglages-diagnostic-texte { font-size: 15px; line-height: 1.5; color: var(--muted); margin: 0; }
/* Journal en monospace (lisible chiffre par chiffre, comme un ticket de
   caisse) : hauteur plafonnée avec défilement interne plutôt que de pousser
   le reste de l'écran, `white-space: pre-wrap` pour ne jamais couper un
   user-agent long sans retour à la ligne. */
.reglages-diagnostic-journal {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12.5px; line-height: 1.5; white-space: pre-wrap; word-break: break-word;
  max-height: 220px; overflow-y: auto; margin: 0;
  background: var(--fond-chaud); border-radius: 10px; padding: 12px; color: var(--text);
}
.reglages-diagnostic-actions { display: flex; gap: 10px; }
.reglages-diagnostic-actions .btn-export { flex: 1 1 0; }

/* ---------- Écran "Changer mon mot de passe" ---------- */
/* Un seul élément pour le succès ET l'échec (reglages.js bascule la classe) :
   même patron que .export-etat (dashboard.js/export). */
.changer-mdp-message {
  margin-top: 14px; padding: 10px 14px; border-radius: 10px;
  font-size: 13.5px; font-weight: 600;
  color: var(--ok); background: var(--ok-bg); border: 1px solid var(--brand-light);
}
.changer-mdp-message.est-erreur {
  color: var(--danger-text); background: var(--danger-bg); border-color: var(--danger-border);
}

/* =====================================================================
   Lot A15 (R-2, 25/08/2026) : la carte « Couleur de Stovo », en tête de
   l'écran Réglages (au-dessus de « Mon compte »). Planche source :
   maquettes/compte-et-reglages/ReglagesPrune.dc.html. Le nuancier et
   l'aperçu sont RENDUS par reglages.js (via app/couleur_logique.js,
   module pur), ce fichier ne pose que leur style.
   ===================================================================== */

/* Même gabarit que .reglages-carte (padding 22px 20px, marge du haut
   18px, comme la planche), mais un gap plus large (14px au lieu de 4px) :
   cette carte empile 4 blocs distincts (étiquette, texte, nuancier,
   aperçu) plutôt que des lignes de compte serrées. */
.reglages-couleur { padding: 22px 20px; display: flex; flex-direction: column; gap: 14px; margin-top: 18px; }
.reglages-couleur-texte { font-size: 15px; line-height: 1.5; color: var(--muted); }

.reglages-nuancier { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px; }
/* Vrai <button> (accessibilité, brief §6) : cible 44px, libellé toujours
   visible sous le disque (jamais la pastille seule). */
.reglages-pastille {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  min-height: 44px; padding: 6px 0;
  font-family: inherit; font-size: 13px; font-weight: 500; color: var(--muted);
  background: none; border: none; cursor: pointer;
  transition: color .15s, transform .1s;
}
.reglages-pastille-disque {
  width: 44px; height: 44px; border-radius: 999px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center; color: #fff;
}
/* Les CINQ couleurs du nuancier sont FIXES (chaque pastille montre
   toujours sa propre teinte, contrairement à --action qui n'en active
   qu'une à la fois sur <html>) : mêmes valeurs que les cinq blocs
   html[data-couleur] plus haut (section :root), dupliquées ici avec la
   même raison — un changement de teinte se fait aux DEUX endroits. */
.reglages-pastille[data-teinte="flamme"] .reglages-pastille-disque { background: #FA5D00; }
.reglages-pastille[data-teinte="bleu"] .reglages-pastille-disque { background: #1D4ED8; }
.reglages-pastille[data-teinte="prune"] .reglages-pastille-disque { background: #7E22CE; }
.reglages-pastille[data-teinte="framboise"] .reglages-pastille-disque { background: #BE185D; }
.reglages-pastille[data-teinte="encre"] .reglages-pastille-disque { background: #1D1E1C; }
/* Sélection : anneau blanc + encre autour du disque (planche), libellé en
   gras + encre (comme .nav-item.actif .nav-label, même logique). La coche
   SVG (rendue par couleur_logique.js) est blanche sur les cinq teintes :
   flamme ne tient que 3,17:1 en blanc, mais c'est un pictogramme, pas du
   texte courant (DESIGN.md, règle 10) ; les quatre autres teintes tiennent
   toutes le 4,5:1 (balayé au rapport de passation). */
.reglages-pastille.est-choisi { color: var(--text); font-weight: 700; }
.reglages-pastille.est-choisi .reglages-pastille-disque {
  box-shadow: 0 0 0 2px #FFFFFF, 0 0 0 4px var(--text);
}
.reglages-pastille:active { transform: translateY(1px); }

/* L'aperçu : le bouton Oui « tel qu'il sera », dans la teinte courante —
   il réutilise .btn-confirmation.btn-oui déjà stylé plus haut (donc suit
   --action automatiquement, aucune couleur à dupliquer ici). C'est un
   <span>, pas un <button> : aria-hidden (brief §5), pointer-events:none
   en renfort pour qu'aucun clic ne lui donne l'air actif, et la légende
   à côté porte tout le sens pour un lecteur d'écran. */
.reglages-apercu { display: flex; align-items: center; gap: 10px; padding-top: 4px; flex-wrap: wrap; }
.reglages-apercu-bouton { flex: 0 0 auto; pointer-events: none; }
.reglages-apercu-texte { font-size: 14px; line-height: 1.5; color: var(--muted); margin: 0; flex: 1 1 200px; min-width: 0; }

/* =====================================================================
   Chantier "Premiers pas", lot 2 (18/09/2026) — la bande de guidage du fil
   de première connexion, paliers 1 à 3 (§7.4 du plan de l'Architecte,
   2026-09-17_architecte_plan-premiers-pas.md). Carte au-dessus de
   .parler-reponse sur l'écran "Saisir", masquée par `hidden` par défaut,
   gérée par premiers_pas.js. Aucune variable de :root touchée ici.
   ===================================================================== */

/* Carte : mêmes jetons que .parler-reponse (l.348-352) et .bandeau-pilotage
   (l.1146-1157). L'ombre chaude (--shadow-chaude) est INTERDITE ici
   (DESIGN.md, règle 4, réservée à l'écran du matin). */
.premiers-pas {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); padding: 18px 20px; margin-bottom: 16px;
  /* Retouche captures (18/09/2026) : .parler-reponse pose text-align: left
     (l.351), repris partout sauf ici. Sans cette ligne, la bande hérite du
     text-align: center de .parler-centre (l.292) : au palier 2, la note en
     trois lignes se lit mal (dernier mot seul au centre) et contredit la
     carte juste en dessous, alignée à gauche. */
  text-align: left;
}

.pp-entete { display: flex; align-items: center; gap: 10px; }
.pp-titre { font-size: 16px; font-weight: 700; color: var(--text); margin: 0; flex: 1 1 auto; }

/* Trois jalons : trois petits disques, le courant en --action (jamais
   --flamme en dur, décision A15), les autres en --border. `aria-hidden`
   côté HTML, doublés du texte lecteur d'écran (.sr-only, déjà défini
   ailleurs dans ce fichier) posé par premiers_pas.js. */
.pp-jalons { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.pp-jalon { width: 8px; height: 8px; border-radius: 999px; background: var(--border); display: block; }
.pp-jalon-actif { background: var(--action); }

/* Croix : 44 px de cible tactile minimum (lots A1 à A4), sans bordure ni
   fond au repos pour rester discrète dans l'en-tête de la carte. */
.pp-fermer {
  flex: 0 0 auto; width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: 16px; color: var(--muted);
  background: none; border: none; border-radius: 14px; cursor: pointer;
  transition: background .15s, color .15s, transform .1s;
}
.pp-fermer:hover { background: var(--fond-chaud); color: var(--text); }
.pp-fermer:active { transform: translateY(1px); }

/* Corps : une seule zone aria-live (#pp-corps, posée côté HTML), son
   contenu ne change qu'au changement de palier OU de phrase modèle rendue
   (premiers_pas.js, correctif du 18/09/2026). Chaque paragraphe reçoit une
   classe qui traduit son RÔLE (§3.3 de la consigne du lot 2), jamais
   devinée dans la glu : `corps` (texte courant, --text), `modele` (le
   marqueur ou la phrase à dire, en gras et tabular-nums, --text) ou `note`
   (secondaire, --muted — jamais --muted-light, piège documenté de ce
   monde). Un paragraphe peut se découper en PLUSIEURS segments (palier 1
   seulement : le marqueur « nouveau produit » en `modele`, le trou
   « ton article » en `trou`, §7.1 du plan — correctif post-relecture du
   18/09) : dans ce cas, les mêmes classes s'appliquent à des <span> au lieu
   d'un <p> entier. */
.pp-corps { margin-top: 14px; display: flex; flex-direction: column; gap: 10px; }
.pp-corps-ligne, .pp-modele, .pp-note, .pp-trou { margin: 0; font-size: 15px; line-height: 1.5; }
.pp-corps-ligne { color: var(--text); }
.pp-modele { color: var(--text); font-weight: 700; font-variant-numeric: tabular-nums; }
.pp-note { color: var(--muted); font-size: 13px; }
/* Le trou à compléter par le client (palier 1) : même gabarit que le
   marqueur voisin, mais en --muted et sans le gras, pour que l'œil
   distingue tout de suite ce qui est à remplacer. */
.pp-trou { color: var(--muted); font-weight: 400; }

/* #pp-secours et #pp-actions : markup déjà en place pour les lots 5 à 7
   (escaliers micro/comprehension, boutons de fin de fil), non utilisés par
   ce lot. Styles minimaux pour qu'un futur lot les trouve prêts, sans rien
   afficher tant qu'ils restent vides. */
.pp-secours { margin-top: 10px; }
.pp-actions { margin-top: 14px; display: flex; flex-wrap: wrap; gap: 10px; }
/* Retouche captures (18/09/2026) : un conteneur vide ne doit pas creuser la
   carte. #pp-actions est vide dans ce lot (ses boutons arrivent aux lots 5
   à 7) mais gardait son margin-top, la carte paraissait plus creuse en bas
   qu'en haut. `:empty` seul, sans !important et sans toucher à la règle
   globale [hidden] (l.748) : #pp-secours est déjà `hidden` donc déjà sans
   effet, cette règle ne fait qu'anticiper le jour où il perdrait sa marge
   à vide lui aussi. */
.pp-secours:empty, .pp-actions:empty { display: none; }

/* ---------- Rayon « Apprendre Stovo », onglet Aide (lot 3, chantier
   Tutoriels, 18/09/2026) ----------
   Une entree de parcours guide (aujourd'hui : "Refaire mes premiers pas").
   Meme gabarit que .aide-geste (bordure haute, titre + texte muted, l.1051)
   pour rester coherent avec le reste de l'Aide, sans creer de nouveau
   jeton : bouton repris de .btn-export (contour, action secondaire,
   cible tactile 44 px, l.1221), message de reponse masque par [hidden]
   (jamais style.display). Aucune variable de :root touchee. */
.aide-tuto {
  border-top: 1px solid var(--border);
  padding: 16px 0 4px;
}
.aide-tuto:first-of-type { border-top: none; }
.aide-tuto-titre { font-size: 14.5px; font-weight: 700; margin-bottom: 5px; }
.aide-tuto-quoi { font-size: 13.5px; color: var(--muted); line-height: 1.6; margin-bottom: 10px; }
.aide-tuto-bouton {
  font-family: inherit; font-size: 14.5px; font-weight: 600;
  min-height: 44px; padding: 12px 16px; border: 1.5px solid var(--border); border-radius: 14px;
  background: var(--card); color: var(--text); cursor: pointer;
  transition: background .15s, border-color .15s, transform .1s;
}
.aide-tuto-bouton:hover { background: var(--fond-chaud); }
.aide-tuto-bouton:active { transform: translateY(1px); }
/* Le message de reponse (stovo:tuto-reponse, aide.js) : demasque et mis au
   focus au moment ou premiers_pas.js repond qu'il n'a rien a relancer. */
.aide-tuto-message {
  font-size: 13.5px; color: var(--text); line-height: 1.6;
  margin: 10px 0 0; padding-top: 10px; border-top: 1px solid var(--border);
}

/* Lot 6 "Premiers pas" (chantier Tutoriels, 18/09/2026) : le secours de
   l'escalier de comprehension, dans #pp-secours (deja pose en index.html,
   hidden). Textes secondaires en --muted (DESIGN.md regle 3), bouton a
   contour repris de .aide-tuto-bouton. */
.pp-secours-texte { font-size: 14px; color: var(--muted); line-height: 1.5; margin: 0 0 10px; }
.pp-secours-texte:last-of-type { margin-bottom: 0; }
.pp-secours-bouton {
  font-family: inherit; font-size: 14.5px; font-weight: 600;
  min-height: 44px; padding: 12px 16px; border: 1.5px solid var(--border); border-radius: 14px;
  background: var(--card); color: var(--text); cursor: pointer;
  margin-top: 10px; transition: background .15s, border-color .15s, transform .1s;
}
.pp-secours-bouton:hover { background: var(--fond-chaud); }
.pp-secours-bouton:active { transform: translateY(1px); }

/* Lot 7 "Premiers pas" (chantier Tutoriels, 18/09/2026) : les boutons de fin
   de fil, dans #pp-actions (deja pose en index.html, deja stylee au lot 2
   -- gap, flex-wrap, masquage a vide -- l.1593/1601). Bouton principal :
   patron du bouton flamme de l'app (.btn-reception-primaire, 19px gras,
   46px), c'est un ecran d'arrivee, l'action principale merite d'etre
   nette. Bouton secondaire : patron a contour de .pp-secours-bouton (fond
   neutre au survol, jamais de rouge : "J'ai fini" n'est pas une action
   destructive, a la difference d'.btn-reception-secondaire). Aucune
   variable de :root touchee. */
.pp-action-principale {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: 19px; font-weight: 700; white-space: nowrap;
  min-height: 46px; padding: 0 16px; border: none; border-radius: 14px;
  background: var(--action); color: #fff; cursor: pointer;
  box-shadow: 0 1px 4px rgba(250,93,0,.25);
  transition: background .15s, transform .1s;
}
.pp-action-principale:hover { background: var(--action-sombre); }
.pp-action-principale:active { transform: translateY(1px); }
.pp-action-secondaire {
  font-family: inherit; font-size: 14.5px; font-weight: 600;
  min-height: 44px; padding: 12px 16px; border: 1.5px solid var(--border); border-radius: 14px;
  background: var(--card); color: var(--text); cursor: pointer;
  transition: background .15s, border-color .15s, transform .1s;
}
.pp-action-secondaire:hover { background: var(--fond-chaud); }
.pp-action-secondaire:active { transform: translateY(1px); }

/* =====================================================================
   Chantier "Tutoriels", lot T2 (22/09/2026) -- le bandeau pas-a-pas et le
   premier parcours complet, "Comprendre mon Pilotage". Reprend le gabarit
   de .maj-bandeau (fixed, meme hauteur au-dessus de la nav, meme fond/
   filet/ombre, l.721) en z-index 54 (SOUS la banniere de mise a jour, rare
   et prioritaire, §3.3 du plan de l'Architecte du 18/09/2026). Aucune
   variable de :root touchee, jamais de replace_all.
   ===================================================================== */
.tuto-bandeau {
  position: fixed; left: 0; right: 0; z-index: 54;
  bottom: calc(78px + env(safe-area-inset-bottom));
  display: flex; flex-direction: column;
  max-height: 50vh; overflow-y: auto;
  background: var(--card); border-top: 1px solid var(--border);
  padding: 14px 16px;
  box-shadow: 0 -2px 10px rgba(29,30,28,.08);
}
.tuto-entete { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
.tuto-titre { font-size: 15px; font-weight: 700; color: var(--text); margin: 0; flex: 1 1 auto; }
/* Progression courte, affichee ("2 / 5") : decorative (aria-hidden cote
   HTML), doublee du texte lecteur d'ecran #tuto-progression-sr (.sr-only,
   deja defini l.1313). */
.tuto-progression { font-size: 13px; font-weight: 600; color: var(--muted); flex: 0 0 auto; }
/* Croix : meme gabarit que .pp-fermer (44px de cible tactile, l.1556),
   sans bordure ni fond au repos. */
.tuto-fermer {
  flex: 0 0 auto; width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: 16px; color: var(--muted);
  background: none; border: none; border-radius: 14px; cursor: pointer;
  transition: background .15s, color .15s, transform .1s;
}
.tuto-fermer:hover { background: var(--fond-chaud); color: var(--text); }
.tuto-fermer:active { transform: translateY(1px); }

.tuto-corps { margin-top: 10px; display: flex; flex-direction: column; gap: 10px; }
/* Titre de l'etape : recoit le focus programmatique a chaque rendu
   (tutoriels.js, { preventScroll: true }). Rien de plus a poser ici : la
   regle :focus-visible (l.1304) ne se declenche que sur une interaction
   clavier, jamais sur un focus() appele depuis le script -- aucun contour
   disgracieux n'apparait donc sans qu'il faille rien desactiver. */
.tuto-etape-titre { font-size: 16px; font-weight: 700; color: var(--text); margin: 0; }
.tuto-corps p { margin: 0; font-size: 14.5px; line-height: 1.5; color: var(--text); }
.tuto-corps p.tuto-note { color: var(--muted); font-size: 13px; }

.tuto-actions { margin-top: 14px; display: flex; flex-wrap: wrap; gap: 10px; flex: 0 0 auto; }
/* "Precedent" et "En savoir plus" : gabarit d'.aide-exemple (contour,
   rayon 14px, fond --card, min-height 44px, l.1071) SANS reutiliser la
   classe elle-meme, dont les ::before/::after ajoutent des guillemets qui
   n'ont pas de sens sur un bouton d'action. */
.tuto-secondaire {
  font-family: inherit; font-size: 14px; font-weight: 600; text-align: left;
  min-height: 44px; padding: 12px 16px; border: 1.5px solid var(--border); border-radius: 14px;
  background: var(--card); color: var(--muted); cursor: pointer;
  transition: background .15s, border-color .15s, transform .1s;
}
.tuto-secondaire:hover { background: var(--fond-chaud); border-color: var(--text); }
.tuto-secondaire:active { transform: translateY(1px); }

/* Lot RGPD F1 (22/09/2026) : les liens legaux de l'ecran de connexion. */
.login-legal { margin-top: 18px; text-align: center; font-size: 12.5px; color: var(--muted); }
.login-legal a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }

/* Correctif de relecture (22/09/2026) : les liens de la section "Tes donnees
   et la loi" de l'Aide (aide-contenu.js) s'affichaient en bleu navigateur
   par defaut. Meme gabarit que .login-lien-centre a. */
.aide-texte a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.aide-texte a:hover { color: var(--muted); }

/* =====================================================================
   Démo en libre-service, lot L6a (07/10/2026) -- le bandeau, et le bouton
   en forme de lien de l'écran de fin. Règles NEUVES seulement : aucune
   variable de :root touchée, aucune règle existante modifiée. Les deux écrans
   de lancement et de fin réutilisent .ecran-login, .login-carte, .btn-login,
   .login-soustitre, .login-note et .login-erreur tels quels.
   Le bandeau est DANS LE FLUX (jamais fixed, jamais en surimpression : un
   bandeau ne cache pas ce qu'il montre, leçon de D70). Fond décor
   (--fond-chaud), texte en encre, bouton à contour : la flamme reste réservée
   à l'action principale de chaque écran (règle 1 de DESIGN.md).
   ===================================================================== */
.demo-bandeau {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px;
  padding: 10px 16px;
  background: var(--fond-chaud); border-bottom: 1px solid var(--border);
}
.demo-bandeau-texte {
  flex: 1 1 200px; margin: 0;
  font-size: 14px; font-weight: 600; line-height: 1.4; color: var(--text);
}
.demo-bandeau-bouton {
  /* Peut rétrécir et passer à la ligne : un libellé long ne doit JAMAIS élargir la page
     (sur un téléphone, une page plus large que l'écran dézoome tout). */
  flex: 0 1 auto; max-width: 100%; display: inline-flex; align-items: center;
  min-height: 44px; padding: 8px 16px; line-height: 1.3;
  font-family: inherit; font-size: 14px; font-weight: 600; text-decoration: none; color: var(--text);
  background: var(--card); border: 1.5px solid var(--border); border-radius: 14px;
  transition: background .15s, border-color .15s, transform .1s;
}
.demo-bandeau-bouton:hover { border-color: var(--text); }
.demo-bandeau-bouton:active { transform: translateY(1px); }
/* La proposition du 3e jour : une seconde ligne dans le même bandeau. */
.demo-sortie { flex: 1 1 100%; display: flex; align-items: center; gap: 10px; }
.demo-sortie-texte { flex: 1 1 auto; margin: 0; font-size: 14px; line-height: 1.45; color: var(--text); }
.demo-sortie-fermer {
  flex: 0 0 auto; width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: 16px; color: var(--muted);
  background: none; border: none; border-radius: 14px; cursor: pointer;
  transition: background .15s, color .15s, transform .1s;
}
.demo-sortie-fermer:hover { background: var(--card); color: var(--text); }
.demo-sortie-fermer:active { transform: translateY(1px); }
/* .btn-login posé sur un <a> (le mail de l'écran de fin) : un lien est en
   ligne par défaut, il faut le mettre en flex pour que la pleine largeur et
   le centrage de .btn-login s'appliquent, et retirer le soulignement. */
/* Le mot « Confidentialité » de la ligne RGPD du lancement est un lien dans une phrase :
   hérite de la couleur du texte, souligné (même geste visuel que .login-legal a). */
.login-note a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.btn-login.demo-lien-bouton {
  display: flex; align-items: center; justify-content: center;
  text-decoration: none; text-align: center; padding: 10px 16px; line-height: 1.3;
}
/* Lot L6b (07/10/2026) : le message « fonction grisée » de la démo, créé par demo.js et posé sous le
   bouton touché (photo de bon ou import). C'est la carte .parler-reponse de Saisir, avec l'air qui lui
   manque au-dessus : collée au bouton, elle se lisait comme sa suite. */
.demo-grisee { margin-top: 12px; }

/* =====================================================================
   Démo en libre-service, lot L7 (08/10/2026) -- la carte des missions
   « L'essentiel », en haut de l'écran Saisir, EN DÉMO SEULEMENT (missions_demo.js
   la crée à la demande, un testeur n'en a pas une ligne dans sa page). Règles
   NEUVES seulement : aucune variable de :root touchée, aucune règle existante
   modifiée. Gabarit de .aide-section (carte repliable, <details> natif, chevron)
   et de .premiers-pas (carte blanche, filet, ombre légère, JAMAIS l'ombre chaude
   réservée à l'écran du matin). La phrase à toucher réutilise .aide-exemple (le
   même geste que dans l'Aide : toucher recopie la phrase dans le champ). La
   coche est en --ok : c'est le teal de « Validé » (DESIGN.md), jamais la flamme,
   réservée à l'action.
   ===================================================================== */
.missions-demo {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); margin-bottom: 16px; overflow: hidden;
  /* .parler-centre centre le texte : la carte se lit à gauche, comme .premiers-pas. */
  text-align: left;
}
.missions-sommaire {
  cursor: pointer; list-style: none; -webkit-user-select: none; user-select: none;
  display: flex; align-items: center; gap: 12px;
  min-height: 52px; padding: 12px 16px;
  font-size: 16px; font-weight: 700; color: var(--text);
}
.missions-sommaire::-webkit-details-marker { display: none; }
.missions-sommaire:focus-visible { outline: 2px solid var(--text); outline-offset: -3px; }
.missions-titre { flex: 1 1 auto; min-width: 0; }
/* Cinq petits disques, visibles même carte repliée : la progression sans un mot de plus. */
.missions-jalons { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.missions-jalon { width: 8px; height: 8px; border-radius: 999px; background: var(--border); display: block; }
.missions-jalon-fait { background: var(--ok); }
.missions-sommaire::after { content: '▾'; color: var(--muted); font-size: 13px; transition: transform .15s; }
.missions-demo[open] > .missions-sommaire::after { transform: rotate(180deg); }
.missions-demo[open] > .missions-sommaire { border-bottom: 1px solid var(--border); }

.missions-corps { padding: 4px 16px 16px; }
.missions-consigne { margin: 12px 0 4px; font-size: 14px; line-height: 1.5; color: var(--muted); }
.missions-liste { list-style: none; margin: 0; padding: 0; }
.missions-ligne { display: flex; align-items: flex-start; gap: 12px; padding: 12px 0; border-top: 1px solid var(--border); }
.missions-ligne:first-child { border-top: none; }

/* La coche : une case native inactive (les lecteurs d'écran lisent son état), redessinée. */
.missions-case {
  -webkit-appearance: none; appearance: none; opacity: 1;
  flex: 0 0 auto; position: relative; width: 22px; height: 22px; margin: 1px 0 0;
  border: 1.5px solid var(--border); border-radius: 7px; background: var(--card);
}
.missions-case:checked { background: var(--ok); border-color: var(--ok); }
.missions-case:checked::after {
  content: ''; position: absolute; left: 6px; top: 2px; width: 6px; height: 11px;
  border: solid #fff; border-width: 0 2.5px 2.5px 0; transform: rotate(45deg);
}

.missions-texte { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.missions-ligne-titre { font-size: 14px; font-weight: 700; line-height: 1.35; color: var(--text); }
.missions-faite .missions-ligne-titre { color: var(--muted); }
/* Un libellé long ne doit JAMAIS élargir la page (leçon du bandeau, lot L6a). */
.missions-phrase { max-width: 100%; overflow-wrap: anywhere; }
.missions-apres { margin: 0; font-size: 13px; line-height: 1.45; color: var(--muted); }
.missions-fini {
  margin: 4px 0 0; padding-top: 14px; border-top: 1px solid var(--border);
  font-size: 14.5px; font-weight: 600; line-height: 1.45; color: var(--text);
}
