
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
  --fond: #12100e;
  --carte: #1b1815;
  --carte2: #221f1b;
  --bord: #2e2a25;
  --or: #d9a441;
  --or-pale: #e8bb6a;
  --vert: #6fa87c;
  --rouge: #c4705f;
  --bleu: #5f8fc4;
  --texte: #e8e0d4;
  --texte-doux: #a09080;
  /* v30 : remonté de #6a5e52 (3,0:1 sur --fond, sous le seuil AA de 4,5) à
     #8a7a6a (4,6:1). Cette couleur porte des prix, des dates, des noms de
     plateforme et le montant de la commission : elle doit être lisible sur un
     téléphone en plein jour. Revenir en arrière = cette seule ligne. */
  --texte-tres-doux: #8a7a6a;
  --rayon: 12px;
  --rayon-sm: 8px;
}
html, body { height: 100%; background: var(--fond); color: var(--texte); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-size: 16px; line-height: 1.5; overscroll-behavior: none; }
a { color: var(--or); text-decoration: none; }
button { cursor: pointer; border: none; font-family: inherit; font-size: inherit; }
input, textarea, select { font-family: inherit; font-size: inherit; color: var(--texte); background: var(--carte2); border: 1px solid var(--bord); border-radius: var(--rayon-sm); padding: 12px; width: 100%; outline: none; }
input:focus, textarea:focus, select:focus { border-color: var(--or); }
textarea { resize: vertical; min-height: 80px; }
select option { background: var(--carte2); }
h1 { font-size: 1.4rem; font-weight: 700; }
h2 { font-size: 1.1rem; font-weight: 600; }

/* ── Bandeau erreur ── */
#bandeau-erreur {
  position: fixed; top: 0; left: 0; right: 0;
  background: #8b1a1a; color: white;
  padding: 12px 16px; z-index: 9999;
  font-size: 0.85rem; line-height: 1.4;
  display: none; flex-direction: column; gap: 6px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.5);
}
#bandeau-erreur .erreur-msg-texte { flex: 1; word-break: break-word; }
#bandeau-erreur button {
  background: rgba(255,255,255,0.2); border: 1px solid rgba(255,255,255,0.4);
  color: white; border-radius: 4px; padding: 4px 12px;
  font-size: 0.8rem; align-self: flex-start; margin-top: 4px;
}

/* ── Pages ── */
.page { display: none; min-height: 100vh; padding-bottom: 80px; }
.page.active { display: block; }

/* ── Barre de navigation ── */
.nav { position: fixed; bottom: 0; left: 0; right: 0; background: var(--carte); border-top: 1px solid var(--bord); display: flex; padding: 8px 0 env(safe-area-inset-bottom); z-index: 100; }
.nav-btn { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 8px 0; font-size: 0.7rem; color: var(--texte-doux); background: none; transition: color 0.15s; }
.nav-btn.active { color: var(--or); }
.nav-btn svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* ── En-tête ── */
.entete { padding: 24px 16px 8px; display: flex; align-items: center; gap: 12px; }
.entete h1 { flex: 1; }
.entete-actions { display: flex; gap: 8px; }
.btn-icone { background: var(--carte2); border: 1px solid var(--bord); border-radius: var(--rayon-sm); padding: 8px; color: var(--texte-doux); display: flex; align-items: center; justify-content: center; }
.btn-icone svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* ── Compteurs ── */
.compteurs { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; padding: 0 16px 16px; }
.compteur { background: var(--carte); border-radius: var(--rayon); padding: 14px 10px; text-align: center; border: 1px solid var(--bord); }
.compteur-valeur { font-size: 1.6rem; font-weight: 700; color: var(--texte-doux); font-family: ui-monospace, 'Courier New', monospace; font-variant-numeric: tabular-nums; line-height: 1; }
.compteur-label { font-size: 0.7rem; color: var(--texte-doux); margin-top: 4px; }

/* ── Boutons modes accueil ── */
.btns-modes { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 0 16px 24px; }
.btn-mode {
  background: var(--or); color: #12100e;
  font-size: 0.9rem; font-weight: 700;
  padding: 15px 12px; border-radius: var(--rayon);
  text-align: center; transition: background 0.15s;
  display: flex; flex-direction: row; align-items: center; justify-content: center; gap: 10px;
  line-height: 1.3;
}
.btn-mode:active { background: var(--or-pale); }
.btn-mode-scene {
  background: var(--carte2); color: var(--texte);
  border: 1px solid var(--bord);
}
.btn-mode-scene:active { background: var(--carte); }
.btn-mode-icone { font-size: 1.8rem; }

/* ── Section lots ── */
.section-titre { padding: 10px 16px 6px; font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--texte-doux); }
.lots-liste { display: flex; flex-direction: column; }

/* ── Carte lot — v28 : lignes avec filet ── */
.lot-carte { display: flex; align-items: center; gap: 10px; padding: 10px 16px; cursor: pointer; user-select: none; -webkit-user-select: none; position: relative; }
.lot-carte:not(:last-child)::after { content: ''; position: absolute; bottom: 0; left: 78px; right: 0; height: 1px; background: var(--bord); }
.lot-carte.selectionnee { background: #221d12; }
.lot-carte.sortie { opacity: 0.45; }
.lot-vignette { width: 62px; height: 62px; min-width: 62px; border-radius: 9px; overflow: hidden; background: var(--carte2); flex-shrink: 0; }
.lot-vignette img { width: 62px; height: 62px; object-fit: cover; display: block; }
.lot-vignette-vide { width: 62px; height: 62px; display: flex; align-items: center; justify-content: center; color: var(--texte-tres-doux); }
.lot-corps { flex: 1; min-width: 0; }
.lot-titre { font-size: 0.9rem; font-weight: 600; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.3; }
.lot-sous { display: flex; align-items: center; gap: 3px; margin-top: 3px; flex-wrap: wrap; font-size: 0.72rem; color: var(--texte-doux); line-height: 1.4; }
.etat-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.lot-sous-plat { color: var(--texte-tres-doux); }
.lot-sous-plat.en-ligne { color: var(--vert); }
.lot-sous-age { color: var(--texte-tres-doux); }
.sep-median { color: var(--texte-tres-doux); flex-shrink: 0; }
.lot-prix-col { flex-shrink: 0; text-align: right; padding-left: 8px; }
.lot-prix-tabular { font-size: 0.88rem; font-weight: 600; color: var(--texte-doux); font-family: ui-monospace, 'Courier New', monospace; font-variant-numeric: tabular-nums; white-space: nowrap; }
.lot-prix-vide { font-size: 0.88rem; color: var(--texte-tres-doux); }
/* Kept for reference in fiche, validation cards */
.etiquette { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 999px; font-size: 0.7rem; font-weight: 700; }
.etiquette-vendre { background: #1e3a1a; color: var(--vert); }
.etiquette-donner { background: #1a2e3a; color: var(--bleu); }
.etiquette-jeter { background: #3a1a1a; color: var(--rouge); }
.etiquette-garder { background: #2e2a1a; color: var(--or); }
.lot-vendu-badge { font-size: 0.65rem; padding: 1px 6px; border-radius: 3px; background: #1a3a1a; color: var(--vert); font-weight: 700; }

/* ── Actions de carte : le bouton « Publier » de la section « prêts » ──
   v28 avait masqué cette classe en croyant y trouver les deux boutons carrés
   des lignes de liste. Elle ne porte que « Publier », et le masquer avait
   supprimé le seul raccourci pour publier un objet depuis l'accueil. ── */
.lot-carte-actions { display: flex; justify-content: flex-end; padding: 0 12px 10px; }

/* ── Zone détail prix vendu (fiche) ── */
.zone-vendu-detail { display: none; flex-direction: column; gap: 2px; padding: 0 16px 12px; font-size: 0.82rem; }
.zone-vendu-detail .prix-realise-val { color: var(--vert); font-weight: 700; }
.zone-vendu-detail .commission-val { color: var(--texte-tres-doux); }

/* ── Commission dans compteur accueil ── */
.cpt-commission { font-size: 0.62rem; color: var(--texte-tres-doux); margin-top: 2px; line-height: 1.3; }

/* ── Spinner ── */
.spinner { display: inline-block; width: 18px; height: 18px; border: 2px solid var(--bord); border-top-color: var(--or); border-radius: 50%; animation: spin 0.7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ── Boutons ── */
.btn { display: block; width: 100%; padding: 15px; border-radius: var(--rayon); font-size: 0.95rem; font-weight: 700; text-align: center; transition: opacity 0.15s; }
.btn:active { opacity: 0.8; }
.btn-or { background: var(--or); color: #12100e; }
.btn-secondaire { background: var(--carte2); border: 1px solid var(--bord); color: var(--texte); }
.btn-danger { background: var(--rouge); color: white; }
.btn-vert { background: var(--vert); color: white; }
.btn-sm { padding: 10px 16px; font-size: 0.85rem; border-radius: var(--rayon-sm); width: auto; display: inline-flex; align-items: center; gap: 6px; }
.padding-16 { padding: 16px; }

/* ── Session analyse en cours ── */
.session-analyse { background: var(--carte); border-radius: var(--rayon); border: 1px solid var(--bord); padding: 16px; margin: 0 16px 8px; display: flex; align-items: center; gap: 12px; }
.session-analyse-info { flex: 1; }
.session-analyse-titre { font-size: 0.9rem; font-weight: 600; }
.session-analyse-sous { font-size: 0.75rem; color: var(--texte-doux); margin-top: 2px; }

/* ── Page Capture — plein écran caméra ── */
#p-capture.active {
  position: fixed; inset: 0;
  min-height: unset; padding: 0;
  background: #000; overflow: hidden;
  display: flex; flex-direction: column;
  z-index: 50;
}

#camera-video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; z-index: 0;
}

#camera-ui {
  position: relative; z-index: 10;
  display: flex; flex-direction: column;
  height: 100%; min-height: 100%;
}

#camera-top {
  background: linear-gradient(rgba(0,0,0,0.65) 0%, transparent 100%);
  padding: 16px 16px 32px;
  display: flex; align-items: center; gap: 12px;
  flex-shrink: 0;
}

.camera-btn-retour {
  background: rgba(0,0,0,0.4); border: 1px solid rgba(255,255,255,0.2);
  border-radius: 50%; width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  color: white; font-size: 1.2rem; flex-shrink: 0;
}

#camera-titre { flex: 1; color: white; font-size: 1rem; font-weight: 700; }
#camera-compteur { color: rgba(255,255,255,0.7); font-size: 0.8rem; flex-shrink: 0; }

#camera-mid { flex: 1; }

#camera-vignettes {
  display: flex; gap: 8px;
  padding: 16px 16px 8px;
  overflow-x: auto; scrollbar-width: none;
  flex-shrink: 0;
}
#camera-vignettes::-webkit-scrollbar { display: none; }

.cam-vignette {
  position: relative; flex-shrink: 0;
  width: 64px; height: 64px;
  border-radius: 8px; overflow: hidden;
  border: 2px solid rgba(255,255,255,0.3);
  background: #222;
}
.cam-vignette img { width: 100%; height: 100%; object-fit: cover; }
.cam-vignette-suppr {
  position: absolute; top: 2px; right: 2px;
  background: rgba(0,0,0,0.75); border: none; border-radius: 50%;
  width: 20px; height: 20px; color: white; font-size: 11px;
  display: flex; align-items: center; justify-content: center;
}

#camera-bottom {
  background: linear-gradient(transparent 0%, rgba(0,0,0,0.75) 100%);
  padding: 16px 24px calc(16px + env(safe-area-inset-bottom));
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-shrink: 0; min-height: 100px;
}

#btn-shutter {
  width: 72px; height: 72px; border-radius: 50%;
  background: rgba(255,255,255,0.9);
  border: 4px solid rgba(255,255,255,0.4);
  box-shadow: 0 0 0 2px rgba(255,255,255,0.6);
  flex-shrink: 0; transition: transform 0.1s, background 0.1s;
}
#btn-shutter:active { transform: scale(0.88); background: white; }
#btn-shutter:disabled { opacity: 0.4; }

#btn-analyser-cam {
  background: var(--or); color: #12100e;
  border: none; border-radius: var(--rayon-sm);
  padding: 12px 16px; font-weight: 700; font-size: 0.85rem;
  white-space: nowrap; flex-shrink: 0;
}
#btn-analyser-cam:disabled { opacity: 0.5; }

