:root {
  /* Identité DOMA : bleu marine, blanc, orange comme couleur d'action.
     Le rouge reste STRICTEMENT réservé aux erreurs et aux retards. */
  --orange: #e8622c;
  --orange-dark: #cf5222;
  /* Orange de TEXTE sur fond clair. L'orange de marque #e8622c ne donne que
     3,4:1 sur blanc et 2,7:1 dans une pastille « À traiter » — sous le seuil
     WCAG AA (4,5:1) pour du texte courant. Cette variante foncée reste le
     même orange DOMA (même teinte), simplement assez sombre pour être
     lisible : 6,0:1 sur blanc. --orange sert toujours pour les FONDS,
     bordures et boutons d'action, où le contraste est porté par le blanc. */
  --orange-text: #a8431a;
  --navy: #171b24;
  --navy-2: #1e2430;
  --border: #e5e7eb;
  --text: #1f2430;
  /* #6b7280 tombait à 4,4:1 sur le fond de page #f6f7f9 — assombri pour
     passer AA partout où .muted est utilisé (5,4:1 sur le fond de page). */
  --text-dim: #5b6472;
  --bg: #f6f7f9;
  --red: #dc2626;
  --red-text: #b02020;   /* rouge de texte sur fond rouge pâle : 6,0:1 */
  --red-bg: #fdecec;
  --green: #16794f;
  --green-bg: #e7f6ef;
  --gray-bg: #eef0f3;
  --radius: 12px;
  /* Ombre unique, très légère, pour toutes les surfaces surélevées. */
  --ombre-carte: 0 1px 2px rgba(23, 27, 36, 0.05);
  /* Hauteur minimale d'une cible tactile (recommandation WCAG 2.5.5 /
     Apple HIG). Appliquée sous @media (pointer: coarse). */
  --cible-tactile: 44px;
}

* { box-sizing: border-box; }

/* ---------- Icônes (famille SVG unique, voir partials/icones.html) ---------- */
.ico {
  display: inline-block;
  vertical-align: -0.18em;
  flex-shrink: 0;
}
.ico-alerte { color: var(--red-text); display: inline-flex; }

body {
  margin: 0;
  font-family: -apple-system, "Helvetica Neue", Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
}

a { color: inherit; text-decoration: none; }
/* `text-decoration: none` sur tous les liens rendait une adresse e-mail
   cliquable strictement identique à du texte inerte dans un tableau. */
a[href^="mailto:"], a[href^="tel:"] { text-decoration: underline; text-underline-offset: 2px; }

/* ---------- Focus clavier ----------
   La feuille de style ne définissait AUCUNE règle de focus : sur les boutons
   orange et dans la barre latérale marine, l'anneau par défaut du navigateur
   était invisible ou quasi invisible. :focus-visible (et non :focus) —
   l'anneau n'apparaît qu'à la navigation au clavier, jamais après un simple
   clic à la souris. */
:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 2px;
  border-radius: 4px;
}
/* Sur le marine de la barre latérale, l'orange manque de contraste : anneau
   blanc doublé d'un liseré marine pour rester visible quel que soit le fond. */
.sidebar :focus-visible,
.banner :focus-visible,
.login-page :focus-visible {
  outline-color: #fff;
  box-shadow: 0 0 0 4px rgba(23, 27, 36, 0.55);
}

.layout { display: flex; min-height: 100vh; }

/* ---------- Menu mobile (tiroir latéral) ----------
   Masqués par défaut (desktop) : la sidebar classique reste visible en
   permanence, ces éléments ne servent qu'en dessous de 860 px, voir plus
   bas. */
.mobile-topbar { display: none; }
.mobile-menu-toggle { display: none; }
.sidebar-overlay { display: none; }

/* ---------- Sidebar ---------- */
.sidebar {
  width: 240px;
  flex-shrink: 0;
  background: var(--navy);
  color: #fff;
  display: flex;
  flex-direction: column;
  padding: 20px 14px;
}

.sidebar-logo {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 6px 18px;
}
.sidebar-logo img { height: 34px; }
.sidebar-logo .badge {
  background: var(--orange);
  color: #fff;
  font-weight: 700;
  font-size: 11px;
  padding: 2px 7px;
  border-radius: 5px;
  letter-spacing: 0.5px;
}
.sidebar-logo-text { font-weight: 800; font-size: 19px; letter-spacing: 0.5px; }

