/* ============================================================================
   SERVERPV — Design System (refonte UI/UX).
   Socle UNIQUE : jetons (couleur/typo/espacement), composants communs.
   Écrit à la main (aucun build). Polices LOCALES (terrain sans réseau).
   Thème CLAIR « SaaS » : fond neutre, cartes blanches, texte foncé.
   Charte QOIoT conservée : navy = structure, or = accent/action.
   Rétrocompatible : toutes les classes historiques restent valides.
   Contrastes vérifiés ≥ 4.5:1 (texte) sur leur fond réel.
   ============================================================================ */

/* ------------------------------------------------------------ Polices locales */
@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;
  src:url('/_passerelle/static/fonts/inter-400.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}
@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;
  src:url('/_passerelle/static/fonts/inter-500.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}
@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;
  src:url('/_passerelle/static/fonts/inter-600.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}
@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;
  src:url('/_passerelle/static/fonts/inter-700.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}
@font-face{font-family:'Barlow Condensed';font-style:normal;font-weight:600;font-display:swap;
  src:url('/_passerelle/static/fonts/barlow-condensed-600.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}
@font-face{font-family:'Barlow Condensed';font-style:normal;font-weight:700;font-display:swap;
  src:url('/_passerelle/static/fonts/barlow-condensed-700.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}

/* ======================================================= 1. JETONS (tokens) */
:root{
  /* — Charte QOIoT — */
  --qo-gold:#928340; --qo-gold-light:#a89550; --qo-gold-ink:#7a6d34;
  --qo-navy:#324860; --qo-navy-2:#263a4e; --qo-navy-3:#1c2d3f;

  /* — Neutres (biais navy, choisis) — */
  --qo-bg:#eef2f7;            /* fond de page */
  --qo-surface:#ffffff;       /* cartes / surfaces */
  --qo-surface-sub:#f4f7fb;   /* fonds discrets (thead, hover, chips) */
  --qo-text:#1c2b3a;          /* texte principal  (~13:1 sur blanc) */
  --qo-text-soft:#546a7e;     /* texte secondaire (~5.3:1 sur blanc) */
  --qo-text-faint:#768899;    /* texte ténu       (~4.6:1 sur blanc) */
  /* CC-148 — `--qo-muted` était employé 43 fois et déclaré NULLE PART : chacune de ces 43
     déclarations était donc invalide, et le texte reprenait la couleur héritée au lieu du gris
     discret. On l'aligne sur le texte secondaire, qui est ce que ces 43 usages cherchaient. */
  --qo-muted:var(--qo-text-soft);
  --qo-border:#dbe4ee;
  --qo-border-strong:#c4d1e0;

  /* — Sémantique : UNE valeur par intention (solide + fond doux + texte) — */
  --ok:#1b7a3d;     --ok-bg:#e7f4ec;     --ok-tx:#146c33;
  --warn:#8a6a00;   --warn-bg:#faf0d6;   --warn-tx:#6f5600;
  --danger:#b00020; --danger-bg:#fbe4e9; --danger-tx:#950018;
  --info:#2563a8;   --info-bg:#e6eef9;   --info-tx:#1f5490;
  --neutral-bg:#eef2f7; --neutral-tx:#3d5163;

  /* — Contrat de contrôle (CC-090) : hauteur UNIQUE des boutons/champs pour l'alignement du site. */
  --ctrl-h:42px;
  /* — Rayons / ombres — */
  --radius:9px; --radius-sm:6px; --radius-pill:999px;
  --shadow-sm:0 1px 2px rgba(28,45,63,.06);
  --shadow:0 1px 2px rgba(28,45,63,.05), 0 6px 18px -10px rgba(28,45,63,.18);
  --shadow-lg:0 1px 3px rgba(28,45,63,.08), 0 20px 40px -18px rgba(28,45,63,.28);

  /* — Échelle d'espacement (base 4px) — */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px; --sp-6:32px; --sp-7:48px;

  /* — Typo — */
  --f-display:'Barlow Condensed','Inter',system-ui,sans-serif;
  --f-body:'Inter',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;

  /* — Alias HÉRITÉS (compat totale des gabarits existants) — */
  --bleu:var(--qo-navy); --bleu-fonce:var(--qo-navy-3);
  --gris-fond:var(--qo-bg); --gris-bord:var(--qo-border);
  --texte:var(--qo-text); --rouge:var(--danger); --vert:var(--ok);
  --qo-warn:var(--warn); --or:var(--qo-gold);
  --rayon:var(--radius); --rayon-bouton:var(--radius-sm);
  --qo-white:var(--qo-surface); --qo-bg-token:var(--qo-bg);
}

/* ================================================================= 2. BASE */
*{box-sizing:border-box;}
html{-webkit-text-size-adjust:100%;}
body{
  margin:0;
  font-family:var(--f-body);
  font-size:16.5px;
  line-height:1.55;
  color:var(--qo-text);
  background:var(--qo-bg);
  min-height:100vh;
  -webkit-font-smoothing:antialiased;
}

h1,h2,h3{font-family:var(--f-display);font-weight:700;line-height:1.12;text-wrap:balance;margin:0;}
h1{font-size:1.95rem;margin:.1rem 0 1rem;letter-spacing:.2px;color:var(--qo-navy-3);}
h2{font-size:1.4rem;margin:0 0 .6rem;color:var(--qo-navy-3);}
h3{font-size:1.12rem;letter-spacing:.15px;}
p{margin:0 0 .8rem;}
a{color:var(--qo-navy-2);text-underline-offset:2px;}
a:hover{color:var(--qo-gold-ink);}
strong{font-weight:700;}
hr{border:none;border-top:1px solid var(--qo-border);margin:var(--sp-5) 0;}
[x-cloak]{display:none !important;}

.surtitre,.eyebrow{
  text-transform:uppercase;font-size:.72rem;font-weight:700;
  letter-spacing:.16em;color:var(--qo-gold-ink);
}
.surtitre.sur-marine{color:var(--qo-gold);}
.reserve{color:var(--qo-text-soft);}
p.reserve,.reserve{font-style:normal;}   /* on abandonne l'italique systématique */
.reserve em{font-style:italic;}

/* ============================================================ 3. EN-TÊTE / NAV */
/* Barre pleine largeur (fond blanc + trait or sous l'en-tête). */
.barre-nav{position:sticky;top:0;z-index:20;background:var(--qo-surface);
  border-bottom:3px solid var(--qo-gold);box-shadow:var(--shadow-sm);}

/* En-tête. Base (< 1540px) : logo à gauche, utilisateur à droite, menu sur sa
   propre ligne en dessous (filets masqués). */
.entete{
  color:var(--qo-navy-3);
  display:flex;align-items:center;flex-wrap:wrap;gap:.4rem 1rem;
  padding:.45rem 1.3rem;
}
.entete .marque{order:0;flex:0 0 auto;display:flex;align-items:center;}
/* Borné : /logo sert une image téléversée par le client, de proportions quelconques. Un logo
   panoramique reprendrait toute la largeur gagnée sur le menu et ferait revenir le repli. */
.entete .logo-marque{height:64px;width:auto;max-width:180px;object-fit:contain;display:block;}
.entete .utilisateur{order:1;margin-left:auto;flex:0 0 auto;
  display:flex;align-items:center;gap:.6rem;font-size:.95rem;color:var(--qo-navy-2);}
.entete .nom-complet{font-weight:600;}
/* Lien « Aide » (administrateur) : pastille discrète à droite, à l'écart du menu central. */
.lien-aide{display:inline-flex;align-items:center;gap:.3em;font-size:.8rem;font-weight:700;
  text-decoration:none;color:var(--qo-navy-2);background:var(--qo-surface-sub);
  border:1px solid var(--qo-border-strong);border-radius:999px;padding:.26rem .7rem;white-space:nowrap;}
.lien-aide:hover,.lien-aide:focus-visible{background:var(--qo-navy);color:#fff;border-color:var(--qo-navy);}
.lien-aide span{font-weight:800;}
/* « Aide » dans le menu : masqué sur desktop (la pastille d'en-tête suffit), affiché en mobile. */
/* CC-095 — « ? Aide » désormais un onglet du menu (desktop + hamburger) ; sélecteur de langue à droite. */
.utilisateur .menu-langue{display:inline-flex;align-items:center;gap:.3rem;}
/* Sélecteur de langue (FR/EN/ES/IT) : petits liens dans l'en-tête. */
/* Sélecteur de langue : petit menu déroulant natif, discret (CC-088). */
.lang-select{width:auto;min-width:0;min-height:0;height:auto;font-family:var(--f-body);
  font-size:.72rem;font-weight:700;letter-spacing:.02em;color:var(--qo-navy);
  background:var(--qo-surface);border:1px solid var(--qo-border-strong);border-radius:var(--radius-sm);
  padding:.12rem 1.1rem .12rem .35rem;line-height:1.2;cursor:pointer;appearance:auto;}
.lang-select:hover{border-color:var(--qo-navy);}
.hamburger{order:2;}
.entete .filet{display:none;}
nav.menu{
  order:3;flex:1 1 100%;
  display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:0;
  padding:.1rem 1rem;
}

/* Desktop large : TOUT sur une seule ligne — logo | filet | menu centré | filet | utilisateur.
   Le menu est ainsi centré horizontalement ET verticalement, posé sur la « ligne d'horizon ». */
/* CC-151 — LE SEUIL EST PASSÉ DE 1100 À 1540 px. Mesuré : la barre de l'administrateur
   demande ~1525 px une fois les onglets resserrés (5 langues, pastilles d'alerte comprises).
   À 1100 px elle ne tenait donc pas : elle repliait sur DEUX rangées, et les deux filets dorés
   (align-self:center) venaient couper le menu en son milieu. Sous ce seuil, c'est le menu ☰
   de CC-094 qui prend le relais — il existe et il est testé. */
@media (min-width:1540px){
  .entete{flex-wrap:nowrap;gap:0;padding:.4rem 1.6rem;}
  .entete .filet{display:block;flex:1 1 0;min-width:28px;height:0;
    border-top:2px solid var(--qo-gold);align-self:center;}
  .entete .filet.filet-g{order:1;margin:0 1.1rem 0 1.4rem;}
  /* nowrap : sans lui, nav.menu hérite du flex-wrap:wrap de sa règle de base et tout
     dépassement redevient une deuxième rangée au lieu de se voir. */
  nav.menu{order:2;flex:0 1 auto;flex-wrap:nowrap;padding:0;}
  .entete .filet.filet-d{order:3;margin:0 1.4rem 0 1.1rem;}
  .entete .utilisateur{order:4;margin-left:0;}
}
nav.menu a{
  color:var(--qo-navy-2);text-decoration:none;
  padding:.85rem 1.1rem;min-height:48px;display:inline-flex;align-items:center;
  font-weight:600;font-size:.86rem;text-transform:uppercase;letter-spacing:.05em;
  border-bottom:3px solid transparent;margin-bottom:-3px;
}
nav.menu a:hover,nav.menu a:focus-visible{background:var(--qo-surface-sub);color:var(--qo-navy-3);}
nav.menu a[aria-current="page"]{color:var(--qo-gold-ink);border-bottom-color:var(--qo-gold);}
nav.menu a .avenir{font-size:.7rem;opacity:.8;margin-left:.35rem;text-transform:none;}
/* CC-091 — sélecteur de langue déplacé dans le menu (bas), près de « Aide ». */
nav.menu .menu-langue{display:inline-flex;align-items:center;gap:.35rem;
  padding:.4rem 1.1rem;color:var(--qo-navy-2);font-weight:600;}
nav.menu .menu-langue .lang-select{font-size:.8rem;}
/* CC-093 — roue dentée « Paramètres » : menu déroulant regroupant les onglets d'administration. */
.menu-param{position:relative;display:inline-flex;align-items:center;}
.menu-param-btn{background:none;border:none;font-family:var(--f-body);cursor:pointer;color:var(--qo-navy-2);
  padding:.85rem 1.1rem;min-height:48px;height:auto;text-transform:uppercase;font-size:.86rem;font-weight:600;
  letter-spacing:.05em;display:inline-flex;align-items:center;gap:.35rem;
  border-bottom:3px solid transparent;margin-bottom:-3px;border-radius:0;}
.menu-param-btn:hover{background:var(--qo-surface-sub);color:var(--qo-navy-3);}
.menu-param-liste{position:absolute;top:100%;right:0;z-index:30;min-width:13rem;
  background:var(--qo-surface);border:1px solid var(--qo-border);border-radius:var(--radius-sm);
  box-shadow:var(--shadow);padding:.3rem;display:flex;flex-direction:column;gap:.1rem;}
.menu-param-liste a{padding:.55rem .8rem;border-radius:var(--radius-sm);text-transform:none;
  font-size:.92rem;font-weight:600;letter-spacing:0;min-height:auto;border:none;margin:0;color:var(--qo-navy-2);}
.menu-param-liste a:hover{background:var(--qo-surface-sub);color:var(--qo-navy-3);}
/* CC-151 — Onglets resserrés en mode barre : c'est ce qui ramène la largeur demandée sous le
   seuil. Placé APRÈS `nav.menu a` et `.menu-param-btn` : une media query n'ajoute aucune
   spécificité, un bloc posé plus haut aurait été écrasé par ces deux règles. */
@media (min-width:1540px){
  nav.menu a,.menu-param-btn{padding-left:.5rem;padding-right:.5rem;font-size:.78rem;}
}
@media (max-width:1539px){
  .menu-param{width:100%;flex-direction:column;align-items:stretch;}
  .menu-param-btn{width:100%;justify-content:flex-start;min-height:46px;border-bottom:none;margin-bottom:0;
    border-radius:var(--radius-sm);font-size:1rem;}
  .menu-param-liste{position:static;box-shadow:none;border:none;padding:.1rem 0 .4rem 1rem;min-width:0;}
  .menu-param-liste a{font-size:1rem;}
  /* CC-094 — hamburger sous 1540px : le menu ne déborde JAMAIS sur plusieurs lignes (une ligne desktop
     ≥1540px, sinon menu déroulant vertical). `.entete .hamburger` (spécificité 0,2,0) pour battre la
     règle de base `.hamburger{display:none}` située PLUS BAS dans le fichier. */
  .entete .hamburger{display:inline-flex;}
  .entete .lien-aide{display:none;}          /* pastille Aide -> passe dans le hamburger */
  nav.menu{display:none;flex-direction:column;align-items:stretch;justify-content:flex-start;
    gap:2px;padding:.4rem .6rem .7rem;}
  nav.menu.menu-ouvert{display:flex;}
  nav.menu a{width:100%;justify-content:flex-start;font-size:1rem;min-height:46px;
    border-bottom:none;margin-bottom:0;border-radius:var(--radius-sm);}
  nav.menu a.menu-aide{display:inline-flex;}
  nav.menu .menu-langue{width:100%;justify-content:flex-start;padding:.85rem 1.1rem;
    border-top:1px solid var(--qo-border);margin-top:.3rem;}
}

main.contenu{max-width:960px;margin:0 auto;padding:1.4rem 1.1rem 4rem;color:var(--qo-text);}

footer.pied{text-align:center;color:var(--qo-text-faint);font-size:.85rem;padding:1.5rem 1rem 2rem;}

/* ================================================================ 4. SURFACES */
.carte{
  background:var(--qo-surface);border:1px solid var(--qo-border);
  border-radius:var(--radius);padding:1.2rem 1.3rem;margin-bottom:1rem;
  box-shadow:var(--shadow-sm);
}
.carte > :last-child{margin-bottom:0;}
.carte.accent-gold{border-left:4px solid var(--qo-gold);}
.carte.accent-danger{border-left:4px solid var(--danger);}
/* Titre de carte : plus compact + filet de séparation = structure claire et cohérente. */
.carte > h2{font-size:1.14rem;padding-bottom:.55rem;margin-bottom:.9rem;
  border-bottom:1px solid var(--qo-border);display:flex;align-items:center;gap:.5rem;}

/* En-tête de page : surtitre de contexte + titre + état, mis en avant (motif SaaS). */
.page-tete{margin:.2rem 0 1.4rem;}
.page-tete .fil{display:block;margin-bottom:.25rem;}
.page-tete .titre-ligne{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap;}
.page-tete .titre-ligne h1{margin:0;}

/* Grille d'informations clé / valeur (remplace les <p><strong>… répétés). */
.infos{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:.9rem 1.6rem;}
.infos .k{font-size:.72rem;text-transform:uppercase;letter-spacing:.06em;
  color:var(--qo-text-faint);font-weight:700;}
.infos .v{margin-top:.15rem;font-weight:500;}
.encart{
  background:var(--qo-surface-sub);border:1px solid var(--qo-border);
  border-left:4px solid var(--qo-gold);border-radius:0 var(--radius-sm) var(--radius-sm) 0;
  padding:.9rem 1.1rem;margin-bottom:1rem;
}
fieldset{border:1px solid var(--qo-border);border-radius:var(--radius-sm);padding:.8rem 1rem;margin:0 0 1rem;}
fieldset legend{font-weight:700;padding:0 .4rem;}
fieldset label{display:block;margin:.3rem 0;}

/* ================================================================= 5. BOUTONS
   Un composant, 5 rôles. Les libellés .bouton (liens) et <button> partagent tout.
   Rôles : primaire (or, défaut) · secondaire (marine) · tertiaire (contour)
           · danger (rouge, VRAI composant désormais) · .btn-power (icône ronde). */
button,.bouton,.btn{
  font-family:var(--f-body);font-size:1rem;font-weight:700;line-height:1.1;
  padding:.4rem 1.05rem;min-height:var(--ctrl-h);vertical-align:middle;
  display:inline-flex;align-items:center;justify-content:center;gap:.5rem;
  border:1px solid transparent;border-radius:var(--radius-sm);
  background:var(--qo-gold);color:#fff;cursor:pointer;text-decoration:none;
  transition:background .12s ease, box-shadow .12s ease;
}
button:hover,.bouton:hover,.btn:hover{background:var(--qo-gold-light);color:#fff;}
button:focus-visible,.bouton:focus-visible,.btn:focus-visible{
  outline:3px solid var(--qo-navy-3);outline-offset:2px;}
button:disabled,.btn:disabled{opacity:.5;cursor:not-allowed;}

button.secondaire,.bouton.secondaire,.btn.secondaire,.btn-secondary{
  background:var(--qo-navy);color:#fff;}
button.secondaire:hover,.bouton.secondaire:hover,.btn.secondaire:hover{background:var(--qo-navy-2);color:#fff;}

button.tertiaire,.bouton.tertiaire,.btn.tertiaire{
  background:var(--qo-surface);color:var(--qo-text);border-color:var(--qo-border-strong);}
button.tertiaire:hover,.bouton.tertiaire:hover{background:var(--qo-surface-sub);color:var(--qo-text);}

/* .danger était une classe FANTÔME (jamais définie) : elle est désormais réelle et
   l'emporte sur .secondaire quel que soit l'ordre des classes dans le HTML. */
button.danger,.bouton.danger,.btn.danger,
button.secondaire.danger,.bouton.secondaire.danger{
  background:var(--danger);color:#fff;border-color:transparent;}
button.danger:hover,.bouton.danger:hover,.btn.danger:hover{background:#8f0019;color:#fff;}

/* Petit bouton destructeur discret (suppression de ligne) — conservé. */
.lien-suppr{
  background:var(--danger);color:#fff;border:none;border-radius:var(--radius-sm);
  padding:.3rem .65rem;min-height:auto;font-size:.85rem;font-weight:700;cursor:pointer;}
.lien-suppr:hover{background:#8f0019;}

/* Bouton rond « power » (déconnexion). */
.btn-power{
  width:44px;height:44px;min-height:44px;padding:0;border-radius:50%;
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--qo-navy);color:#fff;border:0;cursor:pointer;}
.btn-power:hover,.btn-power:focus-visible{background:var(--danger);color:#fff;}
.btn-power svg{display:block;}

/* ================================================================= 6. BADGES
   Historique : .badge-role, .badge-statut, .email-badge (conservés).
   NOUVEAU : .badge sémantique unique (.is-ok/.is-warn/.is-danger/.is-info). */
.badge-role{
  background:var(--qo-navy);color:#fff;padding:.15rem .55rem;border-radius:var(--radius-pill);
  font-size:.74rem;font-weight:700;letter-spacing:.04em;}
.badge-statut{
  background:var(--qo-navy);color:#fff;font-size:.78rem;font-weight:700;
  padding:.15rem .6rem;border-radius:var(--radius-pill);white-space:nowrap;
  display:inline-flex;align-items:center;gap:.35em;}

.badge{
  display:inline-flex;align-items:center;gap:.4em;white-space:nowrap;
  font-size:.76rem;font-weight:700;line-height:1;letter-spacing:.02em;
  padding:.34em .7em;border-radius:var(--radius-pill);
  background:var(--neutral-bg);color:var(--neutral-tx);}
.badge .dot{width:.5em;height:.5em;border-radius:50%;background:currentColor;}
.badge.is-ok{background:var(--ok-bg);color:var(--ok-tx);}
.badge.is-warn{background:var(--warn-bg);color:var(--warn-tx);}
.badge.is-danger{background:var(--danger-bg);color:var(--danger-tx);}
.badge.is-info{background:var(--info-bg);color:var(--info-tx);}

/* ============================================================== 7. FORMULAIRES */
form.pile{display:flex;flex-direction:column;gap:1rem;max-width:460px;}
label{font-weight:600;display:block;margin-bottom:.3rem;}
label.label-normal,.label-normal{font-weight:400;}
input[type=text],input[type=password],input[type=email],input[type=number],
input[type=date],input[type=time],input[type=week],input[type=search],select,textarea{
  width:100%;padding:.6rem .75rem;font-size:1rem;font-family:var(--f-body);
  border:1px solid var(--qo-border-strong);border-radius:var(--radius-sm);
  background:var(--qo-surface);color:var(--qo-text);
  /* CC-148 — LE CONTRAT DE HAUTEUR, appliqué aux champs eux-mêmes et plus seulement aux boutons.
     Sans lui, une même rangée alignait trois hauteurs différentes (champ ~45 px, liste ~43 px,
     bouton 42 px) : c'est ce désalignement d'un ou deux pixels, répété partout, qui donne
     l'impression d'un écran « pas fini ». */
  min-height:var(--ctrl-h);box-sizing:border-box;}
input:focus,select:focus,textarea:focus{
  outline:3px solid rgba(146,131,64,.35);outline-offset:1px;border-color:var(--qo-gold);}
input::placeholder,textarea::placeholder{color:var(--qo-text-faint);}
input[type=checkbox],input[type=radio]{width:1.15rem;height:1.15rem;accent-color:var(--qo-gold);vertical-align:middle;}

.field{margin-bottom:.9rem;}
.field label{font-size:.92rem;}

/* ================================================================= 8. TABLEAUX
   .tbl-lignes (historique) restylé + .table (nouvelle convention unique).
   .table-historique (ex-<style> local) alignée sur le même rendu. */
.tbl-lignes,.table,.table-historique{
  width:100%;border-collapse:separate;border-spacing:0;margin-bottom:.8rem;
  font-size:.92rem;background:var(--qo-surface);
  border:1px solid var(--qo-border);border-radius:var(--radius-sm);overflow:hidden;}
.tbl-lignes th,.tbl-lignes td,
.table th,.table td,
.table-historique th,.table-historique td{
  padding:.55rem .75rem;text-align:left;border-bottom:1px solid var(--qo-border);vertical-align:top;}
.tbl-lignes thead th,.table thead th,.table-historique thead th{
  background:var(--qo-surface-sub);color:var(--qo-text-soft);
  font-size:.74rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;white-space:nowrap;}
.tbl-lignes tbody tr:last-child td,
.table tbody tr:last-child td,
.table-historique tbody tr:last-child td{border-bottom:none;}
.table tbody tr:hover td,.tbl-lignes tbody tr:hover td{background:var(--qo-surface-sub);}
.tbl-lignes .num,.table .num{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums;}
.tbl-lignes tfoot td{background:var(--qo-surface-sub);font-weight:600;}
.ajout-ligne{border-top:2px dashed var(--qo-border);padding-top:.8rem;margin-top:.4rem;}
.table-wrap{overflow-x:auto;}   /* conteneur scrollable pour tables larges */

/* ======================================================= 9. MESSAGES / CALLOUTS
   .message-succes/.message-erreur (historiques) + .callout 4 niveaux (nouveau).
   Ajoute enfin le niveau « avertissement » (--warn) qui manquait. */
.message-succes,.message-erreur,.message-avertissement,.message-info,.callout{
  padding:.75rem 1rem;border-radius:var(--radius-sm);font-size:.95rem;
  border:1px solid transparent;display:flex;gap:.55rem;align-items:flex-start;}
.message-succes{background:var(--ok-bg);color:var(--ok-tx);border-color:#bfe3cc;}
.message-erreur{background:var(--danger-bg);color:var(--danger-tx);border-color:#f2c2cd;}
.message-avertissement,.callout.warn{background:var(--warn-bg);color:var(--warn-tx);border-color:#ecd9a3;}
.message-info,.callout.info{background:var(--info-bg);color:var(--info-tx);border-color:#c7dbf3;}
.callout.ok{background:var(--ok-bg);color:var(--ok-tx);border-color:#bfe3cc;}
.callout.danger{background:var(--danger-bg);color:var(--danger-tx);border-color:#f2c2cd;}
.callout .ic{font-weight:800;flex:none;line-height:1.4;}

/* ============================================================ 10. GRILLES / LISTES
   .grille-actions et .grille-filtres PROMUES ici (avaient une définition
   uniquement en media-query ou dupliquée dans des <style> locaux). */
.grille-actions{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:1rem;margin-bottom:1rem;}
.grille-filtres{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:.8rem;margin-bottom:.9rem;}
.grille-form{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:1rem;}

/* CC-151 — UN MENU DÉROULANT N'EST PAS UN CHAMP PLEINE LARGEUR DANS UNE RANGÉE.
   Le contrat de champ (§ 7) donne width:100% au <select>, donc une taille de base pleine
   largeur : dans le catalogue des prestations il monopolisait sa ligne et éclatait chaque
   article en trois lignes (référence+désignation / catégorie / prix+€+Enregistrer).
   La hauteur, elle, reste celle du contrat : le menu garde l'alignement de ses voisins. */
.presta-ligne select{width:auto;min-width:9rem;}

/* Ligne de liste générique (remplace .email-ligne dupliqué 4×, .presta-ligne, etc.) */
.email-ligne,.ligne-liste,.rangee{
  display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;}
/* CC-150 — UNE RANGÉE DE CHAMPS S'ALIGNE PAR LE BAS, jamais par le milieu. Avec `center`, un
   libellé qui passe sur deux lignes (« Nouvel équipement (créé sur le site et rattaché) ») décale
   son champ vers le bas pendant que ses voisins restent en haut : les contrôles ne sont plus sur
   la même ligne, et l'écran paraît bâclé. Aligner par le bas met tous les CHAMPS au même niveau,
   quelle que soit la hauteur des libellés. */
.rangee-champs{display:flex;align-items:flex-end;gap:.6rem;flex-wrap:wrap;}
.rangee-champs > div{display:flex;flex-direction:column;justify-content:flex-end;}
.rangee-champs label{margin-bottom:.3rem;}
.email-ligne,.ligne-liste{padding:.5rem 0;border-top:1px solid var(--qo-border);}
.email-ligne:first-of-type,.ligne-liste:first-of-type{border-top:none;}
.email-action{display:flex;align-items:center;gap:.5rem;margin-top:.6rem;flex-wrap:wrap;
  border-top:1px solid var(--qo-border);padding-top:.6rem;}
.email-action input[type=email]{min-height:auto;padding:.4rem .55rem;max-width:280px;}
/* CC-099 — boutons d'envoi homogènes : même hauteur (contrat) et largeur.
   Sur mobile, champ + bouton en pleine largeur → tous les boutons identiques. */
.email-action > button{min-width:9rem;}
@media (max-width:640px){
  .email-action input[type=email]{max-width:none;flex:1 1 100%;}
  .email-action > button{width:100%;}
}

/* Panneau e-mails repliable (ex-<style> du partiel). */
.panneau-emails{margin:.6rem 0;}
.panneau-emails summary{cursor:pointer;font-weight:600;padding:.2rem 0;}
.panneau-corps{margin-top:.4rem;}
.email-badge{font-size:.76rem;font-weight:700;padding:.15rem .55rem;border-radius:var(--radius-pill);
  background:var(--neutral-bg);color:var(--neutral-tx);white-space:nowrap;}
.email-badge.email-ENVOYE,.email-ENVOYE{background:var(--ok-bg);color:var(--ok-tx);}
.email-badge.email-ERREUR,.email-ERREUR{background:var(--danger-bg);color:var(--danger-tx);}
.email-badge.email-AUCUN,.email-AUCUN{background:var(--neutral-bg);color:var(--neutral-tx);}

/* ================================================== 11. CARTES D'INTERVENTION */
a.lien-interv{display:block;text-decoration:none;color:inherit;transition:border-color .12s,box-shadow .12s;}
a.lien-interv:hover{border-color:var(--qo-gold);box-shadow:var(--shadow);}
.ligne-ref{display:flex;justify-content:space-between;align-items:center;gap:.5rem;flex-wrap:wrap;margin-bottom:.3rem;}

/* Bloc d'actions documentaires (page détail). */
.action-doc{display:flex;align-items:center;gap:.8rem;flex-wrap:wrap;
  padding:.75rem 0;border-top:1px solid var(--qo-border);}
.action-doc:first-of-type{border-top:none;}
.action-titre{font-weight:700;flex:1 1 38%;min-width:150px;}
.action-statut{color:var(--qo-text-soft);flex:1 1 26%;min-width:160px;
  display:flex;align-items:center;gap:.45rem;flex-wrap:wrap;}
.action-statut.ok{color:var(--ok);font-weight:600;}
.barre-actions{display:flex;gap:.4rem;flex-wrap:wrap;margin-left:auto;}

/* ======================================================= 12. SECTIONS REPLIABLES */
.section-tech{border-top:1px solid var(--qo-border);}
.section-titre{
  width:100%;text-align:left;background:none;color:var(--qo-text);
  font-family:var(--f-body);font-size:1.02rem;font-weight:700;
  padding:.7rem .2rem;min-height:44px;border:none;border-radius:0;justify-content:flex-start;}
.section-titre:hover{background:var(--qo-surface-sub);color:var(--qo-text);}
.section-corps{padding:.3rem .2rem .8rem;}

/* ============================================================= 13. SIGNATURE */
.zone-signature{
  width:100%;height:44vh;min-height:240px;background:#fff;
  border:2px dashed var(--qo-navy);border-radius:var(--radius-sm);
  touch-action:none;cursor:crosshair;display:block;}
.boutons-signature{display:flex;gap:.8rem;}
.boutons-signature button{flex:1 1 auto;}

/* ============================================================= 14. PAGINATION */
.pagination{display:flex;align-items:center;gap:1rem;margin-top:1rem;flex-wrap:wrap;}

/* ============================================================ 15. CONNEXION */
body.ecran-connexion{display:flex;align-items:flex-start;justify-content:center;background:var(--qo-bg);}
.boite-connexion{width:100%;max-width:420px;margin:8vh 1rem 0;}
.boite-connexion .marque-connexion{text-align:center;margin-bottom:.4rem;}
.boite-connexion .sous-titre{
  text-align:center;color:var(--qo-text-soft);margin-bottom:1.4rem;
  text-transform:uppercase;letter-spacing:.16em;font-size:.78rem;font-weight:700;}
.boite-connexion .carte{border-top:4px solid var(--qo-gold);box-shadow:var(--shadow);}

/* ========================================================= 16. UTILITAIRES
   Remplacent les motifs inline les plus fréquents (voir audit). */
.w-100{width:100%;}
.ml-auto{margin-left:auto;}
.mt-1{margin-top:var(--sp-1);} .mt-2{margin-top:var(--sp-2);} .mt-3{margin-top:var(--sp-4);}
/* CC-148 — CES TROIS CLASSES SONT DES MODIFICATEURS : elles doivent l'emporter sur la largeur par
   défaut de `form.pile` (0,0,1,1), qui les battait en spécificité (0,0,1,0). Un formulaire marqué
   « form-large » restait donc à 460 px, et sa carte « En-tête » paraissait deux fois plus étroite
   que la carte « Modèle » juste au-dessus — l'écran semblait bancal sans raison visible. */
/* Ces trois classes sont des MODIFICATEURS : elles doivent l'emporter sur la largeur par défaut de
   `form.pile` (spécificité 0,0,1,1), qui les battait. La classe DOUBLÉE porte la spécificité à
   (0,0,2,0) sans `!important` et sans dépendre de la balise — un `<div class="form-large">` est
   traité comme un `<form>`. */
.form-etroit.form-etroit{max-width:460px;}
.form-moyen.form-moyen{max-width:560px;}
.form-large.form-large{max-width:720px;}
/* Pleine largeur : pour un formulaire dont les cartes doivent s'aligner sur celles qui l'entourent.
   Sur le bon d'intervention, quatre cartes étaient à 720 px et trois à 925 px sur la même page —
   l'écran paraissait bancal sans qu'on voie pourquoi. */
.form-pleine.form-pleine{max-width:none;}
.entre-actions{display:flex;gap:.6rem;flex-wrap:wrap;align-items:center;}
.titre-page{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;}

/* CC-099 — barre d'actions de bas de page homogène : tous les boutons de même
   hauteur (contrat --ctrl-h) et de même largeur. Empilés pleine largeur sur
   mobile (cas smartphone), en ligne avec une largeur mini partagée sur desktop. */
.actions-page{display:flex;flex-direction:column;gap:.6rem;margin-top:1.1rem;}
.actions-page > a.bouton,.actions-page > button,.actions-page > .btn{width:100%;margin:0;}
.actions-page > form{margin:0;width:100%;}
.actions-page > form > button,.actions-page > form > a.bouton{width:100%;}
@media (min-width:640px){
  .actions-page{flex-direction:row;flex-wrap:nowrap;align-items:stretch;}
  /* flex:1 1 0 → tous les boutons partagent la largeur à parts strictement égales
     (min-width:13rem laissait « Retour au détail » déborder et casser l'égalité). */
  .actions-page > a.bouton,.actions-page > button,.actions-page > .btn,
  .actions-page > form{flex:1 1 0;min-width:0;width:auto;}
  .actions-page > form > button,.actions-page > form > a.bouton{width:100%;}
}
/* Bouton « appareil photo » (la galerie reste accessible via « Choisir un fichier »). */
.choix-source{display:flex;gap:.6rem;flex-wrap:wrap;margin-bottom:.6rem;}
.choix-source > .bouton{flex:1 1 10rem;}

/* Indicateur de chargement htmx (aucun n'existait). À poser via hx-indicator. */
.htmx-indicator{opacity:0;transition:opacity .15s;}
.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{opacity:1;}
.spinner{display:inline-block;width:1em;height:1em;border:2px solid currentColor;
  border-right-color:transparent;border-radius:50%;animation:spin .6s linear infinite;vertical-align:-.15em;}
@keyframes spin{to{transform:rotate(360deg);}}

/* ============================================================ 17. HAMBURGER (mobile) */
.hamburger{display:none;}
.hamburger{
  align-items:center;justify-content:center;width:48px;min-height:48px;padding:0;
  font-size:1.4rem;line-height:1;background:var(--qo-navy);color:#fff;border:0;
  border-radius:var(--radius-sm);cursor:pointer;}

/* ============================================================ 18. RESPONSIVE
   Un seul bloc mobile (fini les 5 media-queries éparses). */
@media (max-width:600px){
  body{font-size:17px;}
  main.contenu{padding:1rem .8rem 3rem;}
  h1{font-size:1.6rem;} h2{font-size:1.22rem;}

  .carte{padding:1rem;overflow-x:auto;}      /* table large défile DANS la carte */
  .entete{padding:.5rem .8rem;}
  .entete .logo-marque{height:46px;}

  /* Champs à 16px : empêche le zoom auto iOS. */
  input[type=text],input[type=password],input[type=email],input[type=number],
  input[type=date],input[type=time],input[type=week],input[type=search],select,textarea{font-size:16px;}

  /* Grilles à 1 colonne = cibles larges. */
  .grille-actions,.grille-filtres,.grille-form{grid-template-columns:1fr;}

  .action-doc .barre-actions,.action-doc .bouton{margin-left:0;}
  .zone-signature{height:50vh;min-height:260px;}

  /* Page signature : NOM en haut + boutons en bas TOUJOURS visibles. */
  #form-signature{gap:.55rem;}
  #form-signature .sig-nom{position:sticky;top:0;z-index:5;background:var(--qo-navy-3);
    color:#fff;padding:.5rem .6rem;border-radius:var(--radius-sm);border-bottom:2px solid var(--qo-gold);}
  #form-signature .sig-nom label{color:#fff;}
  #form-signature .zone-signature{height:42vh;min-height:190px;}
  #form-signature .boutons-signature{position:sticky;bottom:0;z-index:5;background:var(--qo-navy-3);
    padding:.6rem;border-radius:var(--radius-sm);border-top:3px solid var(--qo-gold);}
}

@media (prefers-reduced-motion:reduce){
  *{animation-duration:.001ms !important;transition-duration:.001ms !important;}
}

/* ============ CC-086 — Alignement & homogénéité des rangées de boutons d'action ============
   Bloc AUTONOME ajouté en fin de feuille. POUR TOUT ANNULER : supprimer ce bloc et retirer les
   classes `rangee-boutons` (parametres_habilitations) et `bascule` (parametres_email) des gabarits.
   N'affecte QUE les rangées d'actions de : Utilisateurs, Destinataires e-mail, Supervision
   techniciens, Catalogue des habilitations. Ne change aucune couleur ni aucun comportement. */

/* Boutons d'action COMPACTS et homogènes (même hauteur/graisse) dans les rangées denses. */
.ligne-user button, .ligne-user .bouton,
.hab-ligne button, .hab-ligne .bouton, .hab-dispense .bouton, .hab-dispense a.bouton,
.email-ligne.rangee-boutons button{
  min-height:36px;padding:.38rem .7rem;font-size:.85rem;line-height:1.1;white-space:nowrap;}

/* 1) Comptes existants (Utilisateurs) : rangée alignée, hauteurs égales, plus d'enroulement anarchique. */
.ligne-user{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem .5rem;
  padding:.55rem 0;border-top:1px solid var(--qo-border);}
.ligne-user:first-of-type{border-top:none;}
.ligne-user > .reserve{flex:0 0 8.5rem;}                       /* colonne « #id · identifiant » */
.ligne-user input[type=text],.ligne-user input[type=email],
.ligne-user input[type=password],.ligne-user select{height:36px;min-width:0;flex:1 1 8rem;}
.ligne-user > label.reserve{flex:0 0 auto;}                    /* case « actif » */
.ligne-user button{flex:0 0 auto;}

/* 2) Destinataires e-mail : bouton bascule à largeur fixe -> « Supprimer » toujours aligné. */
button.bascule{min-width:8.2rem;}

/* 3) Supervision techniciens : COLONNE d'action de droite à LARGEUR CONSTANTE (--col-action).
   Tout ce qui s'y trouve (menu, champ, « Enregistrer », « Consulter/co-signer », « PDF ») occupe
   la même largeur -> alignement vertical net, bords gauche ET droit alignés d'une ligne à l'autre. */
.hab-ligne{--col-action:15rem;display:flex;flex-wrap:wrap;align-items:flex-start;gap:.4rem .6rem;padding:.35rem 0;}
.hab-ligne > div.reserve{flex:1 1 16rem;min-width:0;}          /* libellé habilitation (div, pas le span) */
.hab-dispense{flex:0 0 var(--col-action);width:var(--col-action);margin-left:auto;}
/* Formulaire de dispense (menu + éventuel motif + Enregistrer) : pile verticale, tout pleine largeur. */
form.hab-dispense{display:flex;flex-direction:column;gap:.35rem;align-items:stretch;}
form.hab-dispense select,form.hab-dispense input[type=text],form.hab-dispense button{width:100%;min-width:0;}
form.hab-dispense select{height:36px;}
/* Cluster EPI : « Consulter/co-signer » pleine largeur ; « Consulter » + « PDF » se partagent la colonne. */
span.hab-dispense{display:flex;gap:.4rem;}
span.hab-dispense a.bouton{flex:1 1 0;min-width:0;}
span.hab-dispense.reserve{display:block;text-align:right;}   /* « obligatoire pour tous » = texte simple */

/* 4) Catalogue des habilitations : 3 boutons d'action en COLONNES à largeur fixe -> alignement
   vertical net d'une ligne à l'autre (ancré à droite). Le nom absorbe l'espace restant. */
.email-ligne.rangee-boutons{gap:.45rem;}
.email-ligne.rangee-boutons > strong{flex:1 1 auto;min-width:0;}
.email-ligne.rangee-boutons form{flex:0 0 auto;margin:0;}
.email-ligne.rangee-boutons button{font-size:.82rem;padding:.38rem .3rem;}
/* Largeur fixe par colonne (ancrage à droite via nth-last : Désactiver toujours en dernier). */
.email-ligne.rangee-boutons form:nth-last-of-type(1) button{width:6.8rem;}   /* Désactiver / Réactiver */
.email-ligne.rangee-boutons form:nth-last-of-type(2) button{width:11rem;}    /* Autoriser dispenses / Oblig. tous */
.email-ligne.rangee-boutons form:nth-last-of-type(3) button{width:9rem;}     /* Rendre facultatif / obligatoire */
@media (min-width:760px){ .email-ligne.rangee-boutons{flex-wrap:nowrap;} }

/* ============ CC-089 — Boutons d'action iconographiques (poubelle rouge / disquette bleue) ============
   Icône SVG (Feather) via mask + currentColor. Le libellé texte reste dans le DOM pour l'accessibilité
   (nom accessible du bouton), masqué visuellement par font-size:0. Objectif : rangées compactes, zéro
   saut de ligne. `.lien-suppr` (deletes de ligne) devient une poubelle sans toucher au HTML.
   POUR ANNULER : supprimer ce bloc + retirer les classes `btn-suppr`/`btn-enreg` ajoutées. */
.btn-suppr, .btn-enreg, button.lien-suppr {
  display:inline-flex !important; align-items:center; justify-content:center; vertical-align:middle;
  width:var(--ctrl-h) !important; min-width:var(--ctrl-h) !important;
  height:var(--ctrl-h) !important; min-height:var(--ctrl-h) !important;
  padding:0 !important; font-size:0 !important; line-height:0 !important; gap:0 !important;
  border:1px solid transparent; border-radius:var(--radius-sm); cursor:pointer; flex:0 0 auto;
  transition:background .12s ease, box-shadow .12s ease; box-shadow:none;
}
.btn-suppr::before, .btn-enreg::before, button.lien-suppr::before {
  content:""; width:18px; height:18px; background-color:currentColor; display:block;
  -webkit-mask:center/contain no-repeat var(--ic); mask:center/contain no-repeat var(--ic);
}
button.btn-suppr, button.lien-suppr, .btn-suppr {
  color:#fff; background:var(--danger); border-color:transparent;
  --ic:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http://www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%23000%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpolyline%20points%3D%223%206%205%206%2021%206%22/%3E%3Cpath%20d%3D%22M19%206v14a2%202%200%200%201-2%202H7a2%202%200%200%201-2-2V6m3%200V4a2%202%200%200%201%202-2h4a2%202%200%200%201%202%202v2%22/%3E%3Cline%20x1%3D%2210%22%20y1%3D%2211%22%20x2%3D%2210%22%20y2%3D%2217%22/%3E%3Cline%20x1%3D%2214%22%20y1%3D%2211%22%20x2%3D%2214%22%20y2%3D%2217%22/%3E%3C/svg%3E");
}
button.btn-suppr:hover, button.lien-suppr:hover, .btn-suppr:hover { background:#8f0019; }
button.btn-enreg, .btn-enreg {
  color:#fff; background:var(--qo-navy); border-color:transparent;
  --ic:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http://www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%23000%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M19%2021H5a2%202%200%200%201-2-2V5a2%202%200%200%201%202-2h11l5%205v11a2%202%200%200%201-2%202z%22/%3E%3Cpolyline%20points%3D%2217%2021%2017%2013%207%2013%207%2021%22/%3E%3Cpolyline%20points%3D%227%203%207%208%2015%208%22/%3E%3C/svg%3E");
}
button.btn-enreg:hover, .btn-enreg:hover { background:var(--qo-navy-2); }
/* Focus visible homogène pour ces boutons-icônes. */
.btn-suppr:focus-visible, .btn-enreg:focus-visible, button.lien-suppr:focus-visible {
  outline:3px solid var(--qo-navy-3); outline-offset:2px;
}

/* ============================================ 22. HARMONISATION DES BOUTONS D'ACTION
   AUDIT UI 2026-09-07 — les libellés d'action ont des longueurs très différentes
   (« Créer », « Ouvrir », « Voir le PDF », « Voir / gérer », « PDF officiel », « Consulter ») :
   comme les blocs d'action sont alignés à DROITE, les bords GAUCHES formaient un escalier.
   On impose une largeur minimale COMMUNE : les boutons deviennent de même longueur et
   s'alignent sur une verticale nette, sur toutes les pages et dans les 5 langues.
   Les boutons-icônes (disquette / poubelle) sont explicitement EXCLUS : ils restent carrés. */
.barre-actions .bouton:not(.btn-suppr):not(.btn-enreg):not(.lien-suppr),
.barre-actions button:not(.btn-suppr):not(.btn-enreg):not(.lien-suppr),
.action-doc .bouton:not(.btn-suppr):not(.btn-enreg):not(.lien-suppr),
.rangee.mt-2 .bouton:not(.btn-suppr):not(.btn-enreg):not(.lien-suppr),
.rangee.mt-2 button:not(.btn-suppr):not(.btn-enreg):not(.lien-suppr){
  min-width:9.25rem;            /* couvre le libellé le plus long, dans les 5 langues */
}

/* Les boutons d'un même bloc s'alignent à droite, donc bords gauches sur la même verticale. */
.barre-actions{justify-content:flex-end;}

@media (max-width:600px){
  /* Mobile : la largeur fixe deviendrait trop large -> les boutons se partagent la ligne
     et restent alignés naturellement (bord à bord), sans débordement horizontal. */
  .barre-actions .bouton:not(.btn-suppr):not(.btn-enreg):not(.lien-suppr),
  .barre-actions button:not(.btn-suppr):not(.btn-enreg):not(.lien-suppr),
  .rangee.mt-2 .bouton:not(.btn-suppr):not(.btn-enreg):not(.lien-suppr),
  .rangee.mt-2 button:not(.btn-suppr):not(.btn-enreg):not(.lien-suppr){
    min-width:0;flex:1 1 9rem;
  }
}

/* --- Correctif 2026-09-07 : cartes du tableau de bord (habilitations / EPI) ---------------
   La largeur commune imposée plus haut rendait le formulaire « adresse e-mail + Envoyer »
   trop large : il se repliait sur deux lignes, et « Voir » / la corbeille ne s'alignaient
   plus avec le champ. On garde l'harmonisation des boutons MAIS on empêche le repli :
   le champ e-mail devient élastique (il se rétrécit au lieu de pousser le bouton à la ligne). */
.rangee.mt-2{align-items:center;}
.rangee.mt-2 form{margin:0;}
.rangee.mt-2 form.rangee{
  align-items:center;flex-wrap:nowrap;   /* champ + bouton restent sur LA MÊME ligne */
  flex:1 1 22rem;min-width:0;            /* le formulaire s'adapte à la place disponible */
}
.rangee.mt-2 form.rangee input[type=email],
.rangee.mt-2 form.rangee input[type=text]{
  flex:1 1 8rem;min-width:0;             /* le champ absorbe la contrainte, pas le bouton */
}

/* --- Correctif 2026-09-07 : alignement des badges d'état (cartes EPI / habilitations) -----
   `.ligne-ref` répartit ses enfants avec `space-between`. Avec TROIS éléments
   (titre + « verrouillé » + « RAS »), le badge du milieu se déplaçait selon la longueur du
   titre : « Septembre 2026 » et « Août 2026 » ne donnaient pas le même alignement.
   Le titre absorbe désormais l'espace disponible : les badges sont TOUJOURS groupés et
   collés au bord DROIT, quelle que soit la longueur du mois. */
.ligne-ref > strong:first-child{flex:1 1 auto;min-width:0;}

/* --- Correctif 2026-09-07 : bouton aligné sur un menu déroulant ---------------------------
   Cas « Attribuer à » : le <select> est imbriqué DANS le <label>, qui occupe donc deux lignes
   (texte au-dessus, menu en dessous). Avec `align-items:center`, le bouton se centrait sur
   l'ENSEMBLE des deux lignes et flottait au-dessus du menu.
   On empile proprement le libellé et son menu, puis on aligne la ligne par le BAS : le bouton
   se retrouve exactement sur la même base que le menu déroulant. */
form.rangee > label.label-normal{display:inline-flex;flex-direction:column;gap:.3rem;}
form.rangee:has(> label.label-normal select){align-items:flex-end;}

/* Hauteur STRICTEMENT identique entre le menu déroulant et le bouton qui l'accompagne :
   le bouton-icône est figé à 42px (--ctrl-h) alors que le <select> faisait ~45px (padding
   vertical). Même alignés par le bas, la différence de 3px restait visible. On aligne les
   deux sur la hauteur de contrôle commune, et on centre le texte du menu verticalement. */
form.rangee:has(> label.label-normal select) select{
  height:var(--ctrl-h);padding-top:0;padding-bottom:0;line-height:calc(var(--ctrl-h) - 2px);
}

/* ============================== 24. CHAMPS TECHNIQUES PILOTÉS PAR LE MODÈLE (CC-115)
   Le bon d'intervention est UN SEUL document : sur PC il tend vers la page A4, sur smartphone les
   mêmes blocs, dans le même ordre, se replient à la largeur de l'écran. Pas de « version mobile »
   séparée — une grille fluide (auto-fit) suffit. */
.ct-grille{display:grid;gap:.5rem .9rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));}
.ct-champ{display:flex;flex-direction:column;gap:.25rem;min-width:0;}
.ct-champ > label{font-weight:600;}
.ct-case{display:flex;align-items:center;gap:.45rem;min-height:var(--ctrl-h);}
.ct-case-res{display:flex;flex-direction:row;align-items:center;gap:.5rem;flex-wrap:wrap;}
.ct-case-res > label{flex:1 1 auto;min-width:0;}
.ct-case-res select{flex:0 0 auto;width:auto;min-width:6.5rem;}
.ct-mesure-saisie{display:flex;align-items:center;gap:.4rem;}
.ct-mesure-saisie input{flex:1 1 auto;min-width:0;}
.ct-unite{flex:0 0 auto;color:var(--qo-muted);font-weight:600;}
.ct-unite-saisie{flex:0 0 5.5rem;max-width:5.5rem;}

/* Configurateur : édition des sections et de leurs champs. */
.ct-sec{border-top:1px solid var(--qo-border);padding-top:.6rem;margin-top:.8rem;}
.ct-sec h3{margin:.2rem 0 .5rem;}
.ct-table{width:100%;border-collapse:collapse;}
.ct-table th{text-align:left;font-size:.82rem;color:var(--qo-muted);font-weight:600;padding:.2rem .35rem;}
.ct-table td{padding:.2rem .35rem;vertical-align:middle;border-top:1px solid var(--qo-border);}
.ct-inline{display:flex;align-items:center;gap:.35rem;}
.ct-inline input[type=text]{min-width:8rem;}
.ct-ajout{display:flex;flex-wrap:wrap;gap:.4rem;align-items:center;margin-top:.6rem;}
.ct-suppr-sec{margin-top:.4rem;}
/* Aperçu : les champs tels qu'ils seront remplis (même ordre que le BI et le PDF). */
.bi-champs{display:flex;flex-wrap:wrap;gap:.15rem .8rem;}
.bi-ch{white-space:nowrap;}
.bi-res{color:var(--qo-muted);font-style:italic;}
@media (max-width:640px){
  .ct-table,.ct-table tbody,.ct-table tr,.ct-table td{display:block;width:100%;}
  .ct-table th{display:none;}
  .ct-table td{border-top:none;padding:.15rem 0;}
  .ct-table tr{border-top:1px solid var(--qo-border);padding:.4rem 0;}
  .bi-ch{white-space:normal;}
}

/* ====================== 25. CONNECTEURS CRM/ERP — liste générique (CC-116)
   Une carte par connecteur, Axonaut compris : même identité visuelle, même feu tricolore.
   Les états réutilisent les couleurs d'état du design system (badges is-ok / is-danger). */
.cx-titre{margin:1.4rem 0 .4rem;}
.cx-carte{padding:.9rem 1rem;}
.cx-tete{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;justify-content:space-between;}
.cx-nom{margin:0;font-size:1.05rem;}
.cx-pays{font-weight:400;}
.cx-statut{font-size:.7rem;font-weight:700;letter-spacing:.04em;padding:.1rem .35rem;
  border-radius:var(--radius-sm);background:var(--qo-surface-sub);color:var(--qo-muted);vertical-align:middle;}
.cx-etat{font-weight:600;white-space:nowrap;}
.cx-ok{color:var(--ok);}
.cx-ko{color:var(--danger,#b00020);}
.cx-warn{color:var(--qo-gold,#928340);}
.cx-off{color:var(--qo-muted);}
.cx-meta{margin:.35rem 0 .2rem;}
.cx-msg{color:var(--danger,#b00020);}
.cx-reglages{margin-top:.4rem;}
.cx-reglages > summary{cursor:pointer;font-weight:600;padding:.35rem 0;min-height:var(--ctrl-h);
  display:flex;align-items:center;}
.cx-form{display:flex;flex-direction:column;gap:.3rem;margin:.4rem 0;}
.cx-ligne{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;margin:.4rem 0;}
.cx-actions{display:flex;gap:.5rem;flex-wrap:wrap;margin-top:.3rem;}
.cx-aide{margin:0 0 .3rem;}
.cx-req{color:var(--danger,#b00020);}
@media (max-width:640px){
  .cx-tete{flex-direction:column;align-items:flex-start;gap:.25rem;}
  .cx-form input,.cx-form select{width:100%;}
}

/* ================================ 26. STOCK VÉHICULE (CC-116)
   Pensé pour le SMARTPHONE d'abord : une ligne par article, quantité et pastille lisibles d'un
   coup d'œil, zone tactile large (une seule main). Le même balisage s'étale sur grand écran. */
.stk-liste{padding:.2rem .4rem;}
.stk-ligne{border-top:1px solid var(--qo-border);}
.stk-ligne:first-child{border-top:none;}
.stk-tete{display:flex;align-items:center;gap:.5rem;padding:.6rem .3rem;cursor:pointer;
  min-height:48px;flex-wrap:wrap;}
.stk-past{font-size:1rem;flex:0 0 auto;}
.stk-qte{font-weight:700;font-size:1.15rem;min-width:2.2rem;text-align:right;}
.stk-unite{color:var(--qo-muted);font-size:.85rem;}
.stk-nom{flex:1 1 auto;min-width:0;}
.stk-tag{background:var(--qo-surface-sub);border-radius:var(--radius-sm);padding:.1rem .4rem;
  font-size:.78rem;color:var(--qo-muted);white-space:nowrap;}
.stk-chevron{color:var(--qo-muted);flex:0 0 auto;}
.stk-detail{padding:.2rem .3rem .8rem;}
.stk-form{display:flex;flex-direction:column;gap:.3rem;margin:.5rem 0;
  padding:.5rem;background:var(--qo-surface-sub);border-radius:var(--radius-sm);}
.stk-form-ligne{flex-direction:row;flex-wrap:wrap;align-items:center;}
.stk-alerte{border-left:6px solid var(--danger,#b00020);}
.stk-hist{width:100%;border-collapse:collapse;}
.stk-hist th{text-align:left;font-size:.8rem;color:var(--qo-muted);padding:.25rem .4rem;}
.stk-hist td{padding:.3rem .4rem;border-top:1px solid var(--qo-border);vertical-align:top;}
.stk-neg{color:var(--danger,#b00020);font-weight:600;white-space:nowrap;}
.stk-pos{color:var(--ok);font-weight:600;white-space:nowrap;}
.stk-sync-ko{color:var(--qo-gold,#928340);font-size:.8rem;}
.stk-hist-repli > summary{cursor:pointer;font-weight:600;padding:.4rem 0;min-height:var(--ctrl-h);
  display:flex;align-items:center;}
/* Dossier technicien : navigation par sections (extensible sans changer le gabarit). */
.dossier-onglets{display:flex;gap:.4rem;flex-wrap:wrap;margin:.6rem 0 1rem;}
.dossier-onglet{padding:.4rem .7rem;background:var(--qo-surface-sub);border-radius:var(--radius-sm);
  text-decoration:none;min-height:var(--ctrl-h);display:inline-flex;align-items:center;}
@media (max-width:640px){
  .stk-hist,.stk-hist tbody,.stk-hist tr,.stk-hist td{display:block;width:100%;}
  .stk-hist th{display:none;}
  .stk-hist td{border-top:none;padding:.15rem .2rem;}
  .stk-hist tr{border-top:1px solid var(--qo-border);padding:.45rem 0;}
  .stk-form-ligne > *{width:100%;}
}

/* ============================ 27. FICHE DU TECHNICIEN (CC-117)
   Objectif : comprendre le profil en quelques secondes. Une liste de vignettes (visage, nom,
   feu), puis une fiche avec bandeau, chiffres clés, trois pastilles d'état et le détail replié.
   Tout en CSS : rien à charger, lisible sur un téléphone tenu d'une main. */

/* ---- Liste : vignettes cliquables ---- */
.dt-vignettes{display:grid;gap:.8rem;grid-template-columns:repeat(auto-fill,minmax(min(100%,190px),1fr));}
.dt-vignette{position:relative;display:flex;flex-direction:column;align-items:center;gap:.25rem;
  padding:1.1rem .8rem 1rem;background:var(--qo-surface,#fff);border:1px solid var(--qo-border);
  border-radius:var(--radius-md,12px);text-decoration:none;color:inherit;
  transition:transform .12s ease, box-shadow .12s ease;border-top:4px solid var(--qo-border);}
.dt-vignette:hover,.dt-vignette:focus-visible{transform:translateY(-2px);
  box-shadow:0 6px 18px rgba(50,72,96,.14);}
.dt-vignette-rouge{border-top-color:var(--danger,#b00020);}
.dt-vignette-orange{border-top-color:var(--qo-gold,#928340);}
.dt-vignette-vert{border-top-color:var(--ok,#2e7d32);}
.dt-vignette-feu{position:absolute;top:.5rem;right:.6rem;font-size:.95rem;}
.dt-vignette-avatar{width:60px;height:60px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;background:var(--qo-navy,#324860);color:#fff;font-weight:700;font-size:1.25rem;
  letter-spacing:.04em;margin-bottom:.2rem;}
.dt-vignette-nom{font-weight:700;text-align:center;line-height:1.2;}
.dt-vignette-role{font-size:.8rem;color:var(--qo-muted);}
.dt-vignette-pied{font-size:.78rem;color:var(--qo-muted);margin-top:.35rem;
  padding-top:.35rem;border-top:1px solid var(--qo-border);width:100%;text-align:center;}

/* ---- Fiche : bandeau ---- */
.dt-heros{background:linear-gradient(135deg,var(--qo-navy,#324860) 0%,#22344a 100%);color:#fff;
  border-radius:var(--radius-md,12px);padding:1.1rem 1.2rem;margin-bottom:.9rem;}
.dt-heros-haut{display:flex;align-items:center;gap:.9rem;flex-wrap:wrap;}
.dt-avatar{flex:0 0 auto;width:66px;height:66px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;font-size:1.5rem;font-weight:700;letter-spacing:.04em;
  background:rgba(255,255,255,.14);color:#fff;border:2px solid rgba(255,255,255,.35);}
.dt-heros-id{flex:1 1 200px;min-width:0;}
.dt-nom{margin:0;font-size:1.6rem;line-height:1.15;color:#fff;text-transform:uppercase;letter-spacing:.01em;}
.dt-sous-nom{margin:.15rem 0 0;font-size:.86rem;color:rgba(255,255,255,.78);}
.dt-statut{flex:0 0 auto;font-size:.75rem;font-weight:700;padding:.2rem .55rem;border-radius:999px;
  background:rgba(255,255,255,.16);}
.dt-statut-on{color:#8ff0a4;}
.dt-statut-off{color:rgba(255,255,255,.6);}
.dt-stats{display:grid;gap:.5rem;grid-template-columns:repeat(auto-fit,minmax(78px,1fr));
  margin-top:.9rem;padding-top:.8rem;border-top:1px solid rgba(255,255,255,.18);}
.dt-stat{display:flex;flex-direction:column;align-items:center;text-align:center;}
.dt-stat-n{font-size:1.8rem;font-weight:700;line-height:1;}
.dt-stat-l{font-size:.72rem;color:rgba(255,255,255,.72);text-transform:uppercase;letter-spacing:.03em;margin-top:.2rem;}

/* ---- Trois pastilles d'état ---- */
.dt-etats{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,150px),1fr));
  margin-bottom:.9rem;}
.dt-etat{display:flex;align-items:center;gap:.5rem;padding:.7rem .85rem;background:var(--qo-surface,#fff);
  border:1px solid var(--qo-border);border-radius:var(--radius-sm);text-decoration:none;color:inherit;
  min-height:var(--ctrl-h);}
.dt-etat-pastille{width:12px;height:12px;border-radius:50%;flex:0 0 auto;background:var(--qo-muted);}
.dt-vert .dt-etat-pastille{background:var(--ok,#2e7d32);}
.dt-orange .dt-etat-pastille{background:var(--qo-gold,#928340);}
.dt-rouge .dt-etat-pastille{background:var(--danger,#b00020);}
.dt-etat-nom{font-weight:600;flex:1 1 auto;}
.dt-etat-info{color:var(--qo-muted);font-size:.85rem;white-space:nowrap;}

/* ---- Période ---- */
.dt-periodes{display:flex;gap:.3rem;flex-wrap:wrap;margin:0 0 .9rem;}
.dt-periode{padding:.3rem .65rem;border-radius:999px;background:var(--qo-surface-sub);
  text-decoration:none;font-size:.85rem;font-weight:600;min-height:34px;display:inline-flex;align-items:center;}
.dt-periode-on{background:var(--qo-navy,#324860);color:#fff;}

/* ---- Activité ---- */
.dt-duo{display:grid;gap:.8rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr));}
.dt-carte{padding:.9rem 1rem;}
.dt-titre-carte{margin:0 0 .6rem;font-size:.82rem;text-transform:uppercase;letter-spacing:.05em;
  color:var(--qo-muted);}
.dt-barre{margin:.45rem 0;}
.dt-barre-tete{display:flex;justify-content:space-between;gap:.5rem;font-size:.9rem;}
.dt-barre-n{font-weight:700;}
.dt-barre-fond{height:9px;background:var(--qo-surface-sub);border-radius:5px;overflow:hidden;margin-top:.22rem;}
.dt-barre-jauge{height:100%;background:linear-gradient(90deg,var(--qo-navy,#324860),#4a678a);border-radius:5px;}
.dt-chrono{display:flex;align-items:flex-end;gap:.3rem;height:104px;overflow-x:auto;padding-top:.3rem;}
.dt-chrono-col{flex:1 0 22px;display:flex;flex-direction:column;justify-content:flex-end;
  align-items:center;height:100%;gap:.2rem;}
.dt-chrono-barre{width:100%;background:var(--qo-gold,#928340);border-radius:3px 3px 0 0;min-height:4px;}
.dt-chrono-mois{font-size:.68rem;color:var(--qo-muted);}
.dt-tags{display:flex;flex-wrap:wrap;gap:.35rem;}
.dt-tag{background:var(--qo-surface-sub);border-radius:999px;padding:.22rem .6rem;font-size:.85rem;}

/* ---- Sections repliées ---- */
.dt-section{background:var(--qo-surface,#fff);border:1px solid var(--qo-border);
  border-radius:var(--radius-sm);margin-top:.7rem;}
.dt-section-titre{cursor:pointer;font-weight:700;padding:.75rem 1rem;min-height:var(--ctrl-h);
  display:flex;align-items:center;gap:.5rem;list-style:none;}
.dt-section-titre::-webkit-details-marker{display:none;}
.dt-section-titre::after{content:'▸';margin-left:auto;color:var(--qo-muted);}
.dt-section[open] > .dt-section-titre::after{content:'▾';}
.dt-section-corps{padding:0 1rem 1rem;}
.dt-ico{font-size:1.05rem;}
.dt-sous{margin:.8rem 0 .3rem;font-size:.95rem;}
.dt-note{margin:.4rem 0 0;}
.dt-liste{margin:.2rem 0 .5rem;padding-left:1.1rem;}
.dt-lien{margin-left:.4rem;}
.dt-mini-stats{display:flex;gap:1.1rem;flex-wrap:wrap;margin-bottom:.5rem;}
.dt-mini-stats b{font-size:1.15rem;}
.dt-alerte{color:var(--danger,#b00020);}
.dt-inline{display:flex;gap:.3rem;align-items:center;flex-wrap:wrap;}
.dt-inline input[type=text]{min-width:7rem;}
.dt-table{width:100%;border-collapse:collapse;}
.dt-table th{text-align:left;font-size:.78rem;color:var(--qo-muted);padding:.25rem .35rem;font-weight:600;}
.dt-table td{padding:.32rem .35rem;border-top:1px solid var(--qo-border);vertical-align:middle;}
.dt-badge{font-size:.76rem;font-weight:700;padding:.1rem .45rem;border-radius:var(--radius-sm);
  background:var(--qo-surface-sub);white-space:nowrap;}
.dt-ok{color:var(--ok,#2e7d32);}
.dt-ko{color:var(--danger,#b00020);}
.dt-warn{color:var(--qo-gold,#928340);}
.dt-neg{color:var(--danger,#b00020);font-weight:600;}
.dt-pos{color:var(--ok,#2e7d32);font-weight:600;}
.dt-recherche{display:flex;gap:.4rem;margin-bottom:.6rem;flex-wrap:wrap;}
.dt-recherche input{flex:1 1 180px;min-width:0;}
.dt-pagination{display:flex;gap:.6rem;align-items:center;justify-content:center;margin-top:.6rem;}
.dt-transparence{margin-top:1.3rem;padding:.6rem .8rem;background:var(--qo-surface-sub);
  border-radius:var(--radius-sm);border-left:4px solid var(--qo-gold,#928340);font-size:.82rem;}

@media (max-width:640px){
  .dt-nom{font-size:1.3rem;}
  .dt-avatar{width:56px;height:56px;font-size:1.25rem;}
  .dt-stat-n{font-size:1.5rem;}
  .dt-vignettes{grid-template-columns:repeat(auto-fill,minmax(min(100%,150px),1fr));gap:.6rem;}
  .dt-table,.dt-table tbody,.dt-table tr,.dt-table td{display:block;width:100%;}
  .dt-table th{display:none;}
  .dt-table td{border-top:none;padding:.12rem .2rem;}
  .dt-table tr{border-top:1px solid var(--qo-border);padding:.45rem 0;}
  .dt-chrono{height:86px;}
}

/* ============================ 28. ESPACE PERSONNEL DU TECHNICIEN (CC-118)
   Fiche de progression : on doit comprendre en cinq secondes qui on est, où on en est et quelle
   est la prochaine étape. Smartphone d'abord — une colonne, gros chiffres, zones tactiles larges.
   Progression personnelle : aucun classement, aucune couleur « mauvais élève ». */

/* ---- Profil + niveau ---- */
.esp-heros{background:linear-gradient(135deg,var(--qo-navy,#324860) 0%,#22344a 100%);color:#fff;
  border-radius:var(--radius-md,12px);padding:1.1rem 1.2rem;margin-bottom:.8rem;}
.esp-tete{display:flex;align-items:center;gap:.9rem;flex-wrap:wrap;}
.esp-photo-form{flex:0 0 auto;margin:0;}
.esp-photo{position:relative;display:flex;align-items:center;justify-content:center;
  width:72px;height:72px;border-radius:50%;overflow:hidden;cursor:pointer;
  background:rgba(255,255,255,.14);border:2px solid rgba(255,255,255,.35);
  font-size:1.6rem;font-weight:700;letter-spacing:.03em;}
.esp-photo img{width:100%;height:100%;object-fit:cover;}
.esp-photo input[type=file]{position:absolute;inset:0;opacity:0;cursor:pointer;}
.esp-id{flex:1 1 180px;min-width:0;}
.esp-nom{margin:0;font-size:1.5rem;line-height:1.15;color:#fff;text-transform:uppercase;}
.esp-fonction{margin:.1rem 0 0;color:rgba(255,255,255,.78);font-size:.9rem;}
.esp-niveau{margin-top:1rem;}
.esp-niveau-tete{display:flex;justify-content:space-between;align-items:baseline;gap:.6rem;
  flex-wrap:wrap;margin-bottom:.35rem;}
.esp-niveau-nom{font-size:1.15rem;font-weight:700;letter-spacing:.02em;}
.esp-niveau-vers{font-size:.82rem;color:rgba(255,255,255,.8);}
.esp-jauge{height:12px;background:rgba(255,255,255,.18);border-radius:6px;overflow:hidden;}
.esp-jauge-remplie{height:100%;background:linear-gradient(90deg,var(--qo-gold,#928340),#c4ae5e);
  border-radius:6px;transition:width .4s ease;}
.esp-en-cours{margin:.9rem 0 0;color:rgba(255,255,255,.85);font-size:.9rem;}

/* Détail du niveau : le technicien voit de quoi il est fait. */
.esp-detail-niveau{background:var(--qo-surface,#fff);border:1px solid var(--qo-border);
  border-radius:var(--radius-sm);margin-bottom:.8rem;}
.esp-detail-niveau > summary{cursor:pointer;padding:.7rem 1rem;font-weight:600;
  min-height:var(--ctrl-h);display:flex;align-items:center;}
.esp-briques{padding:0 1rem .3rem;}
.esp-brique{margin:.5rem 0;}
.esp-brique-tete{display:flex;justify-content:space-between;gap:.5rem;font-size:.9rem;}
.esp-brique-n{font-weight:700;}
.esp-jauge-fine{height:8px;background:var(--qo-surface-sub);}
.esp-jauge-fine .esp-jauge-remplie{background:var(--qo-navy,#324860);}
.esp-note{margin:.3rem 0 .8rem;font-size:.82rem;}

/* ---- Prochaine étape : la carte la plus importante ---- */
.esp-etape{border-left:5px solid var(--qo-gold,#928340);}
.esp-etape-urgente{border-left-color:var(--danger,#b00020);}
.esp-etape-titre{margin:0 0 .35rem;font-size:1.05rem;}
.esp-etape-objet{margin:0 0 .5rem;font-size:1rem;}
.esp-etape-action{margin-top:.7rem;}
.esp-carte-titre{margin:0 0 .6rem;font-size:1rem;}

/* ---- Cartes-liens vers les modules ---- */
.esp-liens{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));
  margin-bottom:.8rem;}
.esp-lien{display:flex;align-items:center;gap:.7rem;text-decoration:none;color:inherit;padding:.85rem 1rem;}
.esp-lien:hover{box-shadow:0 4px 14px rgba(50,72,96,.12);}
.esp-lien-alerte{border-left:5px solid var(--qo-gold,#928340);}
.esp-lien-ico{font-size:1.5rem;flex:0 0 auto;}
.esp-lien-corps{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;}
.esp-lien-titre{font-size:.82rem;color:var(--qo-muted);}
.esp-lien-valeur{font-weight:700;font-size:1.05rem;}
.esp-lien-detail{font-size:.82rem;color:var(--qo-gold,#928340);}
.esp-lien-fleche{color:var(--qo-muted);font-size:1.3rem;}

/* ---- Badges ---- */
.esp-badges{display:flex;flex-wrap:wrap;gap:.5rem;}
.esp-badge{display:flex;flex-direction:column;align-items:center;gap:.15rem;padding:.6rem .5rem;
  border-radius:var(--radius-sm);background:var(--qo-surface-sub);min-width:92px;text-align:center;}
.esp-badge-on{background:linear-gradient(160deg,#fdf6e0,#f3e7c0);}
.esp-badge-off{opacity:.55;}
.esp-badge-ico{font-size:1.4rem;line-height:1;}
.esp-badge-nom{font-size:.74rem;font-weight:600;}
.esp-badge-reste{font-size:.7rem;color:var(--qo-muted);}

/* ---- Activité / évolution ---- */
.esp-duo{display:grid;gap:.7rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr));}
.esp-evo-n{font-size:2rem;font-weight:700;margin:0;line-height:1;}
.esp-hausse{color:var(--ok,#2e7d32);font-weight:700;}
.esp-baisse{color:var(--qo-muted);font-weight:700;}
.esp-comp-niveau{font-weight:700;color:var(--qo-navy,#324860);}

/* ---- Interventions / formations / demandes ---- */
.esp-interv{list-style:none;margin:0;padding:0;}
.esp-interv li{display:flex;gap:.6rem;align-items:baseline;padding:.4rem 0;
  border-top:1px solid var(--qo-border);}
.esp-interv li:first-child{border-top:none;}
.esp-interv-date{flex:0 0 auto;color:var(--qo-muted);font-size:.85rem;min-width:3.2rem;}
.esp-interv-obj{flex:1 1 auto;min-width:0;}
.esp-interv-etat{flex:0 0 auto;}
.esp-demandes{list-style:none;margin:0 0 .5rem;padding:0;}
.esp-demandes li{padding:.45rem 0;border-top:1px solid var(--qo-border);}
.esp-demandes li:first-child{border-top:none;}
.esp-statut{font-size:.72rem;font-weight:700;padding:.1rem .45rem;border-radius:999px;
  background:var(--qo-surface-sub);margin-right:.4rem;}
.esp-statut-acceptee,.esp-statut-planifiee{color:var(--ok,#2e7d32);}
.esp-statut-terminee{color:var(--qo-muted);}
.esp-statut-refusee{color:var(--danger,#b00020);}
.esp-demande-objet{font-weight:600;}
.esp-nouvelle-demande > summary{cursor:pointer;font-weight:600;padding:.4rem 0;
  min-height:var(--ctrl-h);display:flex;align-items:center;}
.esp-form{display:flex;flex-direction:column;gap:.3rem;margin-top:.4rem;}
.esp-documents{background:var(--qo-surface,#fff);border:1px solid var(--qo-border);
  border-radius:var(--radius-sm);margin-top:1rem;padding:0 1rem;}
.esp-documents > summary{cursor:pointer;font-weight:700;padding:.8rem 0;
  min-height:var(--ctrl-h);display:flex;align-items:center;}

@media (max-width:640px){
  .esp-nom{font-size:1.25rem;}
  .esp-photo{width:60px;height:60px;font-size:1.3rem;}
  .esp-evo-n{font-size:1.7rem;}
  .esp-badge{min-width:78px;}
}

/* ============================ 29. STOCK VÉHICULE — TABLEAU (CC-119)
   Un tableau, lisible en cinq secondes. Sur téléphone, chaque ligne se déplie en bloc étiqueté
   (les en-têtes deviennent des libellés via `data-libelle`) : pas de défilement horizontal. */
.stk-carte{padding:.4rem .6rem;}
.stk-titre{margin:1.2rem 0 .5rem;font-size:1.05rem;}
.stk-table{width:100%;border-collapse:collapse;}
.stk-table th{text-align:left;font-size:.78rem;text-transform:uppercase;letter-spacing:.03em;
  color:var(--qo-muted);padding:.4rem .5rem;font-weight:600;}
.stk-table td{padding:.55rem .5rem;border-top:1px solid var(--qo-border);vertical-align:middle;}
.stk-table .stk-num{text-align:right;white-space:nowrap;}
.stk-produit{font-weight:600;}
.stk-qte{font-size:1.1rem;font-weight:700;}
.stk-unite{font-size:.8rem;font-weight:400;color:var(--qo-muted);}
.stk-etat{font-weight:600;white-space:nowrap;}
.stk-correct{color:var(--ok,#2e7d32);}
.stk-faible{color:var(--qo-gold,#928340);}
.stk-epuise{color:var(--danger,#b00020);}
.stk-ligne-faible{background:rgba(146,131,64,.06);}
.stk-ligne-epuise{background:rgba(176,0,32,.06);}
.stk-ligne-seuils td{border-top:none;padding-top:0;}
.stk-alerte{border-left:5px solid var(--qo-gold,#928340);}
.stk-neg{color:var(--danger,#b00020);font-weight:700;}
.stk-pos{color:var(--ok,#2e7d32);font-weight:700;}
.stk-non-confirme{display:inline-block;margin-left:.35rem;padding:.05rem .35rem;border-radius:999px;
  background:var(--qo-surface-sub);color:var(--qo-muted);font-size:.72rem;font-weight:600;}
.stk-inline{display:flex;gap:.4rem;align-items:center;flex-wrap:wrap;margin:.3rem 0;}
.stk-inline label{display:inline-flex;align-items:center;gap:.3rem;}
/* CC-151 — Le champ « Semaine » entre enfin dans le contrat de hauteur ci-dessus : il était
   le seul type oublié, donc rendu natif (~24 px) à côté d'un bouton de 42 px. Contrepartie du
   width:100% qu'il hérite maintenant : dans une rangée en flex-wrap, une taille de base pleine
   largeur lui prendrait une ligne entière. On la lui retire — mais AU-DESSUS de 640 px
   seulement, sinon cette règle (0,1,1) battrait `.stk-inline > *` (0,1,0) et le champ ne
   passerait plus en pleine largeur sur téléphone. */
@media (min-width:641px){
  .stk-inline input[type=week]{width:auto;flex:0 0 auto;}
}
.stk-actions{margin-top:.6rem;}
.stk-note{margin:.1rem 0 .6rem;}
.stk-correction{margin-top:.6rem;}
.stk-correction > summary{cursor:pointer;font-weight:600;padding:.5rem 0;
  min-height:var(--ctrl-h);display:flex;align-items:center;}

@media (max-width:640px){
  .stk-table thead{display:none;}
  .stk-table,.stk-table tbody,.stk-table tr,.stk-table td{display:block;width:100%;}
  .stk-table tr{border-top:2px solid var(--qo-border);padding:.5rem 0;}
  .stk-table td{border-top:none;padding:.2rem .3rem;display:flex;justify-content:space-between;
    align-items:center;gap:.6rem;min-height:34px;}
  .stk-table td::before{content:attr(data-libelle);font-size:.78rem;color:var(--qo-muted);
    text-transform:uppercase;letter-spacing:.03em;}
  .stk-table .stk-num{text-align:right;}
  .stk-produit{font-size:1.02rem;}
  .stk-inline > *{width:100%;}
}

/* Matériel utilisé dans le bon d'intervention (CC-119) — même logique responsive que le stock. */
.mat-table{width:100%;border-collapse:collapse;}
.mat-table th{text-align:left;font-size:.78rem;color:var(--qo-muted);padding:.3rem .4rem;font-weight:600;}
.mat-table td{padding:.4rem .4rem;border-top:1px solid var(--qo-border);vertical-align:middle;}
.mat-table .mat-num{text-align:right;white-space:nowrap;}
.mat-table input{width:4.5rem;text-align:right;}
@media (max-width:640px){
  .mat-table thead{display:none;}
  .mat-table,.mat-table tbody,.mat-table tr,.mat-table td{display:block;width:100%;}
  .mat-table tr{border-top:2px solid var(--qo-border);padding:.45rem 0;}
  .mat-table td{border-top:none;padding:.15rem .2rem;display:flex;justify-content:space-between;
    align-items:center;gap:.6rem;min-height:34px;}
  .mat-table td::before{content:attr(data-libelle);font-size:.78rem;color:var(--qo-muted);}
  .mat-table input{width:5rem;}
}

/* Contrôles EPI signés : une liste déroulante plutôt qu'une carte par mois (CC-120).
   L'écran ne s'allonge plus avec l'ancienneté du technicien, et deux boutons suffisent. */
.epi-choix .epi-select{width:100%;max-width:26rem;height:var(--ctrl-h);}
.epi-choix .rangee{gap:.5rem;flex-wrap:wrap;}
.epi-choix p{margin:.2rem 0 .4rem;}
@media (max-width:640px){ .epi-choix .rangee > .bouton{flex:1 1 45%;} }

/* Feuille d'heure du bon d'intervention (CC-121) — saisie en quelques secondes sur un téléphone.
   La durée est en lecture seule : elle se calcule, elle ne se tape pas. */
.fh-carte{border:1px solid var(--qo-border);border-radius:var(--radius-sm);padding:.6rem .9rem;margin:.6rem 0;}
.fh-carte > legend{font-weight:700;padding:0 .35rem;}
/* QUATRE champs, jamais trois. En `auto-fit`, la grille produisait selon la largeur disponible
   4, 3, 2 ou 1 colonnes — et a 3 on obtenait une rangee pleine plus une orpheline. C est tres
   exactement le « pas aligne » que l ecran donnait a voir. */
.fh-grille{display:grid;gap:.6rem .8rem;grid-template-columns:repeat(2,minmax(0,1fr));}
@media (min-width:900px){ .fh-grille{grid-template-columns:repeat(4,minmax(0,1fr));} }
.fh-duree{font-weight:700;background:var(--qo-surface-sub);}
@media (max-width:560px){ .fh-grille > .fh-pause{grid-column:1 / -1;} }

/* ============================================================ 30. Demande anticipée (CC-122)
   Une ligne « anticipée » n'est pas une alerte : le stock va bien, le besoin est à venir.
   Elle se signale donc discrètement, sans reprendre le rouge/orange des états de stock. */
.stk-tag{display:inline-block;margin-left:.4rem;padding:.05rem .4rem;border-radius:.6rem;
  font-size:.72rem;letter-spacing:.02em;background:var(--qo-surface-2,#eef1f6);color:var(--qo-muted);
  border:1px solid var(--qo-border);vertical-align:middle;}
.stk-anticipe .stk-produit,.stk-anticipe td:first-child{color:var(--qo-muted);}

/* ---- Vue globale des stocks (CC-122) : outil d'affectation, lecture par matériel puis détenteur. */
.stk-groupe-tete{display:flex;align-items:baseline;justify-content:space-between;gap:.6rem;
  flex-wrap:wrap;margin-bottom:.3rem;}
.stk-total{font-size:.9rem;color:var(--qo-muted);white-space:nowrap;}
.stk-recherche{gap:.5rem;flex-wrap:wrap;}
.stk-recherche input[type=search]{min-width:min(100%,18rem);flex:1 1 12rem;}
.stk-zeros{display:inline-flex;align-items:center;gap:.35rem;font-size:.85rem;color:var(--qo-muted);}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0,0,0,0);white-space:nowrap;border:0;}

/* ============================================================ 31. Journal de traçabilité (CC-122)
   Beaucoup de lignes, lues en diagonale : la date et l'acteur guident l'œil, le reste s'efface. */
.jrn-filtres{display:grid;gap:.6rem .8rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,11rem),1fr));
  align-items:end;}
.jrn-filtres .jrn-large{grid-column:1/-1;}
.jrn-filtres .jrn-actions{display:flex;gap:.5rem;align-items:center;}
.jrn-table td{vertical-align:top;}
.jrn-quand{white-space:nowrap;font-variant-numeric:tabular-nums;}
.jrn-action{font-size:.78rem;background:var(--qo-surface-2,#eef1f6);padding:.05rem .35rem;
  border-radius:.3rem;border:1px solid var(--qo-border);}
.jrn-details{font-size:.8rem;margin-top:.15rem;word-break:break-word;}
.jrn-avant{color:var(--qo-muted);text-decoration:line-through;}
.jrn-apres{font-weight:600;}
.jrn-pagination{display:flex;gap:.8rem;align-items:center;justify-content:center;margin:.8rem 0;}

/* ============================================================ 32. Pastilles d'alerte (CC-122)
   Petites, jamais clignotantes : elles signalent, elles ne réclament pas. Le chiffre compte
   autant que la couleur — « 3 » se lit d'un coup d'œil, une couleur seule laisse deviner. */
.cloche{display:inline-flex;align-items:center;gap:.15rem;margin-left:.35rem;font-size:.72rem;
  line-height:1;vertical-align:middle;}
.cloche-n{font-weight:700;font-variant-numeric:tabular-nums;}
.cloche-rouge .cloche-n{color:var(--qo-danger,#b3261e);}
.cloche-orange .cloche-n{color:var(--qo-warn,#a25b00);}
/* Panneau des alertes (accueil) : une ligne = une action, chacune cliquable. */
.alertes-panneau{display:grid;gap:.4rem;margin:.2rem 0 .6rem;}
.alerte-ligne{display:flex;align-items:center;gap:.5rem;padding:.5rem .7rem;border-radius:.5rem;
  border:1px solid var(--qo-border);background:var(--qo-surface,#fff);text-decoration:none;
  color:inherit;}
.alerte-ligne:hover{border-color:var(--qo-accent,#1b3a6b);}
.alerte-rouge{border-left:3px solid var(--qo-danger,#b3261e);}
.alerte-orange{border-left:3px solid var(--qo-warn,#a25b00);}
.alerte-fleche{margin-left:auto;color:var(--qo-muted);}

/* ---- Stock techniciens : le total d'abord, les détenteurs au clic (CC-123). ---------------- */
.stk-deplier{background:none;border:0;padding:0;font:inherit;color:inherit;cursor:pointer;
  text-align:left;display:inline-flex;align-items:baseline;gap:.35rem;}
.stk-deplier:hover{color:var(--qo-accent,#1b3a6b);}
.stk-detenteurs td{background:var(--qo-surface-2,#f2f4f8);padding:.5rem .8rem;}
.stk-qui{list-style:none;margin:0;padding:0;display:grid;gap:.25rem .9rem;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,15rem),1fr));}
.stk-qui li{display:flex;align-items:baseline;gap:.45rem;padding:.15rem 0;}
.stk-qui-n{font-family:ui-monospace,monospace;font-weight:600;font-variant-numeric:tabular-nums;}
.stk-qui-epuise .stk-qui-n{color:var(--qo-danger,#b3261e);}
.stk-qui-faible .stk-qui-n{color:var(--qo-warn,#a25b00);}
.stk-resume{margin:.2rem 0 .7rem;}
.stk-global input[type=text]{max-width:5rem;}
.stk-derogation .stk-produit{font-style:italic;}

/* ---- Échanges entre techniciens (CC-123) : ce qui attend une réponse se voit en premier. --- */
.stk-echanges{list-style:none;margin:.4rem 0 .8rem;padding:0;display:grid;gap:.4rem;}
.stk-echange{display:flex;flex-wrap:wrap;gap:.5rem .8rem;align-items:center;
  padding:.55rem .8rem;border:1px solid var(--qo-border);border-radius:.45rem;
  background:var(--qo-surface,#fff);}
.stk-echange-attente{border-left:3px solid var(--qo-accent,#1b3a6b);}
.stk-echange-txt{flex:1 1 18rem;}

/* ============================================================ 33. Sélection multiple (CC-123)
   La barre d'action n'existe que lorsqu'une case est cochée : un bouton « Supprimer » visible en
   permanence sur une liste invite à l'accident. */
.sel-case{width:1.05rem;height:1.05rem;flex:0 0 auto;cursor:pointer;accent-color:var(--qo-accent,#1b3a6b);}
.sel-aide{display:flex;align-items:center;gap:.45rem;margin:.2rem 0 .5rem;font-size:.85rem;}
.sel-barre{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem;margin-top:.7rem;
  padding:.6rem .8rem;border-radius:.5rem;border:1px solid var(--qo-border);
  background:var(--qo-surface-2,#f2f4f8);}
.sel-compte{font-size:.9rem;}
.sel-action{background:var(--qo-danger,#b3261e);border-color:var(--qo-danger,#b3261e);color:#fff;}
.sel-action:hover{filter:brightness(1.08);}
/* Écran de récapitulatif : ce qui part, ce qui est refusé, et pourquoi. */
.lot-titre{font-size:1.05rem;margin:0 0 .5rem;}
.lot-liste{margin:.2rem 0 0;padding-left:1.15rem;}
.lot-liste li{margin-bottom:.3rem;}
.lot-consequences{margin:.15rem 0 .3rem;padding-left:1rem;font-size:.88rem;}
.lot-refus{border-left:3px solid var(--qo-warn,#a25b00);}
.lot-actions{display:flex;flex-wrap:wrap;gap:.7rem;align-items:center;}
.lot-actions .danger{background:var(--qo-danger,#b3261e);border-color:var(--qo-danger,#b3261e);color:#fff;}

/* ============================================================ 34. Feuilles d'heures (CC-124)
   Un relevé : la semaine se lit par jours, chacun portant son total. Jamais de classement entre
   techniciens — c'est un décompte d'heures, pas une mesure de performance. */
.fh-total{font-size:1.02rem;margin:.2rem 0 .8rem;}
.fh-jour{margin:0 0 1.1rem;}
.fh-jour-titre{font-size:.95rem;margin:0 0 .3rem;display:flex;align-items:baseline;gap:.6rem;
  padding-bottom:.25rem;border-bottom:1px solid var(--qo-border);}
.fh-jour-total{margin-left:auto;font-variant-numeric:tabular-nums;font-weight:600;}
.fh-comm{font-size:.85rem;margin-top:.15rem;}
.fh-note{margin-top:.6rem;font-size:.85rem;}

/* ============================================================ 35. Feuille d'heures (CC-127)
   Un tableau qu'on lit et qu'on corrige, sur téléphone comme sur écran. Les lignes venues d'un
   bon signé se distinguent des lignes saisies : leur référence est en évidence. */
.fh-bloc{margin-bottom:1rem;}
.fh-tete{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:.6rem;}
.fh-titre{font-size:1.05rem;margin:0;}
.fh-nav{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap;}
.fh-periode{font-variant-numeric:tabular-nums;font-size:.9rem;}
.fh-etat{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem .9rem;margin:.5rem 0 .7rem;
  font-size:.92rem;}
.fh-total{margin-left:auto;}
.fh-tableau-boite{overflow-x:auto;}
.fh-tableau{width:100%;border-collapse:collapse;font-size:.9rem;}
.fh-tableau th{text-align:left;font-size:.74rem;text-transform:uppercase;letter-spacing:.03em;
  color:var(--qo-muted);padding:.35rem .5rem;border-bottom:1px solid var(--qo-border);}
.fh-tableau td{padding:.35rem .5rem;border-top:1px solid var(--qo-border);vertical-align:middle;}
.fh-tableau .fh-num{text-align:right;white-space:nowrap;}
.fh-tableau input[type=text]{width:100%;min-width:4rem;}
.fh-tableau .fh-num input{max-width:4.5rem;text-align:right;}
.fh-ref{font-family:ui-monospace,monospace;font-size:.82rem;white-space:nowrap;}
.fh-type-conge,.fh-type-absence{background:var(--qo-surface-2,#f2f4f8);}
.fh-type-conge .fh-ref,.fh-type-absence .fh-ref{color:var(--qo-muted);}
.fh-aide{font-size:.84rem;margin:.5rem 0 0;}
.fh-actions{display:flex;flex-wrap:wrap;gap:.6rem;margin-top:.7rem;}
.fh-ajout{margin-top:.8rem;}
.fh-ajout>summary{cursor:pointer;font-weight:600;padding:.3rem 0;}
.fh-inline{display:flex;flex-wrap:wrap;gap:.5rem;align-items:center;margin-top:.4rem;}
/* CC-151 — UNE RANGÉE « EN LIGNE » DOIT RESTER EN LIGNE. Le contrat de champ (§ 7) donne
   width:100% à tout input/select : en flex, cette largeur devient la taille de BASE, et avec
   flex-wrap chaque champ réclamait sa propre ligne. Le formulaire de correction d'un trajet
   s'affichait ainsi sur sept lignes empilées, la paire heures/minutes seule au milieu du vide.
   On ne remet à plat que les enfants de cette rangée : les largeurs mesurées de .duree-hm
   (CC-147) et son usage en tableau ne bougent pas. */
.fh-inline > input:not([type=checkbox]),
.fh-inline > select,
.fh-inline .duree-hm{width:auto;flex:0 1 auto;min-width:0;max-width:100%;}
/* Les lieux absorbent la place restante. `:not([size])` protège les champs dont la largeur est
   voulue en caractères (km, véhicule) : sans lui, deux champs de 4 et 8 signes passeraient à
   9 rem chacun. */
.fh-inline > input[type=text]:not([size]){flex:1 1 9rem;}
.fh-recap{font-size:1.3rem;margin:0;}
@media (max-width:640px){
  .fh-tableau thead{display:none;}
  .fh-tableau,.fh-tableau tbody,.fh-tableau tr,.fh-tableau td{display:block;width:100%;}
  .fh-tableau tr{border-top:2px solid var(--qo-border);padding:.4rem 0;}
  .fh-tableau td{border-top:none;padding:.2rem .3rem;display:flex;justify-content:space-between;
    align-items:center;gap:.6rem;}
  .fh-tableau td::before{content:attr(data-libelle);font-size:.76rem;color:var(--qo-muted);}
  .fh-total{margin-left:0;}
}
/* Type de document sur une ligne de feuille (CC-129) : on doit savoir à quoi le trajet se rattache. */
.fh-doc{display:inline-block;padding:.02rem .3rem;border-radius:.25rem;font-size:.72rem;
  background:var(--qo-surface-2,#eef1f6);border:1px solid var(--qo-border);color:var(--qo-muted);}
.fh-doc-libre{font-style:italic;}

/* ------------------------------------------------------------------ Trajets (CC-132)
   Le trajet se lit d'un coup d'œil : quand, combien, et rattaché à quoi. */
.fh-trajets{margin:.8rem 0;border-top:1px solid var(--qo-border);padding-top:.6rem}
.fh-trajets > summary{cursor:pointer;font-weight:600}
.fh-trajet{padding:.5rem 0;border-top:1px solid var(--qo-border)}
.fh-trajet:first-of-type{border-top:0}
.fh-trajet-tete{display:flex;flex-wrap:wrap;gap:.45rem;align-items:baseline;margin:0 0 .35rem}
.fh-trajet-duree{font-variant-numeric:tabular-nums;font-weight:600}
.fh-trajet-ajout{margin-top:.7rem;padding-top:.7rem;border-top:1px dashed var(--qo-border)}
.fh-vers-trajet{text-decoration:none;font-size:1.05em}
.fh-modele-lien{display:flex;flex-wrap:wrap;gap:.5rem;align-items:baseline;margin:0 0 .3rem}

/* =====================================================================================
   IMPRESSION DEPUIS LE NAVIGATEUR (CC-134, réduit en CC-135)
   -------------------------------------------------------------------------------------
   SERVERPV produit des PDF téléchargeables : c'est LA façon d'obtenir un document. Ces règles
   ne sont donc PAS une fonctionnalité — aucun bouton n'y mène. Elles sont un filet : si un
   utilisateur fait Ctrl+P sur un écran, il ne doit pas obtenir un torchon avec les menus, les
   filtres et des tableaux coupés en deux. Elles ne coûtent rien et ne s'affichent jamais.

   Trois principes tiennent tout ce bloc :
     1. on n'imprime que le CONTENU (l'écran sert à naviguer, le papier à lire) ;
     2. rien de lisible ne se coupe en deux — une intervention, un trajet, une ligne de
        tableau tiennent d'un seul tenant ;
     3. ce qui défile à l'écran doit se déplier sur le papier : un conteneur `overflow`
        COUPE ce qu'il contient à l'impression, il faut le neutraliser.
   ===================================================================================== */
@media print {
  @page { size: A4 portrait; margin: 12mm 10mm 14mm; }

  /* Le fond blanc et l'encre noire économisent la cartouche et gardent le contraste ; les
     éléments qui portent une couleur de sens (badges) la conservent explicitement. */
  html, body { background: #fff !important; color: #000 !important; }
  body { font-size: 10.5pt; line-height: 1.35; }

  /* --- 1. Ce qui ne s'imprime pas : tout ce qui sert à naviguer ou à agir. --- */
  .barre-nav, nav, .menu-param, .menu-langue, .menu-aide, .btn-power,
  .filtres, .pagination, .fh-actions, .fh-ajout, .fh-trajet-ajout,
  .lien-suppr, .btn-suppr, .btn-dictee, .btn-reformuler, .ia-proposition,
  .bouton, button, input[type="submit"], .selection-barre, .panneau-emails,
  .filet, .banniere-langue { display: none !important; }
  /* Un formulaire de FILTRE ne s'imprime pas ; un formulaire qui ne contient que des données
     affichées (feuille d'heures verrouillée) reste visible : on cible les commandes, pas les
     conteneurs. */
  form.carte { display: none !important; }

  /* --- 2. Rien de lisible ne se coupe en deux. --- */
  .carte, .fh-trajet, .fh-ligne, .bloc-ligne, .niveau, .palier,
  tr, thead, tfoot, li, figure, .dt-bloc { break-inside: avoid; page-break-inside: avoid; }
  h1, h2, h3 { break-after: avoid; page-break-after: avoid; }
  p, li { orphans: 3; widows: 3; }
  /* Un titre suivi d'un seul élément en bas de page produit une page presque vide : on garde
     le titre avec ce qu'il annonce plutôt que d'imposer un saut. */
  section, .carte { break-before: auto; }

  /* --- 3. Les en-têtes de tableau se répètent sur chaque page. --- */
  thead { display: table-header-group; }
  tfoot { display: table-footer-group; }
  table { width: 100% !important; border-collapse: collapse; }
  th, td { padding: 2mm 1.5mm; }

  /* --- 4. Ce qui défile à l'écran se déplie sur le papier. --- */
  .table-wrap, .fh-tableau-boite, .carte, .dt-chrono, .tableau,
  [style*="overflow"] { overflow: visible !important; max-height: none !important; }
  /* `position: sticky` fige un élément sur CHAQUE page imprimée : il faut le relâcher. */
  .barre-nav, .sig-nom, .boutons-signature { position: static !important; }

  /* --- 5. Un bloc replié ne s'imprimerait pas : on ouvre tout ce qui porte du contenu. --- */
  details > *:not(summary) { display: block !important; }
  details > summary { list-style: none; font-weight: 600; }

  /* --- 6. Les couleurs de SENS restent lisibles en noir et blanc. --- */
  .badge, .badge-statut, .etat, .fh-doc {
    border: 1px solid #666 !important; background: #fff !important; color: #000 !important;
    print-color-adjust: exact; -webkit-print-color-adjust: exact;
  }
  a { color: #000 !important; text-decoration: none; }

}
.ligne-trajets{display:flex;flex-wrap:wrap;gap:.35rem;margin-top:.25rem}
.trajet-puce{font-size:.86em;color:var(--qo-muted);border:1px solid var(--qo-border);
  border-radius:3px;padding:.05rem .35rem;white-space:nowrap}
/* Saisie rapide d'un trajet : l'essentiel en ligne, le détail replié (CC-135). */
.fh-tr-doc{max-width:22rem}
.fh-tr-detail{margin-top:.4rem}
.fh-tr-detail > summary{cursor:pointer;font-size:.86em;color:var(--qo-muted)}
.fh-tr-detail > div{margin-top:.4rem}
/* Champs techniques : texte long et choix multiples (CC-138). */
.ct-long{grid-column:1/-1}
.ct-long textarea{width:100%;min-height:4.5rem;resize:vertical}
.ct-multi{grid-column:1/-1}
.ct-multi-titre{display:block;font-weight:600;margin-bottom:.3rem}
.ct-multi-cases{display:flex;flex-wrap:wrap;gap:.4rem 1rem}

/* ------------------------------------------------------- Aperçu A4 de la feuille d'heures (CC-139)
   Même principe que l'aperçu du bon d'intervention : une page 210×297 PROPORTIONNELLE, obtenue par
   container-query (1 mm = 1/210 de la largeur disponible). Le document se juge sur son allure —
   une liste de réglages ne dit pas si la page est équilibrée. */
.fh-wrap{container-type:inline-size;width:100%}
.fh-a4{--mm:calc(100cqw / 210);width:100%;height:calc(297 * var(--mm));margin:14px auto;
  background:#fff;color:#1b2530;border:1px solid #cfd6df;box-shadow:0 8px 26px rgba(20,30,45,.14);
  padding:calc(6 * var(--mm)) calc(8 * var(--mm));border-radius:3px;
  font-size:calc(3.2 * var(--mm));display:flex;flex-direction:column;box-sizing:border-box}
.fh-a4-entete{display:flex;gap:calc(4 * var(--mm));border:1px solid #2b3f56;border-radius:2px;
  margin-bottom:calc(3 * var(--mm))}
.fh-a4-soc{flex:0 0 36%;padding:calc(2 * var(--mm));border-right:1px solid #2b3f56}
.fh-a4-logo{max-height:calc(16 * var(--mm));max-width:100%;display:block;
  margin-bottom:calc(1 * var(--mm))}
.fh-a4-nom{font-weight:800;color:#2b3f56}
.fh-a4-coord{font-size:calc(2.6 * var(--mm));color:#8894a4}
.fh-a4-ident{flex:1;border-collapse:collapse;font-size:calc(2.9 * var(--mm))}
.fh-a4-ident td{padding:calc(.8 * var(--mm)) calc(2 * var(--mm));vertical-align:top}
.fh-a4-band{background:#2b3f56;color:#fff;text-align:center;font-weight:700;
  padding:calc(1.2 * var(--mm));border:1px solid #2b3f56;border-bottom:2px solid #928340;
  font-size:calc(3.4 * var(--mm))}
.fh-a4-table{width:100%;border-collapse:collapse;font-size:calc(2.7 * var(--mm));
  margin-top:calc(3 * var(--mm))}
.fh-a4-table th,.fh-a4-table td{border:1px solid #cfd6df;padding:calc(1.1 * var(--mm));
  text-align:left}
.fh-a4-table thead th{background:#2b3f56;color:#fff;border-color:#2b3f56;
  border-bottom:2px solid #928340}
.fh-a4-num{text-align:right;font-variant-numeric:tabular-nums}
.fh-a4-total td{background:#f2f4f8}
.fh-a4-bas{margin-top:auto}
.fh-a4-mention{font-size:calc(2.6 * var(--mm));color:#8894a4;font-style:italic;
  margin-bottom:calc(2 * var(--mm))}
.fh-a4-sig{border-collapse:collapse;width:45%;font-size:calc(2.7 * var(--mm))}
.fh-a4-sig th{background:#2b3f56;color:#fff;border:1px solid #2b3f56;
  border-bottom:2px solid #928340;padding:calc(1.1 * var(--mm));text-align:center}
.fh-a4-sig td{border:1px solid #cfd6df;padding:calc(1.1 * var(--mm));text-align:center}
.fh-a4-trait{height:calc(14 * var(--mm))}

/* ------------------------------------------------- Garde-fou « écran large » (CC-139)
   La personnalisation des documents montre une page A4 fidèle et des tableaux d'édition à cinq
   colonnes. Sous 900 px, ces écrans ne deviennent pas « serrés » : ils deviennent illisibles, avec
   des éléments qui se chevauchent. Un refus franc vaut mieux qu'une page cassée — et personne ne
   met en page un document debout, téléphone en main. */
.ecran-large-avert{display:none}
@media (max-width: 900px){
  .ecran-large .ecran-large-avert{display:block;border:1px solid var(--qo-border);
    border-left:4px solid var(--qo-navy);background:var(--qo-surface);padding:1.1rem 1.2rem;
    border-radius:4px;margin:1rem 0}
  .ecran-large .ela-titre{font-weight:700;margin:0 0 .4rem}
  .ecran-large .ela-msg{margin:0 0 .8rem}
  /* Tout le reste de la page disparaît : on ne laisse pas l'utilisateur se battre avec un
     document qui déborde. Le HTML reste intact — c'est un masquage, pas une amputation. */
  .ecran-large > *:not(.page-tete):not(.ecran-large-avert){display:none !important}
}

/* ---------------------------------------------- Saisie technique : l'essentiel d'abord (CC-140)
   Le technicien est debout, téléphone en main. Un menu déroulant à trois choix lui coûte trois
   gestes ; des boutons lui en coûtent un. Et les champs de détail attendent derrière un dépliage
   plutôt que d'allonger l'écran pour tout le monde. */
.ct-chips{grid-column:1/-1}
.ct-chips-titre{display:block;font-weight:600;margin-bottom:.35rem}
.ct-chips-liste{display:flex;flex-wrap:wrap;gap:.4rem}
.ct-chip{display:inline-flex;align-items:center;gap:.35rem;padding:.5rem .8rem;
  border:1px solid var(--qo-border);border-radius:999px;cursor:pointer;font-weight:400;
  background:var(--qo-surface);min-height:44px;line-height:1.1}
.ct-chip input{margin:0}
.ct-chip.est-choisi{border-color:var(--qo-navy);background:var(--qo-fond-2,#f2f4f8);font-weight:600}
.ct-chip-vide{opacity:.65}
.ct-detail{margin-top:.7rem;border-top:1px dashed var(--qo-border);padding-top:.6rem}
.ct-detail > summary{cursor:pointer;font-size:.9em;color:var(--qo-muted);
  padding:.4rem 0;min-height:44px;display:flex;align-items:center}
/* Constat et réserves : des zones de texte qui grandissent avec ce qu'on écrit (CC-140). */
#observations, #reserves{width:100%;min-height:3.2rem;resize:vertical}

/* ------------------------------------------------- Fiche d'un équipement (CC-141)
   Lue debout, téléphone en main, avant de commencer : le repère, puis ce qui s'est passé. */
.eq-ligne{display:flex;flex-wrap:wrap;gap:.5rem;align-items:baseline;margin:0 0 .4rem}
.eq-enfants{margin:0;padding-left:1.1rem}
.eq-enfants li{margin-bottom:.3rem}
.eq-histo{list-style:none;margin:0;padding:0}
.eq-histo > li{border-top:1px solid var(--qo-border);padding:.1rem 0}
.eq-histo > li:first-child{border-top:0}
.eq-histo a{display:flex;flex-wrap:wrap;gap:.5rem;align-items:baseline;
  padding:.7rem .2rem;min-height:44px;text-decoration:none;color:inherit}
.eq-histo a:hover{background:var(--qo-fond-2,#f2f4f8)}
.eq-date{font-variant-numeric:tabular-nums;font-weight:600;min-width:6.2rem}
.eq-quoi{flex:1;min-width:0}
.eq-com{margin:0 0 .5rem .2rem;font-size:.9em;color:var(--qo-muted)}
/* La création d'un équipement se replie dès que le site en porte déjà (CC-142). */
.parc-nouveau{margin-top:.8rem;border-top:1px solid var(--qo-border);padding-top:.6rem}
.parc-nouveau > summary{cursor:pointer;font-weight:600;min-height:44px;display:flex;
  align-items:center}

/* --------------------------------------- Prestations : lisibles sur un téléphone (CC-142)
   C'est LE tableau qu'on montre au client, et c'était le seul tableau de saisie du produit sans
   règle mobile : le « Total TTC » et le bouton de suppression tombaient hors de l'écran, et il
   fallait faire glisser la table de côté au moment de la présenter. On applique le motif déjà
   écrit deux fois ailleurs (`.stk-table`, `.fh-tableau`) : une ligne devient un bloc, et chaque
   cellule porte son étiquette. */
@media (max-width: 640px){
  .tbl-lignes thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
  .tbl-lignes tbody tr{display:block;border-bottom:1px solid var(--qo-border);padding:.3rem 0}
  .tbl-lignes tbody td{display:flex;justify-content:space-between;gap:1rem;border:0;
    padding:.35rem .6rem;text-align:right}
  .tbl-lignes tbody td[data-libelle]::before{content:attr(data-libelle);
    color:var(--qo-text-soft);font-weight:600;text-align:left}
  .tbl-lignes tfoot td{display:flex;justify-content:space-between;border:0;padding:.35rem .6rem}
  .tbl-lignes tfoot td[colspan]{justify-content:flex-start}
  .tbl-lignes tfoot tr{display:flex;justify-content:space-between;align-items:baseline}
}

/* ============================ CC-144 — APPROVISIONNEMENT CÔTÉ RESPONSABLE
   Deux gestes, deux cartes : honorer une demande qui attend, et attribuer du matériel à plusieurs
   personnes d'un coup. Le tableau réutilise `.stk-table` (donc son repli mobile) : rien de neuf. */

/* Une demande en attente — encadrée pour qu'on voie tout de suite combien il y en a. */
.stk-demande{border:1px solid var(--qo-border);border-radius:var(--radius-sm);
  padding:.7rem .8rem;margin-top:.7rem;}
.stk-demande:first-of-type{margin-top:.4rem;}
.stk-demande-tete{display:flex;align-items:baseline;gap:.6rem;flex-wrap:wrap;margin-bottom:.4rem;}
/* Le message du technicien est du texte qu'il a écrit : on le rend tel quel, sans le reformater. */
.stk-message{white-space:pre-wrap;font-family:inherit;font-size:.86rem;margin:.3rem 0;
  background:var(--qo-surface-sub);border-radius:var(--radius-sm);padding:.5rem .6rem;
  overflow-wrap:anywhere;}
.stk-motif > summary{cursor:pointer;font-size:.86rem;padding:.3rem 0;min-height:44px;
  display:flex;align-items:center;}

/* Attribution en lot : le filtre, puis les destinataires en cases à cocher. */
.stk-lot-filtre{width:100%;max-width:22rem;margin-bottom:.5rem;}
.stk-lot-motif{width:100%;max-width:28rem;margin-top:.5rem;}
.stk-cibles{margin-top:.7rem;border:1px solid var(--qo-border);border-radius:var(--radius-sm);
  padding:.5rem .7rem;display:flex;flex-wrap:wrap;gap:.3rem 1.2rem;}
.stk-cibles legend{font-weight:600;font-size:.86rem;padding:0 .3rem;}
/* Cibles tactiles : on coche des noms sur un écran, parfois debout à l'atelier. */
.stk-cibles .label-normal{min-height:44px;display:flex;align-items:center;gap:.4rem;}

/* ============================ CC-146 — FEUILLE D'HEURES : SAISIE EN HEURES, TOTAL VIVANT
   Le total du serveur reste la référence ; le total provisoire se recalcule pendant qu'on tape et
   dit clairement qu'il n'est pas encore enregistré. */
.fh-provisoire{margin-left:.5rem;white-space:nowrap;}
.fh-provisoire strong{color:var(--qo-navy,#324860);}

/* La barre d'enregistrement colle en bas sur téléphone : le bouton ne doit jamais être « plus
   bas », et le témoin dit ce que l'enregistrement automatique vient de faire. */
.fh-barre-enreg{display:flex;align-items:center;gap:.8rem;flex-wrap:wrap;}
.fh-enreg-ok{color:var(--ok,#2e7d32);font-weight:600;}
.fh-enreg-ko{color:var(--danger,#b00020);font-weight:600;}
.fh-barre-enreg .htmx-request{opacity:.55;}

@media (max-width:640px){
  .fh-barre-enreg{position:sticky;bottom:0;z-index:5;background:var(--qo-surface,#fff);
    padding:.6rem;margin:0 -.4rem;border-top:2px solid var(--qo-gold,#928340);
    border-radius:var(--radius-sm);}
  /* …sans masquer la dernière ligne du tableau derrière elle. */
  .fh-tableau-boite{padding-bottom:.6rem;}
}
/* Une barre collante se répéterait sur chaque page imprimée (régression CC-134). */
@media print{ .fh-barre-enreg{position:static;border-top:none;} }

/* ============================ CC-147 — LE TEMPS SE RÈGLE, IL NE SE TAPE PLUS
   Deux listes côte à côte : heures, puis minutes. Aucune unité à deviner, donc aucune erreur d'un
   facteur 60 possible. Elles restent serrées pour tenir dans une cellule de tableau sur téléphone. */
/* `flex` et non `inline-flex` : dans une grille, la cellule doit occuper SA colonne. En largeur
   intrinsèque, « Pause » laissait un creux de 51 px à droite — ou débordait sur sa voisine dès
   qu'on élargissait les listes. Dans les deux cas la rangée paraissait décalée par rapport à
   « Heure de début » juste au-dessus. */
.duree-hm{display:flex;align-items:center;gap:.3rem;white-space:nowrap;width:100%;}
/* CC-148 — LARGEUR MESURÉE, pas devinée. Le texte le plus long est « 00 min » (6 caractères, ~3,1em
   à 0,95rem) auquel s'ajoutent les retraits (0,35 + 0,9rem) et la flèche du select. À 4,2rem le
   « n » de « min » tombait hors du champ : l'écran affichait « 00 mi ». 6,2rem laisse la place en
   français comme en allemand (« Min. »). */
/* LARGEUR MESURÉE, ET PAR LISTE. « 00 min » = 3,10 em ≈ 49,6 px à 16 px, plus ~16 px de flèche
   native, 24 px de retrait et 2 px de bordure : 91,6 px, soit 5,75 rem. C'est ce calcul qui
   manquait — à 4,2 rem puis à 5,4 rem, le « n » tombait hors du champ et l'écran affichait
   « 00 mi ». Les heures, elles, ne montrent jamais plus que « 23 h » (1,96 em) : 4,6 rem
   suffisent, et les 25 px économisés par paire comptent dans un tableau. */
.duree-hm select{flex:0 1 auto;padding-left:.4rem;padding-right:1.1rem;
  background-position:right .25rem center;}
.duree-hm .duree-h{min-width:4.6rem;}
.duree-hm .duree-m{min-width:6rem;}
/* Dans un tableau la place est comptée, mais un libellé coupé coûte plus cher qu'une colonne
   large : on garde la largeur qui ne coupe pas, on réduit seulement le corps du texte. */
.fh-tableau .duree-hm select{font-size:.86rem;}
@media (max-width:640px){
  /* En mode blocs, la durée se lit à droite de son libellé comme les autres valeurs. */
  .duree-hm{gap:.3rem;}
  /* Sur téléphone non plus on ne coupe pas « 00 min » : c'est là que ce formulaire est rempli.
     Les largeurs par liste sont posées plus haut — on n'ajoute ici que la cible tactile. */
  .duree-hm select{min-height:var(--ctrl-h);}
}

/* ============================ CC-149 — LE VOCABULAIRE DU MÉTIER
   Deux blocs sur le même écran : installer le vocabulaire d'un métier, et régler sa propre liste.
   C'est la même chose vue à deux moments, d'où un seul écran. */
.metier-liste{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,17rem),1fr));}
.metier-carte{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;margin:0;
  border:1px solid var(--qo-border);border-radius:var(--radius-sm);padding:.6rem .8rem;}
.metier-nom{flex:1 1 auto;font-weight:600;min-width:0;}
.metier-compte{font-variant-numeric:tabular-nums;white-space:nowrap;}
/* Une famille retirée du choix reste lisible : elle n'est pas supprimée, seulement mise de côté. */
.fam-inactive{opacity:.55;}
.fam-ligne{gap:.4rem;margin:0;flex-wrap:nowrap;}
.fam-ligne input[type=text]{flex:1 1 auto;min-width:0;}
@media (max-width:640px){ .fam-ligne{flex-wrap:wrap;} }
/* L'explication d'un champ vit SOUS lui, en petit : dans le libellé, elle le fait passer sur deux
   lignes et décale le contrôle par rapport à ses voisins. */
/* CC-151 — L'AIDE SOUS UN CHAMP SORT DE LA RANGÉE. Placée DANS une colonne de .rangee-champs,
   elle allongeait cette colonne : flex-end alignait alors le bas de l'AIDE, et le champ remontait
   d'une ligne au-dessus de ses voisins (« Famille », « Rôle », le bouton restaient en bas).
   Elle se pose donc SOUS la rangée. Marge explicite : en <p>, la marge du navigateur creusait
   un trou sous le bloc. Un test interdit désormais de la remettre dans une colonne. */
.champ-aide{display:block;font-size:.78rem;margin:.2rem 0 0;line-height:1.25;}
/* CC-150 — les métiers d'un technicien : des cases, alignées comme partout ailleurs. */
.metiers-choix{border:1px solid var(--qo-border);border-radius:var(--radius-sm);padding:.6rem .8rem;
  display:flex;flex-wrap:wrap;gap:.3rem 1.4rem;}
.metiers-choix legend{font-weight:600;font-size:.86rem;padding:0 .3rem;}
.metiers-choix .label-normal{display:flex;align-items:center;gap:.45rem;min-height:var(--ctrl-h);}