#camera-fallback {
  flex: 1; display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 16px; padding: 32px; text-align: center;
}
#camera-fallback p { color: rgba(255,255,255,0.7); font-size: 0.9rem; line-height: 1.5; }
.btn-fallback {
  background: var(--carte2); border: 1px solid var(--bord);
  border-radius: var(--rayon); padding: 16px 24px;
  font-size: 0.95rem; font-weight: 700; color: var(--texte);
  width: 100%; max-width: 320px; text-align: center;
}

/* ── Fiche lot ── */
.fiche-photos { display: flex; gap: 8px; overflow-x: auto; padding: 16px; scrollbar-width: none; }
.fiche-photos::-webkit-scrollbar { display: none; }
.fiche-photo { flex-shrink: 0; width: 140px; height: 140px; border-radius: var(--rayon-sm); overflow: hidden; background: var(--carte2); cursor: zoom-in; }
.fiche-photo:active { opacity: 0.8; }
.fiche-photo img { width: 100%; height: 100%; object-fit: cover; }
/* Ticket 40 : une photo redressee le DIT, sous elle, et se defait. La mention
   est discrete (texte tertiaire, 0.7rem) parce qu'elle n'est pas une alerte ;
   le bouton, lui, garde les 40 px de toute cible tactile — on l'atteint d'une
   main, l'autre tenant l'objet. */
.fiche-photo-bloc { flex-shrink: 0; width: 140px; }
.photo-redressee { display: flex; align-items: center; justify-content: space-between; gap: 4px; margin-top: 4px; font-size: 0.7rem; color: var(--texte-tres-doux); line-height: 1.3; }
.btn-annuler-rotation { flex-shrink: 0; min-height: 40px; padding: 0 12px; border-radius: var(--rayon-sm); background: var(--carte2); border: 1px solid var(--bord); color: var(--texte-doux); font-size: 0.7rem; font-weight: 600; }
.btn-annuler-rotation:active { opacity: 0.8; }
/* Retour de Lucile, 9 sept. : ecarter une photo ratee avant publication. Le
   bouton fait toute la largeur du bloc photo (140 px) et 40 px de haut, comme
   toute cible tactile — on s'en sert une main tenant l'objet. */
.btn-ecarter-photo { display: block; width: 100%; min-height: 40px; margin-top: 4px; padding: 0 8px; border-radius: var(--rayon-sm); background: var(--carte2); border: 1px solid var(--bord); color: var(--texte-doux); font-size: 0.7rem; font-weight: 600; }
.btn-ecarter-photo:active { opacity: 0.8; }
/* La photo de couverture : celle qui part en premier, donc la vignette de la
   liste de resultats sur les trois plateformes. En or, la couleur d'accent :
   ce n'est ni une erreur ni un succes, c'est l'element actif du groupe. Le
   liseré est sur la vignette elle-meme parce que la question posee est
   « laquelle », et qu'un badge sans ancrage oblige a compter les photos. */
.fiche-photo-bloc.est-couverture .fiche-photo { outline: 2px solid var(--or); outline-offset: -2px; }
.photo-couverture-badge { margin-top: 4px; padding: 4px 8px; border-radius: var(--rayon-sm); background: var(--or); color: var(--fond); font-size: 0.7rem; font-weight: 700; line-height: 1.3; text-align: center; }
/* Meme gabarit que « Ecarter cette photo » : 140 px de large, 40 px de haut,
   atteignable d'une main. Les deux boutons se suivent sous la meme vignette. */
.btn-couverture { display: block; width: 100%; min-height: 40px; margin-top: 4px; padding: 0 8px; border-radius: var(--rayon-sm); background: var(--carte2); border: 1px solid var(--bord); color: var(--texte-doux); font-size: 0.7rem; font-weight: 600; }
.btn-couverture:active { opacity: 0.8; }
/* La photo ecartee ici que l'annonce publiee montre encore. Le motif de
   l'encart en lisere, en or : ce n'est pas une panne de la machine — rien n'a
   echoue — c'est un geste qui reste a faire chez la plateforme, et il ne doit
   pas se chercher. Rien ne s'y clique : le lien de l'annonce est juste
   au-dessous, dans les liens de plateformes. */
.fiche-photo-en-ligne { margin: 0 16px 16px; padding: 12px; border-left: 3px solid var(--or); border-radius: 0 var(--rayon-sm) var(--rayon-sm) 0; background: #1e1a0e; color: var(--texte); font-size: 0.8rem; line-height: 1.4; }
.fiche-photo-en-ligne-ligne { font-weight: 600; }
.fiche-photo-en-ligne-suite { margin-top: 4px; color: var(--texte-doux); }
/* Ticket 149 : les liens de plateformes, sortis de la liste. Un par plateforme
   reellement en ligne. 40 px de haut, comme toute cible tactile. */
.fiche-liens-plateformes { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 16px 16px; }
.fiche-lien-plateforme { display: inline-flex; align-items: center; min-height: 40px; padding: 8px 16px; border-radius: var(--rayon-sm); background: var(--carte2); border: 1px solid var(--bord); color: var(--vert); font-size: 0.8rem; font-weight: 600; text-decoration: none; }
.fiche-lien-plateforme:active { opacity: 0.8; }
/* OÙ EN EST CET OBJET, une ligne par plateforme. Le motif de l'encart en
   liseré : attirer l'œil sans crier, la couleur portant l'état. Ce n'est pas
   une cible tactile — rien ne s'y clique, le lien de l'annonce est juste
   au-dessus — mais la ligne garde 40 px de haut : elle se lit à bout de bras,
   une main tenant l'objet. Le gris est l'état par défaut, et c'est voulu :
   « pas encore en ligne » n'est ni un succès ni une panne à ses yeux. */
.fiche-etats-plateformes { display: flex; flex-direction: column; gap: 4px; padding: 0 16px 16px; }
.fiche-etats-titre { font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--texte-doux); margin-bottom: 4px; }
.fiche-etat-plateforme { display: flex; align-items: center; min-height: 40px; padding: 8px 12px; background: var(--carte); border: 1px solid var(--bord); border-left: 3px solid var(--texte-tres-doux); border-radius: 0 var(--rayon-sm) var(--rayon-sm) 0; font-size: 0.8rem; color: var(--texte); }
.fiche-etat-plateforme--en_ligne { border-left-color: var(--vert); }
/* « déposée » se peint comme « en ligne », en vert : le dépôt est un fait
   atteint, et le ranger avec les annonces arrêtées serait une seconde erreur.
   C'est le mot qui change, pas le jugement (docs/etat-de-diffusion.md), et la
   même règle tient déjà pour le badge de la liste (.lot-sous-plat.en-ligne). */
.fiche-etat-plateforme--deposee { border-left-color: var(--vert); }
/* Arrêtées : ni vert ni rouge. Une pause n'est pas une panne, c'est un geste
   voulu ; le gris clair les distingue de ce qui n'est jamais parti, qui garde
   le --texte-tres-doux par défaut. Même couleur que .lot-sous-plat.arretee. */
