/* Caly-Bornes — extensions fonctionnelles du thème clair.
   Les tokens et composants transversaux vivent dans design-system.css.
   Ce fichier ne contient que les mises en page et composants métier. */

/* CB058 — outils normatifs stricts du dossier. Les contrôles restent lisibles
   au téléphone et ne partagent jamais une ligne trop étroite. */
.norm-tools-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-top: 14px;
}
.norm-tool-card {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px;
  background: var(--surface, #fff);
}
.norm-tool-card h4 { margin: 0 0 4px; }
.norm-form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 9px;
  margin: 12px 0;
}
.norm-form-grid label {
  display: grid;
  gap: 5px;
  min-width: 0;
  font-size: .75rem;
  font-weight: 650;
}
.norm-form-grid input,
.norm-form-grid select {
  width: 100%;
  min-height: 44px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface, #fff);
  color: var(--text);
  font: inherit;
}
.norm-form-grid .norm-check {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
}
.norm-form-grid .norm-check input { width: 20px; min-height: 20px; }
.norm-result {
  display: block;
  min-height: 44px;
  margin-top: 10px;
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--bg-soft, #f4f7fb);
  line-height: 1.4;
}
.norm-result:empty { display: none; }
.norm-result[data-state="ok"] { color: #166534; background: #ecfdf3; }
.norm-result[data-state="warning"] { color: #92400e; background: #fffbeb; }
.norm-result[data-state="error"] { color: #991b1b; background: #fef2f2; }
.norm-manufacturer-directory {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 7px;
  margin: 12px 0;
}
.norm-manufacturer-card,
.norm-import-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  padding: 10px;
  border: 1px solid var(--border);
  border-left: 4px solid #d97706;
  border-radius: 9px;
  background: var(--bg-soft, #f8fafc);
}
.norm-manufacturer-card[data-state="active"] { border-left-color: #16a34a; }
.norm-manufacturer-card div,
.norm-import-row > div:first-child { display: grid; gap: 3px; min-width: 0; }
.norm-manufacturer-card span,
.norm-import-row span { color: var(--text-muted); font-size: .7rem; line-height: 1.35; }
.norm-manufacturer-card a { white-space: nowrap; font-size: .7rem; font-weight: 750; }
.norm-import-panel {
  margin-top: 12px;
  border-top: 1px solid var(--border);
  padding-top: 12px;
}
.norm-import-panel > summary { cursor: pointer; font-weight: 800; }
.norm-form-grid textarea {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface, #fff);
  color: var(--text);
  font: inherit;
  resize: vertical;
}
.norm-span-2 { grid-column: 1 / -1; }
.norm-import-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; }
.norm-import-list { display: grid; gap: 8px; margin-top: 12px; }
.norm-import-row[data-state="DOCUMENT_VALIDATED"] { border-left-color: #16a34a; }
.norm-import-row[data-state="REJECTED"] { border-left-color: #dc2626; }

@media (max-width: 760px) {
  .norm-tools-grid,
  .norm-form-grid,
  .norm-manufacturer-directory { grid-template-columns: 1fr; }
  .norm-tool-card { padding: 12px; }
  .norm-tool-card .btn-sm { width: 100%; min-height: 44px; }
  .norm-span-2 { grid-column: auto; }
  .norm-manufacturer-card,
  .norm-import-row { flex-direction: column; }
  .norm-import-actions { width: 100%; justify-content: stretch; }
}

/* CB048 — estimateur strict de durée de recharge. */
.ce-intro {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  align-items: flex-start;
  padding: 2px 2px 14px;
}
.ce-intro h3 { margin: 5px 0 6px; font-size: 1.15rem; }
.ce-intro p { margin: 0; color: var(--text-muted); line-height: 1.5; max-width: 780px; }
.ce-nature {
  display: inline-flex;
  color: #9a3412;
  background: #fff7ed;
  border: 1px solid #fed7aa;
  border-radius: 999px;
  padding: 3px 9px;
  font-size: .68rem;
  font-weight: 800;
  letter-spacing: .06em;
}
.ce-scope {
  flex: 0 0 auto;
  display: grid;
  gap: 2px;
  min-width: 190px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: 9px;
  background: var(--bg-card);
}
.ce-scope span { color: var(--text-muted); font-size: .78rem; }
.ce-section {
  border: 1px solid var(--border);
  border-radius: 10px;
  margin: 0 0 12px;
  padding: 12px;
  min-width: 0;
  background: var(--bg-card);
}
.ce-section legend { padding: 0 6px; font-weight: 750; color: var(--text); }
.ce-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px 12px;
}
.ce-three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ce-span-2 { grid-column: 1 / -1; }
.ce-section .fld { min-width: 0; }
.ce-section .fld > span { line-height: 1.35; }
.ce-section input[readonly] { background: var(--surface-2); color: var(--text-muted); }
.ce-section [aria-invalid="true"] {
  border-color: #dc2626 !important;
  box-shadow: 0 0 0 2px rgba(220, 38, 38, .13) !important;
}
.ce-field-error {
  display: block;
  margin-top: 4px;
  color: #b91c1c;
  font-size: .72rem;
  line-height: 1.35;
}
.ce-error-box,
.ce-stale {
  padding: 9px 11px;
  margin: 0 0 10px;
  border-left: 4px solid #dc2626;
  border-radius: 7px;
  background: #fef2f2;
  color: #991b1b;
  font-size: .82rem;
}
.ce-stale { border-left-color: #d97706; background: #fffbeb; color: #92400e; }
.ce-note { margin: 9px 2px 0; font-size: .76rem; line-height: 1.45; }
.ce-hypotheses {
  margin-top: 10px;
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--surface-2);
  font-size: .8rem;
  line-height: 1.45;
}
.ce-hypotheses ul { margin: 6px 0 9px; padding-left: 20px; }
.ce-confirm {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  gap: 9px;
  align-items: start;
  width: 100%;
  min-width: 0;
  min-height: 44px;
  font-weight: 650;
}
.ce-confirm input[type="checkbox"] {
  width: 20px;
  height: 20px;
  min-width: 20px;
  padding: 0;
  margin: 2px 0 0;
  justify-self: start;
}
.ce-confirm span { min-width: 0; overflow-wrap: anywhere; }
.ce-actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin: 4px 0 14px; }
.ce-result-card {
  border: 1px solid #93c5fd;
  border-left: 5px solid #2563eb;
  border-radius: 10px;
  background: color-mix(in srgb, var(--bg-card) 94%, #dbeafe);
  padding: 14px;
}
.ce-result-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.ce-result-head h3 { margin: 7px 0 0; font-size: 1.22rem; }
.ce-result-card > p { line-height: 1.55; }
.ce-result-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  margin-top: 10px;
}
.ce-result-grid > div {
  display: grid;
  gap: 4px;
  padding: 9px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-panel);
}
.ce-result-grid span { color: var(--text-muted); font-size: .7rem; }
.ce-result-grid strong { font-size: .86rem; }
.ce-proof { margin-top: 11px; font-size: .78rem; }
.ce-proof summary { cursor: pointer; font-weight: 700; }
.ce-proof code { overflow-wrap: anywhere; }

@media (max-width: 760px) {
  .ce-intro { display: grid; }
  .ce-scope { min-width: 0; width: 100%; }
  .ce-grid,
  .ce-three,
  .ce-result-grid { grid-template-columns: minmax(0, 1fr); }
  .ce-span-2 { grid-column: auto; }
  .ce-section { padding: 10px; }
  .ce-actions .btn { width: 100%; }
  .ce-result-head { display: grid; }
}
svg.cIcon { display: inline-block; vertical-align: middle; }
/* Scrollbars discrètes (façon Google) */
*::-webkit-scrollbar { width: 12px; height: 12px; }
*::-webkit-scrollbar-thumb { background: #cdd2d9; border-radius: 8px; border: 3px solid transparent; background-clip: content-box; }
*::-webkit-scrollbar-thumb:hover { background: #b3b9c2; background-clip: content-box; }
select, option { color-scheme: light; }
select option { background: #fff; color: var(--text); padding: 4px 8px; }
.hidden { display: none !important; }
/* ── Connexion ── */
.login-screen { height: 100vh; display: flex; align-items: center; justify-content: center; background: var(--bg-dark); }
.login-box {
  background: var(--bg-panel); border: 1px solid var(--border-2); border-radius: 16px;
  padding: 2.4rem 2.6rem; width: 372px; display: flex; flex-direction: column; gap: 12px;
  box-shadow: var(--shadow-2);
}
.login-logo { font-size: 1.6rem; font-weight: 600; color: var(--accent); text-align: center; }
.login-sub { text-align: center; color: var(--text-muted); font-size: .85rem; margin-bottom: 8px; }
.login-hint { text-align: center; color: var(--text-faint); font-size: .78rem; }
.login-error { color: var(--danger); font-size: .82rem; text-align: center; min-height: 1em; }

/* Téléphone : la cible réelle est 310 px de large (Galaxy A16, densité forcée).
   ⚠ Conservée du lot des « quatre portes », retiré le 2026-08-04 : cette règle-ci
   ne concerne pas les portes mais la boîte de connexion elle-même, qui débordait
   en largeur sans elle. */
@media (max-width: 500px) {
  .login-box { width: 100%; max-width: 100%; padding: 1.6rem 1.1rem; border-radius: 0; }
  .login-screen { align-items: flex-start; padding-top: 6vh; }
}

/* ── Mise en page : barre latérale ── */
/* ⚠ `100dvh` : hauteur RÉELLEMENT visible, barre d'adresse du navigateur
   déduite. `100vh` vaut la hauteur AVEC la barre rétractée : les derniers
   pixels du contenu se cachaient dessous. La ligne `100vh` reste en premier
   comme repli pour les navigateurs qui ignorent `dvh`. Précédent dans le
   dépôt : app.js pose déjà `100dvh` pour ce même motif. */
.app { display: flex; flex-direction: column; height: 100vh; height: 100dvh; }

/* Barre du haut (remplace la sidebar : navigation via le hub Accueil + « ← Accueil »). */
.topbar {
  display: flex; align-items: center; gap: 12px; flex-shrink: 0;
  height: 56px; padding: 0 18px; background: var(--bg-panel);
  border-bottom: 1px solid var(--border); box-shadow: var(--shadow-1); z-index: 50;
}
.topbar .brand { flex-shrink: 0; }
.topbar-home {
  display: inline-flex; align-items: center; gap: 7px; background: var(--brand-100);
  color: var(--brand-700); border: 1px solid transparent; padding: 7px 15px;
  border-radius: var(--radius-pill); cursor: pointer; font-size: .86rem; font-weight: 600; font-family: inherit;
}
.topbar-home:hover { background: var(--brand-50); }
.topbar-home svg { width: 16px; height: 16px; }
.topbar-alerts {
  position: relative; display: inline-flex; align-items: center; gap: 5px; background: transparent;
  border: 1px solid var(--border); border-radius: var(--radius-pill); padding: 6px 12px;
  cursor: pointer; color: var(--text-muted);
}
.topbar-alerts:hover { color: var(--text); background: var(--surface-2); }
.topbar-alerts svg { width: 17px; height: 17px; }
.topbar-alerts .alerts-badge { position: static; margin: 0; }

.sidebar {
  width: 256px; flex-shrink: 0; display: flex; flex-direction: column; overflow: hidden;
  background: var(--bg-panel); border-right: 1px solid var(--border);
  transition: width .18s ease;
}
.sidebar__brand {
  display: flex; align-items: center; gap: 10px; height: 60px; padding: 0 14px;
  flex-shrink: 0;
}
.sidebar__burger {
  background: transparent; border: 0; color: var(--text-muted); cursor: pointer;
  padding: 6px; border-radius: 50%; line-height: 0; display: grid; place-items: center;
}
.sidebar__burger:hover { color: var(--text); background: var(--surface-2); }
.sidebar__burger svg { width: 20px; height: 20px; }
.brand { display: flex; align-items: center; gap: 11px; min-width: 0; }
.brand-mark {
  width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0;
  background: linear-gradient(135deg, #4285f4, #1a73e8); color: #fff;
  display: grid; place-items: center; box-shadow: var(--shadow-1);
}
.brand-mark svg { width: 19px; height: 19px; }
.brand-text { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }
.brand-name { font-weight: 600; color: var(--text); font-size: 15.5px; white-space: nowrap; }
.brand-sub { font-size: 11px; color: var(--text-faint); white-space: nowrap; }

.sidenav { flex: 1; overflow-y: auto; padding: 6px 12px 12px; display: flex; flex-direction: column; gap: 1px; }

/* Groupes déroulants */
.nav-group { display: flex; flex-direction: column; }
.nav-group__header {
  display: flex; align-items: center; justify-content: space-between; width: 100%;
  background: transparent; border: 0; color: var(--text-faint); cursor: pointer;
  text-transform: uppercase; font-size: .68rem; letter-spacing: .06em; font-weight: 700;
  padding: 15px 14px 6px;
}
.nav-group__header:hover { color: var(--text-muted); }
.nav-grp-caret { font-size: .7rem; opacity: .8; transition: transform .15s ease; }
.nav-group.collapsed .nav-grp-caret { transform: rotate(-90deg); }
.nav-group.collapsed .nav-group__items { display: none; }
.nav-group__items { display: flex; flex-direction: column; gap: 1px; }

/* Élément de nav = pastille arrondie (façon Gmail) */
.tab {
  display: flex; align-items: center; gap: 13px; width: 100%; text-align: left;
  background: transparent; border: 0; color: var(--text-muted);
  padding: 9px 14px; border-radius: var(--radius-pill); cursor: pointer; font-size: 14px; font-weight: 500;
  transition: background .12s, color .12s;
}
.tab:hover { color: var(--text); background: var(--surface-2); }
.tab.active { color: var(--brand-700); background: var(--brand-100); font-weight: 600; }
.tab .nav-ico { width: 19px; height: 19px; flex-shrink: 0; color: var(--text-muted); display: grid; place-items: center; }
.tab .nav-ico svg { width: 19px; height: 19px; }
.tab:hover .nav-ico { color: var(--text); }
.tab.active .nav-ico { color: var(--brand-700); }
.nav-lbl { flex: 1; }

.sidebar__footer { border-top: 1px solid var(--border); padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; flex-shrink: 0; }
.sidebar__status { display: flex; align-items: center; gap: 10px; min-height: 14px; }
.user-label { font-size: .82rem; color: var(--text-muted); }

/* Menu compte */
.account-menu { position: relative; }
.account-btn {
  width: 100%; justify-content: space-between;
  background: transparent; border: 1px solid var(--border); color: var(--text);
  padding: 8px 12px; border-radius: var(--radius-pill); cursor: pointer; font-size: .84rem;
  display: flex; align-items: center; gap: 6px;
}
.account-btn:hover { background: var(--surface-2); border-color: var(--border); }
.account-caret { font-size: .7rem; opacity: .7; }
.account-dropdown {
  /* Menu déplacé du pied de sidebar vers le topbar : il doit s'ouvrir VERS LE BAS
     (ancré à droite), sinon il sort de l'écran par le haut. */
  position: absolute; right: 0; left: auto; top: calc(100% + 6px); bottom: auto; min-width: 190px;
  background: var(--bg-panel); border: 1px solid var(--border-2); border-radius: 12px;
  box-shadow: var(--shadow-2); padding: 6px; z-index: 100;
  display: flex; flex-direction: column; gap: 2px;
}
.account-dropdown.hidden { display: none; }
.account-item {
  background: transparent; border: 0; color: var(--text); text-align: left;
  padding: 9px 12px; border-radius: 8px; cursor: pointer; font-size: .85rem;
}
.account-item:hover { background: var(--surface-2); color: var(--accent); }
.sync-badge { font-size: .74rem; font-weight: 700; color: var(--success); }
.sync-badge.pending { color: var(--warning); }

/* Repli en rail d'icônes (bouton ☰) */
.app.nav-collapsed .sidebar { width: 64px; }
.app.nav-collapsed .brand-text,
.app.nav-collapsed .nav-lbl,
.app.nav-collapsed .nav-grp-lbl,
.app.nav-collapsed .nav-grp-caret,
.app.nav-collapsed .nav-group__header,
.app.nav-collapsed .user-label,
.app.nav-collapsed .account-caret,
.app.nav-collapsed .sidebar__status { display: none; }
.app.nav-collapsed .nav-group.collapsed .nav-group__items { display: flex; }
.app.nav-collapsed .tab,
.app.nav-collapsed .account-btn { justify-content: center; padding-left: 0; padding-right: 0; gap: 0; }
.app.nav-collapsed .sidebar__brand { justify-content: center; padding: 0 8px; }
.app.nav-collapsed .sidebar__footer { padding: 10px 8px; }

/* Responsive : la barre latérale se superpose sur petit écran */
@media (max-width: 820px) {
  .sidebar { position: fixed; top: 0; left: 0; height: 100vh; z-index: 200; box-shadow: var(--shadow-3); }
  .app.nav-collapsed .sidebar { width: 0; border-right: 0; }
  .content { width: 100%; }
}

/* Badge d'alertes dans la nav */
.alerts-badge {
  display: inline-grid; place-items: center; min-width: 20px; height: 20px; padding: 0 6px; margin-left: auto;
  border-radius: 999px; font-size: .7rem; font-weight: 700;
  background: var(--danger); color: #fff; line-height: 1;
}
.alerts-badge.warn { background: var(--warning-strong); }
.alerts-badge.hidden { display: none; }
.alerts-badge.pulse { animation: alertPulse 1.6s ease-in-out infinite; }
@keyframes alertPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(217,48,37,.5); }
  50% { box-shadow: 0 0 0 6px rgba(217,48,37,0); }
}

/* ── Contenu ── */
.content { flex: 1; overflow-y: auto; padding: 26px 28px 44px; }
.content h2 { font-size: 1.3rem; font-weight: 500; margin-bottom: 18px; letter-spacing: -.01em; }
.count {
  display: inline-block; font-size: .76rem; font-weight: 600; background: var(--surface-2); color: var(--text-muted);
  padding: 2px 9px; border-radius: 999px; vertical-align: middle; margin-left: 6px; line-height: 1.4;
}
.content h2 .count, .alerts-subtab.active .count, .subtab.active .count { font-size: .8rem; padding: 3px 10px; background: var(--brand-50); color: var(--brand-700); }
.view-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 18px; flex-wrap: wrap; }
.view-head h2 { margin-bottom: 0; }

/* ── Recherche unique de l'en-tête ────────────────────────────────────────
   Client, site, borne ou identifiant OCPP. `min-width:0` sur le conteneur (posé
   en ligne dans index.html) est indispensable : sans lui l'élément refuse de
   rétrécir et fait déborder l'en-tête sur un écran de 310 px. */
.topbar-recherche { flex: 1; min-width: 0; position: relative; max-width: 460px; margin: 0 10px; }
.topbar-recherche input {
  width: 100%; padding: 7px 12px; border: 1px solid var(--border);
  border-radius: 18px; background: var(--bg-card); color: var(--text);
  font: inherit; font-size: .86rem; min-width: 0;
}
.topbar-recherche input:focus { outline: none; border-color: var(--brand-500, #06b6d4); }
.q-resultats {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 60;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: var(--shadow-3); max-height: 60vh; overflow-y: auto; padding: 4px;
}
.q-resultats .q-item {
  display: grid; gap: 5px; width: 100%; text-align: left;
  border: 0; background: none; padding: 8px 10px; border-radius: 7px;
  cursor: pointer; font: inherit;
}
.q-resultats .q-item:hover, .q-resultats .q-survol { background: var(--brand-50); }
.q-resultats .q-resultat-entete { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.q-resultats .q-type {
  font-size: .66rem; text-transform: uppercase; letter-spacing: .4px;
  padding: 2px 6px; border-radius: 4px; flex: 0 0 auto;
  background: var(--surface-2); color: var(--text-muted);
}
.q-resultats .q-type-site { background: #dbeafe; color: #1e40af; }
.q-resultats .q-lbl { font-size: .88rem; font-weight: 650; color: var(--text); overflow-wrap: anywhere; }
.q-resultats .q-contexte {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px 8px;
  font-size: .72rem; color: var(--text-muted);
}
.q-resultats .q-contexte-item { min-width: 0; overflow-wrap: anywhere; }
.q-resultats .q-contexte-item b { color: var(--text); font-weight: 650; }
.q-resultats .q-detail {
  font-size: .74rem; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.q-vide { padding: 10px 12px; font-size: .82rem; color: var(--text-muted); }
/* La loupe n'existe QUE sur téléphone : sur poste le champ tient sans elle. */
.topbar-loupe { display: none; }

/* ⚠ MESURÉ SUR L'APPAREIL (Galaxy A16, 310 px) : avec la marque, le bouton
   Accueil, les alertes, l'état réseau, la synchronisation et le compte, le champ
   de recherche tombait à 26 px de large — on ne lit ni l'invite, ni ce qu'on
   tape. Il se replie donc derrière une loupe et s'ouvre PAR-DESSUS l'en-tête,
   sur toute la largeur. Aucun espace vertical perdu en permanence : sur 630 px
   de haut, une deuxième ligne fixe aurait coûté 7 % de l'écran pour un champ
   qu'on ouvre quelques secondes. */
@media (max-width: 640px) {
  .topbar-loupe {
    display: inline-flex; align-items: center; justify-content: center;
    width: 38px; height: 38px; flex: 0 0 auto; border: 1px solid var(--border);
    background: var(--bg-card); color: var(--text); border-radius: 50%; cursor: pointer;
  }
  .topbar-recherche { display: none; margin: 0; }
  .topbar-recherche.q-ouverte {
    display: block; position: absolute; left: 8px; right: 8px; top: 8px;
    z-index: 70; max-width: none;
  }
  .topbar-recherche.q-ouverte input { height: 38px; }
  .q-resultats { position: fixed; left: 8px; right: 8px; top: 56px; }
  .q-resultats .q-item { min-height: 48px; padding: 10px; }
  .q-resultats .q-contexte { grid-template-columns: 1fr; gap: 2px; font-size: .76rem; }
}

/* Fil d'Ariane injecté au-dessus du titre par `filDAriane` (app.js). Il retrace
   le chemin RÉELLEMENT parcouru : chaque segment ramène là où l'on est passé.
   Premier élément de la page — c'est ce que le pouce rencontre en haut d'écran
   sur téléphone, où la barre latérale est repliée.
   Il DOIT pouvoir passer à la ligne : sur 310 px, quatre segments ne tiennent
   pas sur une seule, et un `nowrap` provoquerait un débordement horizontal. */
.fil-ariane { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 4px; margin-bottom: 12px; }
.fil-ariane .fil-seg {
  border: 0; background: none; padding: 4px 6px; border-radius: 6px; cursor: pointer;
  font: inherit; font-size: .82rem; color: var(--brand-700); white-space: nowrap;
}
.fil-ariane .fil-seg:hover { background: var(--brand-50); text-decoration: underline; }
.fil-ariane .fil-sep { color: var(--text-muted); font-size: .82rem; }
.fil-ariane .fil-actuel {
  font-size: .82rem; color: var(--text-muted); padding: 4px 2px;
  overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
/* Cible tactile : 6 px de padding vertical donnent ~30 px de haut, insuffisant
   au doigt. On élargit sur écran tactile SANS toucher au rendu sur poste. */
@media (pointer: coarse) {
  .fil-ariane .fil-seg { padding: 8px 8px; font-size: .86rem; }
  .fil-ariane .fil-actuel { font-size: .86rem; }
}

/* ── Cartes statistiques (tuiles) ── */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 16px; margin-bottom: 20px; }
.stat { background: var(--bg-panel); border: 1px solid var(--border-2); border-radius: var(--radius); padding: 18px 20px; box-shadow: var(--shadow-1); }
.stat-ico { width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; margin-bottom: 14px; }
.stat-ico svg { width: 22px; height: 22px; }
.stat-ico.red { background: var(--danger-bg); color: var(--danger); }
.stat-ico.amber { background: var(--warning-bg); color: #e37400; }
.stat-ico.green { background: var(--success-bg); color: var(--success); }
.stat-ico.blue { background: var(--brand-50); color: var(--accent); }
.stat-ico.slate { background: var(--surface-2); color: var(--text-muted); }
.stat-val { font-size: 1.9rem; font-weight: 500; color: var(--text); line-height: 1.05; letter-spacing: -.01em; }
.stat-title { font-size: .84rem; color: var(--text-muted); margin-top: 6px; font-weight: 500; }
.stat-sub { font-size: .72rem; color: var(--text-faint); margin-top: 6px; }

tr.row-link { cursor: pointer; }
tr.row-link:hover { background: var(--brand-50); }
tr.row-link td:last-child { color: var(--accent); font-weight: 600; text-align: right; }

/* ── Badges de statut ── */
.badge { font-size: .72rem; font-weight: 600; padding: 3px 10px; border-radius: 999px;
  background: var(--surface-2); color: var(--text); display: inline-block; }
.badge.b-prospect { background: #e8eaed; color: #3c4043; }
.badge.b-audite { background: #d2e3fc; color: #174ea6; }
.badge.b-concu { background: #e9d8fd; color: #6b21a8; }
.badge.b-en_travaux { background: #feefc3; color: #976400; }
.badge.b-en_service { background: #ceead6; color: #137333; }
.badge.b-planifiee { background: #e8eaed; color: #3c4043; }
.badge.b-installee { background: #feefc3; color: #976400; }
.badge.b-hors_service { background: #fad2cf; color: #a50e0e; }
.badge.b-actif { background: #d2e3fc; color: #174ea6; }

/* ── Listes clé/valeur ── */
.kv { display: grid; grid-template-columns: 200px 1fr; gap: 7px 14px; margin-bottom: 14px; }
.kv .k { color: var(--text-muted); font-size: .82rem; }
.kv .v { font-size: .88rem; }

/* ── Sous-onglets (façon Chrome : onglets « dossier » qui se fondent dans le contenu) ── */
.subtabs {
  display: flex; gap: 4px; align-items: flex-end;
  flex-wrap: wrap;                           /* fiche borne : jusqu'à 7 onglets → repli propre sur écran étroit */
  margin-bottom: 16px; padding-top: 4px;
  border-bottom: 1px solid var(--border);   /* arête du contenu : l'onglet actif vient s'y connecter */
}
.mt-subtabs { gap: 0; margin-bottom: 0; align-items: flex-end; }
.mt-actions {
  display: flex; gap: 4px; align-items: center; flex-wrap: wrap; margin-top: 8px;
}
.subtab {
  background: var(--bg-card);                /* onglet inactif : gris clair, légèrement en retrait */
  border: 1px solid var(--border);
  border-bottom: none;
  color: var(--text-muted); cursor: pointer;
  padding: 9px 18px; font-size: .88rem; font-weight: 600;
  position: relative; top: 1px;              /* inactifs poussés sous l'arête */
  border-radius: 10px 10px 0 0;
  margin-bottom: -1px;                       /* chevauche la bordure du conteneur */
  transition: background .12s ease, color .12s ease;
}
.subtab:hover { color: var(--text); background: var(--surface-2); }
.subtab.active {
  background: var(--bg-panel);               /* blanc = même surface que le contenu → onglet « ouvert » */
  color: var(--brand-700); top: 0; z-index: 1;
  border-color: var(--border);
  border-bottom: 1px solid var(--bg-panel);  /* masque l'arête du conteneur sous l'onglet actif */
  box-shadow: 0 -1px 3px rgba(60,64,67,.08); /* léger relief comme l'onglet de premier plan de Chrome */
}
.subtab.active::after { content: none; }     /* retire l'ancien soulignement Material */

/* Boutons commandes OCPP */
.cmd-btn { text-align: left; justify-content: flex-start; padding: 11px 14px; transition: all .15s; }
.cmd-btn:hover { background: var(--surface-2); border-color: var(--accent); color: var(--text); }
.cmd-btn.cmd-danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.cmd-btn.cmd-danger:hover { background: #b91c1c; border-color: #b91c1c; color: #fff; }

/* ── Formulaires ── */
input, select, textarea {
  background: var(--bg-panel); border: 1px solid var(--border); color: var(--text);
  padding: 10px 12px; border-radius: var(--radius-sm); font-size: .88rem; font-family: inherit; width: 100%;
  transition: border-color .12s, box-shadow .12s;
}
input::placeholder, textarea::placeholder { color: var(--text-faint); }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--brand-50); }
textarea { resize: vertical; min-height: 64px; }
.fld { display: flex; flex-direction: column; gap: 5px; }
.fld span { font-size: .78rem; color: var(--text-muted); }

/* ── Fenêtres modales ── */
.modal-ov {
  position: fixed; inset: 0; background: rgba(32,33,36,.5); display: flex;
  align-items: center; justify-content: center; z-index: 1000; padding: 20px;
}
.modal {
  background: var(--bg-panel); border: 1px solid var(--border-2); border-radius: 16px;
  padding: 24px; width: 480px; max-width: 100%; max-height: 90vh; overflow-y: auto; box-shadow: var(--shadow-3);
}
.modal h3 { color: var(--text); margin-bottom: 14px; font-size: 1.1rem; font-weight: 600; }
.modal-form { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.modal-form .fld:has(textarea) { grid-column: 1 / -1; }
.modal-actions { grid-column: 1 / -1; display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; }
/* Modal générique (import logs, etc.) */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(32,33,36,.5);
  display: flex; align-items: center; justify-content: center;
  z-index: 9999; padding: 20px;
}
.modal-box {
  background: var(--bg-panel); border: 1px solid var(--border-2);
  border-radius: 16px; padding: 24px; max-width: 600px; width: 100%;
  max-height: 90vh; overflow-y: auto; overflow-x: hidden; box-shadow: var(--shadow-3);
}
.modal-box * { box-sizing: border-box; }
.modal-box h3 { margin: 0 0 10px; color: var(--text); }
.cpw-modal-box { max-width: 460px; }
.cpw-description { font-size: .85rem; }
.cpw-form { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.cpw-error { display: none; font-size: .82rem; }
.cpw-error.is-visible { display: block; }
.modal-button-row { display: flex; justify-content: flex-end; gap: 8px; margin-top: 6px; }
.error-back-row { margin-top: 12px; }
.required-mark { color: var(--danger); }

/* ── États divers ── */
.loading, .empty, .error { padding: 30px; text-align: center; color: var(--text-muted); font-size: .9rem; }
.error { color: var(--danger); }
.empty {
  background: var(--bg-panel); border: 1px dashed var(--border); border-radius: var(--radius);
}

/* ── Toasts ── */
.toast {
  /* ⚠ `--barre-h` vaut 0 tant que la barre basse n'est pas affichée : ce
     décalage est donc sans effet sur poste et tablette. Sans lui, le message
     éphémère se peint DERRIÈRE la barre — 276 appels à `toast()` concernés,
     et pas un seul à modifier. */
  position: fixed; bottom: calc(24px + var(--barre-h, 0px)); left: 50%; transform: translateX(-50%) translateY(20px);
  background: #323639; border: 1px solid #3c4043; color: #fff;
  padding: 12px 20px; border-radius: 10px; font-size: .85rem; opacity: 0;
  transition: all .25s; z-index: 200; box-shadow: var(--shadow-2);
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast.error { border-color: var(--danger); color: #ffc2bd; }

/* ───────── Cartes d'alerte (cycle de vie) ───────── */
.alerts-list { display: flex; flex-direction: column; }
.alert-card {
  display: flex; gap: 15px; padding: 16px 18px; border-radius: var(--radius);
  border: 1px solid var(--border-2); border-left: 4px solid var(--border); margin-bottom: 12px;
  background: var(--bg-panel); align-items: flex-start; box-shadow: var(--shadow-1);
}
.alert-card.sev-error { border-left-color: var(--danger); }
.alert-card.sev-warn { border-left-color: var(--warning-strong); }
.alert-card.sev-info { border-left-color: var(--accent); }
.alert-card .alert-icon {
  width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center;
  flex-shrink: 0; font-size: 1.15rem; line-height: 1;
}
.alert-card .alert-icon svg { width: 20px; height: 20px; }
.alert-card.sev-error .alert-icon { background: var(--danger-bg); color: var(--danger); }
.alert-card.sev-warn .alert-icon { background: var(--warning-bg); color: #e37400; }
.alert-card.sev-info .alert-icon { background: var(--brand-50); color: var(--accent); }
.alert-card.st-resolved .alert-icon { background: var(--success-bg); color: var(--success); }
.alert-card .alert-body { flex: 1; min-width: 0; }
.alert-card .alert-title { font-weight: 500; font-size: 1rem; color: var(--text); margin-bottom: 4px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.alert-card .alert-meta { font-size: .78rem; color: var(--text-faint); }
.alert-card .alert-msg { font-size: .88rem; margin: 4px 0; color: var(--text-muted); line-height: 1.55; }
.alert-card .alert-actions { display: flex; gap: 9px; flex-wrap: wrap; margin-top: 12px; }
/* Pastille de statut */
.alert-status {
  display: inline-flex; align-items: center; gap: 5px; font-size: .72rem; font-weight: 600; padding: 3px 11px;
  border-radius: 999px; vertical-align: middle; white-space: nowrap;
}
.alert-status.st-active   { background: var(--danger-bg); color: #c5221f; }
.alert-status.st-acked    { background: var(--brand-50); color: var(--brand-700); }
.alert-status.st-resolved { background: var(--success-bg); color: var(--success); }
.alert-status.st-archived { background: var(--surface-2); color: var(--text-muted); }
.alert-card.st-acked .alert-icon { opacity: .7; }
/* Sous-onglets Actives / Archivées (façon Chrome : onglets « dossier ») */
/* flex-wrap : sans lui, le 3e onglet (« Alertes archivées ») sortait de l'écran
   sur téléphone et devenait DÉFINITIVEMENT inatteignable — `.content` masque le
   débordement horizontal, il n'y a donc aucun geste pour aller le chercher.
   Même traitement que `.subtabs`. */
.alerts-subtabs { display: flex; flex-wrap: wrap; gap: 4px; align-items: flex-end; margin: 18px 0 12px; padding-top: 4px; border-bottom: 1px solid var(--border); }
.alerts-subtab {
  background: var(--bg-card); border: 1px solid var(--border); border-bottom: none; cursor: pointer; position: relative; top: 1px;
  color: var(--text-muted); font-weight: 600; font-size: .88rem; padding: 9px 16px; border-radius: 10px 10px 0 0; margin-bottom: -1px;
  display: inline-flex; align-items: center; gap: 8px; transition: background .12s ease, color .12s ease;
}
.alerts-subtab:hover { color: var(--text); background: var(--surface-2); }
.alerts-subtab.active {
  background: var(--bg-panel); color: var(--brand-700); top: 0; z-index: 1;
  border-color: var(--border); border-bottom: 1px solid var(--bg-panel);
  box-shadow: 0 -1px 3px rgba(60,64,67,.08);
}
.alerts-subtab.active::after { content: none; }
/* Archive regroupée par borne */
.archive-group {
  border: 1px solid var(--border-2); border-radius: var(--radius); margin: 14px 0;
  overflow: hidden; background: var(--bg-panel); box-shadow: var(--shadow-1);
}
.archive-group__head {
  display: flex; align-items: center; gap: 11px; padding: 13px 16px;
  background: var(--surface-2); border-bottom: 1px solid var(--border-2);
}
.archive-group__head .ag-borne { font-weight: 600; color: var(--text); }
.archive-group__head .ag-cp { font-size: .78rem; color: var(--text-faint); font-family: ui-monospace, "Roboto Mono", monospace; }
.archive-group .alerts-list { padding: 12px 14px 2px; }
.archive-group .alert-card { box-shadow: none; }

/* ── Dashboard refondu — sections operationnelles ── */
.dash-section {
  font-size: .8rem; text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-faint); margin: 20px 0 12px; font-weight: 700;
  display: flex; align-items: center; gap: 8px;
}
.dash-section svg { width: 16px; height: 16px; }
.dash-actions {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px; margin-bottom: 8px;
}
.dash-action {
  display: flex; align-items: center; gap: 13px;
  background: var(--bg-panel); border: 1px solid var(--border-2); border-radius: var(--radius);
  padding: 14px 16px; cursor: pointer; text-align: left; box-shadow: var(--shadow-1);
  transition: box-shadow .15s, transform .15s, border-color .15s; color: var(--text);
}
.dash-action:hover { box-shadow: var(--shadow-2); transform: translateY(-1px); }
.dash-action.active.sev-error { border-left: 4px solid var(--danger); background: var(--danger-bg); }
.dash-action.active.sev-warn { border-left: 4px solid var(--warning-strong); background: var(--warning-bg); }
.dash-action.active.sev-info { border-left: 4px solid var(--accent); background: var(--brand-50); }
.dash-action .da-icon { flex-shrink: 0; color: var(--text-muted); display: inline-flex; }
.dash-action .da-icon svg { width: 26px; height: 26px; }
.dash-action.active.sev-error .da-icon { color: var(--danger); }
.dash-action.active.sev-warn .da-icon { color: #e37400; }
.dash-action.active.sev-info .da-icon { color: var(--accent); }
.dash-action .da-body { flex: 1; min-width: 0; }
.dash-action .da-count { font-size: 1.5rem; font-weight: 600; color: var(--accent); line-height: 1; }
.dash-action.active.sev-error .da-count { color: var(--danger); }
.dash-action.active.sev-warn .da-count { color: #b06000; }
.dash-action:not(.active) .da-count { color: var(--text-muted); }
.dash-action .da-label { font-size: .76rem; color: var(--text-muted); margin-top: 3px; }

.dash-live-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px; margin-bottom: 8px;
}
.dash-live {
  background: var(--bg-panel); border: 1px solid var(--border-2); border-radius: var(--radius);
  padding: 16px 18px; display: flex; flex-direction: column; gap: 4px; box-shadow: var(--shadow-1);
}
.dash-live .dl-icon { font-size: 1.3rem; }
.dash-live .dl-val { font-size: 1.4rem; font-weight: 600; color: var(--text); }
.dash-live .dl-val strong { color: var(--accent); font-weight: 600; }
.dash-live .dl-val .dl-unit { font-size: .9rem; color: var(--text-muted); font-weight: 600; margin-left: 4px; }
.dash-live .dl-label { font-size: .78rem; color: var(--text-muted); }
.dash-live .dl-sub { font-size: .68rem; color: var(--text-faint); }

.dash-shortcuts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.dash-short {
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius-pill);
  padding: 8px 16px; cursor: pointer; color: var(--text-muted); font-size: .82rem; font-weight: 500; transition: all .15s;
  display: inline-flex; align-items: center; gap: 7px;
}
.dash-short svg { width: 15px; height: 15px; }
.dash-short:hover { border-color: #c6dafc; color: var(--brand-700); background: var(--brand-50); }

.dash-ev-row { cursor: pointer; }
.dash-ev-row:hover { background: var(--brand-50); }
.dash-ev-row code { font-size: .72rem; color: var(--text-muted); font-family: ui-monospace, "Consolas", monospace; }

/* ── Tableau ChangeConfiguration interactif ── */
.cfg-table { font-size: .82rem; table-layout: fixed; width: 100%; }
.cfg-table th { background: var(--surface-2); color: var(--text-muted); font-weight: 700; font-size: .72rem; text-transform: uppercase; letter-spacing: .3px; }
.cfg-table td { vertical-align: middle; padding: 9px 11px; word-break: break-word; overflow-wrap: anywhere; }
.cfg-table tr:hover { background: var(--surface-2); }
.cfg-key { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cfg-key code { font-size: .82rem; color: var(--text); font-weight: 600; word-break: break-all; overflow-wrap: anywhere; background: transparent; padding: 0; }
.cfg-key .cfg-desc { font-size: .68rem; color: var(--text-muted); line-height: 1.3; }
.cfg-tip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--surface-2); color: var(--text-muted);
  font-size: .65rem; font-weight: 700; cursor: help; margin-left: 4px; flex-shrink: 0;
}
.cfg-tip:hover { background: var(--accent); color: #fff; }
.cfg-current { font-family: ui-monospace, "Consolas", monospace; color: var(--accent); font-size: .8rem; word-break: break-all; overflow-wrap: anywhere; display: inline-block; max-width: 100%; }
.cfg-new-val { box-sizing: border-box; }
.cfg-new-val:focus { outline: none; border-color: var(--accent); }
.cfg-apply { padding: 5px 11px; font-size: .72rem; }
.cfg-csl-wrap { display: flex; flex-direction: column; gap: 4px; }
.cfg-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.cfg-chip {
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-muted);
  padding: 3px 9px; border-radius: 999px; font-size: .68rem; cursor: pointer;
  font-family: ui-monospace, "Consolas", monospace; transition: all .12s;
}
.cfg-chip:hover { color: var(--text); border-color: var(--text-muted); }
.cfg-chip.active { background: var(--brand-50); border-color: var(--accent); color: var(--brand-700); font-weight: 700; }
.cfg-csl-preview { color: var(--text-muted); }
#cfg-table-host { overflow-x: hidden !important; }
#ob-list { overflow-x: hidden !important; }

/* ── Moteur de formulaires / Audits ── */
.head-actions { display: flex; align-items: center; gap: 8px; }
.save-state { font-size: .78rem; color: var(--text-muted); min-width: 90px; text-align: right; }
.save-state.ok { color: var(--success); }
.save-state.err { color: var(--danger); }
.fe-form { display: flex; flex-direction: column; gap: 18px; }
.fe-section-title { font-size: .95rem; color: var(--text); font-weight: 600; margin-bottom: 12px; padding-bottom: 6px; border-bottom: 1px solid var(--border); }
.fe-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 16px; }
.fe-field { display: flex; flex-direction: column; gap: 5px; }
.fe-field[data-type="textarea"], .fe-field[data-type="checklist"], .fe-field[data-type="photo"] { grid-column: 1 / -1; }
.fe-label { font-size: .82rem; color: var(--text-muted); font-weight: 600; }
.fe-req { color: var(--danger); }
.fe-aide { font-size: .74rem; color: var(--text-faint); font-style: italic; }
.fe-choices { display: flex; flex-wrap: wrap; gap: 6px; }
.fe-choice { display: flex; align-items: center; gap: 6px; background: var(--bg-panel);
  border: 1px solid var(--border); border-radius: 8px; padding: 7px 12px; font-size: .82rem; cursor: pointer; }
.fe-choice:hover { border-color: var(--accent); }
.fe-choice input { width: auto; }
.fe-num-row, .fe-mesure-row { display: flex; align-items: center; gap: 8px; }
.fe-num-row .fe-input, .fe-mesure-row .fe-input { max-width: 160px; }
.fe-unit { color: var(--text-muted); font-size: .82rem; white-space: nowrap; }
.fe-conf { font-size: .72rem; font-weight: 700; padding: 3px 10px; border-radius: 999px; }
.fe-conf.ok { background: var(--success-bg); color: var(--success); }
.fe-conf.ko { background: var(--danger-bg); color: #c5221f; }
.fe-conf.warn { background: var(--warning-bg); color: #8a4b00; }
.fe-ref { font-size: .72rem; color: var(--text-muted); margin-top: 3px; }
.fe-photo { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.fe-photo-prev { max-width: 240px; max-height: 180px; border-radius: 8px; border: 1px solid var(--border); }
.fe-field.ro .fe-value { font-size: .88rem; white-space: pre-wrap; }
.fe-empty { color: var(--text-muted); }
.print-title { font-size: 1.3rem; font-weight: 700; margin-bottom: 16px; }

/* Entête papier : caché à l'écran, révélé à l'impression. Il porte l'identité
   de l'organisation (Organisation › Société) sur les fiches, qui sortaient
   jusqu'ici sur papier blanc, sans aucune mention de l'entreprise. */
#doc-entete { display: none; }

@media print {
  #doc-entete { display: block; }
  body { background: #fff; color: #000; height: auto; overflow: visible; }
  .sidebar, .no-print, .subtabs, button { display: none !important; }
  .content { overflow: visible; padding: 0; }
  .subpane { display: block !important; }
  .panel { border: none; background: #fff; padding: 0; box-shadow: none; }
  .fe-section-title { color: #000; border-color: #999; }
  .fe-label { color: #444; }
  .fe-section { break-inside: avoid; margin-bottom: 14px; }
  a.link { color: #000; text-decoration: none; }
  .kv { break-inside: avoid; }
}

/* ── Hors-ligne / synchro ── */
.net-state { font-size: .74rem; font-weight: 700; color: var(--warning); white-space: nowrap; }
.sync-bar { background: var(--warning-bg); border: 1px solid var(--warning-strong); color: var(--warning);
  padding: 9px 14px; border-radius: var(--radius-sm); margin-bottom: 14px; font-size: .82rem;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.dot-pending { color: var(--warning); font-weight: 700; cursor: help; }

/* ── Supervision OCPP ── */
.ocpp-badge { font-size: .72rem; font-weight: 700; padding: 3px 11px; border-radius: 999px;
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.ocpp-badge::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.ocpp-badge.ok { background: var(--success-bg); color: var(--success); }
.ocpp-badge.charging { background: #f3e8fd; color: #6b21a8; }
.ocpp-badge.warn { background: var(--warning-bg); color: #b06000; }
.ocpp-badge.ko { background: var(--danger-bg); color: #c5221f; }
.ocpp-badge.off { background: var(--surface-2); color: var(--text-muted); }
.alarm-bar { background: var(--danger-bg); border: 1px solid var(--danger); color: #c5221f;
  padding: 10px 14px; border-radius: var(--radius-sm); margin-bottom: 14px; font-size: .82rem; }
.doc-actions { display: flex; gap: 6px; }

/* ── Champ conformité C/NC/NV/SO ── */
.fe-conform { display: flex; gap: 5px; flex-wrap: wrap; }
.fe-cf-btn { border: 1px solid var(--border); background: var(--bg-panel); color: var(--text-muted);
  border-radius: 8px; padding: 6px 12px; font-size: .76rem; font-weight: 700; cursor: pointer; }
.fe-cf-btn:hover { color: var(--text); border-color: var(--text-muted); }
.fe-cf-btn.active.cf-C { background: var(--success); color: #fff; border-color: var(--success); }
.fe-cf-btn.active.cf-NC { background: var(--danger); color: #fff; border-color: var(--danger); }
.fe-cf-btn.active.cf-NV { background: #b45309; color: #fff; border-color: #b45309; }
.fe-cf-btn.active.cf-SO { background: #5f6368; color: #fff; border-color: #5f6368; }
.fe-cf-ro { font-size: .8rem; font-weight: 700; }
.fe-cf-ro.cf-C { color: var(--success); }
.fe-cf-ro.cf-NC { color: var(--danger); }
.fe-cf-ro.cf-NV { color: #b06000; }
.fe-cf-ro.cf-SO { color: var(--text-muted); }

/* ── Application terrain ── */
.terrain-form { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; max-width: 540px; margin-bottom: 14px; }

/* ── Schéma unifilaire (lecture seule) ── */
.sv-tree { overflow-x: auto; padding: 2px; }
.sv-children { margin-left: 16px; padding-left: 18px; border-left: 2px solid var(--border); }
.sv-card { display: inline-block; background: var(--bg-panel); border: 1px solid var(--border-2);
  border-radius: var(--radius-sm); padding: 9px 14px; margin: 6px 0; min-width: 210px; box-shadow: var(--shadow-1); }
.sv-type { font-size: .67rem; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); }
.sv-label { font-size: .9rem; font-weight: 600; }
.sv-params { font-size: .74rem; color: var(--text-muted); margin-top: 3px; }
.sv-card.sv-t-source { border-left: 3px solid var(--accent); }
.sv-card.sv-t-borne, .sv-card.sv-t-pdc { border-left: 3px solid var(--success); }
.sv-card.sv-t-disj_diff, .sv-card.sv-t-ddr { border-left: 3px solid var(--warning-strong); }

/* ─── Cartes Leaflet ─── */
.caly-darkmap .leaflet-container { background: #e8eaed; }
.caly-darkmap .leaflet-control-attribution { background: rgba(255,255,255,.85) !important; color: #5f6368 !important; }
.caly-darkmap .leaflet-control-attribution a { color: var(--accent) !important; }
.caly-darkmap .leaflet-bar a, .caly-darkmap .leaflet-bar a:hover { background: #fff; color: var(--text); border-color: var(--border); }

/* ─── Switch liste blanche (Supervision → Cartes RFID) ──────────────── */
.rfid-switch { display: inline-flex; align-items: center; cursor: pointer; user-select: none; }
.rfid-switch.disabled { cursor: not-allowed; opacity: .55; }
.rfid-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.rfid-slider {
  position: relative; display: inline-block; width: 38px; height: 20px;
  background: #94a3b8; border-radius: 20px; transition: background .2s; flex: 0 0 auto;
}
.rfid-slider::before {
  content: ''; position: absolute; left: 2px; top: 2px;
  width: 16px; height: 16px; border-radius: 50%; background: #fff; transition: transform .2s;
  box-shadow: 0 1px 2px rgba(0,0,0,.3);
}
.rfid-switch input:checked + .rfid-slider { background: #16a34a; }
.rfid-switch input:checked + .rfid-slider::before { transform: translateX(18px); }
.rfid-switch input:disabled + .rfid-slider { opacity: .5; }

/* ───────── Vague 5 : Accueil « hub » par phase ───────── */
.tab--home { margin-bottom: 6px; font-weight: 600; }

.hub { max-width: 1100px; margin: 0 auto; padding-bottom: 24px; }
.hub-hero {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 18px;
  padding: 22px 24px; margin-bottom: 22px; border-radius: var(--radius);
  background: linear-gradient(135deg, var(--brand-100, #e8f0fe), rgba(16,185,129,.06));
  border: 1px solid var(--border);
}
.hub-hero__h { margin: 0; font-size: 1.55rem; color: var(--text); }
.hub-hero__sub { margin: 4px 0 0; color: var(--text-muted); font-size: .9rem; }
.hub-hero__status { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.hub-hero__scope {
  color: var(--text-muted); font-size: .7rem; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
}
.hub-hero__pills { display: flex; gap: 10px; flex-wrap: wrap; }
.hub-pill {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  min-width: 92px; padding: 10px 14px; border-radius: var(--radius-sm);
  background: var(--bg-panel); border: 1px solid var(--border); cursor: pointer;
  transition: transform .12s, box-shadow .12s;
}
.hub-pill:hover { transform: translateY(-2px); box-shadow: 0 4px 14px rgba(0,0,0,.08); }
.hub-pill__ico { color: var(--text-muted); }
.hub-pill__v { font-size: 1.25rem; font-weight: 700; color: var(--text); line-height: 1.1; }
.hub-pill__l { font-size: .68rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: .03em; }
.hub-pill.is-danger .hub-pill__v, .hub-pill.is-danger .hub-pill__ico { color: var(--danger); }
.hub-pill.is-danger { border-color: var(--danger); background: var(--danger-bg); }

.hub-row { margin-bottom: 22px; }
.hub-row__head { display: flex; align-items: baseline; gap: 10px; margin: 0 2px 10px; }
.hub-row__dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; align-self: center; }
.hub-row__title { margin: 0; font-size: 1.02rem; color: var(--text); }
.hub-row__desc { font-size: .8rem; color: var(--text-faint); }
.hub-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr)); gap: 12px; }
.hub-card {
  position: relative; display: flex; align-items: center; gap: 13px; text-align: left;
  padding: 16px 16px 16px 18px; border-radius: var(--radius);
  background: var(--bg-panel); border: 1px solid var(--border); cursor: pointer;
  border-left: 4px solid var(--accent, var(--brand-500, #1a73e8));
  transition: transform .12s, box-shadow .12s, border-color .12s;
}
.hub-card:hover { transform: translateY(-3px); box-shadow: 0 8px 22px rgba(0,0,0,.10); }
.hub-card__ico {
  width: 44px; height: 44px; flex-shrink: 0; display: grid; place-items: center;
  border-radius: 12px; color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.hub-card__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.hub-card__t { font-size: .98rem; font-weight: 600; color: var(--text); }
.hub-card__s { font-size: .78rem; color: var(--text-muted); }
.hub-card__go { color: var(--text-faint); font-size: 1.3rem; flex-shrink: 0; }
.hub-card:hover .hub-card__go { color: var(--accent); }
.hub-card__badge {
  position: absolute; top: 10px; right: 12px; min-width: 20px; height: 20px; padding: 0 6px;
  display: grid; place-items: center; border-radius: 999px;
  background: var(--danger); color: #fff; font-size: .72rem; font-weight: 700;
}

/* CB-107 — quatre portes métier remplacent le catalogue exhaustif sur
   l'accueil central. L'A16 conserve sa barre basse et masque ces portes. */
.hub-phase-nav { margin-bottom: 22px; }
.hub-phase-nav__head {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 18px;
  margin: 0 2px 12px;
}
.hub-phase-nav__head h2 { margin: 0; font-size: 1.08rem; color: var(--text); }
.hub-phase-nav__head p { margin: 3px 0 0; color: var(--text-muted); font-size: .8rem; }
.hub-phase-nav__head > span {
  flex: 0 0 auto; color: var(--text-muted); font-size: .72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em;
}
.hub-phase-nav__grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px;
}
.hub-phase-gateway {
  position: relative; display: flex; flex-direction: column; align-items: stretch;
  min-width: 0; min-height: 176px; padding: 16px; text-align: left;
  border: 1px solid var(--border); border-top: 4px solid var(--phase-accent);
  border-radius: var(--radius); background: var(--bg-panel); color: var(--text);
  font: inherit; cursor: pointer;
  transition: transform .12s, box-shadow .12s, border-color .12s;
}
.hub-phase-gateway:hover {
  transform: translateY(-3px); border-color: var(--phase-accent);
  box-shadow: 0 8px 22px rgba(0,0,0,.10);
}
.hub-phase-gateway:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--phase-accent) 45%, transparent);
  outline-offset: 3px;
}
.hub-phase-gateway__head { display: flex; align-items: center; gap: 9px; min-width: 0; }
.hub-phase-gateway__ico {
  display: grid; place-items: center; width: 38px; height: 38px; flex: 0 0 auto;
  border-radius: 11px; color: var(--phase-accent);
  background: color-mix(in srgb, var(--phase-accent) 12%, transparent);
}
.hub-phase-gateway__title {
  min-width: 0; font-size: 1rem; font-weight: 700; overflow-wrap: anywhere;
}
.hub-phase-gateway__arrow {
  margin-left: auto; color: var(--phase-accent); font-size: 1.2rem; font-weight: 700;
}
.hub-phase-gateway__desc {
  display: block; min-height: 32px; margin-top: 9px;
  color: var(--text-muted); font-size: .76rem; line-height: 1.35;
}
.hub-phase-gateway__count {
  display: inline-flex; align-self: flex-start; margin-top: 9px; padding: 3px 8px;
  border-radius: 999px; color: var(--phase-accent); font-size: .7rem; font-weight: 700;
  background: color-mix(in srgb, var(--phase-accent) 10%, transparent);
}
.hub-phase-gateway__preview {
  margin: 9px 0 0; padding: 0; list-style: none; color: var(--text-muted);
  font-size: .72rem; line-height: 1.45;
}
.hub-phase-gateway__preview li {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hub-phase-gateway__preview li::before { content: '•'; margin-right: 6px; color: var(--phase-accent); }
.hub-phase-gateway__more { margin-top: 3px; color: var(--text-faint); font-size: .7rem; }

@media (max-width: 1050px) {
  .hub-phase-nav__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hub-phase-gateway { min-height: 156px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   TÉLÉPHONE (≤640px) — PLACÉ EN FIN DE FICHIER À DESSEIN : ces surcharges ont
   la même spécificité que les règles de base (.kv, .stats, .view-head…) ; pour
   gagner la cascade elles DOIVENT venir après. Ne pas remonter ce bloc.
   Barre du haut compacte, rangées de boutons à la ligne, tableaux à défilement
   interne, fiches clé/valeur qui se coupent proprement — zéro débordement de page.
   Navigation : bouton « Accueil », hub d'accueil, fils d'Ariane.
   ══════════════════════════════════════════════════════════════════════════ */
/* Énergie — rangée d'actions de la barre d'onglets (Calculer, 💾, 📂…).
   `flex:0 0 auto` et `white-space:nowrap` étaient en style EN LIGNE dans
   app.js : sortis ici pour que le bloc téléphone puisse les redéfinir sans
   recourir à `!important`. */
.en-actions { flex: 0 0 auto; white-space: nowrap; }

/* Jetons — rangée « SendLocalList / + Nouveau token ». Le `flex-shrink:0`
   était en style en ligne : sorti ici pour que le bloc téléphone puisse
   faire passer les deux boutons à la ligne. */
.tok-actions { flex-shrink: 0; }

@media (max-width: 640px) {
  .app { overflow-x: hidden; }                 /* garde-fou : rien ne déborde la page */
  .topbar { height: 52px; padding: 0 8px; gap: 6px; }
  .brand-mark { width: 30px; height: 30px; }
  .brand-name { font-size: 14px; }
  .brand-sub { display: none; }                /* sous-titre masqué faute de place */
  .topbar-home { padding: 7px 10px; }
  .topbar-home .topbar-home-lbl { display: none; }   /* icône Accueil seule */
  .user-label { display: none; }               /* le menu compte garde son chevron */
  .net-state { display: none; }
  .account-btn { min-width: 40px; justify-content: center; padding-left: 4px; padding-right: 4px; }  /* cible tactile confortable */
  .sync-badge { white-space: nowrap; font-size: .68rem; }   /* jamais sur 2 lignes */

  .content { padding: 16px 12px 32px; overflow-x: hidden; }  /* le contenu ne défile jamais latéralement en entier */
  .stats { grid-template-columns: 1fr; gap: 12px; }
  .view-head { gap: 8px 10px; }
  .view-head > * { min-width: 0; }             /* les outils d'en-tête passent à la ligne */
  .head-actions { flex-wrap: wrap; }           /* boutons d'en-tête : à la ligne au lieu d'être rognés */

  /* En-tête de panneau : `.panel h3` est en `display:flex` et n'a pas de repli.
     Onglet Historique de la fiche borne : le <span> d'actions y loge SIX
     boutons (Analyser, Logs bruts, Relais, Capture live, Importer, payload).
     Mesuré sur l'appareil : rangée de 445 px dans un panneau de 275 — cinq
     boutons sur six hors écran, et rien pour aller les chercher.
     ⚠ Le `float:right` du <span> est sans effet : un enfant de conteneur flex
     ne flotte pas. C'est bien le repli qu'il fallait, pas un alignement. */
  .panel h3 { flex-wrap: wrap; }
  .panel h3 > span { flex-wrap: wrap; min-width: 0; }

  /* (voir aussi la règle `(pointer: coarse)` en fin de fichier) */
  .view-head > span { flex-wrap: wrap; }        /* rangée d'actions des cartes client */

  /* Fiches clé/valeur : label plus étroit + valeurs longues (id OCPP…) coupées proprement */
  .kv { grid-template-columns: 116px 1fr; gap: 6px 10px; }
  .kv .v { min-width: 0; overflow-wrap: anywhere; }

  /* Tableaux : défilement horizontal DANS le tableau, pas sur la page entière.
     ⚠ `table.tbl` (vue Santé) doit y figurer aussi : mesurée à 350 px sur un
     écran de 320, elle était rognée sans aucun moyen d'atteindre ses colonnes. */
  .content table.grid,
  .content table.tbl { display: block; width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .subtabs { overflow-x: auto; }

  /* Jetons : les deux boutons totalisent 349 px, ils ne tiennent pas sur 320.
     Il faut que le PARENT se replie d'abord — sans cela le conteneur des
     boutons se dimensionne sur son contenu et son propre `flex-wrap` reste
     sans effet. */
  .tok-head { flex-wrap: wrap; }
  .tok-head > .tok-actions { flex: 1 1 100%; flex-wrap: wrap; }

  /* Énergie — rangée « onglets + actions ».
     Mesuré sur 375 px : les boutons d'action (Calculer, 💾, 📂…) sont en
     `white-space:nowrap` et `flex:0 0 auto`, ils prenaient donc toute la
     largeur ; la barre d'onglets, en `flex:1 1 auto;min-width:0`, se trouvait
     écrasée à 0 px de large. Son `overflow-x:auto` devenait inopérant et les
     trois onglets disparaissaient. On envoie les actions à la ligne. */
  .en-topbar { flex-wrap: wrap; }
  /* `.en-topbar > .en-subtabs` (2 classes) doit l'emporter sur le `<style>`
     du composant, injecté après cette feuille, qui impose overflow-x:auto.
     Un repli sur deux lignes vaut mieux qu'un défilement latéral : le geste
     ne s'invente pas, et rien n'indique qu'un 3e onglet existe. */
  .en-topbar > .en-subtabs { flex: 1 1 100%; flex-wrap: wrap; overflow-x: visible; }
  /* Mesuré sur 360 px (Galaxy A10) : la rangée de boutons atteignait 381 px.
     Elle passait à 375 px, elle débordait à 360 — d'où le repli. */
  .en-topbar > .en-actions { flex: 1 1 100%; flex-wrap: wrap; white-space: normal; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Écrans TRÈS étroits — doit rester le DERNIER bloc du fichier (cascade).

   Mesuré sur l'appareil de Carlos (Galaxy A16 SM-A166B) : le réglage Samsung
   « affichage agrandi » force la densité à 540 au lieu de 450, si bien que
   Chrome ne voit que **310 px** de large et non les 360 attendus. Le bouton de
   compte sortait alors de l'écran (bord droit à 340 px) et devenait
   inatteignable — `.topbar .brand` est en `flex-shrink:0`, le nom de marque ne
   cédait donc jamais sa place.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 400px) {
  .topbar .brand-text { display: none; }        /* le logo ⚡ suffit à identifier l'app */
  /* ⚠ CORRIGÉ le 2026-08-03. Cette règle laissait la marque rétrécir SOUS la
     taille de son propre logo : le texte étant masqué juste au-dessus, il ne
     restait que le rond de 30 px dans une boîte tombée à 17 px — le logo
     débordait et venait chevaucher le bouton Accueil dès que l'en-tête se
     chargeait (constaté à l'ajout de la loupe de recherche).
     Le texte masqué, la marque n'a plus rien à céder : elle vaut 30 px, point.
     C'est aux éléments qui PEUVENT se réduire de le faire. */
  .topbar .brand { flex: 0 0 auto; min-width: auto; }
  .topbar .brand-mark { flex: 0 0 auto; }
  .account-menu { flex-shrink: 0; }             /* le compte reste toujours atteignable */

  /* app.js contient 149 rangées `display:flex` en style EN LIGNE : les traiter
     une par une serait sans fin. On agit donc sur la cause — `.btn` et
     `.btn-ghost` sont en `white-space:nowrap`, leur largeur minimale est celle
     du libellé entier, et une rangée de deux boutons ne peut plus se réduire
     (constaté : « ↔ Changer de site / client » et « + Ajouter » sortaient de
     l'écran). En autorisant le retour à la ligne DANS le bouton, la rangée
     redevient compressible sans toucher au balisage. */
  .content .btn,
  .content .btn-ghost { white-space: normal; }
  .content .btn,
  .content .btn-ghost,
  .content .btn-sm { min-width: 0; }

  /* Onglets de fiche : à 310 px les 8 onglets de la borne occupaient SEPT
     lignes, poussant le contenu hors de l'écran d'entrée de jeu. Libellés
     resserrés → deux par ligne. `overflow-x` repasse à `visible` : ils se
     replient, le défilement latéral hérité du bloc 640 n'a plus d'objet et
     ne laisse qu'un ascenseur parasite. */
  /* Onglets resserrés : plus d'onglets visibles d'un coup dans la bande. */
  .subtab { padding: 7px 10px; font-size: .78rem; }
  .subtab .count { font-size: .7rem; padding: 1px 6px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Onglets de fiche : BANDE DÉFILANTE sur téléphone (motif choisi le 31/07).

   Les 8 onglets d'une fiche borne occupaient 4 lignes sur un écran de 310 px
   de large et 630 de haut — le contenu commençait sous la ligne de flottaison.
   Ici : une seule ligne, comme la barre d'onglets de Chrome lui-même.

   ⚠ On ne masque PAS l'ascenseur : sa présence, et surtout l'onglet suivant
   coupé au bord, sont les deux seuls indices qui disent « ça défile ». Un
   `scroll-snap` en `proximity` (et non `mandatory`) aide le doigt sans jamais
   contrarier un défilement volontaire.
   ⚠ Ne concerne QUE `.subtabs`. Les barres d'Alertes et d'Énergie n'ont que
   3 onglets : un repli sur 2 lignes y reste préférable — aucun geste à deviner.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  .subtabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    scroll-padding-inline: 12px;
    scrollbar-width: thin;
  }
  .subtabs::-webkit-scrollbar { height: 3px; }
  .subtabs::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; border: 0; }
  /* `flex:0 0 auto` : sans lui les onglets se compriment au lieu de défiler. */
  .subtabs > .subtab { flex: 0 0 auto; scroll-snap-align: center; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Outils qui exigent un POSTE avec des ports USB : générer une application
   terrain à copier sur une clé, importer les clés branchées.

   ⚠ Le critère n'est PAS la largeur. Mesuré sur le Galaxy A16 de Carlos :
   310 px en portrait mais **644 px en paysage** — un seuil à 640 px laissait
   donc réapparaître ces outils dès qu'on tournait le téléphone.
   `pointer: coarse` désigne un appareil piloté au doigt (téléphone, tablette),
   c'est-à-dire précisément ceux où aucune clé USB n'est exploitable.

   ⚠ Masquage d'AFFICHAGE seulement : rien n'est retiré du code, tout revient
   dès qu'on ouvre l'application sur un poste.
   ══════════════════════════════════════════════════════════════════════════ */
@media (pointer: coarse) {
  .outil-poste { display: none !important; }
}

/* Rangées d'onglets repliées : `.subtab` porte `margin-bottom:-1px` pour se
   raccorder au trait du bas ; quand la barre passe sur plusieurs lignes, ce
   décalage fait CHEVAUCHER les rangées (constaté en paysage, où la bande
   défilante ne s'applique plus). Un interligne suffit à les séparer. */
.subtabs { row-gap: 6px; }

/* ═══════════════════════════════════════════════════════════════════════
   Analyse énergie — onglets et actions sur DEUX rangées
   ⚠ Le seuil de 640 px NE SUFFISAIT PAS : en paysage le Galaxy A16 fait
   644 px, la règle mobile ne se déclenchait donc pas. Mesuré dans cet état :
   la rangée d'actions occupait 347 px des 551 disponibles, il ne restait que
   194 px aux onglets pour 415 px de contenu — « 2 · Borne & véhicule » était
   tronqué et « 3 · Verdict » entièrement hors du champ (221 px perdus).
   Rendus à toute la largeur, les 3 onglets tiennent sur une ligne à 644 px
   et se replient proprement sur deux en portrait.
   ⚠ « !important » sur flex : la barre porte « flex:1 1 auto » en STYLE EN
   LIGNE (app.js, attribut style du <nav id="en-maintabs">), qui bat toute
   règle de feuille non marquée — sans lui le correctif resterait sans effet.
   Choix assumé : REPLI et non défilement latéral. Trois onglets seulement,
   et un geste horizontal ne s'invente pas.
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 820px) {
  .en-topbar { flex-wrap: wrap; }
  .en-topbar > .en-subtabs {
    flex: 1 1 100% !important;
    flex-wrap: wrap;
    overflow-x: visible;
    min-width: 0;
    row-gap: 6px;
  }
  .en-topbar > .en-actions {
    flex: 1 1 100%;
    flex-wrap: wrap;
    white-space: normal;
    justify-content: flex-start;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   Téléphone EN PAYSAGE — l'entête reprenait sa taille de bureau
   ⚠⚠ Toute la compaction mobile de la barre du haut est bornée à 640 px.
   Or le Galaxy A16 fait 310 px en portrait mais 644 px EN PAYSAGE : la
   barre y reprenait sa taille pleine, sur un écran qui ne fait plus que
   310 px de haut. Constat de Carlos : « l'entête prend la moitié de
   l'écran en paysage et 20 % environ en portrait ».
   Critère retenu : écran COURT et piloté au doigt. On ne reprend ici que
   les règles VERTICALES — surtout pas les mises en une colonne du bloc
   640 px, qui gaspilleraient les 644 px de large disponibles en paysage.
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-height: 520px) and (pointer: coarse) {
  .topbar { height: 44px; padding: 0 8px; gap: 6px; }
  .brand-mark { width: 26px; height: 26px; }
  .brand-name { font-size: 13px; }
  .brand-sub { display: none; }
  .topbar-home { padding: 5px 9px; }
  .topbar-home .topbar-home-lbl { display: none; }
  .user-label { display: none; }
  .net-state { display: none; }
  .account-btn { min-width: 40px; justify-content: center; padding-left: 4px; padding-right: 4px; }
  /* Les rangées d'onglets de niveau supérieur perdent leur respiration
     inutile : sur 310 px de haut, chaque pixel vertical compte. */
  .subtabs, .en-subtabs { row-gap: 4px; }
  .subtab, .en-subtab { padding: 6px 10px; }
  .mt-actions { padding-top: 2px; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Panneaux de verdict — le texte étranglé par le tampon
   Ces bandeaux sont une rangée `display:flex` posée EN STYLE EN LIGNE :
   un bloc de texte en `flex:1 1 auto` et, à côté, un tampon de verdict en
   `flex:0 0 auto` qui garde sa largeur coûte que coûte. Sur écran étroit
   le texte se retrouvait dans une colonne de quelques mots de large
   (« Ajout possible uniquement… »).
   ⚠ « !important » obligatoire : les valeurs `flex` sont EN LIGNE.
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 820px) {
  .en-verdict { flex-wrap: wrap !important; gap: 10px !important; }
  .en-verdict > div { flex: 1 1 100% !important; min-width: 0; }
  .en-verdict > div:last-child { align-self: flex-start !important; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Onglets Énergie — où suis-je ?
   Constat de Carlos : « lisibilité non intuitive ». Mesuré au banc :
   l'onglet ACTIF est peint en `--bg-panel` = rgb(255,255,255), sur un
   `.panel` dont le fond est rgb(255,255,255) EXACTEMENT — soit un rapport
   de contraste de 1,00:1. Aucun écart de luminance : rien ne dit sur quel
   écran on se trouve. Ne subsistent qu'un liseré gris de 1 px et une ombre
   à 8 % d'opacité, invisibles en plein soleil sur un chantier.
   S'y ajoute, propre à Énergie : le rail auquel les onglets « dossier »
   viennent s'accrocher est ANNULÉ par le `border:0` de l'attribut style du
   <nav id="en-maintabs"> (app.js). Un onglet dossier sans rail flotte.
   Remède : rendre son arête à la bande, et marquer l'actif par un TRAIT
   D'ACCENT — seul repère qui survive au plein soleil (4,51:1 mesuré,
   contre 1,15:1 pour le seul fond teinté, qui reste décoratif).
   ⚠ `!important` sur la 1re règle uniquement : le `border:0` est EN LIGNE.
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 820px) {
  .en-topbar > .en-subtabs { border-bottom: 1px solid var(--border) !important; }
  .en-topbar > .en-subtabs > .en-subtab {
    margin-bottom: 0;
    top: 0;
    border-bottom: 1px solid var(--border);
    border-radius: 9px;
  }
  .en-topbar > .en-subtabs > .en-subtab.active {
    background: var(--brand-50);
    color: var(--brand-700);
    border-color: var(--accent);
    box-shadow: inset 0 -3px 0 var(--accent);
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   Onglets Énergie — libellés NUS sur écran étroit (choix de Carlos)
   Mesuré au banc, bande utile 258 px : libellés complets = 468,8 px, donc
   TROIS rangées et 99,2 px de haut. En version nue — sans émoji, sans
   badge, sans suffixe — 215,6 px, soit UNE rangée de 26,9 px.
   72 px rendus, près d'un quart de l'écran en paysage.
   Le poste garde tout : ces règles ne se déclenchent jamais au-delà de
   820 px, et le `title=` de chaque onglet porte déjà l'explication longue.
   ⚠ Ordre : ce bloc doit rester APRÈS celui qui marque l'onglet actif.
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 820px) {
  /* ⚠ « !important » indispensable : le composant injecte un <style> APRES la
     feuille, contenant « .en-subtab .badge { display: inline-block } ». Meme
     specificite (0,2,0) — c'est donc l'ORDRE qui tranchait, et la feuille
     perdait. Les badges restaient, la bande gardait 3 rangees au lieu d'une. */
  .en-subtab .en-emoji,
  .en-subtab .en-lg,
  .en-subtab .badge { display: none !important; }
  /* Cible tactile confortable — n'a de sens qu'une fois la bande sur UNE
     rangée : posée sur les libellés longs, elle coûtait 33 px de plus. */
  .en-topbar > .en-subtabs > .en-subtab {
    min-height: 40px;
    display: inline-flex;
    align-items: center;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   Onglet actif LISIBLE sur écran étroit — toutes les bandes
   Demande de Carlos : « le défaut d'onglet actif existe partout, corrige
   partout ». Précision mesurée, car le motif n'est PAS fautif en soi :
   « .subtab.active » (l.307) peint « var(--bg-panel) » = blanc, la même
   surface que le contenu, et sa bordure basse blanche perce le rail de
   « .subtabs » (l.293). C'est la métaphore du dossier ouvert, et sur poste
   elle fonctionne.
   Ce qui ne fonctionne pas au doigt, en plein jour : l'écart entre l'onglet
   ACTIF (blanc, 255) et un onglet INACTIF (`--bg-card`, rgb 241,243,244)
   vaut environ 1,06:1. Seule la couleur du texte (--brand-700 contre
   --text-muted) porte encore l'information. Un trait d'accent la rend
   immédiate, et survit au plein soleil.
   Borné à 820 px : au-delà, la métaphore du dossier reste intacte.
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 820px) {
  .subtab.active,
  .alerts-subtab.active {
    background: var(--brand-50);
    border-bottom-color: var(--accent);
    box-shadow: inset 0 -3px 0 var(--accent);
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   États actifs — reprise des cas signalés par l'audit du 31/07/2026
   ═══════════════════════════════════════════════════════════════════════ */

/* 1. Pastilles de sous-vue Énergie et filtres de plan.
   Leur état actif était peint EN STYLE EN LIGNE par `_enStylePlanBtn`
   (app.js) : hors d'atteinte de toute règle de feuille, même marquée.
   La fonction pose désormais une classe ; l'apparence est identique —
   fond d'accent, texte blanc — mais elle devient corrigible et thémable.
   Leur contraste était déjà bon : ce correctif est de propreté, pas de
   lisibilité. */
.en-sim-chip.active,
.en-plan-f.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
  font-weight: 700;
}

/* 2. Filtres de relevés « Tous / Brouillons / Terminés » (`.mt-fstatut`).
   Le pire cas de l'audit, et il touche AUSSI le poste. Ces boutons portent
   la classe `.subtab` mais n'ont AUCUN rail : le conteneur est un simple
   <div style="display:flex">, et le bouton porte `border-bottom:0` en style
   en ligne. L'onglet actif se distinguait donc à 1,05:1 du contenu et
   1,11:1 de ses voisins — soit rien. Ce n'est pas un onglet-dossier mais un
   filtre de liste : savoir lequel est armé conditionne la lecture de tous
   les résultats affichés dessous. Le trait d'accent s'applique donc à
   TOUTE largeur, poste compris.
   ⚠ Le trait passe par `box-shadow: inset`, jamais par `border-bottom-color`
   qui reste inerte quand la largeur de bordure basse est nulle. */
.mt-fstatut.active {
  background: var(--brand-50);
  box-shadow: inset 0 -3px 0 var(--accent);
}

/* 3. Bande d'alertes : interligne manquant.
   `.alerts-subtabs` déclare `flex-wrap: wrap` et ses onglets portent
   `margin-bottom:-1px` pour percer le rail — mais elle n'a jamais reçu le
   `row-gap` posé sur `.subtabs`. Repliée, ses rangées se CHEVAUCHENT de
   1 px, exactement le défaut déjà corrigé ailleurs. */
.alerts-subtabs { row-gap: 6px; }

/* 4. `#mt-subtabs` porte `gap:0` en style EN LIGNE, qui écrase à la fois le
   `gap: 4px` de `.subtabs` et le `row-gap: 6px` correctif : ses onglets se
   touchent bord à bord, et entre 641 et 820 px ses rangées se chevauchent. */
#mt-subtabs { gap: 4px !important; row-gap: 6px !important; }

/* ═══════════════════════════════════════════════════════════════════════
   Onglet actif — trait d'accent à TOUTE largeur, poste compris
   (décision de Carlos, 31/07/2026 : « oui étends-le »)
   Motif du défaut : `.subtabs` garde `flex-wrap: wrap` au-delà de 820 px.
   Dès qu'une bande à 7 ou 8 onglets se replie, les rangées SUPÉRIEURES ne
   touchent plus aucun rail — la métaphore du dossier n'opère que pour la
   rangée du bas — et l'onglet actif y redevient blanc sur blanc : 1,05:1
   contre le contenu, 1,11:1 contre ses voisins. La couleur du texte ne
   rattrape rien : --brand-700 contre --text-muted ne vaut que 1,13:1 en
   LUMINANCE, un écart de teinte et non de clarté, donc nul en plein soleil
   comme pour un œil déficient en couleur.
   Le fond blanc est CONSERVÉ sur poste : l'apparence « dossier » voulue
   reste, on lui ajoute seulement un repère qui ne dépend ni du rail ni de
   la rangée. Le relief d'origine est préservé — les deux ombres sont
   cumulées, la seconde étant `inset`.
   ⚠ Toujours par `box-shadow: inset`, jamais par `border-bottom-color` :
   celui-ci est inerte partout où la bordure basse est de largeur nulle.
   ═══════════════════════════════════════════════════════════════════════ */
.subtab.active,
.alerts-subtab.active {
  box-shadow: 0 -1px 3px rgba(60, 64, 67, .08), inset 0 -3px 0 var(--accent);
}

/* ═══════════════════════════════════════════════════════════════════════
   Panneaux de verdict — la RÉPONSE juste sous le TITRE
   (demande de Carlos, 31/07/2026)
   Le balisage est : [ bloc de texte { titre, explication } ] [ tampon ].
   Replié tel quel, l'ordre devient titre → explication → tampon : la
   réponse se retrouve enterrée sous un paragraphe, alors que c'est elle
   qu'on vient chercher.
   Le tampon ne peut pas se glisser ENTRE le titre et l'explication tant
   que le bloc de texte génère une boîte. D'où `display: contents` : le
   bloc cesse de produire une boîte, ses deux enfants deviennent des
   éléments du panneau, et `order` peut alors les intercaler.
   Résultat sur écran étroit : titre, puis TAMPON, puis explication.
   Le poste ne change pas (règle bornée à 820 px, tampon à droite).
   ⚠ `!important` partout : `display:flex` et les valeurs `flex` des
   enfants sont posés EN STYLE EN LIGNE dans le gabarit d'app.js.
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 820px) {
  .en-verdict {
    display: flex !important;
    flex-direction: column !important;
    flex-wrap: nowrap !important;
    align-items: stretch !important;
    gap: 8px !important;
  }
  .en-verdict > div:first-child { display: contents !important; }
  .en-verdict > div:first-child > :first-child { order: 1; }   /* le titre */
  .en-verdict > div:last-child {                                /* le tampon */
    order: 2;
    flex: 0 0 auto !important;
    align-self: flex-start !important;
    margin: 2px 0 !important;
  }
  .en-verdict > div:first-child > :last-child { order: 3; }    /* l'explication */
}

/* ═══════════════════════════════════════════════════════════════════════
   Carte Verdict — la réponse SOUS le titre (demande de Carlos, 31/07/2026)
   Rangée mesurée sur l'appareil, largeur 242 px :
     icône 20 + espace 10 + titre `flex:0 0 150px` FIGÉ + espace 10
     → il ne restait que 67 px à la réponse, soit un mot par ligne
     et 103 px de haut pour une seule phrase.
   Le titre cesse d'être figé et la réponse passe à la ligne, sur toute la
   largeur, indentée de 30 px pour rester alignée sous le titre (icône 20
   + espace 10). Les trois rangées viennent de la même fonction `ligne()`,
   donc « Chargé à l'heure ? », « Contrat tenu ? » et « Énergie de charge »
   sont traitées d'un coup.
   ⚠ `!important` : les valeurs `flex` sont posées EN STYLE EN LIGNE.
   Le poste ne change pas (règle bornée à 820 px).
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 820px) {
  .en-vr {
    flex-wrap: wrap !important;
    align-items: center !important;
    row-gap: 4px !important;
  }
  .en-vr-t { flex: 1 1 auto !important; }
  .en-vr-r { flex: 1 1 100% !important; padding-left: 30px; }
}

/* ─── Journal complet sur téléphone ────────────────────────────────────────
   Trois colonnes sur 310 px de large, c'est illisible : chaque colonne reçoit
   une centaine de pixels et la ligne brute part en confettis. On empile.

   ⚠ « screen and » est OBLIGATOIRE : une page A4 en portrait fait 794 px, donc
   sans lui la règle s'applique À L'IMPRESSION et casse les tableaux imprimés.
   ⚠ Ce bloc doit rester EN FIN de fichier : c'est la cascade qui lui donne
   raison sur les styles en ligne du tableau. */
@media screen and (pointer: coarse) and (max-width: 900px) {
  .jr-grid, .jr-grid tbody, .jr-grid tr, .jr-grid td { display: block !important; width: 100% !important; }
  .jr-grid thead { display: none !important; }
  .jr-grid tr {
    border: 1px solid var(--border, #dadce0) !important;
    border-radius: 8px;
    margin-bottom: 8px;
    padding: 8px 10px;
    background: var(--bg-panel, #fff);
  }
  .jr-grid td { border: 0 !important; padding: 3px 0 !important; }
  /* Le libellé de colonne devient un intertitre : sans lui, on ne sait plus si
     on lit la signification ou la cause. */
  .jr-grid td[data-col]:not(:first-child)::before {
    content: attr(data-col);
    display: block;
    font-size: .64rem;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--text2, #5f6368);
    margin-bottom: 1px;
  }
  /* Une case sans interprétation ne mérite pas une ligne « — » : elle disparaît. */
  .jr-grid td.jr-vide { display: none !important; }
  .jr-grid td:first-child code { font-size: .66rem !important; line-height: 1.35; }

  /* Filtres : une commande par ligne, pleine largeur, doigts d'adulte. */
  .jr-filtres { flex-direction: column !important; align-items: stretch !important; gap: 8px !important; }
  .jr-filtres label { width: 100% !important; }
  .jr-filtres select, .jr-filtres input { width: 100% !important; min-height: 38px; }
  .jr-filtres button { width: 100%; min-height: 40px; }

  .jr-grid tr { padding: 8px !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   CB047 — contrat ergonomique par rôle et mobile de référence
   UX-001/002/003/004/005/007 · QA-004/005/008

   Ces règles sont fondées sur la LARGEUR réellement disponible, pas seulement
   sur `pointer:coarse` : elles restent ainsi vérifiables dans une émulation
   stricte et protègent aussi une petite fenêtre de poste. Aucune commande n'est
   masquée ; les outils matériellement inutilisables au téléphone restent régis
   séparément par `.outil-poste`.
   ═══════════════════════════════════════════════════════════════════════════ */

.cIconHost,
[data-icon] { display: inline-grid; place-items: center; line-height: 0; vertical-align: middle; }
.cIconHost > .cIcon,
[data-icon] > .cIcon { display: block; }

.hub-hero__txt { flex: 1 1 320px; min-width: 0; }
.hub-hero__h { overflow-wrap: anywhere; }
.hub-primary {
  display: inline-flex; align-items: center; justify-content: space-between; gap: 18px;
  max-width: 430px; width: 100%; margin-top: 14px; min-height: 48px;
  padding: 10px 14px; border: 1px solid var(--brand-500, #1a73e8);
  border-radius: var(--radius-sm); background: var(--brand-700, #1967d2); color: #fff;
  font: inherit; text-align: left; cursor: pointer;
}
.hub-primary > span:first-child { min-width: 0; }
.hub-primary strong { display: block; font-size: .9rem; }
.hub-primary small { display: block; margin-top: 2px; font-size: .72rem; opacity: .88; }
.hub-primary:hover { background: var(--accent-hover); box-shadow: var(--shadow-1); }

.ux-sync-state {
  position: fixed; right: 18px; bottom: calc(var(--barre-h, 0px) + 16px); z-index: 320;
  max-width: min(460px, calc(100vw - 24px)); min-height: 44px; padding: 9px 14px;
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  background: var(--bg-panel); color: var(--text); box-shadow: var(--shadow-3);
  font: inherit; font-size: .82rem; font-weight: 600; text-align: left;
}
.ux-sync-state.is-pending, .ux-sync-state.is-queue { border-color: #f59e0b; background: #fffbeb; color: #92400e; }
.ux-sync-state.is-synced { border-color: #22c55e; background: #ecfdf5; color: #166534; }
.ux-sync-state.is-offline, .ux-sync-state.is-error { border-color: #dc2626; background: #fef2f2; color: #991b1b; }

/* OCPP-010 — provenance et âge restent lisibles sans dépendre de la couleur. */
.ocpp-evidence-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:8px 0 14px}
.ocpp-evidence{display:flex;flex-direction:column;align-items:flex-start;gap:5px;padding:10px 12px;border:1px solid var(--border,#dbe3ef);border-radius:10px;background:var(--surface,#fff)}
.ocpp-evidence-kicker{font-size:.68rem;font-weight:700;letter-spacing:.055em;text-transform:uppercase;color:var(--text-muted,#64748b)}
.ocpp-evidence small,.ocpp-table-meta{display:block;margin-top:4px;font-size:.7rem;line-height:1.35;color:var(--text-muted,#64748b)}
.ocpp-evidence-note{font-size:.78rem;line-height:1.45;margin:-6px 0 10px}
.ocpp-evidence.is-unavailable{margin:8px 0 14px}
@media(max-width:760px){.ocpp-evidence-grid{grid-template-columns:1fr}.ocpp-evidence-grid.is-expanded{grid-template-columns:1fr}.ocpp-table-meta{max-width:180px;white-space:normal}}
.ux-sync-state.is-conflict { border-color: #ea580c; background: #fff7ed; color: #9a3412; cursor: pointer; }
.ux-sync-state:disabled { opacity: 1; cursor: default; }
.ux-conflict { background: #ffedd5; color: #9a3412; }
body:has(.ux-sync-state:not(.hidden)) .content { padding-bottom: 104px; }

.form-error {
  grid-column: 1 / -1; padding: 9px 11px; border-left: 4px solid var(--danger);
  border-radius: 6px; background: var(--danger-bg); color: var(--danger);
  font-size: .82rem; line-height: 1.45;
}
.field-error { color: var(--danger); font-size: .76rem; line-height: 1.3; }
[aria-invalid="true"] { border-color: var(--danger) !important; box-shadow: 0 0 0 3px var(--danger-bg) !important; }

@media screen and (max-width: 900px) {
  .subtabs {
    display: grid !important;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: stretch; gap: 6px; overflow: visible !important;
    border-bottom: 0; padding: 4px 0; scrollbar-width: none;
  }
  .subtabs > .subtab {
    min-width: 0; min-height: 44px; width: 100%; padding: 8px 10px;
    top: 0; margin-bottom: 0; border: 1px solid var(--border);
    border-radius: 9px; white-space: normal; overflow-wrap: anywhere;
    line-height: 1.2; text-align: center;
  }
  .subtabs > .subtab.active {
    border-color: var(--brand-500, #1a73e8); border-bottom-color: var(--brand-500, #1a73e8);
    box-shadow: inset 0 0 0 1px var(--brand-500, #1a73e8);
  }
  .mt-actions {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: stretch; gap: 6px; width: 100%;
  }
  .mt-actions > button { width: 100%; min-width: 0; white-space: normal; }
  .mt-retour { display: flex; flex-wrap: wrap; gap: 6px; }
  .view-head, .hub-row__head { flex-wrap: wrap; }
  .view-head > *, .hub-row__head > * { min-width: 0; max-width: 100%; }
}

@media screen and (max-width: 700px) {
  .topbar { height: 60px; min-height: 60px; padding: 0 8px; gap: 6px; }
  .topbar-loupe, .topbar-alerts, .account-btn, .topbar-home {
    min-width: 44px; min-height: 44px; justify-content: center;
  }
  .topbar-loupe { width: 44px; height: 44px; }
  .account-menu { flex: 0 0 auto; }
  .account-item { min-height: 44px; }
  .topbar-recherche.q-ouverte { top: 8px; }
  .topbar-recherche.q-ouverte input { height: 44px; min-height: 44px; font-size: 16px; }
  .q-resultats { top: 60px; }

  .content { max-width: 100%; padding: 14px 10px 34px; }
  .content > *, .panel, .hub, .hub-hero, .hub-row { min-width: 0; max-width: 100%; }
  .hub-hero { display: block; padding: 14px 12px; }
  .hub-primary { max-width: 100%; }
  .hub-hero__pills { margin-top: 12px; }
  .hub-row__desc { flex: 1 1 100%; padding-left: 20px; }

  button, [role="button"], .btn, .btn-ghost, .btn-sm, .subtab, .fil-seg {
    min-height: 44px;
  }
  input:not([type="checkbox"]):not([type="radio"]), select, textarea {
    min-height: 44px; max-width: 100%; min-width: 0 !important; font-size: 16px !important;
  }
  input[type="checkbox"], input[type="radio"] { width: 24px; height: 24px; flex: 0 0 24px; }
  label:has(> input[type="checkbox"]), label:has(> input[type="radio"]) { min-height: 44px; align-items: center; }
  .modal-form { grid-template-columns: minmax(0, 1fr); }
  .modal-form > * { min-width: 0; }
  .modal-actions { flex-wrap: wrap; justify-content: stretch; }
  .modal-actions > button { flex: 1 1 120px; white-space: normal; }

  /* Un tableau large devient une suite de fiches ; aucune colonne critique ne
     dépend d'un zoom ou d'un geste horizontal invisible. */
  .content table.ux-mobile-cards,
  .modal table.ux-mobile-cards,
  .modal-box table.ux-mobile-cards {
    display: block !important; width: 100%; overflow: visible !important;
    border: 0; background: transparent; box-shadow: none;
  }
  table.ux-mobile-cards thead { display: none; }
  table.ux-mobile-cards tbody { display: grid; gap: 10px; width: 100%; }
  table.ux-mobile-cards tbody tr {
    display: block; width: 100%; margin: 0; padding: 5px 10px;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--bg-panel); box-shadow: var(--shadow-1);
  }
  table.ux-mobile-cards tbody td {
    display: grid; grid-template-columns: minmax(88px, 38%) minmax(0, 1fr);
    gap: 8px; align-items: start; width: 100%; padding: 8px 0;
    border: 0; border-bottom: 1px solid var(--border); text-align: left !important;
    overflow-wrap: anywhere; white-space: normal;
  }
  table.ux-mobile-cards tbody td:last-child { border-bottom: 0; }
  table.ux-mobile-cards tbody td::before {
    content: attr(data-ux-label); color: var(--text-muted); font-size: .7rem;
    font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  }
  table.ux-mobile-cards tbody td[colspan] { grid-template-columns: minmax(0, 1fr); }
  table.ux-mobile-cards tbody td[colspan]::before { display: none; }
  table.ux-mobile-cards tbody td > * { min-width: 0; max-width: 100%; }
  .table-wrap:has(table.ux-mobile-cards) { overflow: visible; }

  .ux-sync-state { left: 12px; right: 12px; bottom: calc(var(--barre-h, 0px) + 10px); max-width: none; }
}

@media screen and (max-width: 420px) {
  .mt-actions { grid-template-columns: minmax(0, 1fr); }
}

/* Filtres du Journal repliés sur téléphone : ils prenaient 60 % de la hauteur
   avant la première ligne. Le bouton n'existe QUE sur écran tactile étroit —
   sur grand écran les filtres restent affichés en permanence. */
#jr-toggle { display: none; }
@media screen and (pointer: coarse) and (max-width: 900px) {
  #jr-toggle { display: inline-flex !important; margin-bottom: 10px; }
  .jr-filtres { display: none !important; }
  .jr-filtres.ouvert { display: flex !important; }
}

/* Tableau des demandes de diagnostic sur téléphone. Mesuré : 728 px de large
   dans un conteneur de 253 — il fallait le faire défiler latéralement pour
   atteindre l'état et les boutons, qui sont justement ce qu'on vient y chercher.
   Même mise en fiches que le Journal complet. */
@media screen and (pointer: coarse) and (max-width: 900px) {
  .diag-demandes, .diag-demandes tbody, .diag-demandes tr, .diag-demandes td {
    display: block !important; width: 100% !important;
  }
  .diag-demandes thead { display: none !important; }
  .diag-demandes tr {
    border: 1px solid var(--border, #dadce0) !important;
    border-radius: 8px; margin-bottom: 8px; padding: 8px 10px;
    background: var(--bg-panel, #fff);
  }
  .diag-demandes td { border: 0 !important; padding: 2px 0 !important; }
  .diag-demandes td[data-col]::before {
    content: attr(data-col) " · ";
    font-size: .68rem; text-transform: uppercase; letter-spacing: .04em;
    color: var(--text2, #5f6368);
  }
  /* La date ouvre la fiche : elle se passe d'étiquette et se lit en titre. */
  .diag-demandes td[data-col="Demandée"]::before { content: none; }
  .diag-demandes td[data-col="Demandée"] { font-weight: 600; font-size: .88rem; margin-bottom: 2px; }
  /* Les boutons d'action, pleine largeur et espacés : on les vise au doigt. */
  .diag-demandes td:last-child { display: flex !important; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
  .diag-demandes td:last-child::before { content: none; }
  .diag-demandes td:last-child button { flex: 1 1 auto; min-height: 36px; }
}

/* Sous-onglet « Fichier de diagnostic » au téléphone. Mesuré sur Galaxy A16 :
   les deux champs de date faisaient 93 et 98 px de large pour 30 px de haut —
   un champ datetime-local à cette taille n'affiche rien de lisible et ne se
   vise pas au doigt. Les boutons plafonnaient à 29 px de haut.
   On empile, on élargit, et on remonte les hauteurs de frappe. */
@media screen and (pointer: coarse) and (max-width: 900px) {
  #diag-sp-fichier > div:first-of-type { flex-direction: column !important; align-items: stretch !important; }
  #diag-sp-fichier label { width: 100% !important; }
  #diag-from, #diag-to, #diag-logtype {
    width: 100% !important; min-height: 40px !important; font-size: .9rem;
  }
  #diag-request { width: 100%; min-height: 44px; }
  #diag-export, #diag-purge { flex: 1 1 100%; min-height: 40px; }
}


/* ─── Récupération de largeur sur TOUS les écrans tactiles étroits ──────────
   Mesuré sur Galaxy A16 (viewport 310 px) : `.panel` porte 20 px de marge
   intérieure de chaque côté, soit 40 px — 13 % de la largeur de l'écran perdus
   en blanc, sur chaque panneau de l'application.

   ⚠ `screen and` obligatoire : une page A4 en portrait fait 794 px, sans lui la
   règle s'appliquerait à l'impression et resserrerait tous les documents.
   ⚠ Le bloc d'impression (plus haut) met déjà `.panel { padding: 0 }` : il n'y
   a donc aucun conflit, l'impression garde son propre réglage. */
@media screen and (pointer: coarse) and (max-width: 900px) {
  .panel { padding: 10px !important; }
  .panel h3 { margin-bottom: 8px; }
}

/* ─── Tableaux de 4 colonnes et plus, en fiches sur téléphone ───────────────
   La classe `fiches-mobile` est posée par le script, qui n'y met que les
   tableaux d'au moins 4 colonnes : en dessous, ils tiennent dans la largeur et
   les empiler ferait perdre de la place. Les intitulés viennent de l'en-tête,
   reportés sur chaque cellule en `data-col`.

   ⚠ `screen and` obligatoire : sans lui, la règle casserait l'impression, où
   les tableaux doivent rester des tableaux. */
@media screen and (pointer: coarse) and (max-width: 900px) {
  .fiches-mobile, .fiches-mobile tbody, .fiches-mobile tr, .fiches-mobile td {
    display: block !important; width: 100% !important;
  }
  .fiches-mobile thead { display: none !important; }
  .fiches-mobile tr {
    border: 1px solid var(--border, #dadce0) !important;
    border-radius: 8px; margin-bottom: 8px; padding: 8px 10px;
    background: var(--bg-panel, #fff);
  }
  .fiches-mobile td { border: 0 !important; padding: 2px 0 !important; }
  .fiches-mobile td[data-col]::before {
    content: attr(data-col) " · ";
    font-size: .68rem; text-transform: uppercase; letter-spacing: .04em;
    color: var(--text2, #5f6368);
  }
  /* La PREMIÈRE colonne est presque toujours le nom ou la date : elle sert de
     titre à la fiche et se passe d'étiquette. */
  .fiches-mobile td:first-child::before { content: none; }
  .fiches-mobile td:first-child { font-weight: 600; font-size: .88rem; margin-bottom: 2px; }
  /* Dernière colonne = actions : boutons alignés, visables au doigt. */
  .fiches-mobile td:last-child:has(button) {
    display: flex !important; gap: 6px; flex-wrap: wrap; margin-top: 6px;
  }
  .fiches-mobile td:last-child:has(button)::before { content: none; }
  .fiches-mobile td:last-child button { flex: 1 1 auto; min-height: 36px; }
  /* Une cellule vide ne mérite pas une ligne : on l'efface. */
  .fiches-mobile td:empty { display: none !important; }
}

/* ══════════════════════════════════════════════════════════════════════════
   ALERTES — ligne de verdict et compteurs compacts            (2026-08-03)

   Deux défauts relevés par Carlos sur l'écran Alertes :

   1. Le VERDICT occupait une quatrième tuile dans la rangée des compteurs, avec
      une PHRASE là où les trois autres affichent un nombre (« Action urgente »
      en 1,9 rem, légende « Action urgente requise » — sa propre répétition).
      Dans une rangée de chiffres, on cherche un nombre et on lisait un slogan.
      Il devient une ligne de synthèse, qui énumère ce qui la compose.

   2. Les tuiles faisaient 154 px de haut, empilées une par ligne : 616 px sur
      un écran de 578. On faisait défiler un écran entier AVANT la première
      alerte — sur un écran qui n'existe que pour montrer des alertes.
      Les trois compteurs passent sur une seule ligne, format compact.

   ⚠ `.stats` n'est utilisé QUE par cet écran (vérifié) : la règle ne peut pas
   déborder ailleurs. `.stat` étant partagé, tout est porté par `.stats .stat`.
   ⚠ Ce bloc doit rester APRÈS le `@media 640px` général, qui force
   `grid-template-columns: 1fr` — à spécificité égale, c'est le dernier qui gagne.
   ══════════════════════════════════════════════════════════════════════════ */
.alerte-verdict {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  padding: 10px 14px; border-radius: var(--radius); margin-bottom: 14px;
  border: 1px solid var(--border-2); background: var(--bg-panel);
}
.alerte-verdict strong { font-size: .96rem; }
.alerte-verdict .alerte-verdict-detail { font-size: .82rem; color: var(--text-muted); }
.alerte-verdict .alerte-verdict-ico { display: inline-flex; flex: 0 0 auto; }
.alerte-verdict.red   { border-color: var(--danger);  background: var(--danger-bg); }
.alerte-verdict.red   .alerte-verdict-ico { color: var(--danger); }
.alerte-verdict.amber { border-color: #e37400;        background: var(--warning-bg); }
.alerte-verdict.amber .alerte-verdict-ico { color: #e37400; }
.alerte-verdict.green { border-color: var(--success); background: var(--success-bg); }
.alerte-verdict.green .alerte-verdict-ico { color: var(--success); }

@media (max-width: 640px) {
  .stats { grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 14px; }
  .stats .stat { padding: 10px 6px; text-align: center; }
  .stats .stat .stat-ico { width: 28px; height: 28px; margin: 0 auto 6px; }
  .stats .stat .stat-ico svg { width: 15px; height: 15px; }
  .stats .stat .stat-val { font-size: 1.45rem; }
  /* Trois libellés sur 275 px : ils DOIVENT pouvoir passer à la ligne, sinon
     « Avertissements » et « Résolues à valider » débordent de leur tuile. */
  .stats .stat .stat-title { font-size: .68rem; margin-top: 2px; line-height: 1.15; hyphens: auto; }
  .alerte-verdict { padding: 9px 11px; gap: 7px; }
  .alerte-verdict strong { font-size: .9rem; }
}

/* Pavé d'aide des Alertes, replié par défaut (voir app.js). On le lit une fois ;
   il coûtait 125 px à chaque visite sur un écran de 578 px. */
.alerte-aide { padding: 0; }
.alerte-aide > summary {
  cursor: pointer; padding: 10px 14px; font-size: .86rem; font-weight: 500;
  color: var(--accent); display: flex; align-items: center; gap: 8px; list-style: none;
}
.alerte-aide > summary::-webkit-details-marker { display: none; }
.alerte-aide > summary::after { content: '▾'; margin-left: auto; opacity: .6; }
.alerte-aide[open] > summary::after { content: '▴'; }
.alerte-aide > div { padding: 0 14px 12px; font-size: .86rem; line-height: 1.5; color: var(--text-muted); }

/* ══════════════════════════════════════════════════════════════════════════
   ALERTES — les ONGLETS remplacent la rangée de compteurs      (2026-08-03)

   Demande de Carlos : « les 3 cadres Critiques / Avertissements / Résolues à
   valider n'apportent rien ; les onglets en dessous peuvent faire le même
   usage s'ils sont positionnés pareil, avec la même présentation ».

   Il a raison deux fois. Ces trois tuiles répétaient mot pour mot la ligne de
   verdict placée juste au-dessus, ET les onglets portaient déjà les effectifs.
   Trois blocs de 107 px pour une donnée affichée deux fois ailleurs.

   Les onglets prennent donc l'allure des tuiles — un nombre en évidence,
   son libellé dessous, sur UNE seule ligne — en gardant leur rôle : on clique.
   `column-reverse` met le compteur au-dessus du mot alors que le HTML l'écrit
   après, sans toucher au balisage.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  .alerts-subtabs {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px;
    border-bottom: none; margin: 12px 0 14px; padding-top: 0; align-items: stretch;
  }
  .alerts-subtab {
    display: flex; flex-direction: column-reverse; align-items: center; justify-content: center;
    gap: 1px; top: 0; border: 1px solid var(--border); border-bottom: 1px solid var(--border);
    border-radius: var(--radius); padding: 9px 4px; text-align: center; line-height: 1.15;
    font-size: .7rem; min-height: 62px;
  }
  /* L'icône ne dit rien que le mot ne dise déjà, et elle vole la place du chiffre. */
  .alerts-subtab svg { display: none; }
  .alerts-subtab .count {
    display: block; font-size: 1.4rem; font-weight: 600; padding: 0;
    background: none; color: inherit;
  }
  .alerts-subtab.active {
    border-color: var(--brand-500, #06b6d4); background: var(--brand-50); color: var(--brand-700);
  }
  .alerts-subtab.active .count { background: none; padding: 0; color: inherit; }
}

/* ── Les mêmes onglets, sur POSTE ────────────────────────────────── (03/08)
   Carlos : « idem sur ordinateur ». Les trois cadres de compteurs ont disparu
   partout (c'est le balisage qui a changé) ; restait la présentation des
   onglets, jusqu'ici réservée au téléphone.

   Sur un grand écran on garde la FORME d'une barre d'onglets — elle est juste,
   familière, et il y a la place — mais le chiffre passe au premier plan : c'est
   lui qu'on vient lire, il ne doit plus être une pastille discrète collée au
   mot. L'icône disparaît comme sur téléphone : elle ne dit rien que le mot ne
   dise déjà. */
@media (min-width: 641px) {
  .alerts-subtab { display: inline-flex; align-items: baseline; gap: 9px; padding: 9px 18px; }
  .alerts-subtab svg { display: none; }
  .alerts-subtab .count {
    font-size: 1.15rem; font-weight: 700; padding: 0; background: none; color: inherit;
  }
  .alerts-subtab.active .count { background: none; padding: 0; color: inherit; }
}

/* Filet de sécurité pour les pastilles de statut : même raccourcies, elles ne
   doivent JAMAIS pouvoir dépasser leur fiche. `nowrap` les faisait sortir du
   cadre sur téléphone (338 px dans 299) au lieu de passer à la ligne. */
.alert-status { max-width: 100%; white-space: normal; overflow-wrap: anywhere; }

/* ═══════════════════════════════════════════════════════════════════════════
   BARRE DE NAVIGATION BASSE — ESSAI (2026-08-04)

   Modèle observé sur l'application « Le Monde » : 4 destinations au pouce + un
   « Menu » de débordement. Trois de ses promesses ne se portent PAS ici et ce
   bloc ne prétend pas le contraire :
     · « quatre entrées fixes » — impossible, la matrice des droits l'interdit ;
       la barre est COMPOSÉE à l'exécution, comme le hub d'accueil ;
     · « toujours visible » — le clavier virtuel et le plein écran la masquent ;
     · « personnalisation » — aucun réceptacle par utilisateur n'existe.

   ⚠ POURQUOI CE BLOC EST EN FIN DE FICHIER. `@media (max-width: 400px)` est
   déclaré AVANT trois blocs 640 px : à spécificité égale, le 640 l'emporte sur
   un écran de 310 px — l'inverse de l'intention. On ne répartit donc RIEN de
   la barre entre ces blocs ; tout est ici, en dernier.

   ⚠ POUR L'ANNULER : supprimer ce bloc. Le balisage devient inerte, la variable
   `--barre-h` retombe à 0, le message éphémère reprend sa place. Rien d'autre.
   ═══════════════════════════════════════════════════════════════════════════ */
.barre-bas { display: none; }

@media (pointer: coarse) and (max-width: 700px) {
  :root { --barre-h: 48px; }
  /* ⚠ SUPPRESSION DU DOUBLON (décision de Carlos, 2026-08-04). La barre porte
     les phases ; les rangées de l'accueil disaient la même chose juste en
     dessous. On ne retire les rangées QUE là où la barre existe : sur poste et
     sur tablette, elles RESTENT la navigation principale — il n'y a pas de
     barre pour les remplacer. Une seule requête média décide des deux, donc
     elles ne peuvent pas disparaître toutes les deux par accident.
     L'accueil garde son en-tête et ses trois pastilles d'état, et l'espace
     ainsi libéré reste disponible. */
  /* ⚠ `.hub > .hub-row` et NON `.hub-row` : le tableau d'affichage utilise la
     même structure mais vit dans `#hub-messages`, donc il n'est pas un enfant
     DIRECT de `.hub`. Sans ce `>`, la règle effacerait précisément le bloc que
     l'espace libéré était censé accueillir. */
  /* ⚠⚠ `.hub--accueil` et NON `.hub` : les pages de PHASE (« Terrain »,
     « Exploitation »…) utilisent la même structure, et leur rangée est elle
     aussi un enfant direct d'un `.hub`. Avec le sélecteur générique, les
     QUATRE pages de la barre s'affichaient VIDES — la vue rendait bien ses
     cartes, le style les effaçait. Constaté par Carlos sur « Exploitation ».
     Deux gardes successives sur ce même sélecteur : d'abord il effaçait le
     tableau d'affichage, puis les pages de phase. Le nommer explicitement met
     fin à la série. */
  .hub--accueil > .hub-row,
  .hub--accueil > .hub-phase-nav { display: none; }

  /* ── L'EN-TÊTE D'ACCUEIL, RESSERRÉ ────────────────────────────────────────
     Mesuré : il occupait 379 px sur 630, soit 60 % de l'écran pour une
     salutation et trois chiffres. L'espace récupéré va au tableau d'affichage.

     ⚠ Le sous-titre « Bienvenue sur Caly-Bornes — choisissez par où commencer »
     est RETIRÉ parce qu'il est devenu FAUX : le choix se fait dans la barre du
     bas, et les rangées auxquelles il renvoyait ne s'affichent plus ici. Une
     phrase qui décrit un écran disparu est pire qu'une phrase absente.

     ⚠ Les trois pastilles passent sur UNE rangée : elles se répartissaient en
     1 + 2 par simple retour à la ligne, ce qui coûtait une hauteur entière pour
     rien. `flex: 1` et un plancher abaissé les font tenir côte à côte à 310 px.
     ───────────────────────────────────────────────────────────────────────── */
  .hub-hero { padding: 14px 14px; margin-bottom: 14px; gap: 12px; }
  .hub-hero__h { font-size: 1.2rem; }
  .hub-hero__sub { display: none; }
  .hub-hero__pills { flex-wrap: nowrap; gap: 6px; width: 100%; }
  .hub-pill { flex: 1 1 0; min-width: 0; padding: 8px 4px; }
  .hub-pill__v { font-size: 1.05rem; }
  .hub-pill__l {
    font-size: .58rem; letter-spacing: 0; text-align: center;
    /* Deux lignes au maximum : « BORNES CONNECTÉES » ne tient pas sur une seule
       à 310 px, et le tronquer donnerait « BORNES CONNEC… ». */
    overflow-wrap: anywhere;
  }
  .barre-bas {
    display: flex; flex-shrink: 0;          /* ⚠ INDISPENSABLE : voir ci-dessous */
    align-items: stretch; justify-content: space-around;
    height: var(--barre-h);
    /* La zone sûre s'ajoute SOUS la barre : sur un téléphone à navigation
       gestuelle, les 24 derniers pixels appartiennent au système. */
    padding-bottom: env(safe-area-inset-bottom, 0px);
    background: var(--bg-panel); border-top: 1px solid var(--border-2);
    /* Bande 40-49 : vérifiée LIBRE. En-tête 50, résultats 60, champ déplié 70,
       menu compte 100, message éphémère 200, modales 1000 et 9999. */
    z-index: 45;
  }
  /* ⚠ `.app { overflow-x: hidden }` du bloc téléphone fait passer l'axe
     VERTICAL en `auto` implicitement. Sans `flex-shrink: 0` ci-dessus et cette
     hauteur bornée, `.app` se mettrait à défiler EN PLUS de `.content` : deux
     ascenseurs imbriqués, symptôme qu'on attribue toujours au mauvais élément. */
  .barre-item {
    flex: 1 1 0; min-width: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 2px; padding: 4px 2px 0;
    background: none; border: none; color: var(--text-muted);
    font: inherit; font-size: .62rem; line-height: 1.1;
    cursor: pointer; position: relative;
  }
  /* ⚠ `.barre-lbl` et NON `span:last-child` : l'entrée qui porte la pastille de
     comptage a DEUX spans, et le dernier est la pastille. La règle de troncature
     s'appliquait donc au compteur, et le libellé perdait sa garde — invisible
     tant que le mot tient, faux dès qu'il déborde. */
  .barre-item .barre-lbl {
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .barre-item.actif { color: var(--accent); font-weight: 600; }
  .barre-item.actif .barre-ico {
    background: color-mix(in srgb, var(--accent) 14%, transparent);
  }
  .barre-ico {
    display: flex; align-items: center; justify-content: center;
    width: 40px; height: 22px; border-radius: 11px;
  }
  /* Pastille de comptage — reprise du principe de la cloche d'en-tête. */
  .barre-pastille {
    position: absolute; top: 1px; left: 56%;
    min-width: 15px; height: 15px; padding: 0 3px; border-radius: 8px;
    background: var(--danger); color: #fff;
    font-size: .58rem; font-weight: 700; line-height: 15px; text-align: center;
  }
}

/* Écran COURT et piloté au doigt (paysage) : icônes seules, sans libellé.
   L'en-tête y est déjà ramené de 56 à 44 px pour la même raison — « l'entête
   prend la moitié de l'écran en paysage ». 44 + 40 = 84 px, l'ordre de grandeur
   du compromis déjà accepté. */
@media (pointer: coarse) and (max-height: 520px) {
  :root { --barre-h: 40px; }
  .barre-item .barre-lbl { display: none; }
  .barre-item { padding-top: 0; }
}

/* Les deux éditeurs plein écran (contrat, plaquette) se posent en `inset: 0`
   au niveau 4000 : ils recouvrent déjà la barre, mais elle continuerait de
   réserver sa hauteur sous eux. On l'efface le temps de l'édition.
   ⚠ C'est le premier des deux effacements assumés du modèle « toujours
   visible » — l'autre étant le clavier virtuel, que le navigateur impose. */
body:has(.ctr-editor-ov) .barre-bas,
body:has(.plq-editor-ov) .barre-bas { display: none; }

/* CB080 — organisation mobile orientée métier. La version centrale conserve
   les libellés, sous-titres et cartes complets ; seules les densités du petit
   écran sont adaptées. */
@media (pointer: coarse) and (max-width: 700px) {
  .format-android { --barre-h: 54px; }
  .format-android .topbar { height: 52px; min-height: 52px; }
  .format-android .content { padding-top: 10px; }

  .hub--android .hub-hero {
    display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px;
    padding: 12px; margin-bottom: 0;
  }
  .hub--android .hub-hero__txt { flex-basis: auto; }
  .hub--android .hub-hero__h { font-size: 1.12rem; }
  .hub--android .hub-hero__sub { display: block; font-size: .76rem; }
  .hub--android .hub-primary { margin-top: 9px; min-height: 44px; padding: 8px 11px; }
  .hub--android .hub-primary small { display: none; }
  .hub--android .hub-hero__status { align-items: stretch; gap: 4px; }
  .hub--android .hub-hero__scope { text-align: left; font-size: .64rem; }
  .hub--android .hub-hero__pills { margin-top: 0; }
  .hub--android .hub-pill { min-height: 66px; padding: 6px 3px; }
  .hub--android .hub-pill__ico { display: none; }
  .hub--android .hub-pill__v { font-size: 1rem; }

  /* CB081 — la messagerie revient sur l'accueil Android sans redevenir une
     seconde page : deux cartes courtes, puis un seul accès à la liste. */
  .hub--android #hub-messages { margin-top: 10px; }
  .hub--android .hub-messages { margin-bottom: 10px; }
  .hub--android .hub-messages .hub-row__head {
    margin-bottom: 6px; flex-wrap: nowrap; align-items: center;
  }
  .hub--android .hub-messages .hub-row__desc {
    flex: 0 1 auto; margin-left: auto; padding-left: 0; text-align: right;
    font-size: .68rem;
  }
  .hub--android .hub-messages .msg-carte {
    min-height: 44px; margin-bottom: 6px; padding: 8px 10px;
  }
  .hub--android .hub-messages .msg-carte__texte {
    display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
  }
  .hub--android .hub-messages #msg-tout { min-height: 44px; width: 100%; }

  /* Une phase montre toutes ses fonctions, sans la succession de grandes
     vignettes observée sur le Galaxy A16. */
  .hub:not(.hub--accueil) .hub-cards {
    grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px;
  }
  .hub:not(.hub--accueil) .hub-card {
    min-height: 92px; padding: 10px; gap: 8px; align-items: flex-start;
    flex-direction: column; border-left-width: 3px;
  }
  .hub:not(.hub--accueil) .hub-card__ico { width: 34px; height: 34px; border-radius: 9px; }
  .hub:not(.hub--accueil) .hub-card__t { font-size: .86rem; line-height: 1.2; }
  .hub:not(.hub--accueil) .hub-card__s,
  .hub:not(.hub--accueil) .hub-card__go { display: none; }
  .mobile-plus .hub-row__desc { padding-left: 20px; }

  .barre-item { min-height: 44px; padding-top: 3px; }
  .barre-item .barre-lbl { font-size: .58rem; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   EN-TÊTE AÉRÉ ET FIL D'ARIANE RETIRÉ — là où la barre basse existe (2026-08-04)

   Mesuré sur 311 px : les 5 éléments n'occupaient que 189 px, mais tassés à
   gauche avec 6 px d'écart. Ce n'était pas un manque de place, c'était une
   absence de mise en page — 122 px inutilisés à droite.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (pointer: coarse) and (max-width: 700px) {
  /* ⚠ Le bouton maison fait DOUBLON avec l'entrée « Accueil » de la barre, qui
     est à portée de pouce alors que celui-ci est en haut de l'écran. */
  #btn-home { display: none; }

  .topbar { gap: 10px; padding: 0 10px; }
  /* Identité à gauche, actions groupées à droite : une lecture, pas un tas. */
  #q-loupe { margin-left: auto; }
  .topbar-alerts, #btn-aide, .account-btn { min-height: 38px; }

  /* ⚠⚠ FIL D'ARIANE RETIRÉ — décision de Carlos, « il n'a plus lieu d'être ».
     Il coûtait 37 px sur 630, et il fait désormais doublon deux fois :
       · pour la BASCULE latérale, la barre du bas dit déjà où l'on est ;
       · pour le RETOUR en profondeur, le geste système d'Android suit
         l'historique des adresses — chaque écran en écrit une.
     Et pour SITUER, le titre de l'écran le dit déjà : la fiche d'un site
     affiche « Clients & sites › Dupont › Parking Nord » dans son propre titre.

     ⚠ Le code du fil n'est PAS supprimé : il reste la navigation sur poste et
     sur tablette, où il n'y a pas de barre basse. Une seule requête média
     décide des deux. */
  #fil-ariane { display: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   LISTE DES SITES — une ligne, un appui, la fiche complète (2026-08-04)

   Sur poste c'est le TABLEAU qui s'affiche : à 1280 px, cinq colonnes alignées
   se lisent mieux qu'une liste. Sur téléphone c'est l'inverse — la règle
   responsive dépliait chaque ligne en blocs « VILLE · … / TYPE · … / STATUT · … »,
   soit une demi-page par site. Les deux rendus existent dans le document, le
   style choisit lequel se montre.
   ═══════════════════════════════════════════════════════════════════════════ */
.site-liste { display: none; }

.client-card-actions {
  display: flex; align-items: center; justify-content: flex-end; gap: 6px;
  flex-wrap: wrap;
}
.client-dossier-choice { max-width: 560px; }
.client-dossier-choice__field,
.client-dossier-choice__help { grid-column: 1 / -1; }
.client-dossier-choice__help { margin: 4px 0 0; font-size: 12px; }
.client-dossier-choice__actions { justify-content: space-between; }
.client-dossier-choice__buttons { display: flex; gap: 8px; }
.client-sites-panel { margin-bottom: 14px; }
.client-sites-panel__head { margin-bottom: 8px; }
.client-sites-panel__title,
.client-sites-heading { display: flex; align-items: center; gap: 8px; }
.client-sites-panel__title { margin: 0; }
.client-sites-orphans { border-left: 3px solid var(--warning); }
.client-sites-orphans__title { margin: 0 0 8px; }
.safe-frame { display: block; width: 100%; border: 0; }
.safe-frame--fill,
.safe-frame--webui { height: 100%; }
.safe-frame--webui,
.safe-frame--constructor { background: #fff; }
.safe-frame--constructor {
  height: calc(100vh - 220px);
  min-height: 460px;
  border: 1px solid var(--surface2);
  border-radius: 8px;
}
.client-more-actions { position: relative; }
.client-more-actions > summary { list-style: none; cursor: pointer; }
.client-more-actions > summary::-webkit-details-marker { display: none; }
.client-more-actions__menu {
  display: none; position: absolute; z-index: 40; right: 0; top: calc(100% + 5px);
  min-width: 190px; padding: 7px; gap: 5px; border: 1px solid var(--border);
  border-radius: 9px; background: var(--surface); box-shadow: 0 10px 28px rgba(15,23,42,.16);
}
.client-more-actions[open] .client-more-actions__menu { display: grid; }
.client-more-actions__menu .btn-sm { width: 100%; min-height: 40px; justify-content: flex-start; }

/* CB-106 — le client et son site restent le contexte de travail. Les actions
   sont révélées par étape sans retirer les douze destinations historiques. */
.dossier-view-head { align-items: flex-end; gap: 20px; }
.dossier-view-head h2 { margin: 5px 0 2px; }
.dossier-view-head p { margin: 0; }
.dossier-back { color: var(--accent); font-size: .8rem; font-weight: 800; text-decoration: none; }
.dossier-back:hover, .dossier-back:focus-visible { text-decoration: underline; }
.dossier-head-actions { align-items: center; }
.dossier-more-actions { position: relative; }
.dossier-more-actions > summary { list-style: none; cursor: pointer; }
.dossier-more-actions > summary::-webkit-details-marker { display: none; }
.dossier-more-actions__menu {
  display: none; position: absolute; z-index: 45; top: calc(100% + 6px); right: 0;
  min-width: 210px; padding: 7px; gap: 6px; border: 1px solid var(--border);
  border-radius: 10px; background: var(--bg-card); box-shadow: 0 12px 30px rgba(15,23,42,.17);
}
.dossier-more-actions[open] .dossier-more-actions__menu { display: grid; }
.dossier-more-actions__menu button { width: 100%; min-height: 40px; justify-content: flex-start; }
.dossier-danger-action { color: var(--danger); }
.dossier-context {
  display: grid; grid-template-columns: minmax(240px,1.2fr) minmax(360px,1fr); gap: 16px;
  align-items: stretch; margin: 0 0 14px; border: 1px solid var(--border); border-radius: 16px;
  background: linear-gradient(120deg,color-mix(in srgb,var(--accent) 9%,var(--bg-card)),var(--bg-card));
  padding: 16px 18px;
}
.dossier-context__identity { display: flex; min-width: 0; flex-direction: column; gap: 4px; }
.dossier-context__identity strong { font-size: 1.2rem; overflow-wrap: anywhere; }
.dossier-context__identity > span:last-child { color: var(--text-muted); font-size: .82rem; overflow-wrap: anywhere; }
.dossier-context__eyebrow { color: var(--accent); font-size: .68rem; font-weight: 850; letter-spacing: .13em; text-transform: uppercase; }
.dossier-context__meta { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); gap: 8px; }
.dossier-context__meta > span { display: flex; min-width: 0; flex-direction: column; gap: 5px; justify-content: center; border-left: 1px solid var(--border); padding-left: 12px; }
.dossier-context__meta small { color: var(--text-muted); font-size: .67rem; font-weight: 800; text-transform: uppercase; }
.dossier-context__meta strong { overflow-wrap: anywhere; }
.dossier-phases { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); gap: 10px; margin: 16px 0 0; }
.dossier-phase {
  display: grid; grid-template-columns: 34px minmax(0,1fr); grid-template-rows: auto auto; column-gap: 10px;
  min-height: 76px; align-items: center; border: 1px solid var(--border); border-radius: 13px;
  background: var(--bg-card); color: var(--text); padding: 10px 12px; text-align: left; cursor: pointer;
}
.dossier-phase > span { grid-row: 1 / 3; display: grid; width: 32px; height: 32px; place-items: center; border-radius: 9px; background: var(--brand-50); color: var(--accent); font-weight: 900; }
.dossier-phase strong { align-self: end; font-size: .9rem; }
.dossier-phase small { align-self: start; color: var(--text-muted); font-size: .72rem; }
.dossier-phase:hover, .dossier-phase:focus-visible { border-color: var(--accent); }
.dossier-phase.active { border-color: var(--accent); background: color-mix(in srgb,var(--accent) 7%,var(--bg-card)); box-shadow: inset 0 3px 0 var(--accent); }
.dossier-phase.active > span { background: var(--accent); color: #fff; }
.dossier-subtabs { margin-top: 8px; padding-top: 0; }
.dossier-subtabs .site-dossier-subtab { min-height: 44px; }

@media (max-width: 900px) {
  .dossier-context { grid-template-columns: 1fr; }
  .dossier-context__meta > span:first-child { border-left: 0; padding-left: 0; }
  .dossier-phase { grid-template-columns: 30px minmax(0,1fr); min-height: 66px; padding: 8px 9px; }
  .dossier-phase > span { width: 28px; height: 28px; }
  .dossier-phase small { display: none; }
}
@media (max-width: 620px) {
  .dossier-view-head { align-items: stretch; }
  .dossier-head-actions { justify-content: space-between; }
  .dossier-context { gap: 12px; padding: 13px; }
  .dossier-context__meta { grid-template-columns: 1fr; gap: 6px; }
  .dossier-context__meta > span, .dossier-context__meta > span:first-child { border-left: 0; border-top: 1px solid var(--border); padding: 7px 0 0; }
  .dossier-phases { grid-template-columns: 1fr; gap: 6px; }
  .dossier-phase { grid-template-rows: auto; min-height: 48px; }
  .dossier-phase > span { grid-row: auto; }
  .dossier-phase strong { align-self: center; }
  .dossier-subtabs { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: 5px; overflow: visible; border-bottom: 0; }
  .dossier-subtabs .site-dossier-subtab { width: 100%; border: 1px solid var(--border); border-radius: 9px; padding: 8px; white-space: normal; text-align: center; }
  .dossier-subtabs .site-dossier-subtab.active { border-color: var(--accent); background: var(--brand-50); }
}
@media (pointer: coarse) {
  .dossier-phase, .dossier-subtabs .site-dossier-subtab, .dossier-head-actions button, .dossier-more-actions > summary { min-height: 44px; }
}

@media (max-width: 700px) {
  /* ⚠ `.content table.sites-table` et non `.sites-table` : la règle responsive
     `.content table.grid { display: block }` (bloc 640 px) a une spécificité
     supérieure et l'emportait — le tableau restait affiché SOUS la liste, les
     deux rendus visibles en même temps. La largeur suffit à choisir le rendu :
     certains WebView Android annoncent encore `pointer:fine`, bien que la
     largeur utile soit celle d'un téléphone. Mesuré avant correction : une
     table dépliée ET sa liste compacte sur 360 px. */
  .content table.sites-table { display: none !important; }
  .site-liste { display: block; }
  .site-ligne {
    display: flex; align-items: center; gap: 8px; width: 100%;
    padding: 10px 4px; text-align: left; cursor: pointer;
    background: none; border: none; border-bottom: 1px solid var(--border);
    font: inherit; color: inherit;
  }
  .site-ligne:last-child { border-bottom: none; }
  .site-ligne__txt { flex: 1 1 auto; min-width: 0; }
  .site-ligne__nom {
    display: block; font-size: .9rem; font-weight: 600; line-height: 1.3;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .site-ligne__sous {
    display: block; font-size: .76rem; color: var(--text-muted); line-height: 1.3;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .site-ligne .badge { flex: 0 0 auto; font-size: .68rem; }
  .site-ligne__go { flex: 0 0 auto; color: var(--text-muted); font-size: 1.1rem; }

  /* Une action métier primaire et un menu secondaire : les anciens cinq
     boutons occupaient trois rangées avant même d'atteindre le premier site. */
  .hub .panel, .view-head + .panel { }
  .panel .view-head h3 { font-size: 1rem; }
  .panel .view-head { flex-wrap: wrap; gap: 6px; }
  .client-card-actions { width: 100%; justify-content: stretch; }
  .client-card-actions > .btn { flex: 1 1 auto; min-height: 44px; }
  .client-more-actions > summary { min-height: 44px; display: inline-flex; align-items: center; }
  .client-more-actions__menu { min-width: min(220px, calc(100vw - 40px)); }
  .client-more-actions__menu .btn-sm { min-height: 44px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   FORMULAIRES AU DOIGT — corrections transverses (2026-08-05)

   ⚠ EN FIN DE FICHIER, comme les autres blocs tactiles : `@media (max-width:400px)`
   est déclaré AVANT deux blocs 640 px et perd la cascade sur un écran de 310 px.

   ⚠⚠ LE DÉFAUT QUI A DÉCLENCHÉ CE BLOC, mesuré sur l'appareil de Carlos.
   `.modal-actions` est en `justify-content:flex-end` et `flex-wrap:nowrap`, avec
   des boutons en `white-space:nowrap`. Largeur utile réelle : 221 px. Sur la
   fenêtre de forçage de mise en service, les trois boutons mesurés donnaient :
       « Voir la règle »                      x = −297 … −192
       « Annuler — je ne mets pas en service » x = −184 … 66
       « Forcer la mise en service »          x =   74 … 266
   Autrement dit : SEULE L'ACTION ENGAGEANTE RESTAIT CLIQUABLE, le refus était
   hors écran. Et le débordement n'était PAS rattrapable — ni la rangée ni la
   boîte ne défilent latéralement (`scrollWidth == clientWidth`, vérifié).
   Un garde-fou dont on ne peut plus sortir que par « oui » n'est pas un
   garde-fou. Même mécanique sur le changement de mot de passe obligatoire.

   ⚠ Une règle existait qui semblait couvrir ce cas — mais elle est préfixée
   `.content`, alors que les fenêtres sont ajoutées à `document.body`. Elle n'a
   jamais protégé une seule modale.

   POUR ANNULER : supprimer ce bloc. Rien d'autre à défaire.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (pointer: coarse) and (max-width: 700px) {

  /* ── Les rangées d'actions se replient au lieu de sortir de l'écran ── */
  .modal-actions {
    flex-wrap: wrap;
    justify-content: stretch;
  }
  .modal-actions > button,
  .modal-actions > .btn,
  .modal-actions > .btn-ghost {
    flex: 1 1 auto;
    white-space: normal;      /* un libellé long tient sur deux lignes */
    min-height: 44px;         /* cible tactile d'une action engageante */
  }

  /* ── Une seule colonne de saisie ──
     `1fr 1fr` donnait 116,7 px et 80,6 px — inégales, parce qu'une piste `1fr`
     ne descend pas sous son mot insécable le plus long (« intracommunautaire »).
     Résultat : « IBAN / RIB (cession prime ADVENIR) » sur quatre lignes de
     libellé au-dessus d'un champ de 81 px, pour saisir 27 caractères. */
  .modal-form { grid-template-columns: 1fr; }

  /* ── Hauteur réellement visible, et la fenêtre part du HAUT ──
     `90vh` se mesure sur le grand viewport, barre d'adresse comprise, alors que
     l'enveloppe `position:fixed;inset:0` se cale sur la zone visible. Avec
     `align-items:center`, l'excédent se partageait EN HAUT ET EN BAS : on
     perdait le titre et les boutons à la fois. */
  .modal, .modal-box { max-height: 90vh; max-height: 90dvh; }
  .modal-ov, .modal-overlay {
    align-items: flex-start;
    overflow-y: auto;
    padding: 12px 0 calc(12px + env(safe-area-inset-bottom, 0px));
  }

  /* ── Champs lisibles et cibles atteignables ──
     14,08 px mesurés. Sous 16 px, plusieurs navigateurs mobiles agrandissent
     la page dès qu'on touche un champ, et l'on perd sa position. */
  input, select, textarea { font-size: 16px; }
  .btn, .btn-ghost { min-height: 40px; }
  .btn-sm { min-height: 36px; }
}

/* Champ obligatoire oublié, signalé le temps qu'on le voie. Le message dit
   lequel, ce halo dit OÙ — sur un formulaire de treize écrans, l'un sans
   l'autre ne sert à rien. */
.fe-field.fe-manquant {
  outline: 2px solid var(--danger);
  outline-offset: 3px;
  border-radius: 6px;
  animation: feManquant 1.2s ease-in-out 2;
}
@keyframes feManquant { 0%,100% { outline-color: var(--danger); } 50% { outline-color: transparent; } }

/* ═══════════════════════════════════════════════════════════════════════════
   CARROUSEL DE FICHE + RÉCAPITULATIF DES OBLIGATOIRES (2026-08-05)

   Décidé sur MESURES prises avec le vrai moteur et le vrai gabarit « recette »
   (71 champs), à deux tailles d'écran :

                          ordinateur 1309 px      téléphone 282 px
     colonnes de grille          4                       1
     hauteur du formulaire   3 410 px = 4,2 écrans   9 390 px = 16,4 écrans
     sections tenant à l'écran   8 / 10                  1 / 10
     section la plus haute     761 px                 1 885 px

   D'où la règle : le carrousel est réservé au TÉLÉPHONE. Sur ordinateur cinq
   sections sur dix occupent moins d'un tiers de la hauteur de l'écran — le
   découpage y échangerait quatre mouvements de molette contre neuf clics, sans
   même supprimer le défilement des deux sections les plus lourdes, et la
   recherche du navigateur ne trouverait plus que la section affichée.
   Le récapitulatif des champs obligatoires, lui, sert PARTOUT.

   ⚠⚠ Le masquage est le SEUL mécanisme employé : les sections restent dans le
   document. `collect()` reconstruit les réponses intégralement depuis le
   document — les détruire pour les recréer effacerait la saisie.

   ⚠ Le bandeau est COLLANT (`sticky`), jamais `fixed` : il garde sa place dans
   le flux, donc les positions de défilement mémorisées par l'application
   restent justes. C'est la leçon de la barre de navigation basse.

   POUR ANNULER : supprimer ce bloc. Le script continue de fonctionner, le
   formulaire redevient une page longue.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Récapitulatif des champs obligatoires — tous écrans ────────────────────
   Il s'efface de lui-même dès qu'il ne manque rien : une barre toujours
   présente devient un décor que l'on ne lit plus. */
.fe-recap {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px;
  padding: 9px 12px; margin-bottom: 4px;
  background: var(--warning-bg); border: 1px solid var(--warning-strong);
  border-radius: var(--radius-sm);
  font-size: .82rem; color: var(--warning);
}
.fe-recap[hidden] { display: none; }
.fe-recap-t { font-weight: 600; }
.fe-recap-l { display: flex; flex-wrap: wrap; gap: 6px; }
.fe-recap-b {
  background: #fff; border: 1px solid var(--warning-strong); color: var(--warning);
  border-radius: var(--radius-pill); padding: 3px 10px; font-size: .78rem;
  cursor: pointer; font-family: inherit;
}
.fe-recap-b:hover { background: var(--warning-strong); color: #fff; }
.fe-recap-p { color: var(--warning); }

/* ── Bandeau de section : rien du tout hors téléphone ───────────────────── */
.fe-nav { display: none; }

@media (pointer: coarse) and (max-width: 700px) {

  .fe-form.fe-carrousel > .fe-section { display: none; }
  .fe-form.fe-carrousel > .fe-section.fe-on { display: block; }

  /* Le sommaire donne déjà le compte section par section ; le récapitulatif
     ferait doublon et coûterait 60 px sur les 413 px réellement utilisables. */
  .fe-form.fe-carrousel > .fe-recap { display: none; }

  .fe-form.fe-carrousel > .fe-nav {
    display: flex; align-items: center; gap: 6px;
    position: sticky; bottom: 0; z-index: 5;
    margin-top: 10px;
    /* ⚠ PAS de réserve `env(safe-area-inset-bottom)` ici : le bandeau n'est
       jamais au bord de l'écran — la barre de navigation basse est SOUS lui,
       en flux, et réserve déjà la zone gestuelle du téléphone. L'y ajouter
       insérait 24 px de vide au milieu de l'écran, pris sur la zone de saisie. */
    padding: 8px;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-2);
  }
  .fe-nav-jauge {
    position: absolute; left: 8px; right: 8px; top: 3px; height: 3px;
    background: var(--surface2); border-radius: 999px; overflow: hidden;
  }
  .fe-nav-jauge > i { display: block; height: 100%; background: var(--accent); transition: width .18s ease; }

  .fe-nav-fl {
    flex: 0 0 auto; min-width: 44px; min-height: 44px;
    font-size: 1.3rem; line-height: 1; font-family: inherit;
    background: var(--bg-card); color: var(--text);
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    cursor: pointer;
  }
  .fe-nav-fl:disabled { opacity: .35; }
  /* Sur la dernière section, « Suivant » devient « Terminer » : il porte un
     libellé, donc il lui faut de la place — mais jamais au point de repousser
     le retour en arrière hors de l'écran (défaut mesuré sur la fenêtre de
     forçage : le refus était à x = −184). */
  .fe-nav-fl.fe-nav-fin {
    font-size: .8rem; padding: 0 8px; white-space: nowrap;
    background: var(--accent); color: #fff; border-color: var(--accent);
  }
  .fe-nav-pos {
    flex: 1 1 auto; min-width: 0; min-height: 44px;
    font-family: inherit; font-size: .78rem; font-weight: 600;
    text-align: center; color: var(--text);
    background: transparent; border: 0; cursor: pointer;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .fe-nav-pos::after { content: ' ▾'; color: var(--text-muted); }

  /* Sommaire : s'ouvre VERS LE HAUT depuis le bandeau collant, donc toujours
     là où l'on vient de toucher. */
  .fe-somm {
    position: absolute; left: 0; right: 0; bottom: calc(100% + 6px);
    /* ⚠⚠ LA HAUTEUR SE MESURE SUR LA PLACE DISPONIBLE, PAS SUR LA FENÊTRE.
       `58dvh` seul débordait de 71 px AU-DESSUS du conteneur qui défile en
       PAYSAGE (644 × 296) : les deux premières entrées du sommaire étaient
       rognées, et IRRATTRAPABLES — le sommaire est déjà en haut de son propre
       défilement, et faire défiler la page ne sert à rien puisque le bandeau
       est collant et emmène le sommaire avec lui. Exactement le défaut qu'on
       s'est juré de ne plus reproduire : une commande hors de portée, sans
       issue. Les 210 px retranchés couvrent l'en-tête, le bandeau lui-même,
       la barre basse et les marges. Le sommaire défile en interne : plus
       court, il reste entièrement atteignable. */
    max-height: 58vh;
    max-height: min(58dvh, calc(100dvh - 210px));  /* repli prudent : la valeur exacte est posee par le script, qui MESURE la place */
    min-height: 76px;
    overflow-y: auto;
    display: flex; flex-direction: column;
    background: var(--bg-panel); border: 1px solid var(--border);
    border-radius: var(--radius-sm); box-shadow: var(--shadow-3);
    padding: 4px;
  }
  .fe-somm[hidden] { display: none; }
  .fe-somm-l {
    display: flex; align-items: center; gap: 8px; width: 100%;
    min-height: 40px; padding: 6px 8px; text-align: left;
    background: transparent; border: 0; border-radius: 8px;
    font-family: inherit; font-size: .82rem; color: var(--text); cursor: pointer;
  }
  .fe-somm-on { background: var(--brand-50); box-shadow: inset 3px 0 0 var(--accent); }
  .fe-somm-t { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .fe-somm-m {
    flex: 0 0 auto; min-width: 18px; height: 18px; border-radius: 999px;
    background: var(--danger); color: #fff;
    font-size: .68rem; line-height: 18px; text-align: center; padding: 0 5px;
  }
}

/* ⚠ À L'IMPRESSION, TOUT REVIENT. Sans cette règle, la fiche remise au client
   ne contiendrait qu'une section sur dix — et rien à l'écran ne l'annoncerait. */
@media print {
  .fe-form.fe-carrousel > .fe-section { display: block !important; }
  .fe-nav, .fe-recap { display: none !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   AIDE — RÈGLES IRVE : champ de recherche et barre des thèmes (2026-08-05)

   ⚠ POURQUOI CES RÈGLES SORTENT DU SCRIPT. Elles étaient écrites EN LIGNE dans
   `VIEWS.aide`. Un style en ligne l'emporte sur la feuille quelle que soit la
   spécificité : la règle téléphone `input { font-size: 16px }` ne pouvait donc
   pas s'appliquer au champ de recherche, resté à 13,8 px. En dessous de 16 px,
   le navigateur mobile agrandit la page dès qu'on touche le champ — on tape un
   mot et l'on a perdu sa position dans la liste.

   ⚠ EN FIN DE FICHIER, comme les autres blocs tactiles : le bloc téléphone doit
   être déclaré APRÈS les blocs 640 px pour l'emporter à spécificité égale.

   POUR ANNULER : supprimer ce bloc. Les fiches restent lisibles, la barre des
   thèmes se replie sur plusieurs lignes comme avant.
   ═══════════════════════════════════════════════════════════════════════════ */
.aide-recherche {
  width: 100%; margin-top: 9px; padding: 7px 9px;
  border: 1px solid var(--border); border-radius: 6px; font-size: .86rem;
}
.aide-themes { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.aide-cat.actif {
  font-weight: 700; border-color: var(--accent); background: var(--brand-50);
}
/* Le compte des fiches du thème : présent, jamais lu à la place du libellé. */
.aide-nb { color: var(--text-muted); font-weight: 400; font-size: .74rem; }
.aide-cat.actif .aide-nb { color: var(--brand-700); }

@media (pointer: coarse) and (max-width: 700px) {
  /* Une seule rangée qui défile latéralement, plutôt que trois rangées
     repliées : à 310 px, huit thèmes repoussaient la première fiche sous la
     ligne de flottaison — on croyait la base vide avant d'avoir fait défiler.
     Les marges négatives font affleurer la rangée aux bords du panneau, sans
     quoi le dernier thème semble être le dernier de la liste. */
  .aide-themes {
    flex-wrap: nowrap; overflow-x: auto;
    margin-left: -13px; margin-right: -13px; padding-left: 13px; padding-right: 13px;
    padding-bottom: 2px; scrollbar-width: none;
  }
  .aide-themes::-webkit-scrollbar { display: none; }
  .aide-cat { flex: 0 0 auto; }
  /* ⚠⚠ ET IL FAUT LE REDIRE ICI. La règle du bloc téléphone qui impose 16 px
     aux champs vise l'ÉLÉMENT `input` ; `.aide-recherche` est une CLASSE et
     l'emporte, requête média ou pas. Sortir le style de la balise ne suffisait
     donc pas : mesuré à 13,76 px sur une maquette à 310 px, la page s'agrandit
     encore dès qu'on touche le champ. La classe se corrige avec la classe. */
  .aide-recherche { font-size: 16px; }
  /* La carte d'une fiche est une cible de doigt, pas une ligne de tableau. */
  .aide-fiche { min-height: 44px; }
  /* Dans le détail d'une fiche, le retour et les sources étaient de simples
     lignes de texte hautes de 16 à 24 px en paysage sur le Galaxy A16. Les
     transformer en cibles tactiles n'altère ni le texte ni les règles. */
  .aide-retour {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 4px 6px;
  }
  .aide-sources .link {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 4px 0;
    overflow-wrap: anywhere;
  }
}

/* ─── Le dernier signe de vie, par point de charge ─────────────────────────
   ⚠⚠ Ce tableau existe parce qu'un point de charge est resté mort dix jours
   sans qu'aucun écran ne puisse le montrer : le journal n'affichait pas la
   colonne du connecteur, et la Vue rapide ne descendait pas sous la borne.
   Il est donc lu au chevet d'une panne — souvent sur un téléphone, sur le
   capot d'une voiture. Il est bâti en grille et non en tableau HTML, pour
   pouvoir s'empiler proprement sans le contorsionnisme du mode fiche. */
.sdv-tete, .sdv-ligne {
  display: grid;
  grid-template-columns: 14px minmax(0, 2fr) 70px 70px 70px minmax(0, 1.4fr);
  gap: 8px;
  align-items: center;
  padding: 7px 2px;
  font-size: .84rem;
}
.sdv-tete {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-muted, #5f6368);
  border-bottom: 1px solid var(--border, #dadce0);
}
.sdv-ligne + .sdv-ligne { border-top: 1px solid var(--border-light, #f1f3f4); }
.sdv-pastille { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
.sdv-cp { font-family: ui-monospace, "SF Mono", Menlo, monospace; word-break: break-all; }
.sdv-role {
  font-family: inherit;
  font-size: .68rem;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--border-light, #f1f3f4);
  color: var(--text-muted, #5f6368);
}
.sdv-etat { font-weight: 600; font-size: .76rem; }
.sdv-nb, .sdv-date { color: var(--text-muted, #5f6368); font-size: .76rem; }

/* ⚠ « screen and » OBLIGATOIRE : une page A4 portrait fait 794 px, et sans lui
   la règle s'appliquerait À L'IMPRESSION. Même piège que le journal complet. */
@media screen and (pointer: coarse) and (max-width: 900px) {
  /* Sur 310 px, six colonnes donnent cinquante pixels chacune. On empile en
     deux lignes : l'identifiant seul, puis l'état et les chiffres. La page ne
     doit JAMAIS défiler latéralement — c'est le seul vrai risque de cet écran. */
  .sdv-tete { display: none; }
  .sdv-ligne {
    grid-template-columns: 14px minmax(0, 1fr) auto;
    grid-template-areas: "pastille cp etat" ". depuis nb" ". date date";
    row-gap: 2px;
    padding: 9px 2px;
  }
  .sdv-pastille { grid-area: pastille; }
  .sdv-cp   { grid-area: cp; }
  .sdv-etat { grid-area: etat; text-align: right; }
  .sdv-depuis { grid-area: depuis; }
  .sdv-nb   { grid-area: nb; text-align: right; }
  .sdv-date { grid-area: date; }
}

/* CB047 — couche de contrat finale. Elle doit rester la dernière : plusieurs
   composants historiques déclarent encore leurs variantes tactiles plus haut. */
@media screen and (max-width: 900px) {
  .subtabs {
    display: grid !important; grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: stretch; gap: 6px; overflow: visible !important;
    border-bottom: 0; padding: 4px 0; scrollbar-width: none;
  }
  .subtabs > .subtab {
    flex: initial; min-width: 0; min-height: 44px; width: 100%; padding: 8px 10px;
    top: 0; margin-bottom: 0; border: 1px solid var(--border); border-radius: 9px;
    white-space: normal; overflow-wrap: anywhere; line-height: 1.2; text-align: center;
  }
  .subtabs > .subtab.active {
    border-color: var(--brand-500, #1a73e8); border-bottom-color: var(--brand-500, #1a73e8);
    box-shadow: inset 0 0 0 1px var(--brand-500, #1a73e8);
  }
  .mt-actions {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: stretch; gap: 6px; width: 100%;
  }
  .mt-actions > button { width: 100%; min-width: 0; white-space: normal; }
}

@media screen and (max-width: 700px) {
  .topbar { height: 60px; min-height: 60px; padding: 0 8px; gap: 6px; }
  .topbar-loupe, .topbar-alerts, .account-btn, .topbar-home,
  button, [role="button"], .btn, .btn-ghost, .btn-sm, .subtab, .fil-seg {
    min-height: 44px !important;
  }
  .topbar-loupe, .topbar-alerts, .account-btn, .topbar-home { min-width: 44px; justify-content: center; }
  .topbar-loupe { width: 44px; height: 44px; }
  input:not([type="checkbox"]):not([type="radio"]), select, textarea {
    min-height: 44px; max-width: 100%; min-width: 0 !important; font-size: 16px !important;
  }
  .content table.ux-mobile-cards,
  .modal table.ux-mobile-cards,
  .modal-box table.ux-mobile-cards { display: block !important; overflow: visible !important; }
}

/* Un téléphone paysage et certaines tablettes dépassent 700 px CSS tout en
   restant pilotés au doigt. La largeur seule ne doit donc jamais réactiver les
   petites cibles historiques ni les champs qui déclenchent le zoom mobile. */
@media screen and (pointer: coarse) {
  .topbar-loupe, .topbar-alerts, .account-btn, .topbar-home,
  button, [role="button"], .btn, .btn-ghost, .btn-sm, .subtab, .fil-seg {
    min-height: 44px !important;
  }
  .topbar-loupe, .topbar-alerts, .account-btn, .topbar-home {
    min-width: 44px; justify-content: center;
  }
  input:not([type="checkbox"]):not([type="radio"]), select, textarea {
    min-height: 44px; max-width: 100%; min-width: 0 !important; font-size: 16px !important;
  }
}

@media screen and (max-width: 420px) {
  .mt-actions { grid-template-columns: minmax(0, 1fr); }
}
.provenance-badge {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 2px 8px;
  border: 1px solid #cbd5e1;
  border-radius: 999px;
  background: #f8fafc;
  color: #334155;
  font-size: .72rem;
  font-weight: 700;
  line-height: 1.2;
  vertical-align: middle;
  white-space: nowrap;
}
.provenance-norme { border-color: #2563eb; background: #eff6ff; color: #1d4ed8; }
.provenance-reglementation { border-color: #7c3aed; background: #f5f3ff; color: #6d28d9; }
.provenance-grd { border-color: #0284c7; background: #f0f9ff; color: #0369a1; }
.provenance-fabricant { border-color: #d97706; background: #fffbeb; color: #b45309; }
.provenance-conseil_caly { border-color: #0f766e; background: #f0fdfa; color: #0f766e; }
.provenance-pratique_interne { border-color: #a16207; background: #fefce8; color: #854d0e; }
.provenance-non_qualifiee { border-color: #94a3b8; background: #f1f5f9; color: #475569; }
.provenance-legend { margin-top: 8px; font-size: .78rem; }
.provenance-legend > summary { color: var(--text2, #475569); cursor: pointer; font-weight: 650; }
.provenance-legend__items { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; }
@media (max-width: 700px) {
  .provenance-badge { min-height: 28px; font-size: .75rem; }
  .provenance-legend__items { gap: 7px; }
}
/* CB053 — consultation courte des veilles : liste + panneau, puis onglets. */
.watch-view-head{display:flex;align-items:end;justify-content:space-between;gap:16px;flex-wrap:wrap}
.watch-filters{display:flex;gap:8px;flex-wrap:wrap}.watch-filters select,.watch-compare-controls select{min-height:42px;border:1px solid var(--border);border-radius:10px;background:var(--bg-card);color:var(--text);padding:0 34px 0 12px}
.watch-layout{display:grid;grid-template-columns:minmax(250px,340px) minmax(0,1fr);gap:18px;align-items:start}
.watch-detail{min-width:0}
.watch-list,.watch-detail-card{min-width:0;border:1px solid var(--border);border-radius:16px;background:var(--bg-card);overflow:hidden}
.watch-list{max-height:calc(100dvh - 220px);overflow:auto}.watch-list-count{padding:12px 16px;border-bottom:1px solid var(--border);font-weight:700}
.watch-item{display:flex;width:100%;flex-direction:column;align-items:flex-start;gap:5px;padding:14px 16px;border:0;border-bottom:1px solid var(--border);background:transparent;color:var(--text);text-align:left;cursor:pointer}
.watch-item:hover,.watch-item.active{background:color-mix(in srgb,var(--accent) 9%,var(--bg-card))}.watch-item.active{box-shadow:inset 4px 0 var(--accent)}
.watch-selection{margin:0 0 18px;border:1px solid var(--border);border-radius:16px;background:var(--bg-card);padding:16px}.watch-selection-head{display:flex;align-items:end;justify-content:space-between;gap:16px;margin-bottom:13px}.watch-selection-head h3,.watch-selection-head p{margin:0}.watch-selection-head p{margin-top:4px;color:var(--text-muted);font-size:.82rem}.watch-view-actions{display:flex;align-items:end;gap:8px;flex-wrap:wrap}.watch-view-actions label,.watch-filter-grid label{display:grid;min-width:0;gap:5px;color:var(--text-muted);font-size:.72rem;font-weight:800}.watch-view-actions select,.watch-filter-grid select,.watch-filter-grid input{width:100%;min-height:42px;border:1px solid var(--border);border-radius:9px;background:var(--bg-card);color:var(--text);padding:8px 10px;font:inherit;font-size:.92rem}.watch-view-actions select{min-width:190px}.watch-filter-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}.watch-filter-footer{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:12px}.watch-filter-footer>div{display:flex;gap:8px;flex-wrap:wrap}.watch-favorite-toggle{display:flex;align-items:center;gap:8px;color:var(--text);font-weight:750}.watch-favorite-toggle input{width:19px;height:19px;margin:0;accent-color:var(--accent)}
.watch-alerts{margin:0 0 18px;border:1px solid var(--border);border-radius:16px;background:var(--bg-card);padding:16px}.watch-alerts>header{display:flex;align-items:start;justify-content:space-between;gap:16px;margin-bottom:13px}.watch-alerts h3,.watch-alerts h4,.watch-alerts p{margin:0}.watch-alerts header p{margin-top:4px;color:var(--text-muted);font-size:.82rem}.watch-alert-badge,.watch-alert-state{display:inline-flex;align-items:center;justify-content:center;min-height:29px;border-radius:999px;background:#dcfce7;color:#166534;padding:5px 10px;font-size:.74rem;font-weight:850;white-space:nowrap}.watch-alert-state[data-enabled="false"]{background:#e2e8f0;color:#475569}.watch-alert-form{display:grid;grid-template-columns:1.6fr repeat(3,minmax(120px,.75fr)) auto;align-items:end;gap:10px;border-block:1px solid var(--border);padding:13px 0}.watch-alert-form label{display:grid;min-width:0;gap:5px;color:var(--text-muted);font-size:.72rem;font-weight:800}.watch-alert-form select,.watch-alert-form input{width:100%;min-height:42px;border:1px solid var(--border);border-radius:9px;background:var(--bg-card);color:var(--text);padding:8px 10px;font:inherit;font-size:.92rem}.watch-alert-columns{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;margin-top:14px}.watch-alert-columns>div{display:grid;align-content:start;gap:9px;min-width:0}.watch-alert-subscription{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:9px 12px;border:1px solid var(--border);border-radius:12px;padding:12px}.watch-alert-subscription.paused{background:color-mix(in srgb,var(--text-muted) 5%,var(--bg-card))}.watch-alert-subscription>div:first-child{display:flex;min-width:0;flex-direction:column;gap:4px}.watch-alert-subscription small,.watch-alert-digest small{color:var(--text-muted);overflow-wrap:anywhere}.watch-alert-actions{display:flex;grid-column:1/-1;gap:8px;flex-wrap:wrap}.watch-alert-digest{border:1px solid var(--border);border-radius:12px;padding:0 12px}.watch-alert-digest summary{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:60px;cursor:pointer}.watch-alert-digest summary>span{display:flex;flex-direction:column;gap:3px}.watch-alert-digest summary>span:last-child{align-items:end;color:var(--text-muted);font-size:.76rem;font-weight:750}.watch-alert-digest ol{display:grid;gap:8px;margin:10px 0;padding:0;list-style:none}.watch-alert-digest li{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:4px 8px;border-top:1px solid var(--border);padding-top:9px}.watch-alert-digest li small{grid-column:1/-1}.watch-alert-severity{display:flex;flex-wrap:wrap;gap:5px;border-top:1px solid var(--border);padding-top:10px}.watch-alert-severity span{border-radius:999px;background:var(--brand-50);color:var(--text-muted);padding:4px 7px;font-size:.7rem;font-weight:800}.watch-alert-severity span[data-level="critical"]{background:#fee2e2;color:#991b1b}.watch-alert-severity span[data-level="high"]{background:#ffedd5;color:#9a3412}.watch-alert-proof{display:block;border-top:1px solid var(--border);padding:10px 0}
.watch-item-row{display:grid;grid-template-columns:minmax(0,1fr) 48px;border-bottom:1px solid var(--border);background:transparent}.watch-item-row:hover,.watch-item-row.active{background:color-mix(in srgb,var(--accent) 9%,var(--bg-card))}.watch-item-row.active{box-shadow:inset 4px 0 var(--accent)}.watch-item-main{display:flex;min-width:0;flex-direction:column;align-items:flex-start;gap:5px;border:0;background:transparent;color:var(--text);padding:14px 8px 14px 16px;text-align:left;cursor:pointer}.watch-item-main b,.watch-item-main small{max-width:100%;overflow-wrap:anywhere}.watch-item-main small{color:var(--text-muted)}.watch-favorite{align-self:stretch;border:0;background:transparent;color:#b45309;font-size:1.45rem;cursor:pointer}.watch-favorite:hover,.watch-favorite:focus-visible{background:#fffbeb}.watch-favorite[aria-pressed="true"]{color:#d97706}
.watch-item small,.watch-revision small{color:var(--text-muted)}.watch-domain{color:var(--accent);font-size:.72rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em}
.watch-detail-head{display:flex;justify-content:space-between;gap:16px;align-items:start;padding:20px}.watch-detail-head h3{margin:5px 0;font-size:1.35rem}
.watch-facts{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1px;background:var(--border);border-block:1px solid var(--border)}.watch-facts span{display:flex;min-width:0;flex-direction:column;gap:5px;background:var(--bg-card);padding:12px}.watch-facts code{overflow:hidden;text-overflow:ellipsis}
.watch-tabs{display:flex;gap:2px;overflow-x:auto;padding:12px 16px 0;background:var(--bg-card)}.watch-tab{white-space:nowrap;border:0;border-bottom:3px solid transparent;background:transparent;color:var(--text-muted);padding:10px 13px;font-weight:700;cursor:pointer}.watch-tab.active{border-color:var(--accent);color:var(--accent)}
.watch-pane{padding:18px}.watch-timeline{display:grid;gap:10px}.watch-revision{display:grid;grid-template-columns:46px 1fr;gap:12px;padding:12px;border:1px solid var(--border);border-radius:12px}.watch-revision.tombstone{border-color:#f59e0b;background:#fff8e7}.watch-revision p{margin:4px 0}.watch-revision-no{display:grid;place-items:center;width:40px;height:40px;border-radius:12px;background:var(--brand-50);color:var(--accent);font-weight:800}
.watch-transitions{margin-top:14px;border-top:1px solid var(--border);padding-top:12px}.watch-transitions summary{cursor:pointer;font-weight:700}.watch-transitions p{padding:8px 0;border-bottom:1px solid var(--border)}.watch-danger{margin-top:14px;color:#b42318;border-color:#f5b7b1}
.watch-compare-controls{display:flex;align-items:end;gap:10px;flex-wrap:wrap}.watch-compare-controls label{display:grid;gap:5px}.watch-diff{margin-top:14px}.watch-diff-row{display:grid;grid-template-columns:minmax(110px,.5fr) minmax(0,1fr) 24px minmax(0,1fr);gap:8px;align-items:center;border-top:1px solid var(--border);padding:10px 0}.watch-diff-row pre{white-space:pre-wrap;overflow-wrap:anywhere;margin:0;padding:9px;border-radius:8px;background:var(--bg-card);color:var(--text);font:inherit;font-size:.84rem}
.watch-revise-form{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.watch-revise-form label{display:grid;gap:6px;font-weight:700}.watch-revise-form input,.watch-revise-form textarea{width:100%;border:1px solid var(--border);border-radius:10px;background:var(--bg-card);color:var(--text);padding:10px}.watch-revise-form textarea{min-height:86px;resize:vertical}.watch-span{grid-column:1/-1}.watch-safety{margin-top:14px;padding:12px;border-left:4px solid var(--accent);background:var(--bg-card);font-size:.88rem}
.watch-workflow{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:16px;border:1px solid var(--border);border-radius:13px;background:var(--bg-card);padding:14px}.watch-workflow p{margin:4px 0 0;color:var(--text-muted);font-size:.84rem}.watch-workflow>div:last-child{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px}
.watch-impact-form{display:grid;gap:14px}.watch-impact-common{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.watch-impact-form label{display:grid;gap:6px;color:var(--text);font-size:.82rem;font-weight:750}.watch-impact-form input,.watch-impact-form select,.watch-impact-form textarea{width:100%;min-height:43px;border:1px solid var(--border);border-radius:9px;background:var(--bg-card);color:var(--text);padding:9px 10px;font:inherit}.watch-impact-form textarea{min-height:76px;resize:vertical}.watch-impact-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:11px}.watch-impact-form fieldset{display:grid;min-width:0;gap:9px;margin:0;border:1px solid var(--border);border-radius:12px;background:color-mix(in srgb,var(--accent) 3%,var(--bg-card));padding:12px}.watch-impact-form legend{padding:0 6px;color:var(--text);font-weight:850}.watch-impact-confirm{display:grid;grid-template-columns:minmax(150px,.6fr) minmax(280px,1.4fr) auto;align-items:end;gap:12px;border:1px solid var(--accent);border-radius:12px;background:var(--brand-50);padding:13px}.watch-impact-confirm>div{display:flex;flex-direction:column;gap:4px}.watch-impact-confirm output{color:var(--accent);font-size:1.1rem;font-weight:850}
.watch-impact-assessment{display:grid;gap:13px;border:1px solid var(--border);border-radius:14px;background:var(--bg-card);padding:15px}.watch-impact-assessment.current{border-top:4px solid var(--accent)}.watch-impact-assessment>header,.watch-impact-assessment>footer,.watch-impact-domain-card>header{display:flex;align-items:start;justify-content:space-between;gap:12px}.watch-impact-assessment h4{margin:4px 0 0}.watch-impact-version{color:var(--text-muted);font-size:.75rem;font-weight:750;text-transform:uppercase}.watch-impact-level{display:inline-flex;border-radius:999px;background:#e2e8f0;color:#334155;padding:5px 9px;font-size:.75rem;font-weight:850}.watch-impact-level[data-level="high"],.watch-impact-domain-card[data-level="high"]>header span{background:#ffedd5;color:#9a3412}.watch-impact-level[data-level="critical"],.watch-impact-domain-card[data-level="critical"]>header span{background:#fee2e2;color:#991b1b}.watch-impact-level[data-level="medium"],.watch-impact-domain-card[data-level="medium"]>header span{background:#fef3c7;color:#92400e}.watch-impact-level[data-level="low"],.watch-impact-domain-card[data-level="low"]>header span{background:#dcfce7;color:#166534}.watch-impact-requirements{display:flex;flex-wrap:wrap;gap:6px}.watch-impact-requirements code{border-radius:999px;background:var(--brand-50);color:var(--accent);padding:5px 8px}.watch-impact-domain-card{min-width:0;border:1px solid var(--border);border-radius:11px;padding:11px;overflow-wrap:anywhere}.watch-impact-domain-card>header span{border-radius:999px;background:#e2e8f0;color:#334155;padding:3px 7px;font-size:.7rem;font-weight:850}.watch-impact-domain-card p{margin:9px 0}.watch-impact-domain-card ul{margin:5px 0 8px;padding-left:20px}.watch-impact-domain-card li{margin:3px 0}.watch-impact-assessment>footer{align-items:center;border-top:1px solid var(--border);padding-top:10px;color:var(--text-muted);font-size:.76rem}.watch-impact-new,.watch-impact-archives{margin-top:14px;border:1px solid var(--border);border-radius:12px;padding:12px}.watch-impact-new>summary,.watch-impact-archives>summary{cursor:pointer;font-weight:800}.watch-impact-new[open]>summary,.watch-impact-archives[open]>summary{margin-bottom:13px}
@media(max-width:980px){.watch-impact-confirm{grid-template-columns:1fr 1fr}.watch-impact-confirm button{grid-column:1/-1;width:100%}}
@media(max-width:1100px){.watch-filter-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.watch-selection-head{align-items:stretch;flex-direction:column}.watch-view-actions{display:grid;grid-template-columns:minmax(0,1fr) auto auto}.watch-view-actions label{min-width:0}.watch-view-actions select{min-width:0}}
@media(max-width:1100px){.watch-alert-form{grid-template-columns:repeat(2,minmax(0,1fr))}.watch-alert-form button{width:100%}.watch-alert-columns{grid-template-columns:1fr}}
@media(max-width:800px){.watch-layout{grid-template-columns:1fr}.watch-list{max-height:250px}.watch-facts{grid-template-columns:repeat(2,minmax(0,1fr))}.watch-detail-head{flex-direction:column}.watch-revise-form{grid-template-columns:1fr}.watch-span{grid-column:auto}.watch-diff-row{grid-template-columns:1fr}.watch-diff-row>span{transform:rotate(90deg);justify-self:start}}
@media(max-width:620px){.watch-selection{padding:12px}.watch-filter-grid,.watch-view-actions{grid-template-columns:1fr}.watch-filter-footer{align-items:stretch;flex-direction:column}.watch-filter-footer>div{display:grid;grid-template-columns:1fr}.watch-filter-footer button,.watch-view-actions button{width:100%}}
@media(max-width:700px){.watch-alerts{padding:12px}.watch-alerts>header,.watch-alert-digest summary{align-items:stretch;flex-direction:column}.watch-alert-form{grid-template-columns:1fr}.watch-alert-subscription{grid-template-columns:1fr}.watch-alert-state{justify-self:start}.watch-alert-actions{grid-column:auto;display:grid}.watch-alert-actions button{width:100%}.watch-alert-digest summary{justify-content:center;padding-block:10px}.watch-alert-digest summary>span:last-child{align-items:start}}
@media(max-width:800px){.watch-workflow{align-items:stretch;flex-direction:column}.watch-workflow>div:last-child{justify-content:stretch}.watch-workflow button{flex:1}.watch-impact-grid,.watch-impact-common,.watch-impact-confirm{grid-template-columns:1fr}.watch-impact-confirm button{grid-column:auto}.watch-impact-assessment>footer{align-items:flex-start;flex-direction:column}}
@media(max-width:420px){.watch-pane{padding:12px}.watch-detail-head{padding:14px}.watch-facts{grid-template-columns:1fr}.watch-tabs{padding-inline:8px}.watch-diff-row{font-size:.84rem}.watch-impact-form fieldset,.watch-impact-assessment{padding:10px}.watch-workflow>div:last-child{display:grid}.watch-workflow button{width:100%}}
@media(pointer:coarse){.watch-impact-form input,.watch-impact-form select,.watch-impact-form textarea,.watch-impact-form button,.watch-workflow button,.watch-filter-grid input,.watch-filter-grid select,.watch-view-actions select,.watch-view-actions button,.watch-filter-footer button,.watch-alert-form input,.watch-alert-form select,.watch-alert-form button,.watch-alert-actions button,.watch-favorite,.watch-item-main{min-height:44px;font-size:16px}}

/* CB054 — registre transparent des sources de veille et des marchés publics. */
/* CB-129 — coque éditoriale commune aux cinq routes historiques. */
.watch-shell{position:relative;overflow:hidden;margin:0 0 20px;border:1px solid color-mix(in srgb,var(--accent) 28%,var(--border));border-radius:20px;background:radial-gradient(circle at 92% 8%,color-mix(in srgb,var(--accent) 14%,transparent),transparent 34%),linear-gradient(135deg,color-mix(in srgb,var(--accent) 7%,var(--bg-card)),var(--bg-card) 58%);box-shadow:0 10px 32px rgba(15,23,42,.055)}
.watch-shell:before{position:absolute;inset:0 auto 0 0;width:5px;background:var(--accent);content:""}
.watch-shell-head{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;padding:24px 26px 20px 30px}.watch-shell-copy{min-width:0;max-width:850px}.watch-shell-kicker{display:inline-flex;align-items:center;gap:7px;color:var(--accent);font-size:.71rem;font-weight:900;letter-spacing:.11em;text-transform:uppercase}.watch-shell-kicker:before{width:8px;height:8px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 6px color-mix(in srgb,var(--accent) 12%,transparent);content:""}.watch-shell-title{display:flex;align-items:center;gap:11px;flex-wrap:wrap;margin:8px 0 7px}.watch-shell-title h2{margin:0;font-size:clamp(1.7rem,2.8vw,2.55rem);line-height:1.08}.watch-shell-title>span,.watch-shell-status{display:inline-flex;align-items:center;min-height:29px;border:1px solid color-mix(in srgb,var(--accent) 25%,var(--border));border-radius:999px;background:color-mix(in srgb,var(--accent) 8%,var(--bg-card));color:var(--accent);padding:5px 10px;font-size:.7rem;font-weight:850;white-space:nowrap}.watch-shell-copy p{max-width:760px;margin:0;color:var(--text-muted);line-height:1.5}.watch-shell-actions{display:flex;max-width:540px;flex:0 0 auto;align-items:center;justify-content:flex-end;gap:8px;flex-wrap:wrap}.watch-shell-actions .btn,.watch-shell-actions .btn-ghost{min-height:44px}
.watch-shell-nav{border-top:1px solid color-mix(in srgb,var(--accent) 16%,var(--border));background:color-mix(in srgb,var(--bg-card) 88%,transparent)}.watch-section-tabs{display:flex;gap:7px;overflow-x:auto;margin:0;padding:12px 22px 11px;scrollbar-width:thin}.watch-section-tab{display:inline-flex;flex:0 0 auto;align-items:center;gap:8px;min-height:44px;border:1px solid transparent;border-radius:12px;background:transparent;color:var(--text-muted);padding:8px 13px;font-weight:780;white-space:nowrap;cursor:pointer}.watch-section-tab>span{display:grid;width:25px;height:25px;place-items:center;border-radius:8px;background:color-mix(in srgb,var(--text-muted) 9%,transparent);font-size:.65rem;font-weight:900}.watch-section-tab:hover,.watch-section-tab:focus-visible{border-color:var(--border);background:var(--bg-card);color:var(--text)}.watch-section-tab.active{border-color:var(--accent);background:var(--accent);color:#fff;box-shadow:0 6px 16px color-mix(in srgb,var(--accent) 20%,transparent)}.watch-section-tab.active>span{background:rgba(255,255,255,.2)}
.watch-shell-guard{display:flex;align-items:center;gap:18px;overflow-x:auto;border-top:1px solid color-mix(in srgb,var(--accent) 12%,var(--border));padding:9px 26px 10px 30px;color:var(--text-muted);font-size:.7rem;font-weight:760;white-space:nowrap}.watch-shell-guard>span:not(.watch-shell-status):before{display:inline-block;width:6px;height:6px;margin-right:7px;border-radius:50%;background:#22c55e;vertical-align:1px;content:""}.watch-shell-guard .watch-shell-status{margin-left:auto;min-height:26px}
@media(max-width:900px){.watch-shell-head{flex-direction:column;gap:16px}.watch-shell-actions{width:100%;max-width:none;justify-content:flex-start}.watch-shell-guard .watch-shell-status{margin-left:0}.watch-shell-guard{flex-wrap:wrap;white-space:normal}}
@media(max-width:620px){.watch-shell{border-radius:15px}.watch-shell-head{padding:19px 16px 16px 20px}.watch-shell-title{align-items:flex-start;flex-direction:column}.watch-shell-title h2{font-size:1.72rem}.watch-shell-actions{display:grid;grid-template-columns:1fr}.watch-shell-actions button{width:100%}.watch-section-tabs{padding:9px 12px}.watch-section-tab{border-color:var(--border);background:var(--bg-card);padding-inline:11px}.watch-shell-guard{display:grid;grid-template-columns:1fr;padding:10px 16px 12px 20px;gap:7px}.watch-shell-guard .watch-shell-status{justify-self:start}}
@media(pointer:coarse){.watch-section-tab,.watch-shell-actions button{min-height:44px;font-size:16px}}
.watch-source-metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin-bottom:18px}
.watch-source-metrics>div{min-width:0;border:1px solid var(--border);border-radius:14px;background:var(--bg-card);padding:15px}
.watch-source-metrics b{display:block;margin-bottom:4px;font-size:1.45rem;color:var(--text)}
.watch-source-section{margin:0 0 18px;border:1px solid var(--border);border-radius:16px;background:var(--bg-card);padding:18px}
.watch-source-section>header{display:flex;align-items:start;justify-content:space-between;gap:14px;margin-bottom:14px}
.watch-source-section h3{margin:0 0 4px}.watch-source-section p{margin:0}
.watch-coverage-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:9px}
.watch-coverage-item{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:48px;border:1px solid var(--border);border-radius:11px;padding:9px 11px;background:var(--bg-card)}
.watch-coverage-item b{display:grid;place-items:center;min-width:26px;min-height:26px;border-radius:999px;background:var(--brand-50);color:var(--accent);padding:3px 7px}
.watch-source-templates,.watch-source-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}
.watch-source-template,.watch-source-card,.watch-source-alert{border:1px solid var(--border);border-radius:13px;background:var(--bg-card);padding:14px}
.watch-source-template{display:flex;align-items:center;justify-content:space-between;gap:12px}.watch-source-template p{margin-top:5px}
.watch-source-added{display:inline-flex;align-items:center;min-height:30px;border-radius:999px;background:#dcfce7;color:#166534;padding:5px 10px;font-size:.78rem;font-weight:800}
.watch-source-card{display:flex;min-width:0;flex-direction:column;gap:10px;border-top:4px solid var(--border)}
.watch-source-card[data-health="healthy"]{border-top-color:#16a34a}.watch-source-card[data-health="silent"],.watch-source-card[data-health="never_collected"]{border-top-color:#d97706}.watch-source-card[data-health="failing"]{border-top-color:#dc2626}.watch-source-card[data-health="paused"],.watch-source-card[data-health="retired"]{border-top-color:#64748b}
.watch-source-card h4{margin:0;font-size:1.02rem}.watch-source-card a{overflow-wrap:anywhere;color:var(--accent)}
.watch-source-categories{display:flex;flex-wrap:wrap;gap:5px}.watch-source-categories span{border-radius:999px;background:var(--brand-50);color:var(--accent);padding:4px 7px;font-size:.71rem;font-weight:750}
.watch-source-facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:7px}.watch-source-facts span{display:flex;min-width:0;flex-direction:column;gap:2px;padding:8px;border-radius:8px;background:var(--bg-card);font-size:.78rem;overflow-wrap:anywhere}.watch-source-facts b{font-size:.68rem;text-transform:uppercase;color:var(--text-muted)}
.watch-source-card>footer{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:auto;padding-top:3px}.watch-health{font-weight:800;font-size:.8rem}
.watch-source-alert{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:center;margin-top:9px;border-left:4px solid #dc2626}.watch-source-alert p{margin-top:4px}.watch-source-alert small{color:var(--text-muted)}
@media(max-width:980px){.watch-source-metrics,.watch-coverage-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.watch-source-templates,.watch-source-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:650px){.watch-source-metrics,.watch-coverage-grid,.watch-source-templates,.watch-source-grid{grid-template-columns:1fr}.watch-source-section{padding:13px}.watch-source-section>header{flex-direction:column}.watch-source-section>header>.btn-ghost{width:100%}.watch-source-alert{grid-template-columns:1fr}.watch-source-alert button{width:100%}.watch-source-template{align-items:flex-start}.watch-source-template button{flex:0 0 auto}}

/* CB055 — opportunités marchés : vues courtes, décision humaine explicite. */
.market-head-actions,.market-actions,.market-saved-searches,.market-score-controls{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.market-search-form{display:grid;grid-template-columns:repeat(5,minmax(0,1fr)) auto auto;gap:10px;align-items:end;margin:0 0 12px;padding:14px;border:1px solid var(--border);border-radius:14px;background:var(--bg-card)}
.market-search-form label{display:flex;min-width:0;flex-direction:column;gap:5px;color:var(--text-muted);font-size:.76rem;font-weight:750}.market-search-form input,.market-search-form select,.market-score-controls select{width:100%;min-height:44px;border:1px solid var(--border);border-radius:9px;background:var(--bg-card);color:var(--text);padding:8px 10px;font:inherit;font-size:1rem}
.market-summary{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:10px;color:var(--text-muted);font-size:.82rem}.market-summary span{display:flex;gap:4px;align-items:baseline}.market-summary b{color:var(--text);font-size:1.12rem}.market-summary code{margin-left:auto}
.market-saved-searches{margin-bottom:12px}.market-layout{display:grid;grid-template-columns:minmax(270px,360px) minmax(0,1fr);gap:16px;align-items:start}.market-results{display:flex;max-height:660px;flex-direction:column;gap:8px;overflow:auto}.market-result{display:flex;min-height:96px;flex-direction:column;gap:5px;text-align:left;border:1px solid var(--border);border-radius:12px;background:var(--bg-card);color:var(--text);padding:13px;cursor:pointer}.market-result:hover,.market-result.active{border-color:var(--accent);box-shadow:0 0 0 2px color-mix(in srgb,var(--accent) 12%,transparent)}.market-result small{color:var(--text-muted)}
.market-status{display:inline-flex;width:max-content;border-radius:999px;background:var(--brand-50);color:var(--accent);padding:4px 8px;font-size:.7rem;font-weight:800;text-transform:uppercase}.market-status[data-status="go"],.market-status[data-status="won"]{background:#dcfce7;color:#166534}.market-status[data-status="no_go"],.market-status[data-status="lost"]{background:#fee2e2;color:#991b1b}.market-status[data-status="preparation"],.market-status[data-status="submitted"]{background:#fef3c7;color:#92400e}.market-status[data-status="archived"]{background:#e2e8f0;color:#475569}
.market-detail,.market-detail-card{min-width:0}.market-detail-card{border:1px solid var(--border);border-radius:14px;background:var(--bg-card);overflow:hidden}.market-detail-head{display:flex;align-items:start;justify-content:space-between;gap:16px;padding:17px}.market-detail-head h3{margin:7px 0 4px}.market-detail-head p{margin:0}.market-facts{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1px;background:var(--border)}.market-facts span{display:flex;min-width:0;flex-direction:column;gap:4px;background:var(--bg-card);padding:12px;overflow-wrap:anywhere}.market-facts b{font-size:.68rem;text-transform:uppercase;color:var(--text-muted)}
.market-tabs{display:flex;gap:2px;overflow-x:auto;padding:12px 16px 0;border-top:1px solid var(--border)}.market-tab{min-height:44px;white-space:nowrap;border:0;border-bottom:3px solid transparent;background:transparent;color:var(--text-muted);padding:9px 12px;font-weight:750;cursor:pointer}.market-tab.active{border-color:var(--accent);color:var(--accent)}.market-pane{padding:15px}.market-publication{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:12px;padding:11px 0;border-bottom:1px solid var(--border)}.market-publication:last-child{border-bottom:0}.market-publication p{margin:3px 0}.market-publication small{color:var(--text-muted)}
.market-alert-strip{margin-bottom:12px;border:1px solid #f59e0b;border-radius:13px;background:#fffbeb;padding:13px}.market-alert-strip h3{margin:0 0 8px}.market-alert-strip article{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:10px;padding:8px 0;border-top:1px solid #fde68a}.market-alert-strip p{margin:3px 0}.market-alert-strip small{color:#92400e}.market-score-controls select{min-width:210px;flex:1}.market-score-result{margin-top:12px}.market-score-total{display:flex;align-items:baseline;justify-content:space-between;padding:12px;border-radius:10px;background:var(--brand-50)}.market-score-total b{font-size:1.55rem;color:var(--accent)}.market-score-row{display:grid;grid-template-columns:minmax(100px,160px) auto minmax(0,1fr);gap:10px;align-items:center;padding:9px 3px;border-bottom:1px solid var(--border)}.market-score-row small{color:var(--text-muted)}
@media(max-width:1100px){.market-search-form{grid-template-columns:repeat(3,minmax(0,1fr))}.market-facts{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:800px){.market-layout{grid-template-columns:1fr}.market-results{max-height:260px}.market-detail-head{flex-direction:column}.market-actions{width:100%}.market-actions button{flex:1}.market-search-form{grid-template-columns:repeat(2,minmax(0,1fr))}.market-score-row{grid-template-columns:1fr auto}.market-score-row small{grid-column:1/-1}}
@media(max-width:520px){.market-head-actions,.market-search-form{display:grid;grid-template-columns:1fr}.market-head-actions button,.market-search-form button{width:100%}.market-summary code{width:100%;margin-left:0}.market-facts{grid-template-columns:1fr}.market-publication,.market-alert-strip article{grid-template-columns:1fr}.market-publication a,.market-alert-strip button{width:100%}.market-pane{padding:12px}.market-score-controls{align-items:stretch;flex-direction:column}.market-score-controls select,.market-score-controls button{width:100%}}
@media(pointer:coarse){.market-result,.market-tab,.market-actions button,.market-score-controls button,.market-alert-strip button{min-height:44px}}

/* CB077 — cinq projections cohérentes, REX et indicateurs recalculables. */
.market-dashboard{margin:0 0 12px;border:1px solid var(--border);border-radius:14px;background:var(--bg-card);padding:13px}.market-dashboard>header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.market-dashboard>header div{display:flex;flex-direction:column;gap:3px}.market-dashboard>header span{color:var(--text-muted);font-size:.78rem}.market-dashboard>div{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:8px;margin-top:11px}.market-dashboard>div>span{display:flex;min-width:0;min-height:88px;flex-direction:column;gap:3px;border:1px solid var(--border);border-radius:10px;background:color-mix(in srgb,var(--accent) 4%,var(--bg-card));padding:10px}.market-dashboard small{color:var(--text-muted);font-weight:800;text-transform:uppercase}.market-dashboard span b{font-size:1.3rem}.market-dashboard em{margin-top:auto;color:var(--text-muted);font-size:.69rem;font-style:normal;overflow-wrap:anywhere}.market-dashboard details{margin-top:10px;border-top:1px solid var(--border);padding-top:9px}.market-dashboard summary{cursor:pointer;font-weight:800}.market-dashboard details p{margin:7px 0;color:var(--text-muted);font-size:.78rem}.market-dashboard details p b{color:var(--text)}
.market-view-tabs{display:flex;gap:2px;overflow-x:auto;margin-bottom:12px;border-bottom:1px solid var(--border)}.market-view-tabs button{flex:0 0 auto;min-height:44px;border:0;border-bottom:3px solid transparent;background:transparent;color:var(--text-muted);padding:9px 16px;font:inherit;font-weight:800;cursor:pointer}.market-view-tabs button.active{border-color:var(--accent);color:var(--accent)}.market-projection{min-width:0}.market-layout:not(.market-view-list){grid-template-columns:minmax(0,1.15fr) minmax(340px,.85fr)}
.market-kanban{display:flex;gap:10px;max-width:100%;overflow-x:auto;padding:1px 1px 9px}.market-kanban>section{display:flex;width:270px;max-height:660px;flex:0 0 270px;flex-direction:column;gap:8px;overflow-y:auto;border:1px solid var(--border);border-radius:12px;background:color-mix(in srgb,var(--accent) 3%,var(--bg-card));padding:10px}.market-kanban>section>header,.market-calendar>section>header,.market-workload>section>header{display:flex;align-items:center;justify-content:space-between;gap:8px;position:sticky;top:0;z-index:1;background:inherit;padding:2px}.market-kanban>section>header span,.market-calendar>section>header span{display:grid;min-width:28px;height:28px;place-items:center;border-radius:999px;background:var(--brand-50);color:var(--accent);font-weight:850}
.market-calendar,.market-workload{display:grid;max-height:660px;gap:9px;overflow:auto}.market-calendar>section,.market-workload>section{display:grid;grid-template-columns:170px repeat(auto-fit,minmax(230px,1fr));gap:8px;align-items:start;border:1px solid var(--border);border-radius:12px;background:var(--bg-card);padding:10px}.market-calendar>section>header,.market-workload>section>header{align-items:flex-start;flex-direction:column}.market-calendar .market-result,.market-workload .market-result{min-height:84px}
.market-map-wrap{display:grid;gap:12px}.market-map{position:relative;min-height:380px;border:1px solid var(--border);border-radius:14px;background:linear-gradient(90deg,transparent 49.8%,var(--border) 50%,transparent 50.2%),linear-gradient(transparent 49.8%,var(--border) 50%,transparent 50.2%),radial-gradient(circle at 25% 45%,color-mix(in srgb,var(--accent) 15%,transparent),transparent 22%),color-mix(in srgb,var(--accent) 3%,var(--bg-card));overflow:hidden}.market-map-point{position:absolute;width:24px;height:24px;transform:translate(-50%,-50%);border:3px solid var(--bg-card);border-radius:999px;background:var(--accent);box-shadow:0 2px 7px #0004;cursor:pointer}.market-map-label{position:absolute;left:10px;bottom:10px;border-radius:8px;background:color-mix(in srgb,var(--bg-card) 92%,transparent);padding:7px 9px;color:var(--text-muted);font-size:.72rem}.market-unmapped{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:8px}.market-unmapped h3{grid-column:1/-1;margin:0}.market-workload>section>header span{color:var(--text-muted);font-size:.78rem}.market-workload>section{grid-template-columns:190px repeat(auto-fit,minmax(230px,1fr))}
.market-rex-modal .modal{width:min(680px,calc(100vw - 24px));max-height:92vh;overflow:auto}.market-rex-modal fieldset{display:grid;gap:10px;margin:0;border:1px solid var(--border);border-radius:12px;padding:12px}.market-rex-modal legend{padding:0 6px;font-weight:850}.market-rex-check{display:flex;align-items:center;gap:9px;color:var(--text);font-weight:750}.market-rex-check input{width:20px;height:20px}.market-rex-card{display:grid;gap:10px;border:1px solid var(--border);border-radius:12px;padding:13px}.market-rex-card header{display:flex;align-items:center;justify-content:space-between;gap:10px}.market-rex-card dl{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px;margin:0;background:var(--border)}.market-rex-card dl>div{background:var(--bg-card);padding:10px}.market-rex-card dt{color:var(--text-muted);font-size:.7rem;font-weight:800;text-transform:uppercase}.market-rex-card dd{margin:4px 0 0;overflow-wrap:anywhere}.market-rex-card code{color:var(--text-muted);font-size:.7rem}
@media(max-width:1100px){.market-dashboard>div{grid-template-columns:repeat(3,minmax(0,1fr))}.market-layout:not(.market-view-list){grid-template-columns:1fr}.market-projection{max-height:520px;overflow:auto}}
@media(max-width:700px){.market-dashboard>header{flex-direction:column}.market-dashboard>div{grid-template-columns:repeat(2,minmax(0,1fr))}.market-calendar>section,.market-workload>section{grid-template-columns:1fr}.market-calendar>section>header,.market-workload>section>header{position:static;flex-direction:row}.market-map{min-height:300px}.market-rex-card dl{grid-template-columns:1fr}.market-projection{max-height:420px}}
@media(max-width:440px){.market-dashboard>div{grid-template-columns:1fr}.market-dashboard>div>span{min-height:72px}.market-map{min-height:260px}}
@media(pointer:coarse){.market-view-tabs button,.market-map-point{min-width:44px;min-height:44px}.market-rex-modal input,.market-rex-modal textarea,.market-rex-modal button{min-height:44px;font-size:16px}}

/* CB056 — couture explicite marché → dossier commercial existant. */
.market-crm-modal .modal{width:min(760px,calc(100vw - 28px));max-height:min(88vh,880px);overflow:auto}.market-crm-modal fieldset{min-width:0;margin:0;padding:12px;border:1px solid var(--border);border-radius:11px}.market-crm-modal legend{padding:0 6px;color:var(--text);font-weight:800}.market-crm-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.market-crm-confirm{display:flex;align-items:flex-start;gap:10px;border:1px solid var(--accent);border-radius:11px;background:var(--brand-50);padding:12px;color:var(--text);font-weight:750;line-height:1.4}.market-crm-confirm input{width:20px;height:20px;flex:0 0 auto;margin:0}.market-crm-summary{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px;border:1px solid var(--border);border-radius:11px;background:var(--border);overflow:hidden}.market-crm-summary div{display:flex;min-width:0;flex-direction:column;gap:4px;background:var(--bg-card);padding:12px}.market-crm-summary b{font-size:.68rem;text-transform:uppercase;color:var(--text-muted)}.market-crm-summary span{overflow-wrap:anywhere}.market-crm-task-list{display:flex;flex-direction:column;gap:7px;margin-top:12px}.market-crm-task-list>div{display:grid;grid-template-columns:30px minmax(0,1fr) auto;align-items:center;gap:9px;border:1px solid var(--border);border-radius:10px;padding:9px}.market-crm-task-list>div>span{display:grid;width:28px;height:28px;place-items:center;border-radius:8px;background:var(--brand-50);color:var(--accent);font-weight:850}.market-crm-task-list small{color:var(--text-muted)}
.market-origin-panel .view-head{margin-bottom:10px}.market-origin-panel .view-head h3{margin:0}.market-origin-panel .view-head p{margin:3px 0 0}.market-origin-list{display:flex;flex-direction:column;gap:8px}.market-origin-list article{display:flex;align-items:center;justify-content:space-between;gap:16px;border:1px solid var(--border);border-radius:11px;background:var(--bg-card);padding:12px}.market-origin-list article>div:first-child{display:flex;min-width:0;flex-direction:column;gap:3px}.market-origin-list small{color:var(--accent);font-weight:800;text-transform:uppercase}.market-origin-list strong{overflow-wrap:anywhere}.market-origin-list article span{color:var(--text-muted);font-size:.8rem}.market-origin-metrics{display:flex;flex:0 0 auto;align-items:center;gap:10px}
@media(max-width:600px){.market-crm-grid,.market-crm-summary{grid-template-columns:1fr}.market-crm-modal .modal{width:calc(100vw - 16px);max-height:94vh;padding:16px}.market-crm-task-list>div{grid-template-columns:30px minmax(0,1fr)}.market-crm-task-list small{grid-column:2}.market-origin-list article{align-items:stretch;flex-direction:column}.market-origin-metrics{flex-wrap:wrap}}
@media(pointer:coarse){.market-crm-modal input,.market-crm-modal select,.market-crm-modal textarea,.market-crm-modal button{min-height:44px;font-size:16px}}

/* CB059 — registres constructeurs mondiaux et technologies VE gouvernés. */
.watch-no-auto{display:inline-flex;align-items:center;min-height:36px;border:1px solid #16a34a;border-radius:999px;background:#dcfce7;color:#166534;padding:7px 12px;font-size:.78rem;font-weight:850;white-space:nowrap}
.watch-global-tabs{display:flex;gap:0;overflow-x:auto;margin:0 0 16px;border-bottom:1px solid var(--border);scrollbar-width:thin}.watch-global-tab{flex:0 0 auto;min-height:46px;border:0;border-bottom:3px solid transparent;background:transparent;color:var(--text-muted);padding:10px 18px;font-weight:800;cursor:pointer}.watch-global-tab.active{border-color:var(--accent);color:var(--accent)}
.watch-global-pane{min-width:0;border:1px solid var(--border);border-radius:16px;background:var(--bg-card);padding:17px}.watch-global-toolbar{display:flex;align-items:start;justify-content:space-between;gap:14px;margin-bottom:14px}.watch-global-toolbar h3{margin:0 0 4px}.watch-global-toolbar p{margin:0;color:var(--text-muted);font-size:.85rem}
.watch-coverage-item{min-width:0;flex-wrap:wrap}.watch-coverage-item>span{min-width:0;font-weight:750}.watch-coverage-item>small{width:100%;color:var(--text-muted);font-size:.7rem}.watch-coverage-item.missing{border-color:#f59e0b;background:#fffbeb}.watch-coverage-item.missing b{background:#fef3c7;color:#92400e}.watch-coverage-item.covered{border-color:#86efac}.watch-tech-grid{grid-template-columns:repeat(5,minmax(0,1fr))}
.watch-global-search{display:grid;max-width:620px;gap:6px;margin:16px 0 12px;color:var(--text-muted);font-size:.76rem;font-weight:800}.watch-global-search input{width:100%;min-height:44px;border:1px solid var(--border);border-radius:10px;background:var(--bg-card);color:var(--text);padding:9px 12px;font:inherit;font-size:1rem}
.watch-global-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:11px;max-height:410px;overflow:auto;padding:2px}.watch-global-card{display:flex;min-width:0;min-height:132px;flex-direction:column;align-items:flex-start;gap:6px;border:1px solid var(--border);border-radius:13px;background:var(--bg-card);color:var(--text);padding:14px;text-align:left;cursor:pointer}.watch-global-card:hover,.watch-global-card:focus-visible{border-color:var(--accent);box-shadow:0 0 0 2px color-mix(in srgb,var(--accent) 12%,transparent)}.watch-global-card b{font-size:1.02rem}.watch-global-card small{margin-top:auto;color:var(--text-muted)}
.watch-global-events{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:11px;max-height:520px;overflow:auto}.watch-global-event{display:flex;min-width:0;flex-direction:column;gap:8px;border:1px solid var(--border);border-radius:13px;background:var(--bg-card);padding:14px}.watch-global-event header{display:flex;align-items:start;justify-content:space-between;gap:12px}.watch-global-event h4{margin:4px 0 0}.watch-global-event p{margin:0}.watch-global-event small{color:var(--text-muted)}.watch-global-event button{align-self:flex-start;margin-top:auto}.watch-status-pill{flex:0 0 auto;border-radius:999px;background:var(--brand-50);color:var(--accent);padding:5px 8px;font-size:.72rem;font-weight:850}
.watch-global-modal{width:min(980px,calc(100vw - 28px));max-height:min(90vh,900px);overflow:auto}.watch-global-modal-head{display:flex;align-items:start;justify-content:space-between;gap:14px}.watch-global-modal-head h3{margin:4px 0}.watch-global-modal-head p{margin:0;color:var(--text-muted)}.watch-global-detail-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px;margin:14px 0;border:1px solid var(--border);border-radius:11px;background:var(--border);overflow:hidden}.watch-global-detail-grid>div{display:flex;min-width:0;flex-direction:column;gap:4px;background:var(--bg-card);padding:11px;overflow-wrap:anywhere}.watch-global-detail-grid b{font-size:.7rem;text-transform:uppercase;color:var(--text-muted)}.watch-global-detail-grid a{color:var(--accent)}
.watch-global-payload{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.watch-global-payload section{min-width:0;border:1px solid var(--border);border-radius:10px;padding:10px}.watch-global-payload h4{margin:0 0 8px}.watch-global-payload pre,.watch-global-history pre{max-height:260px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;margin:0;border-radius:8px;background:color-mix(in srgb,var(--accent) 4%,var(--bg-card));padding:10px;color:var(--text);font-size:.78rem}.watch-global-history{margin-top:13px}.watch-revision-strip,.watch-compare-inline{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:10px}.watch-revision-chip{display:flex;min-height:42px;flex-direction:column;border:1px solid var(--border);border-radius:9px;background:var(--bg-card);color:var(--text);padding:6px 10px;font-weight:800;cursor:pointer}.watch-revision-chip small{color:var(--text-muted);font-size:.66rem}.watch-compare-inline select{min-height:42px;border:1px solid var(--border);border-radius:9px;background:var(--bg-card);color:var(--text);padding:7px 9px}
@media(max-width:1050px){.watch-tech-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.watch-global-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:700px){.watch-view-head{align-items:flex-start}.watch-no-auto{white-space:normal}.watch-global-pane{padding:12px}.watch-global-toolbar{align-items:stretch;flex-direction:column}.watch-global-toolbar button{width:100%}.watch-tech-grid,.watch-global-grid,.watch-global-events,.watch-global-payload,.watch-global-detail-grid{grid-template-columns:1fr}.watch-global-grid,.watch-global-events{max-height:none}.watch-global-modal{width:calc(100vw - 16px);max-height:94vh;padding:15px}.watch-global-modal-head{flex-direction:column}.watch-global-modal-head button{width:100%}.watch-diff-row{grid-template-columns:1fr}}
@media(pointer:coarse){.watch-global-tab,.watch-global-card,.watch-global-search input,.watch-global-event button,.watch-revision-chip,.watch-compare-inline select,.watch-compare-inline button{min-height:44px;font-size:16px}}
.watch-coverage-policy{display:flex;align-items:flex-start;justify-content:space-between;gap:18px}.watch-coverage-policy h3{margin:4px 0 7px}.watch-coverage-policy p{max-width:850px;margin:0;color:var(--text-muted);overflow-wrap:anywhere}.watch-coverage-actions{display:flex;flex:0 0 auto;gap:8px}.watch-coverage-neutrality{display:grid;grid-template-columns:auto minmax(0,1fr);gap:9px;margin:14px 0;border:1px solid #67e8f9;border-radius:11px;background:#ecfeff;color:#164e63;padding:11px 13px}.watch-coverage-policy-facts{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:9px;margin-bottom:14px}.watch-coverage-policy-facts>span{display:flex;min-width:0;min-height:76px;flex-direction:column;justify-content:center;gap:4px;border:1px solid var(--border);border-radius:11px;background:color-mix(in srgb,var(--accent) 4%,var(--bg-card));padding:11px}.watch-coverage-policy-facts b{font-size:1rem;overflow-wrap:anywhere}.watch-coverage-policy-facts small{color:var(--text-muted)}
.watch-coverage-dimension-tabs{display:flex;gap:0;overflow-x:auto;border-bottom:1px solid var(--border)}.watch-coverage-dimension-tab{flex:0 0 auto;min-height:44px;border:0;border-bottom:3px solid transparent;background:transparent;color:var(--text-muted);padding:9px 14px;font-weight:800;cursor:pointer}.watch-coverage-dimension-tab.active{border-color:var(--accent);color:var(--accent)}.watch-coverage-dimensions{min-height:285px;border:1px solid var(--border);border-top:0;border-radius:0 0 12px 12px;padding:13px}.watch-coverage-dimensions section>header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}.watch-coverage-dimensions h4,.watch-coverage-snapshots h4{margin:0}.watch-coverage-dimensions section>header span{color:var(--text-muted);font-size:.8rem}.watch-coverage-table-wrap{max-width:100%;overflow-x:auto}.watch-coverage-table-wrap table{width:100%;border-collapse:collapse}.watch-coverage-table-wrap th,.watch-coverage-table-wrap td{border-bottom:1px solid var(--border);padding:9px 10px;text-align:left}.watch-coverage-table-wrap td{white-space:nowrap}.watch-coverage-state{display:inline-flex;border-radius:999px;padding:4px 8px;font-size:.72rem;font-weight:850}.watch-coverage-state.covered{background:#dcfce7;color:#166534}.watch-coverage-state.missing{background:#fef3c7;color:#92400e}.watch-coverage-two-tables{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.watch-coverage-snapshots{margin-top:13px}.watch-coverage-snapshots>div{display:flex;gap:8px;overflow-x:auto;margin-top:8px;padding-bottom:2px}.watch-coverage-snapshot{display:flex;min-width:165px;flex:0 0 auto;flex-direction:column;gap:3px;border:1px solid var(--border);border-radius:9px;background:var(--bg-card);padding:8px 10px}.watch-coverage-snapshot small{color:var(--text-muted)}
@media(max-width:900px){.watch-coverage-policy{flex-direction:column}.watch-coverage-actions{width:100%}.watch-coverage-actions button{flex:1}.watch-coverage-policy-facts{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:620px){.watch-coverage-neutrality{grid-template-columns:1fr}.watch-coverage-policy-facts,.watch-coverage-two-tables{grid-template-columns:1fr}.watch-coverage-actions{display:grid}.watch-coverage-dimensions{min-height:0;padding:10px}.watch-coverage-dimensions section>header{align-items:flex-start;flex-direction:column}.watch-coverage-table-wrap th,.watch-coverage-table-wrap td{padding:9px 7px;font-size:.84rem}}
@media(pointer:coarse){.watch-coverage-actions button,.watch-coverage-dimension-tab{min-height:44px;font-size:16px}}

/* CB-128 — fil d'actualités de type agrégateur, sans reprendre la marque ni
   les mécanismes opaques d'un service tiers. Source, date et droits restent
   visibles sur chaque carte. */
.watch-news-head{align-items:flex-start}.watch-news-head h2{margin:5px 0 7px;font-size:clamp(1.65rem,2.7vw,2.45rem)}.watch-news-head p{max-width:760px;margin:0;color:var(--text-muted)}
.watch-news-kicker{color:var(--accent);font-size:.74rem;font-weight:900;letter-spacing:.09em;text-transform:uppercase}.watch-news-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;flex-wrap:wrap}
.watch-news-toolbar{display:grid;grid-template-columns:minmax(260px,420px) minmax(0,1fr);align-items:center;gap:14px;margin-bottom:18px;border:1px solid var(--border);border-radius:15px;background:var(--bg-card);padding:12px}
.watch-news-search input{width:100%;min-height:46px;border:1px solid var(--border);border-radius:999px;background:color-mix(in srgb,var(--accent) 3%,var(--bg-card));color:var(--text);padding:10px 17px;font:inherit}
.watch-news-topics{display:flex;gap:7px;overflow-x:auto;padding:2px;scrollbar-width:thin}.watch-news-topics button{flex:0 0 auto;min-height:40px;border:1px solid var(--border);border-radius:999px;background:var(--bg-card);color:var(--text-muted);padding:7px 12px;font-weight:800;white-space:nowrap;cursor:pointer}.watch-news-topics button.active{border-color:var(--accent);background:var(--accent);color:#fff}
.watch-news-layout{display:grid;grid-template-columns:minmax(0,1fr) minmax(280px,350px);gap:18px;align-items:start}.watch-news-feed,.watch-news-sources{min-width:0;border:1px solid var(--border);border-radius:17px;background:var(--bg-card);padding:17px}.watch-news-feed>header,.watch-news-sources>header{display:flex;align-items:start;justify-content:space-between;gap:12px;margin-bottom:14px}.watch-news-feed>header h3,.watch-news-feed>header p,.watch-news-sources>header h3,.watch-news-sources>header p{margin:0}.watch-news-feed>header p,.watch-news-sources>header p{margin-top:3px;color:var(--text-muted);font-size:.8rem}.watch-news-feed>header>span{border-radius:999px;background:#dcfce7;color:#166534;padding:5px 9px;font-size:.7rem;font-weight:850;white-space:nowrap}
.watch-news-card{display:flex;min-width:0;min-height:225px;flex-direction:column;gap:9px;border:1px solid var(--border);border-radius:14px;background:var(--bg-card);padding:15px;box-shadow:0 5px 20px rgba(15,23,42,.035)}.watch-news-card.featured{min-height:265px;margin-bottom:13px;border-color:color-mix(in srgb,var(--accent) 42%,var(--border));background:linear-gradient(135deg,color-mix(in srgb,var(--accent) 8%,var(--bg-card)),var(--bg-card) 62%);padding:clamp(18px,3vw,30px)}.watch-news-card h3{margin:0;font-size:1.08rem;line-height:1.28;overflow-wrap:anywhere}.watch-news-card.featured h3{max-width:900px;font-size:clamp(1.35rem,2.4vw,2rem)}.watch-news-card p{margin:0;color:var(--text-muted);line-height:1.5;overflow-wrap:anywhere}.watch-news-card-meta{display:flex;align-items:center;gap:7px;flex-wrap:wrap;color:var(--text-muted);font-size:.72rem}.watch-news-card-meta span:first-child{border-radius:999px;background:var(--brand-50);color:var(--accent);padding:4px 8px;font-weight:850}.watch-news-card-meta time{margin-left:auto}.watch-news-card footer{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:auto;border-top:1px solid var(--border);padding-top:11px}.watch-news-card a{color:var(--accent);font-weight:800;text-decoration:none}.watch-news-card a:hover{text-decoration:underline}.watch-news-sas{border:0;background:transparent;color:var(--text-muted);padding:6px;font:inherit;font-size:.78rem;font-weight:750;cursor:pointer}.watch-news-sas:hover{color:var(--accent)}
.watch-news-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:13px}.watch-news-empty{display:grid;min-height:300px;place-content:center;text-align:center;border:1px dashed var(--border);border-radius:14px;padding:25px}.watch-news-empty h3{margin:0 0 7px}.watch-news-empty p{max-width:560px;margin:0;color:var(--text-muted)}
.watch-news-sources>div{display:flex;max-height:720px;flex-direction:column;gap:9px;overflow:auto;padding-right:2px}.watch-news-source{display:flex;min-width:0;flex-direction:column;gap:10px;border:1px solid var(--border);border-radius:12px;padding:12px}.watch-news-source h4,.watch-news-source p{margin:0}.watch-news-source h4{margin-top:4px;font-size:.92rem;overflow-wrap:anywhere}.watch-news-source p{margin-top:5px;color:var(--text-muted);font-size:.76rem;line-height:1.4}.watch-news-source-scope{color:var(--accent);font-size:.66rem;font-weight:900;letter-spacing:.07em;text-transform:uppercase}.watch-news-source footer{display:flex;align-items:center;justify-content:space-between;gap:8px}.watch-news-source-state{border-radius:999px;background:var(--brand-50);color:var(--text-muted);padding:4px 7px;font-size:.66rem;font-weight:850}.watch-news-source a{color:var(--accent);font-size:.75rem;font-weight:800;text-decoration:none}.watch-news-sources>.btn-ghost{width:100%;margin-top:12px}.watch-news-layout+.watch-safety{margin-bottom:0}
@media(max-width:1150px){.watch-news-toolbar{grid-template-columns:1fr}.watch-news-layout{grid-template-columns:1fr}.watch-news-sources>div{display:grid;max-height:none;grid-template-columns:repeat(2,minmax(0,1fr));overflow:visible}}
@media(max-width:760px){.watch-news-head,.watch-news-feed>header,.watch-news-sources>header{align-items:stretch;flex-direction:column}.watch-news-actions{display:grid;grid-template-columns:1fr;width:100%}.watch-news-actions button{width:100%}.watch-news-toolbar,.watch-news-feed,.watch-news-sources{padding:12px}.watch-news-grid,.watch-news-sources>div{grid-template-columns:1fr}.watch-news-card{min-height:0}.watch-news-card.featured{min-height:0;padding:17px}.watch-news-card footer{align-items:flex-start;flex-direction:column}.watch-news-card-meta time{width:100%;margin-left:0}.watch-news-feed>header>span{align-self:flex-start}}
@media(pointer:coarse){.watch-news-topics button,.watch-news-search input,.watch-news-card a,.watch-news-sas,.watch-news-source a{min-height:44px;font-size:16px}.watch-news-card a,.watch-news-source a{display:inline-flex;align-items:center}}
.gov-intro{display:flex;justify-content:space-between;gap:18px;align-items:flex-start}.gov-intro h3{margin:0 0 6px}.gov-intro p{margin:0;max-width:820px}.gov-kpis{display:flex;gap:8px;flex-wrap:wrap}.gov-kpis span{padding:9px 12px;background:var(--bg-soft,#f4f7fb);border-radius:9px;white-space:nowrap}.gov-create>summary{font-weight:700;cursor:pointer}.gov-form{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-top:15px}.gov-form label{display:grid;gap:5px;font-weight:600;font-size:.84rem}.gov-form input,.gov-form select,.gov-form textarea{width:100%;padding:9px;border:1px solid var(--border);border-radius:8px;background:var(--surface,#fff);color:var(--text)}.gov-wide{grid-column:1/-1}.gov-toolbar{display:flex;gap:12px;align-items:center;margin:12px 0;flex-wrap:wrap}.gov-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}.gov-card{margin:0}.gov-card-head{display:flex;justify-content:space-between;gap:12px;align-items:flex-start}.gov-card-head h3{margin:7px 0 0}.gov-meta{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}.gov-meta div{padding:8px;background:var(--bg-soft,#f5f7fa);border-radius:7px}.gov-meta dt{font-size:.72rem;color:var(--muted);text-transform:uppercase}.gov-meta dd{margin:3px 0 0;overflow-wrap:anywhere}.gov-alert{display:flex;align-items:center;gap:9px;padding:8px 10px;margin:8px 0;border-left:4px solid #f59e0b;background:#fff8e7;border-radius:7px;color:#4b2c00}.gov-alert span{margin-right:auto}.gov-actions{display:flex;gap:8px;flex-wrap:wrap;margin:10px 0}.gov-history{padding-left:20px}.gov-history li{margin:7px 0}.gov-status-active{background:#dcfce7;color:#166534}.gov-status-expired{background:#fee2e2;color:#991b1b}.gov-status-closed{background:#dbeafe;color:#1e40af}.gov-status-rejected{background:#e5e7eb;color:#374151}@media(max-width:900px){.gov-grid{grid-template-columns:1fr}.gov-form{grid-template-columns:1fr 1fr}.gov-meta{grid-template-columns:1fr}.gov-intro{flex-direction:column}}@media(max-width:560px){.gov-form{grid-template-columns:1fr}.gov-wide{grid-column:auto}.gov-actions .btn-sm,.gov-toolbar button{min-height:44px}.gov-alert{align-items:flex-start;flex-wrap:wrap}}