.workspace {
  display: flex;
  align-items: center;
  gap: 10px;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 10px;
  padding: 9px 10px;
  margin-bottom: 22px;
}
.avatar {
  width: 30px; height: 30px; border-radius: 8px;
  background: var(--orange);
  color: #fff; font-weight: 700; font-size: 12px;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.workspace-name { font-size: 13px; font-weight: 600; }
.workspace-sub { font-size: 11px; color: rgba(255,255,255,0.5); }

/* 0.35 donnait 3,0:1 sur le marine — sous le seuil AA. 0.58 : 5,5:1. */
.nav-section-label {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.6px;
  color: rgba(255,255,255,0.58); padding: 0 10px; margin-bottom: 6px;
  text-transform: uppercase;
}
.nav { list-style: none; margin: 0 0 20px; padding: 0; }
.nav li a {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; border-radius: 8px; font-size: 13.5px;
  color: rgba(255,255,255,0.75);
  border-left: 3px solid transparent;
  margin-bottom: 2px;
}
.nav li a:hover { background: rgba(255,255,255,0.05); }
.nav li a.active {
  background: rgba(232,98,44,0.15);
  border-left: 3px solid var(--orange);
  color: #fff;
  font-weight: 600;
}
.nav-icon {
  width: 18px; height: 18px;
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}

.sidebar-footer { margin-top: auto; padding-top: 14px; border-top: 1px solid rgba(255,255,255,0.08); }
.sidebar-help {
  font-size: 13px; color: rgba(255,255,255,0.68); padding: 9px 10px;
  display: flex; align-items: center; gap: 9px;
}
.sidebar-help-button {
  width: 100%; border: 0; background: transparent; text-align: left;
  cursor: pointer; font-family: inherit;
}
.sidebar-help:hover, .sidebar-help-button:hover { color: #fff; }
.sidebar-user { display: flex; align-items: center; gap: 10px; padding: 8px 10px; }
.sidebar-user-name { font-size: 13px; font-weight: 600; }
.sidebar-user-role { font-size: 11px; color: rgba(255,255,255,0.55); }
.sidebar-user form { margin-left: auto; }
/* Bouton de déconnexion : mesuré à 21 × 18 px avant correction, la plus
   petite cible cliquable de l'application, et à 3,5:1 de contraste. */
.sidebar-user button {
  background: none; border: none; color: rgba(255,255,255,0.72); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 8px; padding: 0;
}
.sidebar-user button:hover { color: #fff; background: rgba(255,255,255,0.08); }

/* ---------- Main ---------- */
.main { flex: 1; min-width: 0; padding: 26px 34px 60px; }

.topbar { display: flex; align-items: center; gap: 14px; margin-bottom: 22px; }
.search {
  flex: 1; max-width: 420px;
  background: #fff; border: 1px solid var(--border); border-radius: 10px;
  padding: 9px 14px; color: var(--text-dim); font-size: 13.5px;
  display: flex; justify-content: space-between; align-items: center;
}
.kbd { font-size: 11px; border: 1px solid var(--border); border-radius: 4px; padding: 1px 5px; color: var(--text-dim); }

.btn {
  border-radius: 9px; padding: 9px 16px; font-size: 13.5px; font-weight: 600;
  border: 1px solid var(--border); background: #fff; color: var(--text); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  font-family: inherit; line-height: 1.25;
}
.btn:hover { border-color: #d1d5db; }
.btn-dark { background: var(--navy); color: #fff; border-color: var(--navy); }
.btn-dark:hover { background: #232a38; }
.btn-orange { background: var(--orange); color: #fff; border-color: var(--orange); }
.btn-orange:hover { background: var(--orange-dark); }
.btn-outline { background: #fff; }
.btn-sm { padding: 6px 11px; font-size: 12.5px; }

/* Action destructrice — modèle unique, repris de la « Zone dangereuse » des
   Paramètres qui était jusqu'ici la seule à signaler visuellement le danger
   (les suppressions de CR, de lot ou de contact ressemblaient exactement à
   « Ouvrir » ou « Versions »). Rouge de bordure et de texte au repos, fond
   rouge plein seulement au survol : assez distinct pour qu'on ne clique pas
   par erreur, assez discret pour ne pas crier au danger en permanence.
   Les confirmations existantes (retaper « CR58 », retaper le nom du
   chantier, confirm()) restent strictement inchangées. */
.btn-danger { color: var(--red-text); border-color: #f0bcbc; background: #fff; }
.btn-danger:hover { background: var(--red); border-color: var(--red); color: #fff; }
.btn-danger:hover .ico { color: #fff; }

.eyebrow { color: var(--orange-text); font-weight: 700; font-size: 11.5px; letter-spacing: 0.5px; text-transform: uppercase; }
h1 { font-size: 24px; margin: 4px 0 4px; }
h2 { font-size: 16px; margin: 0 0 4px; }
.muted { color: var(--text-dim); font-size: 13px; }

.date-line { color: var(--text-dim); font-size: 12px; text-transform: uppercase; letter-spacing: 0.4px; margin-bottom: 6px; }

/* ---------- Stat cards ---------- */
.stat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin: 22px 0 28px; }
.stat-grid.four { grid-template-columns: repeat(4, 1fr); }
.card {
  background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
  padding: 18px 20px; box-shadow: var(--ombre-carte);
}
.stat-label { font-size: 11.5px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.4px; margin-bottom: 10px; font-weight: 700; }
.stat-value { font-size: 30px; font-weight: 800; }
.stat-sub { font-size: 12px; color: var(--text-dim); margin-top: 4px; }
.stat-icon-danger { color: var(--red); }

/* Indicateurs de l'accueil : ce sont désormais des liens, pas des blocs
   inertes — le chiffre affiché mène à l'écran qui le détaille. */
.stat-card {
  display: block; transition: border-color 0.12s ease;
}
.stat-card:hover { border-color: var(--orange); }
.stat-card::after {
  content: ""; display: block; height: 3px; width: 26px; margin-top: 12px;
  border-radius: 2px; background: var(--orange); opacity: 0.35;
}
.stat-card:hover::after { opacity: 1; }

/* ---------- Chantier card ---------- */
.chantier-card {
  background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
  display: flex; overflow: hidden; margin-bottom: 28px; box-shadow: var(--ombre-carte);
}
/* Repli quand le chantier n'a pas de photo : icône de la famille DOMA sur le
   dégradé, à la place de l'emoji 🏗️ de 52 px. */
.chantier-card-repli { color: #7d8c9c; display: inline-flex; }
.chantier-card-illustration {
  width: 220px; background: linear-gradient(160deg,#dfe7ee,#c9d6e2);
  display: flex; align-items: center; justify-content: center; position: relative; flex-shrink: 0;
}
.chantier-card-photo {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
.chantier-card-illustration .pin {
  position: absolute; top: 10px; left: 10px; background: #fff; font-size: 10.5px;
  font-weight: 700; padding: 3px 8px; border-radius: 6px; color: var(--text-dim);
}
.chantier-card-illustration .cr-badge {
  position: absolute; bottom: 10px; right: 10px; background: var(--navy); color: #fff;
  font-size: 10.5px; font-weight: 700; padding: 3px 8px; border-radius: 6px;
}
.chantier-card-body { padding: 20px 24px; flex: 1; }
.chantier-tag { color: var(--orange-text); font-weight: 700; font-size: 11px; letter-spacing: 0.5px; }
.chantier-card-body h3 { margin: 4px 0 2px; font-size: 19px; }
.progress-bar { height: 6px; background: var(--gray-bg); border-radius: 4px; margin: 14px 0; overflow: hidden; }
.progress-bar > div { height: 100%; background: var(--orange); }
.chantier-meta-row { display: flex; gap: 40px; margin-bottom: 16px; flex-wrap: wrap; }
.chantier-meta-row .k { font-size: 11px; color: var(--text-dim); text-transform: uppercase; font-weight: 700; }
.chantier-meta-row .v { font-size: 13.5px; font-weight: 600; margin-top: 2px; }
.chantier-card-actions { display: flex; gap: 10px; }

/* ---------- Header banner (chantier page) ---------- */
.banner {
  background: var(--navy); color: #fff; border-radius: var(--radius);
  padding: 26px 30px; display: flex; justify-content: space-between; align-items: flex-start;
  gap: 24px; margin-bottom: 20px;
}
/* Sur le marine, l'orange de marque atteint 4,8:1 : c'est ici la variante
   claire qui est lisible, pas la foncée — d'où cette exception explicite. */
.banner .eyebrow { color: var(--orange); }
.banner h1 { color: #fff; }
.banner .muted { color: rgba(255,255,255,0.68); }
/* min-width:0 seul ne suffit pas : un élément flex refuse de descendre sous
   la largeur de son plus long MOT insécable. Un nom d'opération ou une
   adresse très longue sans espace poussait donc toute la bannière — et avec
   elle la page entière — à 1308 px sur un écran de 844 px (mesuré).
   overflow-wrap: anywhere autorise la coupure à l'intérieur du mot. */
.banner-ident { min-width: 0; overflow-wrap: anywhere; }
.banner-adresse { margin: 6px 0 0; }
.banner-faits { overflow-wrap: anywhere; }

/* Même protection sur les autres endroits qui affichent une saisie libre
   potentiellement longue : titres de lot, noms de chantier et d'entreprise. */
.lot-accordion-title,
.chantier-card-body h3,
.chantier-tag,
.obs-lot,
.obs-entreprise { overflow-wrap: anywhere; }
/* En-tête synthétique : les faits (dernier CR, prochaine réunion) alignés à
   droite du nom et de l'adresse. */
.banner-faits { display: flex; gap: 34px; flex-shrink: 0; flex-wrap: wrap; }
.banner-cr { text-align: right; }
.banner-cr .k { font-size: 11px; color: rgba(255,255,255,0.62); text-transform: uppercase; letter-spacing: 0.5px; }
.banner-cr .v { font-size: 26px; font-weight: 800; }
.banner-cr .v.banner-v-sm { font-size: 19px; }
.banner-cr .sub { font-size: 12px; color: rgba(255,255,255,0.62); }

.cr-history { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
.cr-pill {
  border: 1px solid var(--border); background: #fff; border-radius: 9px; padding: 8px 14px;
  font-size: 12.5px; font-weight: 700; color: var(--text-dim);
}
.cr-pill.active { border-color: var(--orange); color: var(--orange-text); background: #fff5f0; }
.cr-pill .sub { font-weight: 500; color: var(--text-dim); font-size: 11px; }

/* ---------- Table ---------- */
.section-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; flex-wrap: wrap; gap: 12px; }
.tabs { display: flex; gap: 4px; background: var(--gray-bg); border-radius: 9px; padding: 3px; flex-wrap: wrap; }
.tabs a, .tabs span {
  padding: 6px 13px; border-radius: 7px; font-size: 12.5px; font-weight: 600; color: var(--text-dim);
  display: inline-flex; align-items: center; gap: 6px;
}
.tabs a.active { background: #fff5f0; color: var(--orange-text); box-shadow: 0 1px 2px rgba(0,0,0,0.06); }
.count-pill { background: var(--red); color: #fff; font-size: 10px; border-radius: 8px; padding: 0 5px; margin-left: 4px; }

/* 3 sélecteurs Bâtiment/Étage/Logement de la fiche chantier, sur UNE
   SEULE LIGNE en desktop et compacts en mobile (Jessy, 24/08, 5e et
   dernière version de cette navigation, validée sur maquette avant
   implémentation — voir le long commentaire de fiche_chantier() dans
   structure.py pour l'historique des 4 versions précédentes). Chaque
   sélecteur est un champ texte avec recherche par saisie + menu
   d'options ; voir app/static/selecteur-structure.js pour l'ouverture au
   clic et le filtre (jamais la navigation, portée par de vrais <a href>
   sur chaque option). */
.selecteurs-structure { display: flex; gap: 8px; align-items: stretch; }
.selecteur-structure { position: relative; flex: 1 1 0; min-width: 0; }
.selecteur-structure-label {
  position: absolute; top: 6px; left: 12px; font-size: 9.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.4px; color: var(--text-dim); pointer-events: none;
}
.selecteur-structure-input {
  width: 100%; border: 1px solid var(--border); border-radius: 9px; background: var(--gray-bg);
  font: inherit; font-size: 14px; font-weight: 600; color: var(--text);
  padding: 19px 30px 7px 12px; min-height: var(--cible-tactile);
  transition: border-color 0.12s ease, background 0.12s ease;
}
.selecteur-structure-input::placeholder { color: var(--text-dim); font-weight: 500; }
.selecteur-structure-input:focus { outline: none; border-color: var(--orange); background: #fff; }
.selecteur-structure.a-une-valeur .selecteur-structure-input { border-color: var(--orange); background: #fff5f0; color: var(--orange-text); }
.selecteur-structure .chevron {
  position: absolute; right: 10px; top: 50%; transform: translateY(-40%);
  color: var(--text-dim); font-size: 11px; pointer-events: none; transition: transform 0.15s ease;
}
.selecteur-structure.ouvert .chevron { transform: translateY(-40%) rotate(180deg); }
.selecteur-structure-menu {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 20;
  background: #fff; border: 1px solid var(--border); border-radius: 9px;
  box-shadow: 0 8px 24px rgba(23,27,36,0.12); max-height: 260px; overflow-y: auto;
  display: none; padding: 4px;
}
.selecteur-structure.ouvert .selecteur-structure-menu { display: block; }
.selecteur-structure-option {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  padding: 9px 10px; border-radius: 6px; font-size: 13.5px; font-weight: 600; color: var(--text);
  min-height: var(--cible-tactile);
}
.selecteur-structure-option:hover, .selecteur-structure-option.actif { background: #fff5f0; color: var(--orange-text); }
.selecteur-structure-option .detail { font-size: 11.5px; font-weight: 500; color: var(--text-dim); }
.selecteur-structure-vide { padding: 10px; font-size: 12.5px; color: var(--text-dim); margin: 0; }

.selecteurs-structure-bas {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 10px; flex-wrap: wrap;
}

@media (max-width: 640px) {
  .selecteurs-structure { flex-direction: column; }
}

/* Barre d'action collante : cachée par défaut (desktop, le bouton du
   topbar suffit) — activée seulement sous 860px, voir le media query
   plus bas, pour qu'un CR à générer reste accessible sans remonter en
   haut de l'écran sur mobile pendant une réunion. */
.sticky-action-bar { display: none; }

/* ---------- Accordéon par lot ---------- */
.lot-accordion {
  background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
  margin-bottom: 10px; overflow: hidden; box-shadow: var(--ombre-carte);
}
.lot-accordion > summary {
  list-style: none; cursor: pointer; padding: 14px 18px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; font-weight: 600; user-select: none;
}
.lot-accordion > summary::-webkit-details-marker { display: none; }
.lot-accordion[open] > summary { border-bottom: 1px solid var(--border); }
.lot-accordion-title { font-size: 14px; }
.lot-accordion-title::before {
  content: "▸"; color: var(--text-dim); margin-right: 10px; font-size: 11px;
  display: inline-block; transition: transform 0.15s ease;
}
.lot-accordion[open] .lot-accordion-title::before { transform: rotate(90deg); }
.lot-accordion-meta { font-size: 12.5px; color: var(--text-dim); font-weight: 500; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.lot-accordion table.obs-table { border: none; border-radius: 0; }

/* ---------- Accordéon par promoteur (liste Chantiers) ---------- */
.promoteur-accordion { padding: 16px 20px; }
.promoteur-accordion > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; gap: 8px; user-select: none;
}
.promoteur-accordion > summary::-webkit-details-marker { display: none; }
.promoteur-accordion > summary::before {
  content: "▸"; color: var(--text-dim); font-size: 11px;
  display: inline-block; transition: transform 0.15s ease;
}
.promoteur-accordion[open] > summary::before { transform: rotate(90deg); }

table.obs-table { width: 100%; border-collapse: collapse; background: #fff; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; box-shadow: var(--ombre-carte); }
.card > table.obs-table, .lot-accordion table.obs-table { box-shadow: none; }
table.obs-table th {
  text-align: left; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.4px;
  color: var(--text-dim); padding: 10px 16px; border-bottom: 1px solid var(--border); background: #fafbfc;
}
table.obs-table td { padding: 12px 16px; border-bottom: 1px solid #f0f1f3; font-size: 13px; vertical-align: top; }
table.obs-table tr:last-child td { border-bottom: none; }
table.obs-table tr:hover { background: #fafbfc; cursor: pointer; }
.obs-lot { font-weight: 700; }
.obs-entreprise { color: var(--text-dim); font-size: 12px; }

/* Cellules d'actions (page Comptes rendus, tableaux des lots et de la liste
   de diffusion). Avant correction :
     - sur DESKTOP, `white-space: nowrap` alignait jusqu'à 8 boutons sur une
       seule ligne et poussait la largeur de la page à 1566 px pour un écran
       de 1440 px — toute la page défilait horizontalement ;
     - sur MOBILE, un `style="white-space:nowrap"` en ligne dans
       parametres.html annulait la règle de repli et projetait « Modifier »
       et « Supprimer » hors de l'écran (x=406 → 493 px pour un viewport de
       390 px) : les deux boutons étaient tout simplement inatteignables
       depuis un iPhone ou un iPad en portrait.
   Les boutons passent donc à la ligne à toutes les largeurs. */
.cr-actions, .cell-actions {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  justify-content: flex-end;
}
.cell-actions { justify-content: flex-start; }
.cell-nowrap { white-space: nowrap; }

/* Table de la page Comptes rendus : largeurs de colonnes fixées pour que la
   colonne d'actions absorbe le reste au lieu d'étirer la page. */
.cr-list-table { table-layout: fixed; }
.cr-list-table th:nth-child(1) { width: 76px; }
.cr-list-table th:nth-child(2) { width: 84px; }
.cr-list-table th:nth-child(3) { width: 104px; }
.cr-list-table th:nth-child(4) { width: 150px; }
.cr-list-table th:nth-child(5) { width: 108px; }
.cr-list-table th:nth-child(6) { width: 124px; }
.cr-list-table td { word-break: break-word; }

/* Suppression d'un CR par appui long (mobile) / clic droit (PC) — barre de
   progression sous le texte, calée sur la durée du minuteur JS (2s), pour
   que l'appui montre visiblement où on en est plutôt que de sembler ne
   rien faire pendant deux secondes. */
.cr-delete-target { position: relative; cursor: pointer; user-select: none; -webkit-user-select: none; }
.cr-delete-target::after {
  content: ""; position: absolute; left: 0; bottom: -4px; height: 2px; width: 0%;
  background: var(--red); transition: width 2s linear;
}
.cr-delete-target--pressing::after { width: 100%; }
.obs-resp { color: var(--text-dim); font-size: 12px; margin-top: 3px; }
.obs-struck { text-decoration: line-through; color: var(--text-dim); }
/* Couleurs de pastilles revues pour passer WCAG AA (4,5:1) : le jeu
   précédent tombait à 2,7:1 sur « À traiter » / « Brouillon » et frôlait le
   seuil sur « Pour mémoire » et « Terminé ». Les teintes restent les mêmes,
   seule la luminosité du texte change. */
.pill { display: inline-block; border-radius: 20px; padding: 3px 11px; font-size: 11.5px; font-weight: 700; }
.pill-a_traiter { background: #fdf1e7; color: var(--orange-text); }   /* 5,4:1 */
.pill-en_retard { background: #fce8e8; color: #b02020; }              /* 6,0:1 */
.pill-pm { background: #f3f4f6; color: #4b5563; }                     /* 6,8:1 */
.pill-termine { background: #e8f5e9; color: #1b5e20; }                /* 7,1:1 */

/* Statuts de tâche DOMA SUIVI (voir DESIGN.md section 3 "Statuts et
   couleurs", simplifié le 20/09 à la demande de Jessy — "un code couleur
   ultra simple sur les retards, en cours et terminé", pas le jeu à 7
   teintes d'origine) — gris = pas commencé, orange = tout ce qui avance
   (planifié/en cours/en avance/attente de validation), rouge = problème
   (retard/bloqué), vert = terminé. Les libellés texte restent précis
   (« Bloqué », « En avance »...), seule la couleur est regroupée ; "en
   avance" reste orange, jamais vert, pour ne jamais le confondre avec
   "terminé" (contrainte DESIGN.md conservée). */
.pill-non_commence { background: #f3f4f6; color: #4b5563; }           /* 6,8:1 */
.pill-planifie { background: #fdf1e7; color: var(--orange-text); }    /* 5,4:1 */
.pill-en_cours { background: #fdf1e7; color: var(--orange-text); }    /* 5,4:1 */
.pill-en_avance { background: #fdf1e7; color: var(--orange-text); }   /* 5,4:1 */
.pill-bloque { background: #fce8e8; color: #b02020; }                 /* 6,0:1 */
.pill-attente_validation { background: #fdf1e7; color: var(--orange-text); } /* 5,4:1 */
.type-pill { font-size: 10px; font-weight: 800; color: #4b5563; background: var(--gray-bg); border-radius: 5px; padding: 2px 6px; }

/* Écran chantier simplifié (maquette V2 validée par Jessy le 22/08) — voir
   app/templates/chantier.html. Tableau de tâches compact et directement
   éditable : chaque champ est un <input>/<select> normal, associé à un
   <form> déclaré hors du tableau via l'attribut form="" (un <form> ne peut
   pas envelopper un <tr>, la ligne se soumet donc via ce mécanisme HTML5
   standard plutôt que via du JavaScript sur mesure), et s'auto-soumet au
   changement grâce à [data-auto-submit] (voir app/static/interactions.js). */
table.taches-compact { table-layout: fixed; }
table.taches-compact th { font-size: 11px; }
table.taches-compact td { padding: 6px 10px; vertical-align: middle; }
table.taches-compact input.edit,
table.taches-compact select.edit:not(.pill) {
  width: 100%; font: inherit; font-size: 12.5px; padding: 5px 6px; border-radius: 6px;
  border: 1px dashed transparent; background: transparent; color: inherit;
}
/* select "État" à part (bug trouvé le 20/09) : la règle ci-dessus, plus
   spécifique que .pill-{{ statut }} (2 classes contre 1), écrasait TOUJOURS
   la couleur du statut avec un fond transparent, quel que soit le statut —
   rendant le code couleur invisible précisément là où Jessy vient de
   demander de le simplifier et de le tester. Ce select garde juste la
   largeur/typo/liseré du champ, jamais le fond, pour laisser .pill-{{
   statut }} colorer le fond sans concurrence. */
table.taches-compact select.pill.edit {
  width: 100%; font: inherit; font-size: 12.5px; border: 1px dashed transparent;
}
table.taches-compact input.edit:hover,
table.taches-compact select.edit:not(.pill):hover { border-color: var(--border); background: #fafbfc; }
table.taches-compact select.pill.edit:hover { border-color: var(--border); }
table.taches-compact input.edit:focus,
table.taches-compact select.edit:focus { outline: none; border-color: var(--orange); background: #fff; }
table.taches-compact select.pill.edit:focus { outline: none; border-color: var(--orange); }
table.taches-compact input.edit.duree { width: 52px; text-align: right; display: inline-block; }
table.taches-compact input.edit.av { width: 52px; text-align: right; display: inline-block; }
table.taches-compact .progress-bar { margin: 4px 0 0; }
select.pill.edit {
  -webkit-appearance: none; appearance: none; cursor: pointer; border: 1px dashed transparent;
  background-repeat: no-repeat; background-position: right 8px center; background-size: 9px;
  padding-right: 24px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'><path d='M0 0l5 6 5-6z' fill='%23888'/></svg>");
}
.retard-txt { font-size: 11px; font-weight: 700; color: var(--red-text); margin-top: 3px; }

.menu-plus { position: relative; }
.menu-plus > summary { list-style: none; cursor: pointer; }
.menu-plus > summary::-webkit-details-marker { display: none; }
.menu-plus[open] > summary { }
.menu-plus-liste {
  position: absolute; top: calc(100% + 6px); right: 0; background: #fff; border: 1px solid var(--border);
  border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,.14); width: 240px; overflow: hidden; z-index: 30;
}
.menu-plus-liste a { display: block; padding: 10px 14px; font-size: 13px; color: var(--text-secondary, #444); border-bottom: 1px solid var(--border); }
.menu-plus-liste a:last-child { border-bottom: none; }
.menu-plus-liste a:hover { background: #fafbfc; }

.perimetre-choix { display: flex; gap: 6px; flex-wrap: wrap; }
.perimetre-choix label {
  font-size: 12.5px; padding: 8px 12px; border-radius: 8px; border: 1px solid var(--border);
  background: #fff; cursor: pointer; white-space: nowrap;
}
.perimetre-choix input { margin-right: 6px; }
.perimetre-choix input:checked + span,
.perimetre-choix label:has(input:checked) { color: var(--navy); font-weight: 600; }
.perimetre-choix label:has(input:checked) { border-color: var(--navy); background: #f3f4f6; }

.recherche-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 10px; }
.recherche-row input[type="search"] { flex: 1; min-width: 220px; }
.recherche-row select { min-width: 220px; }

/* Échéances : libellé explicite devant chaque date, et retard signalé en
   rouge avec son icône (le rouge reste réservé aux erreurs et aux retards). */
.echeance-ligne { font-size: 12.5px; white-space: nowrap; }
.echeance-k { color: var(--text-dim); font-size: 10.5px; text-transform: uppercase; font-weight: 700; letter-spacing: 0.3px; }
.obs-retard {
  color: var(--red-text); font-size: 12px; font-weight: 600; margin-top: 4px;
  display: flex; align-items: center; gap: 4px;
}

/* ---------- Pièces jointes ---------- */
.attach-gallery { display: flex; flex-wrap: wrap; gap: 10px; margin: 8px 0 12px; }
.attach-thumb {
  position: relative; width: 84px; height: 84px; border-radius: 10px; overflow: hidden;
  border: 1px solid var(--border); background: var(--gray-bg);
}
.attach-thumb-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.attach-thumb-file { width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: 22px; gap: 4px; }
.attach-thumb-name { font-size: 9px; color: var(--text-dim); padding: 0 4px; text-align: center; word-break: break-all; line-height: 1.2; }
.attach-thumb-status {
  position: absolute; top: 3px; left: 3px; background: rgba(255,255,255,0.92);
  border-radius: 50%; width: 19px; height: 19px; display: flex; align-items: center; justify-content: center;
}
.attach-thumb-status--ok { color: var(--green); }
.attach-thumb-status--attente { color: #b45f06; }
.attach-thumb-status--conflit { color: var(--red-text); }
.attach-thumb-actions { position: absolute; bottom: 0; right: 0; display: flex; }
.attach-thumb-btn {
  background: rgba(31,36,48,0.75); color: #fff; border: none; width: 24px; height: 22px; font-size: 12px;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.attach-thumb-btn:hover { background: rgba(31,36,48,0.95); }

/* ---------- Statut de synchronisation ---------- */
.sync-badge {
  font-size: 11.5px; font-weight: 700; padding: 5px 12px; border-radius: 20px;
  white-space: nowrap; display: inline-flex; align-items: center; gap: 5px;
}
.sync-badge.sync-ok { background: var(--green-bg); color: var(--green); }
.sync-badge.sync-pending { background: #fff5e6; color: #b45f06; }
.sync-badge.sync-error { background: var(--red-bg); color: var(--red); }

/* ---------- Notes manuscrites ---------- */
.notes-mode-tabs { display: flex; gap: 4px; background: var(--gray-bg); border-radius: 9px; padding: 3px; width: fit-content; max-width: 100%; flex-wrap: wrap; margin-bottom: 18px; }
.notes-mode-btn {
  border: none; background: none; padding: 8px 14px; border-radius: 7px;
  font-size: 12.5px; font-weight: 600; color: var(--text-dim); cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px; font-family: inherit;
}
.notes-mode-btn.active { background: #fff; color: var(--text); box-shadow: 0 1px 2px rgba(0,0,0,0.06); }

.canvas-toolbar {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  padding: 10px 14px; background: var(--gray-bg); border-radius: 10px 10px 0 0;
  border: 1px solid var(--border); border-bottom: none;
}
.canvas-tool-group { display: flex; align-items: center; gap: 6px; }
.canvas-tool-group label { margin: 0; }
.canvas-tool-group select { width: auto; padding: 6px 9px; font-size: 12.5px; }
.canvas-tool-btn {
  border: 1px solid var(--border); background: #fff; border-radius: 8px;
  padding: 8px 12px; font-size: 13px; cursor: pointer; font-weight: 600;
  display: inline-flex; align-items: center; gap: 6px; font-family: inherit;
}
.canvas-tool-btn.active { border-color: var(--orange); color: var(--orange-text); background: #fff5f0; }
.canvas-tool-btn-danger { color: var(--red-text); border-color: #f0bcbc; }
.canvas-tool-btn-danger:hover { background: var(--red); border-color: var(--red); color: #fff; }
.canvas-save-status { margin-left: auto; font-size: 11.5px; color: var(--text-dim); }

.notes-canvas {
  width: 100%; height: 55vh; min-height: 380px; display: block;
  background: #fff; border: 1px solid var(--border); border-radius: 0 0 10px 10px;
  border-top: none; touch-action: none; cursor: crosshair;
}

/* ---------- Forms ---------- */
label { display: block; font-size: 12px; font-weight: 700; color: var(--text-dim); margin-bottom: 5px; }
input, select, textarea {
  width: 100%; border: 1px solid var(--border); border-radius: 9px; padding: 9px 11px;
  font-size: 13.5px; font-family: inherit; color: var(--text); background: #fff;
}
textarea { resize: vertical; min-height: 70px; }
.notes-textarea {
  min-height: 50vh; font-size: 16px; line-height: 1.6; padding: 16px;
}
.field { margin-bottom: 16px; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.checkbox-row { display: flex; align-items: center; gap: 8px; }
.checkbox-row input { width: auto; }
.checkbox-row label { margin: 0; }

/* ---------- Modal ---------- */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(15,18,24,0.55);
  display: flex; align-items: flex-start; justify-content: center; padding: 5vh 16px;
  z-index: 50; overflow-y: auto;
}
.modal {
  background: #fff; border-radius: 16px; width: 100%; max-width: 560px;
  padding: 28px 30px 24px; position: relative;
}
/* Bouton de fermeture : 18 px sans surface de clic auparavant, en haut à
   droite — la zone la plus difficile à atteindre au pouce sur un téléphone. */
.modal-close {
  position: absolute; top: 14px; right: 14px; background: none;
  border: 1px solid transparent; border-radius: 9px; cursor: pointer; color: var(--text-dim);
  width: 38px; height: 38px; display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
}
.modal-close:hover { background: var(--gray-bg); color: var(--text); }
.modal h2 { font-size: 21px; margin-top: 6px; }
.modal-footer { display: flex; justify-content: flex-end; gap: 10px; margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--border); }
.modal-footer-split { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; }

.gen-card { border: 1px solid var(--border); border-radius: 12px; padding: 16px; margin: 18px 0; }
.gen-download-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.gen-download { border-radius: 10px; padding: 14px 16px; text-align: left; }
.gen-download .t { font-size: 13.5px; font-weight: 700; }
.gen-download .s { font-size: 11.5px; opacity: 0.7; margin-top: 2px; }
.gen-download.disabled { opacity: 0.5; cursor: not-allowed; }

.alert {
  border-radius: 9px; padding: 10px 14px; font-size: 13px; margin-bottom: 16px;
}
.alert-error { background: var(--red-bg); color: var(--red-text); }
.alert-info { background: #eef2ff; color: #3730a3; }
.alert-warning { background: #fff5f0; color: #b45309; }
.alert > div + div { margin-top: 6px; }

/* ---------- Login ---------- */
.login-page {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  background: var(--navy);
  padding: 24px max(16px, env(safe-area-inset-right)) calc(24px + env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
}
.login-card { background: #fff; border-radius: 16px; padding: 36px 34px; width: 100%; max-width: 380px; }
.login-card img { height: 44px; margin-bottom: 18px; }
.login-card h1 { font-size: 20px; }
/* 16 px : sous ce seuil, Safari iOS zoome automatiquement au focus d'un
   champ et décale toute la mise en page pendant la saisie du mot de passe. */
.login-card input { font-size: 16px; padding: 11px 12px; }
.login-card .btn-orange { width: 100%; justify-content: center; margin-top: 6px; min-height: 46px; }

.empty-state { text-align: center; padding: 40px 20px; color: var(--text-dim); }
.error-picto { color: var(--text-dim); margin-bottom: 12px; }

/* ---------- Mobile / tablette ---------- */
@media (max-width: 860px) {
  .layout { flex-direction: column; }

  /* La sidebar classique (Vue d'ensemble/Chantiers/Entreprises,
     Messagerie/Utilisateurs/Historique/Mon compte/Aide, compte + déconnexion)
     ne tient pas à plat sur un téléphone — elle devient un tiroir plein
     écran masqué hors-champ par défaut, ouvert par le bouton ☰ de la barre
     du haut. Aucun lien n'est retiré : c'est exactement le même menu que sur
     Mac/iPad, juste replié tant qu'on n'en a pas besoin. */
  .mobile-topbar {
    display: flex; align-items: center; gap: 14px;
    position: sticky; top: 0; z-index: 45;
    background: #fff; border-bottom: 1px solid var(--border);
    padding: calc(10px + env(safe-area-inset-top)) max(14px, env(safe-area-inset-right)) 10px max(14px, env(safe-area-inset-left));
  }
  .mobile-menu-toggle {
    display: flex; align-items: center; justify-content: center;
    width: var(--cible-tactile); height: var(--cible-tactile); margin: -8px;
    background: none; border: none; color: var(--navy); border-radius: 8px; cursor: pointer;
  }
  .mobile-menu-toggle:hover { background: var(--gray-bg); }
  .mobile-topbar-logo { height: 22px; }

  .sidebar-overlay {
    display: block; position: fixed; inset: 0; z-index: 55;
    background: rgba(23,27,36,0.45);
    opacity: 0; pointer-events: none; transition: opacity 0.2s ease;
  }
  .sidebar-overlay.visible { opacity: 1; pointer-events: auto; }

  .sidebar {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 60;
    width: min(300px, 84vw); flex-wrap: nowrap;
    transform: translateX(-100%); transition: transform 0.25s ease;
    box-shadow: 2px 0 16px rgba(0,0,0,0.18);
    overflow-y: auto;
    /* Zone sûre iPhone : encoche/Dynamic Island en haut, bord arrondi à
       gauche en paysage. */
    padding: calc(20px + env(safe-area-inset-top)) 14px 20px max(14px, env(safe-area-inset-left));
  }
  .sidebar.sidebar-ouverte { transform: translateX(0); }

  .main {
    padding: 18px max(16px, env(safe-area-inset-right)) 40px max(16px, env(safe-area-inset-left));
  }

  .topbar { flex-wrap: wrap; }
  .search { order: 1; flex-basis: 100%; }

  .stat-grid, .stat-grid.four { grid-template-columns: 1fr 1fr; }
  .field-row { grid-template-columns: 1fr; }
  .gen-download-grid { grid-template-columns: 1fr; }

  /* Les onglets passent à la ligne au lieu de défiler horizontalement : en
     `overflow-x: auto`, les filtres « Pour mémoire » et « Terminé » sortaient
     du viewport à 390 px sans qu'aucun repère n'indique qu'il fallait faire
     glisser la barre — deux filtres sur cinq restaient introuvables, sur
     l'écran qui sert précisément à repérer les retards. */
  .tabs { max-width: 100%; flex-wrap: wrap; }
  .tabs a { flex: 0 0 auto; }

  .banner-faits { gap: 22px; }
  .banner-cr { text-align: left; }

  .sticky-action-bar {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    padding: 12px max(16px, env(safe-area-inset-right)) calc(12px + env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
    background: #fff; border-top: 1px solid var(--border);
    box-shadow: 0 -2px 10px rgba(0,0,0,0.06);
  }
  .sticky-action-bar .btn { flex: 1; text-align: center; min-height: var(--cible-tactile); }
  /* Laisse la place à la barre collante pour que le dernier bloc de
     contenu ne se retrouve jamais masqué derrière elle. */
  body:has(.sticky-action-bar) .main { padding-bottom: 92px; }

  .banner { flex-direction: column; gap: 14px; }

  .chantier-card { flex-direction: column; }
  .chantier-card-illustration { width: 100%; height: 120px; }
  .chantier-meta-row { gap: 20px; }

  /* "display:block" sur <table> sans reconvertir thead/tbody/tr/td laisse
     ces éléments se dimensionner selon leur contenu (algorithme table par
     défaut) et déborder du cadre malgré overflow-x:auto sur la table —
     table-layout:fixed + retour à la ligne du texte est plus fiable et ne
     nécessite aucun changement dans les gabarits qui utilisent .obs-table. */
  table.obs-table { table-layout: fixed; width: 100%; }
  table.obs-table td, table.obs-table th { white-space: normal; word-break: break-word; }

  /* Les 7 colonnes de la page Comptes rendus ne tiennent jamais lisiblement
     sur un téléphone. Elles étaient jusqu'ici traitées en masquant les
     colonnes Version et Envoi (5e et 6e) — une perte d'information assumée
     faute de mieux. La mise en cartes ci-dessous rend cet arbitrage inutile :
     les 7 champs redeviennent tous visibles, empilés et étiquetés. */
  .cr-actions, .cell-actions { justify-content: flex-start; }
  .cr-list-table { table-layout: auto; }
  .cr-list-table th:nth-child(n) { width: auto; }

  /* ---------- Tableaux transformés en cartes ----------
     Une table de 5 ou 6 colonnes ne tient pas sur un écran de téléphone :
     avec table-layout:fixed + word-break, chaque colonne tombait à ~26 px et
     le texte s'écrivait UNE LETTRE PAR LIGNE (page Entreprises mesurée à
     11 450 px de haut pour 25 entreprises, lien e-mail de 26 × 112 px).
     Chaque ligne devient donc une carte empilée, et le libellé de colonne
     réapparaît devant sa valeur via data-label. Aucune ligne, aucune donnée
     et aucun gestionnaire d'événement n'est retiré : la structure du DOM est
     identique, seul l'affichage change (les `onclick` posés sur <tr> et les
     sélecteurs `tbody tr[data-obs-id]` de observations-sync.js continuent
     donc de fonctionner exactement pareil). */
  table.table-cartes,
  table.table-cartes tbody,
  table.table-cartes tr,
  table.table-cartes td { display: block; width: 100%; }
  table.table-cartes { border: none; background: none; box-shadow: none; }
  table.table-cartes thead { display: none; }
  table.table-cartes tr {
    background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
    box-shadow: var(--ombre-carte); margin-bottom: 10px; padding: 4px 2px;
  }
  table.table-cartes tr:hover { background: #fff; }
  table.table-cartes td {
    border-bottom: 1px solid #f2f3f5; padding: 9px 14px;
    display: flex; gap: 12px; align-items: flex-start; justify-content: space-between;
    /* La valeur passe sous son étiquette plutôt que de déborder de la carte
       quand elle est trop longue pour les 62 % restants (cas mesuré :
       « Fin 29/08/2026 » sortait de 68 px hors de la carte à 390 px). */
    flex-wrap: wrap;
  }
  table.table-cartes td > * { min-width: 0; max-width: 100%; }
  /* Les échéances tiennent sur une ligne dans la colonne étroite du tableau
     desktop ; dans une carte, elles doivent pouvoir se replier. */
  table.table-cartes .echeance-ligne { white-space: normal; }
  table.table-cartes tr td:last-child { border-bottom: none; }
  table.table-cartes td::before {
    content: attr(data-label);
    flex: 0 0 38%;
    font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px;
    color: var(--text-dim); padding-top: 2px;
  }
  /* Cellule sans data-label (colonne d'actions) : la carte lui laisse toute
     la largeur plutôt qu'une étiquette vide. */
  table.table-cartes td:not([data-label]) { display: block; }
  table.table-cartes td:not([data-label])::before { content: none; }
  table.table-cartes td.cell-actions { display: flex; justify-content: flex-start; }
  table.table-cartes td.cell-actions::before { flex: 0 0 auto; }
  table.table-cartes td.empty-state { display: block; }
  table.table-cartes td.empty-state::before { content: none; }
  table.table-cartes .cell-nowrap { white-space: normal; }
  /* Adresse e-mail et téléphone : ce sont de vrais liens (ils ouvrent le
     client de messagerie ou le téléphone), mesurés à 16 px de haut. Dans une
     carte, ils occupent leur propre ligne : on peut leur donner une hauteur
     de cible confortable sans déformer quoi que ce soit. */
  table.table-cartes a[href^="mailto:"],
  table.table-cartes a[href^="tel:"] {
    display: inline-flex; align-items: center; min-height: var(--cible-tactile);
  }

  .modal { max-width: 100%; margin: 0 4px; }
  .modal-close { top: 10px; right: 10px; }
}

/* ---------- Zones tactiles ----------
   Mesures relevées avant correction à 390 px : liens de navigation 36 px de
   haut, .btn 36–38 px, .btn-sm 29 px, bouton de déconnexion 21 × 18 px,
   `summary` d'accordéon 17–20 px — tous sous la cible de 44 × 44 px
   recommandée (WCAG 2.5.5, Apple HIG) pour un usage au doigt, souvent debout
   et avec des gants sur un chantier.
   Deux conditions, en OU :
     - `max-width: 860px` couvre tous les téléphones et l'iPad en portrait ;
     - `pointer: coarse` rattrape l'iPad en PAYSAGE (1024 px de large, donc
       hors de la première condition, mais manipulé au doigt) ainsi que les
       Mac à écran tactile.
   La première condition seule laisserait l'iPad en paysage avec des boutons
   de 29 px ; la seconde seule dépendrait entièrement d'une requête média que
   certains navigateurs embarqués et outils de test ne rapportent pas
   correctement. Les deux ensemble ne laissent aucun trou. */
@media (max-width: 860px), (pointer: coarse) {
  .btn { min-height: var(--cible-tactile); padding-top: 10px; padding-bottom: 10px; }
  .btn-sm { min-height: var(--cible-tactile); padding: 11px 14px; }
  .nav li a { min-height: var(--cible-tactile); }
  .sidebar-help { min-height: var(--cible-tactile); }
  .sidebar-user button { width: var(--cible-tactile); height: var(--cible-tactile); }
  .tabs a, .tabs span { min-height: var(--cible-tactile); padding: 12px 14px; }
  .notes-mode-btn, .canvas-tool-btn { min-height: var(--cible-tactile); }
  .voice-mic-btn { min-height: var(--cible-tactile); padding: 10px 16px; }
  .modal-close { width: var(--cible-tactile); height: var(--cible-tactile); }
  .attach-thumb-btn { width: 32px; height: 30px; }
  details > summary { min-height: var(--cible-tactile); display: flex; align-items: center; }
  .lot-accordion > summary { align-items: center; }
  .promoteur-accordion > summary { padding: 4px 0; }
}

/* ---------- Navigation sur téléphone ----------
   Mesuré à 390 px : les trois entrées « Vue d'ensemble » (145 px),
   « Chantiers » (110 px) et « Entreprises » (116 px) totalisent 403 px une
   fois les marges de la barre comptées — « Entreprises » était donc coupée
   au bord droit de l'écran, alors que la note demande précisément que les
   trois entrées principales soient immédiatement visibles.
   Elles passent sur leur propre ligne, en trois parts égales : rien n'est
   tronqué, et chaque cible tactile gagne en largeur. */
@media (max-width: 560px) {
  .sidebar-footer { order: 2; }
  .nav { order: 3; flex: 1 1 100%; gap: 4px; }
  .nav li { flex: 1 1 0; min-width: 0; }
  .nav li a {
    justify-content: center; padding: 9px 4px; gap: 6px;
    font-size: 12.5px; overflow: hidden; text-overflow: ellipsis;
  }
}

@media (max-width: 480px) {
  .stat-grid, .stat-grid.four { grid-template-columns: 1fr; }
  .banner-faits { gap: 18px; }
}

/* Compte "lecture seule" : masque toute action de modification. Le blocage
   réel se fait côté serveur (middleware, voir app/main.py) — ceci n'est
   qu'un confort visuel pour ne jamais présenter un contrôle inutilisable. */
body.ro-lecture-seule .mut,
body.ro-lecture-seule [data-mut] {
  display: none !important;
}
body.ro-lecture-seule .ro-canvas {
  pointer-events: none;
  opacity: 0.75;
}

/* Dictée vocale (voice-dictation.js) */
.voice-mic-btn {
  border: 1px solid var(--border);
  background: #fff;
  border-radius: 999px;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  margin-left: 6px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.voice-mic-btn.voice-mic-active {
  background: var(--red);
  color: #fff;
  border-color: var(--red);
}
.voice-dictation-status {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 8px;
  padding: 8px 12px;
  background: var(--gray-bg);
  border-radius: var(--radius);
  font-size: 13px;
  flex-wrap: wrap;
}
.voice-rec-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--red);
  opacity: 0.5;
  flex-shrink: 0;
}
.voice-rec-dot-live {
  animation: voice-rec-pulse 1.2s infinite;
}
@keyframes voice-rec-pulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 1; }
}
.voice-rec-duree {
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
}
.voice-rec-erreur { color: var(--red-text); }
/* Sur le fond gris du bandeau de dictée, l'orange de marque ne donnait que
   3,0:1 — le message « Texte inséré » était le moins lisible de tous alors
   qu'il confirme le succès de la dictée. */
.voice-rec-ok { color: var(--orange-text); font-weight: 600; }
.voice-rec-transcription { color: var(--text-dim); font-style: italic; }

/* ---------- VIVIEN, assistant IA de DOMA SUIVI (fonctions désactivées
   tant que le cœur métier — Bloc B du plan de développement — n'est pas
   validé) — voir DESIGN.md section 12 pour la distinction avec l'assistant
   de DOMA CR (jamais réutilisé ici : classes et fichiers propres à SUIVI). */
.vivien-toggle {
  position: fixed;
  right: calc(22px + env(safe-area-inset-right));
  bottom: calc(22px + env(safe-area-inset-bottom));
  z-index: 41;
  display: flex; align-items: center; gap: 9px;
  padding: 7px 13px 7px 8px; border: 1px solid rgba(23,27,36,.12);
  border-radius: 999px; background: #fff; color: var(--navy); cursor: pointer;
  box-shadow: 0 10px 30px rgba(23,27,36,.2); font-family: inherit;
}
.vivien-toggle img { border-radius: 50%; }
.vivien-toggle span { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.05; }
.vivien-toggle strong { font-size: 12px; letter-spacing: .4px; }
.vivien-toggle small { margin-top: 3px; color: var(--text-dim); font-size: 10px; }
.vivien-toggle:hover { transform: translateY(-1px); box-shadow: 0 12px 34px rgba(23,27,36,.24); }

.vivien-panel {
  position: fixed; right: 22px; bottom: 88px; z-index: 42;
  width: min(360px, calc(100vw - 32px)); padding: 18px;
  background: #fff; border: 1px solid var(--border); border-radius: 16px;
  box-shadow: 0 18px 55px rgba(23,27,36,.24);
}
.vivien-panel[hidden] { display: none; }
.vivien-panel-head { display: flex; align-items: center; gap: 11px; }
.vivien-panel-head h2 { margin: 1px 0 0; font-size: 19px; }
.vivien-kicker { color: var(--orange-text); font-size: 10px; font-weight: 800; letter-spacing: .7px; }
.vivien-close {
  margin-left: auto; align-self: flex-start; border: 0; background: transparent;
  color: var(--text-dim); cursor: pointer; border-radius: 8px; padding: 0;
  width: 36px; height: 36px; display: inline-flex; align-items: center; justify-content: center;
}
.vivien-close:hover { background: var(--gray-bg); color: var(--text); }
.vivien-message { margin: 16px 0 12px; padding: 13px 14px; background: #fff6f1; border-radius: 11px; }
.vivien-message p { margin: 5px 0 0; color: var(--text-dim); line-height: 1.45; }
.vivien-actions { display: grid; gap: 7px; }
.vivien-actions button, .vivien-actions a { text-align: left; padding: 10px 12px; border: 1px solid var(--border); border-radius: 9px; background: var(--bg); color: var(--text-dim); text-decoration: none; display: flex; align-items: center; gap: 8px; }
.vivien-action-active { color: var(--text); font-weight: 600; border-color: var(--orange); }
.vivien-action-active:hover { background: var(--orange-bg, #fff6f1); }
.vivien-guardrail { margin: 10px 0 0; color: var(--text-dim); font-size: 11px; line-height: 1.4; }

@media (max-width: 700px) {
  .vivien-toggle {
    right: calc(14px + env(safe-area-inset-right));
    bottom: calc(14px + env(safe-area-inset-bottom));
  }
  .vivien-panel {
    right: calc(14px + env(safe-area-inset-right));
    bottom: calc(76px + env(safe-area-inset-bottom));
  }
}

/* ---------- Navigation : rubriques prévues mais pas encore construites ----------
   Visibles pour montrer la structure finale (voir plan de développement par
   blocs), désactivées tant que l'écran correspondant n'existe pas — jamais
   un lien mort. */
.nav-disabled {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; color: var(--text-dim); opacity: .55; cursor: default;
}
.nav-disabled .nav-icon { display: inline-flex; }
.nav-soon {
  margin-left: auto; font-size: 9px; font-weight: 800; letter-spacing: .4px;
  text-transform: uppercase; padding: 2px 6px; border-radius: 999px;
  background: var(--gray-bg); color: var(--text-dim);
}

/* ---------- Dictée vocale VIVIEN (voice-dictation.js, copié de doma-cr-app) ---------- */
.voice-mic-active {
  background: var(--red);
  color: #fff;
  border-color: var(--red);
}
.voice-dictation-status {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 8px;
  padding: 8px 12px;
  background: var(--gray-bg);
  border-radius: var(--radius);
  font-size: 13px;
  flex-wrap: wrap;
}
.voice-rec-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--red);
  opacity: 0.5;
  flex-shrink: 0;
}
.voice-rec-dot-live { animation: voice-rec-pulse 1.2s infinite; }
@keyframes voice-rec-pulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 1; }
}
.voice-rec-duree { font-variant-numeric: tabular-nums; color: var(--text-dim); }
.voice-rec-erreur { color: var(--red-text); }
.voice-rec-ok { color: var(--orange-text); font-weight: 600; }
.voice-rec-transcription { color: var(--text-dim); font-style: italic; }