.fiche-etat-plateforme--en_pause { border-left-color: var(--texte-doux); }
.fiche-etat-plateforme--retiree { border-left-color: var(--texte-doux); }
.fiche-etat-plateforme--en_cours { border-left-color: var(--or); }
.fiche-etat-plateforme--bloque { border-left-color: var(--rouge); }
.decision-segment { display: grid; grid-template-columns: repeat(5, 1fr); gap: 4px; padding: 0 16px 16px; }
.seg-btn { padding: 10px 4px; border-radius: var(--rayon-sm); font-size: 0.75rem; font-weight: 700; text-align: center; transition: all 0.15s; border: 2px solid transparent; color: var(--texte-doux); background: var(--carte2); }
.seg-btn.active-vendre { border-color: var(--vert); color: var(--vert); background: #162016; }
.seg-btn.active-donner { border-color: var(--bleu); color: var(--bleu); background: #0f1e2e; }
.seg-btn.active-jeter { border-color: var(--rouge); color: var(--rouge); background: #2e100e; }
.seg-btn.active-garder { border-color: var(--or); color: var(--or); background: #1e1a0a; }
.champ-fiche { padding: 0 16px 14px; }
.champ-fiche label { display: block; font-size: 0.75rem; color: var(--texte-doux); margin-bottom: 5px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; }
.rangee-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; padding: 0 16px 14px; }
.rangee-2 .champ-fiche { padding: 0; }
.rendement-affiche { background: var(--carte2); border-radius: var(--rayon-sm); padding: 10px 12px; margin: 0 16px 14px; font-size: 0.85rem; color: var(--texte-doux); }
.rendement-affiche strong { color: var(--texte); }
.info-arbitrage { background: #2e1a0a; border-left: 3px solid var(--or); border-radius: 0 var(--rayon-sm) var(--rayon-sm) 0; padding: 10px 12px; margin: 0 16px 14px; font-size: 0.8rem; color: var(--or-pale); }

/* ── Conseil arbitrage (consultatif) ── */
.zone-conseil { background: var(--carte2); border: 1px solid var(--bord); border-radius: var(--rayon-sm); padding: 10px 12px; margin: 0 16px 14px; }
.conseil-texte { font-size: 0.8rem; color: var(--texte-doux); }
.btn-basculer-don { margin-top: 8px; padding: 7px 14px; background: #0f1e2e; border: 1px solid var(--bleu); color: var(--bleu); border-radius: var(--rayon-sm); font-size: 0.8rem; font-weight: 600; }

/* ── Ticket 141 : la décision qui interdit la publication ──
   Fond « garder-or » et liseré or : c'est une décision tenue, pas une erreur,
   donc ni le rouge de l'échec ni le vert de la vente. Le bouton, lui, porte le
   vert de « vendre » : c'est là qu'il mène. 44 px comme « C'est donné ». */
.zone-decision-tenue { background: #1e1a0a; border-left: 3px solid var(--or); border-radius: 0 var(--rayon-sm) var(--rayon-sm) 0; padding: 12px; }
.decision-tenue-texte { font-size: 0.85rem; color: var(--texte-doux); margin-bottom: 12px; }
.btn-vendre-finalement { background: #162016; border: 2px solid var(--vert); color: var(--vert); border-radius: var(--rayon-sm); padding: 12px 16px; min-height: 44px; font-size: 0.9rem; font-weight: 700; cursor: pointer; width: 100%; }

/* ── Statut LBC ── */
.zone-lbc-status { background: #141e14; border-left: 3px solid var(--vert); border-radius: 0 var(--rayon-sm) var(--rayon-sm) 0; padding: 10px 12px; margin: 0 16px 10px; }
.lbc-status-header { font-size: 0.8rem; font-weight: 700; color: var(--vert); margin-bottom: 3px; }
.lbc-status-nom { font-size: 0.78rem; color: var(--texte-doux); font-family: monospace; }
.lbc-status-date { font-size: 0.72rem; color: var(--texte-tres-doux); margin-top: 2px; }

/* ── Plateformes chips ── */
.plateformes-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.plat-chip { padding: 7px 14px; border-radius: 999px; font-size: 0.8rem; font-weight: 600; border: 2px solid var(--bord); color: var(--texte-doux); background: var(--carte2); transition: all 0.15s; }
.plat-chip.actif { border-color: var(--or); color: var(--or); background: #1e1a0a; }

.qcm-section { padding: 0 16px 16px; }
.qcm-titre { font-size: 0.8rem; font-weight: 700; color: var(--texte-doux); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 10px; }
.qcm-question { margin-bottom: 14px; }
.qcm-q { font-size: 0.9rem; margin-bottom: 8px; }
.qcm-options { display: flex; flex-direction: column; gap: 6px; }
.qcm-opt { background: var(--carte2); border: 2px solid var(--bord); border-radius: var(--rayon-sm); padding: 10px 14px; font-size: 0.85rem; text-align: left; color: var(--texte); transition: all 0.15s; }
.qcm-opt.selected { border-color: var(--or); color: var(--or); background: #1e1a0a; }

/* ── Questions bloquantes (ticket du 9 septembre 2026) ───────────────────────
   Le parcours qui remplace le bouton « Publier » tant qu'une question attend.
   Une question par écran, un bouton par réponse : 56 px de haut, bien au-dessus
   des 40 px du minimum, parce qu'on y répond d'une main en tenant l'objet. Les
   vignettes sont dans les boutons — c'est l'humain qui désigne la photo, on ne
   la devine pas depuis un motif. Aucune couleur hors palette. */
.q-progres { font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--texte-doux); font-family: ui-monospace, 'Courier New', monospace; font-variant-numeric: tabular-nums; }
.q-texte { font-size: 1.1rem; font-weight: 600; line-height: 1.4; margin: 8px 0 4px; }
.q-aide { font-size: 0.8rem; color: var(--texte-doux); font-style: italic; margin-bottom: 4px; }
.q-choix { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }
.q-opt { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 56px; background: var(--carte2); border: 1px solid var(--bord); border-radius: var(--rayon); padding: 12px 14px; font-size: 0.95rem; font-weight: 700; color: var(--texte); text-align: left; }
.q-opt:active { background: var(--carte); border-color: var(--or); }
.q-opt-vignette { width: 56px; height: 56px; min-width: 56px; border-radius: var(--rayon-sm); object-fit: cover; background: var(--carte); }
.q-opt-sous { display: block; font-size: 0.75rem; font-weight: 400; color: var(--texte-doux); margin-top: 2px; }
/* ── Ticket 20 : la question montre ses photos ───────────────────────────────
   Le titre de l'objet au-dessus des vignettes (on arbitre entre un titre et
   des photos : il faut voir les deux), le rang de la photo sur la vignette, et
   la case a cocher. Le rang est en chiffres tabulaires comme tout nombre
   comparable (DESIGN.md, « rang de photo ») : c'est le meme comptage que le
   motif du controle photo, a partir de zero. */
.q-objet-titre { padding: 16px 16px 0; font-size: 0.9rem; font-weight: 700; color: var(--texte); }
.q-photo { position: relative; }
.q-photo-num {
  position: absolute; left: 4px; bottom: 4px;
  padding: 2px 6px; border-radius: var(--rayon-sm);
  background: rgba(0,0,0,0.65); color: var(--texte);
  font-size: 0.7rem; font-weight: 700;
  font-family: ui-monospace, 'Courier New', monospace; font-variant-numeric: tabular-nums;
}
.q-photo-motif { margin-top: 4px; font-size: 0.7rem; color: var(--texte-tres-doux); line-height: 1.3; }
/* La case fait partie de la cible tactile du bouton entier (56 px de haut) :
   on coche une photo d'une main, l'autre tenant l'objet. */
.q-case {
  flex-shrink: 0; width: 24px; height: 24px; border-radius: 6px;
  border: 2px solid var(--bord); background: var(--carte);
  display: flex; align-items: center; justify-content: center;
  font-size: 0.8rem; font-weight: 700; color: var(--fond);
}
.q-opt-coche--oui { border-color: var(--or); background: #1e1a0a; }
.q-opt-coche--oui .q-case { background: var(--or); border-color: var(--or); }
/* « Coche au moins une photo » : le bouton existe, il dit ce qui manque. Le
   griser sans le dire ferait chercher. */
.q-valider { margin-top: 16px; }
.q-valider:disabled { opacity: 0.55; }
/* Deja dans la gouttiere de 16 px de la page : le padding de
   .fiche-liens-plateformes ferait un decalage de 32 px. */
.q-liens { padding: 0; margin-top: 12px; }
.q-libre { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }
.q-fin { display: flex; flex-direction: column; gap: 12px; }
.q-fin-titre { font-size: 1.1rem; font-weight: 600; }
.q-fin-sous { font-size: 0.8rem; color: var(--texte-doux); }
/* Le bouton qui remplace « Publier » sur la fiche. Il n'est ni grisé ni caché
   ailleurs : il est REMPLACÉ, pour que la marche à suivre soit évidente. Fond
   de carte et liseré or — c'est un chemin, pas une erreur, et pas encore
   l'action finale, qui garde l'aplat or. */
.btn-questions-fiche { background: #1e1a0a; border: 1px solid var(--or); color: var(--or); border-radius: var(--rayon); padding: 15px; font-size: 0.95rem; font-weight: 700; width: 100%; min-height: 40px; }
.btn-questions-fiche:active { background: var(--carte2); }
/* ── Terminer un objet (ticket 129) ──────────────────────────────────────────
   Remplace la grille .sortie-section de quatre boutons, dont deux portaient des
   classes (.sortie-direct, .sortie-ailleurs) qui n'ont jamais existe dans cette
   feuille : la moitie de la rangee etait sans style. Une seule porte, qui
   demande la raison dans une modale. Cibles a 48 px : on clot un objet d'une
   main, l'autre tenant l'objet. */
.zone-terminer { padding: 0 16px; margin-bottom: 16px; }
#overlay-terminer .modale { max-height: 88vh; overflow-y: auto; }
.terminer-intro { font-size: 0.85rem; color: var(--texte-doux); margin-bottom: 12px; }
.terminer-choix { display: grid; gap: 8px; }
/* `.enlever-btn` (ticket 134) partage l'apparence de `.terminer-btn` sans
   partager son nom : `querySelectorAll('.terminer-btn')` deselectionne toute la
   modale « Terminer », et deux modales sous le meme selecteur se decochent
   l'une l'autre. Meme dessin, deux familles. */
.terminer-btn, .enlever-btn { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%; min-height: 48px; padding: 12px; text-align: left; background: var(--carte2); border: 2px solid var(--bord); border-radius: var(--rayon-sm); color: var(--texte); font-size: 0.9rem; font-weight: 700; }
.terminer-btn span, .enlever-btn span { font-size: 0.75rem; font-weight: 400; color: var(--texte-tres-doux); }
.terminer-btn.selected, .enlever-btn.selected { border-color: var(--or); color: var(--or); background: #1e1a0a; }
.terminer-note { font-size: 0.75rem; color: var(--texte-tres-doux); margin-top: 6px; }
/* L'encart en lisere : attirer l'oeil sans crier. Les annonces qui restent en
   ligne apres la cloture sont le seul point de cette modale qui puisse couter
   de l'argent, elles ne peuvent pas etre en gris discret. */
.terminer-avert { font-size: 0.85rem; color: var(--or-pale); background: #1e1a0e; border-left: 3px solid var(--or); border-radius: 0 var(--rayon-sm) var(--rayon-sm) 0; padding: 10px 12px; }
/* La sortie deja posee, la ou etait le bouton « Terminer » : ce qu'il est
   advenu de l'objet, et la porte de retour si on s'est trompe. En gris doux,
   pas en alerte — un objet donne n'est pas un incident. */
.sortie-faite { display: flex; flex-direction: column; gap: 8px; }
.sortie-faite-texte { font-size: 0.8rem; color: var(--texte-doux); }
.issue-badge { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 999px; font-size: 0.75rem; font-weight: 700; margin: 0 16px 14px; }
.issue-vendu { background: #1a3a1a; color: var(--vert); }
.issue-donne { background: #0f1e2e; color: var(--bleu); }
.issue-jete { background: #3a1a1a; color: var(--rouge); }
/* `.issue-retire` manquait depuis le ticket 129 : majBadgeIssue posait la
   classe, la feuille ne la connaissait pas, et « Retiré » sortait sans fond,
   seule pastille des quatre a ne pas se lire comme une pastille. Fond garder-or
   du DESIGN.md. */
.issue-retire { background: #1e1a0a; color: var(--or); }
.divider { border: none; border-top: 1px solid var(--bord); margin: 8px 0; }
.fusionner-bar { position: fixed; bottom: 72px; left: 16px; right: 16px; background: var(--or); color: #12100e; border-radius: var(--rayon); padding: 14px 16px; display: flex; align-items: center; justify-content: space-between; font-weight: 700; z-index: 50; box-shadow: 0 -4px 20px rgba(0,0,0,0.5); }
.fusionner-bar button { background: #12100e; color: var(--or); border: none; border-radius: var(--rayon-sm); padding: 8px 16px; font-weight: 700; font-size: 0.85rem; }
.vide-etat { padding: 40px 16px; text-align: center; color: var(--texte-tres-doux); font-size: 0.9rem; }

/* ── v4 : lotir ── */
.etiquette-lotir { background: #2a1a3a; color: #b87fe8; }
.seg-btn.active-lotir { border-color: #b87fe8; color: #b87fe8; background: #1a0e2e; }

/* ── v4 : bandeau analyses bas ── */
#bandeau-analyses { position: fixed; bottom: 72px; left: 0; right: 0; background: rgba(18,16,14,0.97); border-top: 1px solid var(--bord); padding: 8px 14px; display: none; align-items: center; gap: 10px; z-index: 95; }
.bandeau-analyses-vign { width: 32px; height: 32px; border-radius: 5px; object-fit: cover; flex-shrink: 0; }
.bandeau-analyses-txt { flex: 1; font-size: 0.78rem; color: var(--texte-doux); }

/* ── v4 : À valider ── */
.aval-carte { background: var(--carte); border-radius: var(--rayon); border: 1px solid var(--or); padding: 14px 16px; display: flex; align-items: center; gap: 12px; cursor: pointer; margin-bottom: 0; }
.aval-nb { font-size: 1.2rem; font-weight: 700; color: var(--or); flex-shrink: 0; }
.aval-info { flex: 1; }
.aval-titre { font-size: 0.9rem; font-weight: 600; }
.aval-sous { font-size: 0.75rem; color: var(--texte-doux); margin-top: 2px; }

/* ── v4 : pistes ── */
.piste-carte { background: var(--carte); border-radius: var(--rayon); border: 1px solid var(--bord); padding: 12px; border-left: 3px solid var(--bord); }
.piste-carte.interet-fort { border-left-color: var(--or); }
.piste-carte.interet-moyen { border-left-color: var(--bleu); }
.piste-carte.interet-faible { border-left-color: var(--texte-tres-doux); }
.piste-libelle { font-size: 0.9rem; font-weight: 600; margin-bottom: 4px; }
.piste-justif { font-size: 0.78rem; color: var(--texte-doux); margin-bottom: 8px; }
.piste-actions { display: flex; gap: 8px; align-items: center; }
.btn-piste-photo { background: var(--or); color: #12100e; border: none; border-radius: var(--rayon-sm); padding: 6px 12px; font-size: 0.8rem; font-weight: 700; cursor: pointer; }
.btn-piste-suppr { background: none; border: 1px solid var(--bord); color: var(--texte-tres-doux); border-radius: var(--rayon-sm); padding: 6px 10px; font-size: 0.75rem; cursor: pointer; }

/* ── v4 : réserve (lotir) ── */
.reserve-carte { background: #1a0e2e; border: 1px solid #3a2a5a; border-radius: var(--rayon); padding: 14px 16px; }
.reserve-famille { font-size: 0.9rem; font-weight: 700; color: #b87fe8; margin-bottom: 4px; }
.reserve-nb { font-size: 0.78rem; color: var(--texte-doux); }
.btn-constituer-lot { background: #b87fe8; color: #12100e; border: none; border-radius: var(--rayon-sm); padding: 8px 14px; font-size: 0.8rem; font-weight: 700; margin-top: 10px; cursor: pointer; width: 100%; }

/* ── v4 : plateformes suggestion ── */
.plat-suggestion-msg { font-size: 0.72rem; color: var(--texte-tres-doux); font-style: italic; margin-top: 4px; }

/* ── Ticket 126 : pourquoi cet objet n'est pas sur les trois plateformes ──
   Encart en lisere, le motif deja employe pour l'arbitrage et le statut LBC.
   Gris pour une exclusion motivee (c'est un fait range), or pour une absence
   sans raison ecrite (c'est une anomalie, elle doit accrocher l'oeil). */
.exclusion-ligne { font-size: 0.75rem; color: var(--texte-doux); background: var(--carte2);
  border-left: 3px solid var(--bord); border-radius: 0 var(--rayon-sm) var(--rayon-sm) 0;
  padding: 8px 12px; margin-top: 8px; }
.exclusion-par { color: var(--texte-tres-doux); font-style: italic; }
.exclusion-manque { font-size: 0.75rem; color: var(--or-pale); background: #1e1a0e;
  border-left: 3px solid var(--or); border-radius: 0 var(--rayon-sm) var(--rayon-sm) 0;
  padding: 8px 12px; margin-top: 8px; }

/* ── Ticket 144 : le label « main propre uniquement » ──
   Une case a cocher pleine largeur, pas une case de formulaire : la fiche
   s'utilise au telephone, une main tenant l'objet, et 44 px de hauteur utile
   sont le minimum pour ne pas la rater. Inactive elle est neutre (--carte2),
   active elle prend l'or, comme toute selection de ce produit. */
.label-remise { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 44px;
  text-align: left; background: var(--carte2); border: 1px solid var(--bord);
  border-radius: var(--rayon-sm); padding: 12px; color: var(--texte); cursor: pointer; }
.label-remise:active { opacity: 0.8; }
.label-remise.actif { border-color: var(--or); background: #1e1a0a; }
.label-remise-case { font-size: 1.1rem; line-height: 1; color: var(--texte-tres-doux); }
.label-remise.actif .label-remise-case { color: var(--or); }
.label-remise-texte { display: block; }
.label-remise-titre { display: block; font-size: 0.85rem; font-weight: 600; }
.label-remise.actif .label-remise-titre { color: var(--or-pale); }
.label-remise-sous { display: block; font-size: 0.75rem; color: var(--texte-tres-doux); margin-top: 2px; }
/* La proposition, ticket 144 : elle PROPOSE, elle ne coche rien. Encart en
   lisere or, le motif deja employe pour l'arbitrage. */
.suggestion-remise { font-size: 0.75rem; color: var(--or-pale); background: #1e1a0e;
  border-left: 3px solid var(--or); border-radius: 0 var(--rayon-sm) var(--rayon-sm) 0;
  padding: 8px 12px; margin-top: 8px; }
.suggestion-remise .btn-suggestion-remise { display: inline-flex; align-items: center; min-height: 40px;
  margin-top: 8px; background: var(--carte2); border: 1px solid var(--bord);
  border-radius: var(--rayon-sm); padding: 8px 14px; font-size: 0.8rem; font-weight: 600;
  color: var(--texte); cursor: pointer; }

/* ── v4 : commentaire photo ── */
.btn-reecrire { display: inline-block; margin-top: 6px; background: var(--carte2); border: 1px solid var(--bord); border-radius: var(--rayon-sm); padding: 8px 14px; font-size: 0.8rem; font-weight: 600; color: var(--texte-doux); cursor: pointer; }
.btn-reecrire:disabled { opacity: 0.5; }

/* ── v4 : overlay méthode ── */

/* ── Réglages ── */
.texte-info { font-size: 0.85rem; color: var(--texte-doux); line-height: 1.5; margin-bottom: 20px; }

/* ── Connexion ── */
.connexion-page { min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 32px 24px; }
.connexion-logo { font-size: 3rem; margin-bottom: 8px; }
.connexion-titre { font-size: 1.6rem; font-weight: 700; margin-bottom: 6px; }
.connexion-sous { color: var(--texte-doux); margin-bottom: 32px; font-size: 0.9rem; }
.connexion-form { width: 100%; max-width: 360px; }
.connexion-input { font-size: 1.1rem; text-align: center; letter-spacing: 0.1em; margin-bottom: 16px; }
.erreur-msg { color: var(--rouge); font-size: 0.85rem; text-align: center; margin-top: 12px; min-height: 20px; }

/* ── Toast ── */
.toast { position: fixed; top: 24px; left: 50%; transform: translateX(-50%); background: var(--carte2); border: 1px solid var(--bord); border-radius: var(--rayon); padding: 12px 20px; font-size: 0.85rem; z-index: 200; opacity: 0; transition: opacity 0.3s; pointer-events: none; white-space: nowrap; max-width: 90vw; text-overflow: ellipsis; overflow: hidden; }
.toast.visible { opacity: 1; }

/* ── Modale ── */
.overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.7); z-index: 150; display: flex; align-items: flex-end; justify-content: center; padding: 0; }
.overlay.hidden { display: none; }
.modale { background: var(--carte); border-radius: var(--rayon) var(--rayon) 0 0; padding: 24px; width: 100%; max-width: 480px; }
.modale h2 { margin-bottom: 16px; }
.modale-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 16px; }

/* ── Validation session ── */
.validation-header { padding: 20px 16px 12px; }
.validation-header h2 { font-size: 1.1rem; }
.validation-sous { font-size: 0.8rem; color: var(--texte-doux); margin-top: 2px; }

/* ── v5 : pastilles statut publication ── */
.pastille { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: 4px; font-size: 0.65rem; font-weight: 700; text-decoration: none; }
.pastille-grise { background: #2a2825; border: 1px solid var(--bord); color: var(--texte-tres-doux); }
.pastille-orange { background: #2e1e0a; border: 1px solid #8a5a20; color: #e8902a; }
.pastille-verte { background: #1a3a1a; border: 1px solid #3a6a3a; color: var(--vert); }
.pastille-rouge { background: #2e1010; border: 1px solid #6a2020; color: var(--rouge); cursor: help; }

/* ── v5 : section Prêts avec bouton Publier ── */
.section-prets-actions { display: flex; align-items: center; gap: 8px; padding: 0 16px 10px; }
.btn-tout-publier { background: var(--or); color: #12100e; border: none; border-radius: var(--rayon-sm); padding: 8px 16px; font-size: 0.8rem; font-weight: 700; cursor: pointer; }
.btn-publier-lot { background: var(--or); color: #12100e; border: none; border-radius: var(--rayon-sm); padding: 5px 10px; font-size: 0.7rem; font-weight: 700; cursor: pointer; flex-shrink: 0; }
/* .lot-carte-actions masqué v28 — voir règle principale */

/* ── v5 : état file sur accueil ── */
.file-statut { background: var(--carte); border: 1px solid var(--bord); border-radius: var(--rayon-sm); padding: 10px 14px; margin: 0 16px 10px; font-size: 0.78rem; color: var(--texte-doux); display: flex; align-items: center; gap: 8px; }
.file-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--texte-tres-doux); flex-shrink: 0; }
.file-dot.actif { background: var(--orange, #e8902a); animation: pulse 1.5s infinite; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }

/* ── v5 : auto-save indicator ── */
.autosave-ok { position: fixed; bottom: 90px; left: 50%; transform: translateX(-50%); background: var(--vert); color: white; border-radius: 999px; padding: 4px 12px; font-size: 0.75rem; opacity: 0; transition: opacity 0.3s; pointer-events: none; z-index: 180; }
.autosave-ok.visible { opacity: 1; }
.autosave-err { background: var(--carte2); border: 1px solid var(--rouge); border-radius: var(--rayon-sm); padding: 8px 14px; margin: 0 16px 14px; font-size: 0.78rem; color: var(--rouge); display: none; }

/* ── v5 : bouton Publier dans la fiche ── */
.btn-publier-fiche { background: var(--or); color: #12100e; border: none; border-radius: var(--rayon); padding: 15px; font-size: 0.95rem; font-weight: 700; width: 100%; cursor: pointer; }

/* « Ne pas mettre en vente finalement » : la même boîte que le bouton doré
   au-dessus — mêmes rayon, padding, graisse et pleine largeur, donc la même
   hauteur sous le pouce — sur le noir du fond plutôt que sur un aplat d'or.
   Le noir demandé est celui de la page (--fond), pas une couleur de plus : la
   bordure est ce qui garde le bouton trouvable une fois la couleur enlevée.
   Il reste à 40 px au moins par son padding de 15, comme tous les boutons
   pleine largeur de cette fiche. */
.btn-ne-pas-vendre { background: var(--fond); color: var(--texte-doux); border: 1px solid var(--bord); border-radius: var(--rayon); padding: 15px; font-size: 0.95rem; font-weight: 700; width: 100%; min-height: 40px; cursor: pointer; }
.btn-ne-pas-vendre:active { opacity: 0.8; }

/* ── v6 : lot non revu — liseré discret ── */
.lot-carte.non-revu { border-left: 3px solid var(--or); }


/* ── v6 : bouton Valider (marquer revu) ── */
.btn-valider-revu { background: var(--carte2); border: 1px solid var(--or); color: var(--or); border-radius: var(--rayon-sm); padding: 8px 16px; font-size: 0.82rem; font-weight: 600; cursor: pointer; width: 100%; }
/* ── ticket 128 : « C'est donné ». Couleurs du don (fond teinté + --bleu),
   44 px de haut : c'est une action principale, faite au téléphone. ── */
.btn-cest-donne { background: #0f1e2e; border: 2px solid var(--bleu); color: var(--bleu); border-radius: var(--rayon-sm); padding: 12px 16px; min-height: 44px; font-size: 0.9rem; font-weight: 700; cursor: pointer; width: 100%; }
/* ── v6 : bouton Tout valider ── */
.btn-tout-valider { background: var(--carte2); border: 1px solid var(--or); color: var(--or); border-radius: 999px; padding: 5px 12px; font-size: 0.75rem; font-weight: 600; cursor: pointer; flex-shrink: 0; }
/* ── v6 : barre annulation tout-valider ── */
.undo-revu-bar { position: fixed; bottom: 70px; left: 50%; transform: translateX(-50%); background: var(--carte2); border: 1px solid var(--bord); border-radius: var(--rayon); padding: 8px 16px; font-size: 0.8rem; color: var(--texte-doux); z-index: 199; opacity: 0; transition: opacity 0.3s; pointer-events: none; white-space: nowrap; }
.undo-revu-bar.visible { opacity: 1; pointer-events: auto; }
.undo-revu-bar a { color: var(--or); cursor: pointer; text-decoration: underline; margin-left: 6px; }

/* ── v6 : pastille a_verifier ── */
.pastille-jaune { background: #2e2000; border: 1px solid #7a5800; color: #d4a000; }

/* ── v8 : liens annonces ── */
.lien-annonce { display: flex; align-items: center; gap: 8px; padding: 10px 14px; background: var(--carte2); border: 1px solid var(--bord); border-radius: var(--rayon-sm); text-decoration: none; color: var(--texte); font-size: 0.85rem; font-weight: 600; }
.lien-annonce:hover { border-color: var(--or); }
.lien-annonce-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--vert); flex-shrink: 0; }
.lien-annonce-nom { flex: 1; }
/* L'etat d'une annonce et l'histoire de ses retraits : du texte tertiaire, au
   meme rang que les prix et les dates (DESIGN.md). Ces lignes existaient sans
   regle et prenaient donc la taille du corps, ce qui les mettait au meme poids
   que les liens qu'elles commentent. La couleur d'un geste en cours ou en
   echec est posee en ligne par app.js : elle porte l'etat, pas la hierarchie. */
.annonce-etat { font-size: 0.8rem; color: var(--texte-tres-doux); }

/* ── v8 : page micro ── */
#p-micro.active { background: #0a0908; }
.micro-page { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; padding: 32px 24px; gap: 24px; text-align: center; }
.micro-titre { font-size: 1.2rem; font-weight: 700; }
.micro-sous { font-size: 0.9rem; color: var(--texte-doux); max-width: 320px; }
.micro-btn { width: 96px; height: 96px; border-radius: 50%; background: var(--rouge); border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background 0.15s, transform 0.1s; }
.micro-btn:active { transform: scale(0.95); }
.micro-btn.enregistrement { background: #8b1a1a; box-shadow: 0 0 0 8px rgba(196,112,95,0.25); animation: pulse 1s infinite; }
.micro-btn svg { width: 40px; height: 40px; fill: white; stroke: none; }
.micro-etat { font-size: 0.85rem; color: var(--texte-doux); min-height: 1.5em; }
.micro-fallback { width: 100%; max-width: 360px; }
.micro-actions { display: flex; flex-direction: column; gap: 10px; width: 100%; max-width: 360px; }

/* ── v12 : bouton sortie-ailleurs ── */
.sortie-ailleurs { background: #1a1200; border: 1.5px solid #6b5000; color: #c8a000; }
.sortie-ailleurs:hover { background: #241900; }
/* ── v26 : bouton vendu en direct ── */
.sortie-direct { background: #0d1f0d; border: 1.5px solid var(--vert); color: var(--vert); }
.sortie-direct:hover { background: #122012; }

/* ── v12 : badge retiré ── */
.issue-retire { background: #1a1a1a; border-color: #555; color: #aaa; }

/* ── v12 : section À confirmer ── */
.confirmer-carte { background: #1a1200; border: 1.5px solid #6b5000; border-radius: var(--rayon); padding: 14px 16px; margin: 4px 16px 8px; }
.confirmer-titre { font-size: 0.9rem; font-weight: 600; margin-bottom: 6px; }
.confirmer-lien { font-size: 0.78rem; color: var(--or); text-decoration: none; display: block; margin-bottom: 10px; }
.confirmer-lien:hover { text-decoration: underline; }
.confirmer-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.confirmer-btn { padding: 6px 12px; border-radius: 999px; font-size: 0.78rem; font-weight: 600; border: 1.5px solid; cursor: pointer; background: none; }
.confirmer-vendu { border-color: var(--vert); color: var(--vert); }
.confirmer-retire { border-color: #6b5000; color: #c8a000; }
.confirmer-expire { border-color: var(--bord); color: var(--texte-doux); }

/* ── v8 : page post-analyse ── */
.postanalyse-page { display: flex; flex-direction: column; gap: 12px; padding: 16px; }
.postanalyse-lot { background: var(--carte); border: 1px solid var(--bord); border-radius: var(--rayon); padding: 14px; margin-bottom: 4px; }
.postanalyse-lot-titre { font-size: 0.9rem; font-weight: 600; }
.postanalyse-lot-actions { display: flex; gap: 8px; margin-top: 10px; }

/* ── v14 : confirmer inline dans carte ── */
.confirmer-inline { border-top: 1px solid var(--bord); padding: 6px 12px 8px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.confirmer-inline-label { font-size: 0.72rem; color: var(--texte-doux); }
.confirmer-btn-sm { background: none; border: 1px solid var(--bord); color: var(--texte-doux); font-size: 0.68rem; padding: 2px 7px; border-radius: 4px; cursor: pointer; }
.confirmer-btn-sm:hover { border-color: var(--or); color: var(--or); }


/* Numero de version, discret, sur la meme ligne que le titre de l'accueil */
.version-entete {
  font-size: 0.58em;
  font-weight: 400;
  letter-spacing: 0.05em;
  color: var(--texte-doux, #8a8078);
  opacity: 0.7;
  margin-left: 3px;
  vertical-align: baseline;
  user-select: none;
  white-space: nowrap;
}

/* ── v16 : commission visible ── */
.sv-commission-mention { font-size: 0.78rem; color: var(--texte-doux); line-height: 1.5; text-align: left; margin: 8px 0 4px; }
.lot-prix-bloc { display: inline-flex; flex-direction: column; gap: 0; }
.preview-net-prix { font-size: 0.75rem; color: var(--texte-doux); margin-top: 4px; min-height: 1.2em; }

/* ── v18 : bandeau mise à jour disponible ── */
#bandeau-maj { display: none; position: fixed; top: 0; left: 0; right: 0; z-index: 9999; background: var(--or, #c8a000); color: #12100e; text-align: center; padding: 10px 16px; font-size: 0.85rem; font-weight: 600; cursor: pointer; }

/* ── v20 : archiver lot ── */
.btn-archiver { font-size: 0.72rem; color: var(--texte-tres-doux); background: none; border: 1px solid var(--bord); border-radius: var(--rayon-sm); padding: 3px 10px; cursor: pointer; }
.btn-archiver:active { opacity: 0.6; }

/* LE BOUTON « Archiver » APPARTIENT A L'OBJET DU DESSUS, ET ÇA DOIT SE VOIR.
   Le filet de separation des lignes d'objet est un `::after` au bas de
   `.lot-carte` : pose apres la ligne, le bouton se retrouvait sous le filet,
   donc visuellement rattache a l'objet SUIVANT — Laurent, le 12 septembre
   2026 : « on a l'impression qu'il archive l'objet du dessous ». L'enveloppe
   reunit la ligne et son bouton, eteint le filet de la ligne et le reprend a
   son bas, sous le bouton. Meme gouttiere (16 px) et meme depart de filet
   (78 px, aligne sous le texte et non sous la vignette) : l'ensemble se lit
   comme un seul bloc a 400 px comme a 1200. */
.ligne-terminee { position: relative; }
.ligne-terminee > .lot-carte:not(:last-child)::after { content: none; }
.ligne-terminee > .lot-carte { padding-bottom: 4px; }
.ligne-terminee-actions { display: flex; justify-content: flex-end; padding: 0 16px 8px; }
.ligne-terminee:not(:last-child)::after { content: ''; position: absolute; bottom: 0; left: 78px; right: 0; height: 1px; background: var(--bord); }
.section-archive-toggle:hover { opacity: 0.8; }

/* ── v21 : bandeau urgences ── */
.urgence-bandeau { display: flex; align-items: flex-start; gap: 10px; background: #7b1a1a; color: #fff; padding: 12px 16px; margin: 0 0 2px; border-left: 4px solid #e53e3e; }
.urgence-icone { font-size: 1.1rem; flex-shrink: 0; margin-top: 1px; }
.urgence-texte { flex: 1; font-size: 0.9rem; font-weight: 600; line-height: 1.4; }
.urgence-lien { font-size: 0.78rem; color: #fbd38d; white-space: nowrap; text-decoration: underline; flex-shrink: 0; margin-top: 2px; }

/* ── v22 : vue opérateur ── */
.lien-operateur { font-size: 0.78rem; color: var(--texte-tres-doux); text-decoration: none; }
.lien-operateur:hover { color: var(--or); }

/* ── v24 : pastilles navigation par état ── */
.pastilles-etat-bar { display: flex; gap: 6px; padding: 0 16px 10px; flex-wrap: wrap; }
.pastille-etat { padding: 4px 12px; border-radius: 999px; font-size: 0.75rem; font-weight: 600; background: var(--carte2); border: 1px solid var(--bord); color: var(--texte-doux); cursor: pointer; transition: all 0.15s; font-family: inherit; }
.pastille-etat:not(.inactive):not(.actif):hover { border-color: var(--or); color: var(--or); }
.pastille-etat.actif { background: var(--or); color: #12100e; border-color: var(--or); }
.pastille-etat.inactive { color: var(--texte-tres-doux); cursor: default; }

/* ── v28 : entête accueil ── */
.entete-accueil { padding: 14px 16px 8px; display: flex; align-items: center; gap: 8px; }
.entete-nom { font-size: 1.05rem; font-weight: 700; flex: 1; }
.badge-initial { width: 32px; height: 32px; border-radius: 50%; background: var(--carte2); border: 1px solid var(--bord); color: var(--texte-doux); font-size: 0.8rem; font-weight: 700; display: flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0; font-family: inherit; }
.badge-initial:active { border-color: var(--or); }

/* ── v28 : alerte action ── */
#zone-alerte:not(:empty) { padding: 0 16px 10px; }
.alerte-action { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-left: 3px solid var(--or); background: #1e1a0e; border-radius: 0 var(--rayon-sm) var(--rayon-sm) 0; cursor: pointer; }
.alerte-action:active { background: #282010; }
/* Une ligne d'action sans adresse ou aller : elle informe, elle n'ouvre rien.
   Le serveur retire l'adresse de celles qu'il envoie a un deposant, nos comptes
   de plateforme ne s'ouvrant pas chez lui (lib/gestes-deposant.mjs). La main du
   curseur promettait un ailleurs qui n'existe pas ; la fleche, elle, est retiree
   par app.js, une fleche vide se lisant encore comme un lien. */
.alerte-action--info { cursor: default; }
.alerte-action--info:active { background: #1e1a0e; }
.alerte-action-texte { flex: 1; min-width: 0; }
.alerte-action-titre { font-size: 0.85rem; font-weight: 600; color: var(--or); }
.alerte-action-detail { font-size: 0.75rem; color: var(--texte-doux); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.alerte-action-fleche { color: var(--or); font-size: 1rem; flex-shrink: 0; }

/* ── v28 : onglets dossier ── */
.onglets-wrapper { padding: 0 16px 0; }
.onglets-rangee { display: flex; align-items: flex-end; }
.onglets-rangee2 { margin-top: -2px; position: relative; z-index: 2; }
.onglets-rangee1 { position: relative; z-index: 1; }
.onglet { padding: 7px 10px; border-radius: 11px 11px 0 0; border: 1px solid var(--bord); border-bottom: none; background: var(--carte2); color: var(--texte-tres-doux); font-size: 0.72rem; font-weight: 600; cursor: pointer; font-family: inherit; margin-left: -10px; position: relative; white-space: nowrap; }
.onglet:first-child { margin-left: 0; }
.onglet:not(.actif):not(.inactif):hover { border-color: var(--or); color: var(--texte-doux); }
.onglet.actif { background: var(--carte); color: var(--texte); padding-top: 10px; padding-bottom: 10px; box-shadow: 0 -3px 12px rgba(0,0,0,0.55); z-index: 5; border-color: var(--bord); }
.onglet.inactif { color: var(--texte-tres-doux); cursor: default; opacity: 0.6; }
.onglet-n { font-size: 0.65rem; margin-left: 3px; }
.onglet.actif .onglet-n { color: var(--or); }
.dossier-contenu { background: var(--carte); border: 1px solid var(--bord); border-radius: 0 0 var(--rayon) var(--rayon); margin: 0 16px 16px; position: relative; z-index: 1; min-height: 48px; overflow: hidden; padding-bottom: 4px; }
.dossier-contenu .section-titre { padding-top: 6px; }

/* ── Bouton d'actualisation dans l'entête (remonté à la demande de Laurent) ──
   Cible tactile de 40 px alors que l'icône n'en fait que 18 : sur un téléphone,
   un bouton plus petit se rate. Il tourne pendant le rafraîchissement. */
.btn-rafraichir {
  width: 40px; height: 40px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--texte-doux); font-family: inherit;
}
.btn-rafraichir svg { width: 18px; height: 18px; }
.btn-rafraichir:active { color: var(--or); }
.btn-rafraichir.tourne svg { animation: tourne-icone 0.8s linear infinite; }
@keyframes tourne-icone { to { transform: rotate(360deg); } }

/* L'entête doit tenir sur une ligne. Si la place manque, c'est le numéro de
   version qui saute, jamais le bouton. */
@media (max-width: 359px) { .version-entete { display: none; } }

/* ── Visionneuse de photos ──────────────────────────────────────────────────
   Fond opaque et non transparent : on regarde une photo pour juger un objet,
   le reste de l'écran ne doit pas la parasiter. */
.visionneuse {
  position: fixed; inset: 0; z-index: 200;
  background: #000;
  display: flex; align-items: center; justify-content: center;
  touch-action: none; overflow: hidden;
}
.visionneuse[hidden] { display: none; }
#vis-image {
  max-width: 100%; max-height: 100%;
  transform-origin: center center;
  will-change: transform;
  user-select: none; -webkit-user-drag: none;
}
.vis-fermer {
  position: absolute; top: 10px; right: 10px; z-index: 2;
  width: 44px; height: 44px; border-radius: 50%;
  background: rgba(0,0,0,0.55); border: none; color: #fff;
  font-size: 1.1rem; cursor: pointer; font-family: inherit;
}
.vis-rang {
  position: absolute; top: 18px; left: 50%; transform: translateX(-50%); z-index: 2;
  color: rgba(255,255,255,0.75); font-size: 0.8rem;
  font-variant-numeric: tabular-nums; pointer-events: none;
}
.vis-fleche {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 48px; height: 64px; border: none; background: rgba(0,0,0,0.35);
  color: #fff; font-size: 2rem; line-height: 1; cursor: pointer; font-family: inherit;
}
.vis-prec { left: 0; border-radius: 0 8px 8px 0; }
.vis-suiv { right: 0; border-radius: 8px 0 0 8px; }
.vis-fleche[hidden] { display: none; }
/* Ticket 149 : la vignette n'ouvre plus la visionneuse depuis la liste — toute
   la carte ouvre la fiche, et c'est dans la fiche que la photo s'agrandit.
   Le curseur suit : « pointer », pas « zoom-in ». */
.lot-vignette { cursor: pointer; }

/* ── v30 : cibles tactiles ────────────────────────────────────────────────────
   L'application s'utilise au téléphone, une main tenant l'objet photographié.
   Quatre boutons descendaient sous le seuil de 40 px fixé par DESIGN.md et se
   rataient au pouce. On garde leur apparence (fond, bordure, taille de texte),
   on ne change que la hauteur utile. */
.confirmer-btn-sm,
.btn-archiver,
.btn-piste-suppr,
.btn-tout-valider {
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ── v30 : état vide qui dit quoi faire ───────────────────────────────────────
   Un état vide qui se contente de constater le vide laisse l'utilisateur
   devant un écran mort. La deuxième ligne dit l'action suivante. */
.vide-etat-action {
  display: block;
  margin-top: 6px;
  font-size: 0.8rem;
  color: var(--texte-doux);
}

/* Une photo en attente d'analyse : meme carte que les autres, mais on voit
   qu'elle respire encore. Pas d'animation agressive : un battement lent sur
   la vignette suffit a dire « ca travaille » sans attirer l'oeil en boucle. */
.lot-carte.carte-attente { cursor: default; }
.lot-carte.carte-attente .lot-titre { color: var(--texte-doux); font-weight: 500; }
.lot-carte.carte-attente .lot-vignette img { animation: attente-respire 2.4s ease-in-out infinite; }
@keyframes attente-respire { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
@media (prefers-reduced-motion: reduce) {
  .lot-carte.carte-attente .lot-vignette img { animation: none; opacity: 0.75; }
}

/* LES FILTRES DOIVENT ETRE AU-DESSUS DE LA LIGNE DE FLOTTAISON.
   Mesure du 4 septembre 2026 sur un ecran de telephone (390x844) : la rangee
   de pastilles commencait a y=815 pour 27 pixels de haut. Elle depassait de
   vingt-neuf pixels, et la barre d'un vrai navigateur en mange davantage.
   Lucile n'a pas rate les categories : elles n'etaient pas a l'ecran.
   Le bloc des compteurs occupait 179 pixels a lui seul. Sur petit ecran il
   passe sur une seule ligne : on garde les quatre chiffres, on rend cent
   pixels a ce qui suit. */
@media (max-width: 480px) {
  /* IL Y A TROIS COMPTEURS, PLUS QUATRE.
     Cette regle disait `repeat(4, 1fr) !important`, ecrit le 4 septembre 2026
     pour tenir quatre chiffres sur une ligne de telephone. Le compteur CO2 a
     ete retire le lendemain et la regle est restee : les deux premiers
     compteurs faisaient 86 pixels et s'arretaient a 186 sur une ligne de 375,
     la moitie droite vide. Remarque de Lucile, 5 septembre.
     Le !important a aussi neutralise trois regles que j'avais posees ensuite
     sur l'identifiant : aucune specificite ne le bat. Un !important est une
     promesse que rien ne changera jamais ; celle-ci a tenu une journee. */
  .compteurs {
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
    padding: 8px 10px;
  }
  .compteurs .compteur:nth-child(3) { grid-column: 1 / -1; }
  .compteur-valeur { font-size: 1.05rem; line-height: 1.15; }
  .compteur-label  { font-size: 0.62rem; line-height: 1.1; }
  .cpt-commission  { font-size: 0.58rem; }
}

/* Et une fois qu'on l'a vue, la rangee reste : elle colle en haut quand on
   fait defiler la liste. Sans ca, choisir un filtre oblige a remonter. */
.onglets-wrapper {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--fond);
}

/* ── ALERTES ───────────────────────────────────────────────────────────────
   Une alerte est un evenement : elle attire l'oeil parce qu'elle vient
   d'arriver. Passe vingt-quatre heures sans que personne n'agisse, ce n'est
   plus un evenement mais un retard : --ancienne la ramene au calme, sans la
   faire disparaitre. La croix est toujours la, en haut a droite. */
.alertes-liste { padding: 0 16px 8px; display: flex; flex-direction: column; gap: 8px; }
.alerte-carte {
  position: relative;
  background: #2e1010;
  border: 1px solid #6a2020;
  border-radius: var(--rayon-sm);
  padding: 10px 34px 10px 12px;
  font-size: 0.8rem;
}
.alerte-carte--pause { background: #1a1a2e; border-color: #3a3a6a; }
.alerte-carte--ancienne { background: transparent; border-color: var(--bord); }
.alerte-titre { font-weight: 700; color: var(--rouge); }
.alerte-carte--pause .alerte-titre { color: #7a7ae8; }
.alerte-carte--ancienne .alerte-titre { color: var(--texte); font-weight: 600; }
.alerte-motif { color: var(--texte-doux); margin-top: 3px; }
/* Ticket 147 : ce que l'échec change pour l'objet. C'est la ligne qui manquait,
   donc elle se lit plus fort que le motif — texte principal, pas texte doux. */
.alerte-consequence { color: var(--texte); font-size: 0.8rem; margin-top: 4px; }
/* Ticket 20 : une carte qui dit « les photos ne correspondent pas » montre les
   photos. Elles restent petites et sur une ligne qui defile : la carte est une
   ligne de liste, pas la fiche. */
.alerte-vignettes { display: flex; gap: 6px; margin-top: 8px; overflow-x: auto; scrollbar-width: none; }
.alerte-vignettes::-webkit-scrollbar { display: none; }
.alerte-vignette {
  flex-shrink: 0; width: 56px; height: 56px; border-radius: var(--rayon-sm);
  object-fit: cover; background: var(--carte2); cursor: pointer;
}
.alerte-vignette:active { opacity: 0.8; }
.alerte-pied { color: var(--texte-tres-doux); font-size: 0.7rem; margin-top: 3px; }
.alerte-detail { margin-top: 6px; }
.alerte-detail summary { color: var(--texte-tres-doux); font-size: 0.7rem; cursor: pointer; }
.alerte-detail pre {
  white-space: pre-wrap; word-break: break-word;
  color: var(--texte-tres-doux); font-size: 0.68rem; margin: 4px 0 0;
}
.alerte-actions { margin-top: 8px; display: flex; gap: 8px; }
.alerte-btn {
  background: none; border: 1px solid var(--bord); border-radius: var(--rayon-sm);
  color: var(--texte-tres-doux); padding: 5px 11px; font-size: 0.75rem; cursor: pointer;
  /* Regle des 40 px : ces deux boutons faisaient 26 px de haut, sous le seuil
     que DESIGN.md impose a toute cible tactile. Apparence inchangee. */
  min-height: 40px; display: inline-flex; align-items: center; justify-content: center;
}
.alerte-btn--primaire { background: #1a1a4a; border-color: #6a2020; color: var(--rouge); }

/* ── Ticket 136 : la decision et la panne ne se peignent pas pareil ────────
   Deux des trois cartes rouges de la capture du 8 septembre etaient le
   garde-fou photo en train de faire son travail. Rouge sang a cote d'un
   plantage de script, elles passaient pour des pannes et appelaient un clic
   sur « Relancer ». Elles prennent l'orange d'alerte deja au catalogue
   (#e8902a, fond teinte alerte #1e1a0e) : visible, mais pas alarmant. */
.alerte-carte--decision { background: #1e1a0e; border-color: #7a5a20; }
.alerte-carte--decision .alerte-titre { color: #e8902a; }
.alerte-carte--decision .alerte-btn--primaire { background: none; border-color: #7a5a20; color: #e8902a; }
.urgence-bandeau--decision { background: #2e1a0a; border-left-color: #e8902a; }

/* ── Une reponse ecrite qui n'est pas partie ────────────────────────────────
   Ce n'est pas une panne de la machine, c'est un acheteur qui attend : fond
   d'alerte teinte (#1e1a0e) et liseré or, comme les autres bandeaux qui
   appellent une decision, pas le rouge des echecs de publication.
   Le TEXTE de la reponse est affiche : c'est ce qu'on demande de valider, le
   cacher derriere un clic reviendrait a demander un accord a l'aveugle.
   Le bouton fait 40 px de haut (cible tactile, telephone, une main). */
.urgence-bandeau--brouillon { background: #1e1a0e; color: var(--texte); border-left-color: var(--or); }
.brouillon-dort-texte {
  margin: 8px 0 0; padding: 8px 12px;
  background: var(--carte); border-radius: 8px;
  font-size: 0.85rem; font-weight: 400; line-height: 1.45; color: var(--texte);
}
.brouillon-dort-actions { display: flex; align-items: center; gap: 12px; margin-top: 8px; flex-wrap: wrap; }
.brouillon-dort-envoi {
  min-height: 40px; padding: 0 16px;
  background: var(--or); color: var(--fond); border: 0; border-radius: 8px;
  font-size: 0.95rem; font-weight: 700; cursor: pointer;
}
.brouillon-dort-envoi:active { background: var(--or-pale); }
.brouillon-dort-envoi:disabled { opacity: 0.55; cursor: default; }
.urgence-bandeau--brouillon .urgence-lien { color: var(--or-pale); }

/* ── Le refus du controle de ton, ecrit sous le texte qu'il retient ─────────
   Il apparait quand le serveur refuse d'envoyer un texte qui sonne la machine
   (controlerTexte). Ce n'est pas un toast : DESIGN.md interdit le toast pour
   une erreur, et des motifs qui s'effacent tout seuls ne disent pas quoi faire.
   Le rouge d'erreur (--rouge) et non l'or : le texte affiche juste au-dessus
   n'est PAS envoyable tel quel, et le distinguer du bandeau qui le porte est
   tout l'interet. Le bouton de contournement reste en retrait (fond de carte,
   liseré rouge) : il ne doit pas se cliquer par reflexe a la place du bouton
   principal, mais il porte les memes 40 px de cible tactile. */
.brouillon-dort-refus {
  margin: 8px 0 0; padding: 8px 12px;
  background: #2e100e; border-left: 3px solid var(--rouge); border-radius: 8px;
}
.brouillon-dort-refus-titre { font-size: 0.8rem; font-weight: 700; color: var(--rouge); }
.brouillon-dort-refus-motifs {
  margin: 4px 0 0; padding-left: 16px;
  font-size: 0.8rem; font-weight: 400; line-height: 1.45; color: var(--texte);
}
.brouillon-dort-forcer {
  min-height: 40px; margin-top: 8px; padding: 0 16px;
  background: var(--carte2); color: var(--rouge);
  border: 1px solid var(--rouge); border-radius: 8px;
  font-size: 0.8rem; font-weight: 700; cursor: pointer;
}
.brouillon-dort-forcer:disabled { opacity: 0.55; cursor: default; }

/* ── Une reponse ecrite sur un fil sans fiche ───────────────────────────────
   La cinquieme famille (lib/propositions-sans-objet.mjs). Meme peinture que le
   brouillon qui dort juste au-dessus, et c'est voulu : dans les deux cas un
   acheteur attend et une reponse est ecrite, donc meme fond d'alerte teinte et
   meme liseré or. Ce qui les distingue se lit dans la phrase, pas dans la
   couleur — inventer un cinquieme ton ferait cinq alarmes de cinq couleurs sur
   le meme ecran, et plus aucune ne se remarquerait.
   L'avertissement, lui, prend l'orange d'arbitrage deja au catalogue (#e8902a) :
   il ne sort que sur le texte qui affirme une disponibilite que rien n'a
   verifiee, et il demande un geste avant le clic. */
.urgence-bandeau--proposition { background: #1e1a0e; color: var(--texte); border-left-color: var(--or); }
.urgence-bandeau--proposition .urgence-lien { color: var(--or-pale); }
.proposition-avertissement {
  margin: 8px 0 0; font-size: 0.8rem; font-weight: 600;
  line-height: 1.45; color: #e8902a;
}

/* ── Une question posee a l'operateur, qui n'a pas d'objet ──────────────────
   La quatrieme famille de bandeaux (lib/decisions-en-attente.mjs). Elle
   n'annonce pas une panne : fond d'arbitrage #2e1a0a et liseré orange #e8902a,
   les memes que .urgence-bandeau--decision et .alerte-carte--decision, qui
   marquent deja dans ce depot « on te demande de trancher ». Le rouge des
   echecs de publication reste a ce qui a echoue.
   Les trois boutons font 40 px de haut : l'application s'utilise au telephone,
   une main tenant l'objet. Ils passent a la ligne plutot que de retrecir. */
.urgence-bandeau--question { background: #2e1a0a; color: var(--texte); border-left-color: #e8902a; font-weight: 700; }
.decision-phrase { margin: 6px 0 0; font-size: 0.85rem; font-weight: 400; line-height: 1.45; }
.decision-mesure { margin: 4px 0 0; font-size: 0.75rem; font-weight: 400; color: var(--texte-doux); }
.decision-issues { display: flex; align-items: center; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.decision-issue {
  min-height: 40px; padding: 0 16px;
  background: var(--carte2); color: var(--texte);
  border: 1px solid #7a5a20; border-radius: 8px;
  font-size: 0.9rem; font-weight: 700; cursor: pointer;
}
.decision-issue:active { background: var(--carte); }
.decision-issue:disabled { opacity: 0.55; cursor: default; }

/* LE REGIME D'ENVOI, EN HAUT DE L'ECRAN DES MESSAGES (ticket du 10 sept. 2026).
   Trois etats, trois apparences, parce qu'ils ne demandent pas la meme chose :
   - `--ouvert` : une ligne discrete en --texte-doux, un point vert. Le systeme
     repond, on n'interrompt personne pour le dire ;
   - `--attention` : silence de moins de 24 h, liseré --or, fond d'alerte. C'est
     probablement un reglage qu'on a pose exprès ;
   - `--anomalie` : silence de plus de 24 h, ou dont on ne sait pas dater le
     debut. Liseré --rouge : personne ne revient reouvrir un interrupteur qu'il
     a oublie, et trois jours de silence total sont une panne, pas un reglage.
   Le rouge est celui des echecs de publication, et c'est voulu : la regle du
   projet est que le succes n'est jamais l'etat par defaut. */
.regime-bandeau {
  margin: 10px 16px 0; padding: 10px 12px;
  border-left: 3px solid var(--bord); border-radius: 0 var(--rayon-sm) var(--rayon-sm) 0;
  background: var(--carte); font-size: 0.85rem; line-height: 1.45; color: var(--texte);
}
.regime-bandeau--ouvert { background: none; border-left-color: var(--vert); color: var(--texte-doux); font-size: 0.8rem; padding: 6px 12px; }
.regime-bandeau--attention { background: #1e1a0e; border-left-color: var(--or); }
.regime-bandeau--anomalie { background: #201512; border-left-color: var(--rouge); }
.regime-bandeau-faire { margin-top: 6px; font-size: 0.8rem; color: var(--texte-doux); }
.regime-bandeau-depuis { margin-top: 4px; font-size: 0.75rem; color: var(--texte-tres-doux); }

/* Un bouton qui parle au serveur le montre : inactif, et son libelle dit ce
   qui se passe (« Relance en cours… »). La classe ne sert qu'a l'apparence,
   l'etat vrai est `disabled`. */
.btn-occupe { opacity: 0.55; cursor: default; }
.alerte-carte--ancienne .alerte-btn--primaire { background: none; border-color: var(--bord); color: var(--texte-doux); }
/* LA CROIX EST UNE CIBLE TACTILE, DONC 40 PX (DESIGN.md : « tout bouton
   tactile porte au minimum 40 px de hauteur utile »). Elle en faisait 30, ce
   qui passait tant qu'elle n'etait que sur les cartes d'echec ; le 11 septembre
   2026 elle est posee sur les trois familles de bandeaux de l'accueil, y
   compris sur une ligne d'une seule ligne de haut, au pouce et l'objet dans
   l'autre main. Le signe, lui, ne grossit pas : seule la zone cliquable. */
.alerte-fermer, .urgence-fermer {
  position: absolute; top: 2px; right: 2px;
  background: none; border: 0; color: var(--texte-tres-doux);
  font-size: 1.15rem; line-height: 1; cursor: pointer;
  width: 40px; height: 40px; border-radius: 4px;
}
.alerte-fermer:hover, .urgence-fermer:hover { color: var(--texte); background: rgba(255,255,255,0.07); }
.urgence-bandeau { position: relative; padding-right: 44px; }
/* La ligne d'action porte sa croix elle aussi, et `position: absolute` se cale
   sur le premier ancetre positionne : sans cette regle, la croix serait allee
   se poser dans le coin de la page. */
.alerte-action { position: relative; padding-right: 44px; }

/* ── Zone « jamais en ligne » ──────────────────────────────────────────────
   Ce bloc n'avait AUCUNE regle : il s'affichait en texte de paragraphe,
   pleine largeur, juste sous le bouton Photographier, et mangeait la moitie
   d'un ecran de telephone. Il passait inapercu parce qu'il n'etait rendu
   qu'une fois et disparaissait au premier rafraichissement. */
.zone-jamais-en-ligne { padding: 0 16px; margin: 2px 0 10px; }
.zone-jamais-en-ligne:empty { display: none; }
.zjel-titre {
  font-size: 0.84rem; font-weight: 700; color: var(--texte);
  display: flex; justify-content: space-between; align-items: baseline; gap: 10px;
}
.zjel-montant { color: var(--or); }
.zjel-sous { font-size: 0.72rem; color: var(--texte-doux); margin: 3px 0 4px; }
.zjel-ligne {
  display: flex; justify-content: space-between; align-items: baseline; gap: 10px;
  padding: 8px 0; border-bottom: 1px solid var(--bord);
  font-size: 0.78rem; cursor: pointer; min-height: 34px;
}
.zjel-ligne:last-child { border-bottom: none; }
.zjel-nom { flex: 1; min-width: 0; color: var(--texte); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.zjel-prix { color: var(--texte-doux); white-space: nowrap; }
.zjel-motif { color: var(--texte-tres-doux); font-size: 0.7rem; flex-shrink: 0; max-width: 45%; text-align: right; }
.zjel-bloques {
  margin-top: 8px; border: 1px solid var(--bord);
  border-radius: var(--rayon-sm); padding: 2px 10px;
}
.zjel-resume {
  font-size: 0.75rem; color: var(--texte-doux); cursor: pointer;
  list-style: none; padding: 9px 0; min-height: 34px;
}
.zjel-resume::-webkit-details-marker { display: none; }
.zjel-resume::before { content: '▸\00a0'; color: var(--texte-tres-doux); }
.zjel-bloques[open] .zjel-resume::before { content: '▾\00a0'; }
.btn-tout-publier { margin-top: 10px; width: 100%; min-height: 44px; }

/* ── Cibles tactiles ───────────────────────────────────────────────────────
   La barre du bas faisait 8 px de marge et 0,7 rem de texte, collee a la
   barre systeme d'Android : le pouce tombait entre les deux. Les onglets
   faisaient 7 px et 0,72 rem. Le minimum recommande pour une cible tactile
   est de 44 a 48 px de haut. */
.nav { padding: 4px 0 max(10px, env(safe-area-inset-bottom)); }
.nav-btn { min-height: 54px; padding: 10px 0 6px; font-size: 0.75rem; gap: 4px; }
.nav-btn svg { width: 26px; height: 26px; }

.onglet { padding: 11px 14px; font-size: 0.8rem; min-height: 42px; }
.onglet.actif { padding-top: 13px; padding-bottom: 13px; }
.onglet-n { font-size: 0.72rem; margin-left: 5px; }

/* ── Onglets : ils se chevauchaient ────────────────────────────────────────
   `margin-left: -10px` faisait passer chaque onglet PAR-DESSUS le precedent,
   et seul l'onglet actif portait un z-index. Le dernier de la rangee se
   retrouvait donc au premier plan et se lisait comme selectionne : sur la
   capture du 4 septembre a 21h36, « Terminée » paraissait actif alors que la
   liste affichait « EN COURS (115) » — en realite aucun onglet n'etait
   choisi, le filtre par defaut etant « tous ».
   Chaque onglet perdait aussi dix pixels de zone cliquable, manges par son
   voisin, sur 7 px de marge interieure. */
.onglet { margin-left: 4px; }
.onglet:first-child { margin-left: 0; }
.onglet.actif {
  border-top: 2px solid var(--or);
  padding-top: 11px;
}
/* Un onglet vide n'est pas cliquable : il doit le montrer, sans disparaitre. */
.onglet.inactif { opacity: 0.45; }
/* La rangee vide de la v28 ne doit pas manger de hauteur. */
.onglets-rangee:empty { display: none; }

/* ── Onglets : quatre, tous cliquables ─────────────────────────────────────
   Avec quatre onglets, la rangee peut deborder sur un telephone etroit.
   Elle defile, sans barre visible, et l'onglet choisi est ramene dans le
   champ par afficherOngletsDossiers. */
.onglets-rangee {
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.onglets-rangee::-webkit-scrollbar { display: none; }
.onglet { flex: 0 0 auto; }
/* Un onglet vide reste cliquable : il s'efface un peu, il ne se ferme pas. */
.onglet.vide { opacity: 0.55; }
.onglet.vide.actif { opacity: 1; }
.dossier-vide {
  padding: 26px 16px;
  text-align: center;
  color: var(--texte-doux);
  font-size: 0.85rem;
}

/* ── Compteurs : trois au lieu de quatre ───────────────────────────────────
   Le compteur CO2 est retire. La grille a deux colonnes laissait donc une
   case vide a droite du troisieme. « Encaissés » porte deja une seconde
   ligne (la commission) : il prend toute la largeur, ce qui lui va. */
.compteurs .compteur:nth-child(3) { grid-column: 1 / -1; }

/* ── Compteurs : trois, et centres ─────────────────────────────────────────
   Mesure du 5 septembre 2026 sur un ecran de 390 points : les deux premiers
   compteurs faisaient 86 pixels et s'arretaient a 186 sur une ligne de 375.
   La moitie droite etait vide. La grille prevoyait encore quatre colonnes,
   comme du temps ou le CO2 en occupait une : le retrait d'hier soir a laisse
   la regle telle quelle.
   L'identifiant l'emporte sur la classe, donc cette regle vaut aussi dans la
   requete de media qui reglait la version a quatre. */
#zone-compteurs.compteurs { grid-template-columns: repeat(2, 1fr); }
#zone-compteurs.compteurs .compteur { min-width: 0; }
#zone-compteurs.compteurs .compteur:nth-child(3) { grid-column: 1 / -1; }

/* ── Se déconnecter, dans l'en-tête ────────────────────────────────────────
   Le bouton existait, tout en bas du panneau Réglages : deux gestes et un
   défilement pour sortir d'un compte. Le 5 septembre 2026, Lucile s'est
   retrouvée sur le compte de Laurent, ce qui est exactement le moment où l'on
   cherche ce bouton et où il ne faut pas avoir à le chercher. */
/* v31 : IL Y ETAIT DEJA, ET LAURENT L'A REDEMANDE LE SOIR MEME.
   La premiere version faisait 44 px, la bonne taille, mais portait une icone
   seule dans `--texte-tres-doux`, la couleur la plus effacee de la palette,
   dans un coin ou rien n'annonce qu'on peut appuyer. Une cible de 44 px qu'on
   ne remarque pas n'est pas une cible.
   Trois changements, aucun exotique : le mot « Sortir » a cote de l'icone, la
   couleur du texte courant plutot que la plus pale, et un contour qui dit que
   c'est un bouton. La largeur fixe saute — un bouton qui porte un mot se
   dimensionne sur son mot — mais les 44 px de hauteur restent. */
.btn-deconnexion {
  background: none; cursor: pointer;
  /* --bord (#2e2a25) donne 1,33:1 sur le fond : mesure, pas jugee a l'oeil.
     Un contour qu'on ne distingue pas du fond ne dit pas « bouton », il ne
     fait qu'occuper de la place. #6a6156 donne 3,13:1, juste au-dessus du
     seuil de 3:1 des composants d'interface, sans alourdir l'en-tete. */
  border: 1px solid #6a6156;
  color: var(--texte-doux);
  min-height: 44px; padding: 0 12px; gap: 7px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--rayon-sm);
  font: inherit; font-size: 13px; line-height: 1;
  white-space: nowrap;
}
.btn-deconnexion-txt { letter-spacing: 0.01em; }
.btn-deconnexion:hover,
.btn-deconnexion:focus-visible {
  color: var(--texte); border-color: var(--texte-doux);
  background: rgba(255,255,255,0.06);
}
/* Sur un tres petit ecran, le mot cede avant l'icone : mieux vaut un bouton
   reconnaissable et etroit qu'un en-tete qui deborde. Le titre reste sur le
   bouton, donc rien n'est perdu pour un lecteur d'ecran. */
@media (max-width: 359px) {
  .btn-deconnexion-txt { display: none; }
  .btn-deconnexion { padding: 0; width: 44px; }
}


/* Ranger un objet bloque. Discret : ce n'est pas une action qu'on cherche,
   c'est une action qu'on trouve quand on en a assez de relire le motif. */
.zjel-ranger {
  background: none;
  border: 1px solid #6a6156;
  color: var(--texte-doux);
  border-radius: 6px;
  padding: 4px 10px;
  min-height: 32px;
  font-size: 0.82rem;
  margin-left: 8px;
  cursor: pointer;
}
.zjel-ranger:hover { border-color: var(--texte-doux); }

/* Un titre d'alerte que le front n'a pas pu resoudre : il se distingue, pour
   qu'on ne le confonde pas avec un vrai nom d'objet. Cause : /api/etat ne
   renvoie que les lots du compte connecte, la file contient ceux de tous. */
.alerte-titre--inconnu { color: var(--texte-tres-doux); font-style: italic; }

/* ── Rachat direct : « tu gagnerais peut-etre plus ailleurs » ──
   Une carte dans le flux, sous le prix : pas d'ombre, pas de rouge, pas
   d'encadre d'erreur. C'est un CONSEIL, pas un avertissement — la carte
   emprunte donc la meme surface et le meme filet que .zone-conseil. Le lien
   porte 40 px de hauteur utile : sur un telephone, une main tenant l'objet,
   un lien plus court se rate. */
.bloc-rachat { background: var(--carte2); border: 1px solid var(--bord); border-radius: var(--rayon-sm); padding: 12px; margin: 0 16px 14px; }
.bloc-rachat-titre { font-size: 0.85rem; font-weight: 600; color: var(--texte); margin-bottom: 4px; }
.bloc-rachat-corps { font-size: 0.8rem; line-height: 1.5; color: var(--texte-doux); margin-top: 4px; }
.bloc-rachat-lien { display: inline-flex; align-items: center; min-height: 40px; font-size: 0.8rem; font-weight: 600; color: var(--or); text-decoration: none; }
.bloc-rachat-lien:active { color: var(--or-pale); }

/* ── Ticket 135 : trois details d'ecran ────────────────────────────────────
   1. Le bandeau d'analyse sur l'ecran de capture. Il etait masque la, c'est-a-
      dire exactement la ou la personne se trouve apres avoir pris sa photo
      (Lucile, retour 1 du 5 septembre 2026). Il y reste, mais EN HAUT : le bas
      appartient au declencheur, et un bandeau par-dessus ferait rater la
      photo. Fond opaque, il se pose sur l'image de la camera. */
#bandeau-analyses.sur-capture {
  top: calc(72px + env(safe-area-inset-top));
  bottom: auto;
  border-top: none;
  border-bottom: 1px solid var(--bord);
  z-index: 96;   /* #p-capture.active est a 50 */
}
/* Le ton dit l'etat reel. Un echec ne se chuchote pas (DESIGN.md, contrainte 2). */
#bandeau-analyses.ton-echec { border-color: var(--rouge); }
#bandeau-analyses.ton-echec .bandeau-analyses-txt { color: var(--rouge); }
#bandeau-analyses.ton-termine .bandeau-analyses-txt { color: var(--vert); }

/* 2. Une session en echec ne disparait plus, et elle porte de quoi agir.
      Trois photos de Paul, le 2 septembre 2026, sont devenues introuvables
      pour lui au bout de six heures. */
.lot-carte.carte-attente-arretee .lot-vignette img { animation: none; opacity: 1; }
.lot-carte.carte-attente-echec .lot-titre { color: var(--rouge); }
.lot-carte.carte-attente .lot-vignette { cursor: pointer; }
/* LA CARTE DE RELAIS : L'ANALYSE A ABOUTI, L'OBJET EST AILLEURS.
   Elle prend la place de la carte « Analyse en cours » et reste dix minutes,
   le temps de dire dans quel onglet l'objet est parti. Toute la ligne est une
   cible, comme une ligne d'objet, et elle mene a cet onglet : le titre reprend
   donc la couleur du texte principal, la vignette ne respire plus. */
.lot-carte.carte-attente-relais { cursor: pointer; }
.lot-carte.carte-attente-relais .lot-titre { color: var(--texte); font-weight: 600; }
.lot-carte.carte-attente-relais .lot-vignette { cursor: pointer; }

.btn-reessayer, .btn-relais {
  font-size: 0.75rem; font-weight: 600; color: var(--or);
  background: var(--carte2); border: 1px solid var(--bord);
  border-radius: var(--rayon-sm); padding: 4px 12px; cursor: pointer;
  min-height: 40px; display: inline-flex; align-items: center; justify-content: center;
}
.btn-reessayer:active, .btn-relais:active { color: var(--or-pale); opacity: 0.7; }

/* 3. Une plateforme prevue n'a pas l'apparence d'une annonce en ligne.
      « en ligne sur leboncoin » est vert et cliquable ; « prevu sur Vinted »
      reste en texte tres doux et ne mene nulle part, parce qu'il n'y a nulle
      part ou aller. */
.lot-sous-plat.prevu { color: var(--texte-tres-doux); font-style: italic; }

/* Une annonce ARRETEE n'est ni l'un ni l'autre : elle a existe, donc pas
   l'italique de ce qui est seulement prevu ; elle ne diffuse plus, donc pas le
   vert de « en ligne ». Le texte doux la laisse lisible sans la faire passer
   pour une bonne nouvelle. */
.lot-sous-plat.arretee { color: var(--texte-doux); }

/* ── L'ECRAN DU DEPOSANT : UNE CONVERSATION AVEC DEBARRAS (ticket 146) ───────
   Laurent, le 8 septembre 2026 : « du point de vue de l'utilisateur,
   l'utilisateur est en train de parler a Debarras, pas au client. » Une entree
   n'est donc pas un fil : c'est une question de Debarras attachee a un objet,
   et deux a quatre boutons pour y repondre en trois secondes.

   Zones tactiles : 44 px sur chaque bouton de reponse. L'ecran s'utilise au
   telephone, une main tenant l'objet (DESIGN.md, contrainte 1). */
.q-carte { background: var(--carte); border: 1px solid var(--bord); border-radius: var(--rayon); margin: 8px 16px; padding: 12px 14px; }
.q-entete { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.q-objet { font-size: 0.9rem; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.q-delai { font-size: 0.75rem; color: var(--texte-tres-doux); white-space: nowrap; font-variant-numeric: tabular-nums; }
.q-delai.presse { color: var(--rouge); font-weight: 700; }
.q-texte { font-size: 0.9rem; line-height: 1.5; margin-top: 6px; color: var(--texte); }
.q-boutons { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.q-bouton {
  background: var(--carte2); border: 2px solid var(--bord); border-radius: var(--rayon-sm);
  padding: 12px 14px; min-height: 44px; font-size: 0.9rem; font-weight: 600; text-align: left;
  color: var(--texte); cursor: pointer; width: 100%;
}
.q-bouton:active { border-color: var(--or); color: var(--or); background: #1e1a0a; }
.q-bouton:disabled { opacity: 0.55; cursor: default; }
/* La voix avant le clavier : Laurent l'a demandee en deuxieme choix, le texte
   libre en dernier recours. Les deux ne s'affichent qu'apres un geste. */
.q-autres { display: flex; gap: 8px; margin-top: 10px; }
.q-autre {
  flex: 1; background: none; border: 1px solid var(--bord); border-radius: var(--rayon-sm);
  padding: 10px; min-height: 40px; font-size: 0.8rem; font-weight: 600; color: var(--texte-doux); cursor: pointer;
}
.q-autre:active { color: var(--or); border-color: var(--or); }
.q-autre.enregistrement { color: var(--rouge); border-color: var(--rouge); }
.q-champ {
  width: 100%; margin-top: 10px; padding: 12px; box-sizing: border-box;
  background: var(--carte2); border: 1px solid var(--bord); border-radius: var(--rayon-sm);
  color: var(--texte); font-size: 0.9rem; resize: vertical;
}
.q-champ:focus { border-color: var(--or); outline: none; }
.q-etat { font-size: 0.8rem; color: var(--texte-doux); margin-top: 10px; }

/* ── Doublon présumé au dépôt (ticket 142) ──────────────────────────────────
   Deux photos côte à côte, la question au-dessus, les deux décisions en bas :
   la personne compare avant de trancher, elle ne lit pas un verdict. */
.doublon-phrase {
  background: #1e1a0e; border: 1px solid var(--bord); border-radius: var(--rayon);
  padding: 12px 14px; font-size: 0.9rem; line-height: 1.5; color: var(--texte);
}
.doublon-photos { display: flex; gap: 12px; margin-top: 16px; }
.doublon-photo { flex: 1; margin: 0; min-width: 0; }
.doublon-photo img {
  width: 100%; aspect-ratio: 1; object-fit: cover;
  border-radius: var(--rayon-sm); border: 1px solid var(--bord); background: var(--carte2);
}
.doublon-photo figcaption {
  font-size: 0.75rem; font-weight: 600; color: var(--texte-tres-doux);
  margin-top: 8px; text-align: center;
}
.doublon-actions { display: flex; flex-direction: column; gap: 12px; margin-top: 24px; }
.doublon-actions .btn { min-height: 48px; }
