:root{--marine:#1e3a5f;--marine-2:#2a4a73;--marine-3:#16304f;--accent:#0e7a5f;--accent-fonce:#0a5c48;--accent-clair:#e7f2ee;--fond:#f5f7fa;--surface:#eef2f6;--surface-2:#e4eaf0;--ligne:#e1e8ed;--texte:#2c3e50;--texte-2:#586376}
/*
 * FEUILLE DE STYLE DU PORTAIL — servie telle quelle, sans étape de
 * construction (règle 9), sans aucune ressource tierce (règle 8).
 *
 * TROIS STRATES, dans cet ordre — l'ordre compte, la dernière précise.
 *
 *  1. LA FONDATION, reprise de la feuille de composants validée avec le
 *     cabinet : base HTML, armature, cartes, boutons, formulaires,
 *     tableaux denses, pastilles, alertes, impression. Ses couleurs
 *     dérivées de la marque ont été JETONNÉES — sans quoi choisir la
 *     palette Bordeaux aurait laissé des îlots verts au milieu.
 *  2. LA LIAISON : la fondation stylise des CLASSES, nos pages écrivent
 *     des ÉLÉMENTS nus. Styler `button` plutôt qu'exiger `class="bouton"`
 *     est plus sûr ici — un bouton qu'on oublie de classer reste correct.
 *  3. LES RÈGLES MÉTIER, que la fondation ne couvre pas : 181 de nos
 *     classes lui sont propres, et TOUS nos blocs @media, qui portent la
 *     mise en page étroite.
 *
 * LE BLOC `:root` CI-DESSOUS EST UN SECOURS : le serveur injecte en tête
 * de cette feuille les jetons de la palette choisie par le cabinet. Les
 * valeurs de couleur d'ici ne servent que si la feuille est ouverte hors du
 * portail ; les ÉCHELLES (espacements, rayons, ombres, typographie), elles,
 * ne viennent que d'ici.
 */

:root {
    /* --- CHARTE v3 (validée par le directeur le 08/10/2026) : des bleus
       calmes sur des blancs doux, AUCUN JAUNE (test `charte.test.ts`). La
       couleur ne sert qu'à dire un état ; l'action a UNE couleur, le bleu
       Satelis.
       Les jetons de MARQUE ci-dessous sont écrasés en tête de feuille par
       la palette choisie par le cabinet (Réglages) ; ceux-ci sont le
       SECOURS si la feuille est ouverte hors du portail. */
    --marine: #0f1e2e; --marine-2: #36729b; --marine-3: #2b5e82;
    --accent: #36729b; --accent-fonce: #2b5e82; --accent-clair: #eef3fa;
    --fond: #f6f8fb; --surface: #f2f6fb; --carte: #ffffff;
    --ligne: #e3e9f1; --texte: #0f1e2e; --texte-2: #4f5f72;

    /* --- LA CHARTE, hors palette : la coque et ses nuances. */
    --texte-3: #66768a;           /* tertiaire : étiquettes, compteurs */
    --ligne-douce: #eef2f7;       /* le filet entre deux lignes de tableau */
    --survol: #f7fafd;            /* survol d'une ligne */
    --survol-2: #f2f6fb;          /* survol d'un bouton discret */
    --selection: #edf3f9;         /* ligne sélectionnée (liseré bleu 2 px) */
    --menu-actif: #e6eef6;        /* l'entrée de menu courante */
    --anneau: #dce6f5;            /* l'anneau de focus d'un champ */
    --champ-bord: #dce3ec;        /* la bordure d'un champ au repos */
    --acier: #4a86ae;             /* bandeaux, illustrations — jamais sous un petit texte */
    --cobalt: #2f5ba8;            /* graphiques, mise en avant ponctuelle */
    --pervenche: #a9bee3;         /* décor */
    --separateur: #c3cdd9;        /* la barre oblique du fil d'Ariane */
    --texte-nav: #3e4e61;         /* une entrée de menu au repos */
    --survol-menu: #e9eff6;       /* survol d'une entrée de menu */
    --brume: #6b8fb5;             /* troisième teinte d'avatar */
    --voile: rgba(15,30,46,.22);  /* le voile sous un panneau */

    /* --- LES ÉTATS (texte / fond) : un statut, pas une identité. La
       palette ne les touche pas — un rouge d'alerte qui vire au bordeaux
       cesserait d'alerter. */
    --etat-signee: #2f7d5b;   --etat-signee-fond: #e7f4ee;
    --etat-etude: #36729b;    --etat-etude-fond: #eef3fa;
    --etat-valider: #4f5f72;  --etat-valider-fond: #f0f3f7; --etat-valider-point: #8797aa;
    --etat-relance: #a6561f;  --etat-relance-fond: #fbefe6; --etat-relance-bord: #f1dccb;
    --etat-retard: #b3261e;   --etat-retard-fond: #fcebea;
    --ligne-forte: #8797aa;
    --surface-2: #e6eef6;
    /* L'« ambre » d'avant était un jaune (#8a5f14) : il devient la terre
       cuite des relances. Les classes qui le portent gardent leur nom. */
    --ambre: #a6561f; --ambre-clair: #fbefe6;
    --rouge: #b3261e; --rouge-fonce: #8f1e18; --rouge-clair: #fcebea;
    --info-clair: #eef3fa; --info: #36729b; --info-badge: #eef3fa; --info-bord: #dce6f5;
    --ambre-bord: #f1dccb; --ambre-survol: #f7e6d9;
    --rouge-bord: #f2c9c6;
    /* Le « sans suite » : un état ÉTEINT, ni alerte ni succès. */
    --eteint: #4f5f72; --eteint-clair: #eff2f5;
    --side-texte-2: #66768a; --side-focus: #36729b;
    /* --- CE QUI SE POSE SUR UN FOND FONCÉ (boutons pleins, annonces), et
       L'ENCRE DES OMBRES ET DES VOILES. Les transparences en dérivent par
       color-mix() : plus aucune couleur écrite à côté. */
    --sur-fonce: #ffffff;
    --encre: #0f1e2e;

    /* --- ÉCHELLES : ni couleur, ni marque. Elles donnent au produit sa
       régularité — c'est ce qui manquait, et sans elles chaque `var()`
       invalide annulait silencieusement sa propriété (une carte se
       retrouvait sans bordure, sans ombre et sans marge).

       L'ÉCHELLE DE TEXTE EST FERMÉE : sept paliers, et aucune taille
       écrite en dur ailleurs dans le fichier. Elle ne l'était pas — la
       strate métier portait 93 déclarations à 33 valeurs différentes
       (.56, .66, .7, .72, .75, .76, .78, .8, .82, .84, .85, .86, .87,
       .875, .88, .9, .92, .93, .95, .98, 1, 1.02…), si bien qu'un même
       écran s'affichait en vingt corps. C'est ce qu'on lisait sur le
       téléphone : « pas homogène ». Deux exceptions, toutes deux
       nommées à leur ligne : le lettrage de la marque, qui n'est pas du
       texte, et les champs de saisie sur téléphone, tenus à 16 px par
       Safari iOS. */
    --texte-xs: 0.75rem;  --texte-s: 0.8125rem; --texte-m: 0.875rem;
    --texte-l: 1rem;      --titre-3: 1.125rem;  --titre-2: 1.375rem; --titre-1: 1.75rem;
    /* Les MOMENTS DE MARQUE (Instrument Serif, charte v3) : 44 / 32 / 24 px. */
    --marque-0: 3.75rem;  --marque-1: 2.75rem;  --marque-1b: 2.375rem; --marque-2: 2rem; --marque-3: 1.5rem;
    --es-1: 0.25rem; --es-2: 0.5rem;  --es-3: 0.75rem; --es-4: 1rem;
    --es-5: 1.5rem;  --es-6: 2rem;    --es-7: 3rem;
    /* Charte v3 : 8 px (menus, boutons), 10 px (champs), 12 à 16 px
       (cartes, panneaux), arrondi complet (puces). */
    --rayon-1: 8px; --rayon-2: 10px; --rayon-3: 999px; --rayon-carte: 12px; --rayon-panneau: 16px;
    /* --- CHARPENTE : ses dimensions sont des jetons — elles doivent
       coïncider entre le bandeau et la colonne principale. */
    --charpente-lat: 15.5rem;   /* 248 px */
    --charpente-haut: 3.25rem;  /* 52 px */
    --ligne-tableau: 2.75rem;   /* 44 px : la ligne d'un tableau dense */
    /* --- LA POLICE DU PRODUIT, auto-hébergée (@font-face ci-dessous).
       L'identité du produit, pas du cabinet : la palette n'y touche pas. */
    --police: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
      Roboto, "Helvetica Neue", Arial, sans-serif;
    /* La police des MOMENTS DE MARQUE — connexion, titre d'accueil,
       documents. Jamais pour une liste ni un formulaire. */
    --police-marque: "Instrument Serif", Georgia, "Times New Roman", serif;
    /* Deux ombres dans la charte : repos et flottant (+ le panneau). */
    --ombre-1: 0 1px 2px rgba(20,40,58,.06);
    --ombre-2: 0 8px 24px rgba(20,40,58,.10);
    --ombre-3: 0 24px 64px rgba(15,30,46,.22), 0 0 0 1px rgba(15,30,46,.06);
    --ombre: var(--ombre-2);
    --bordure: 1px solid var(--ligne);
    --transition: 150ms ease;
  }

/*
 * LES POLICES DU PRODUIT — AUTO-HÉBERGÉES (règle 8 : aucune requête
 * tierce ; licences OFL dans public/polices/). Charte v3 :
 *  - INTER, fichier VARIABLE (~48 Ko) : tout le produit, en chiffres
 *    tabulaires ;
 *  - INSTRUMENT SERIF (~21 Ko) : les seuls moments de marque — connexion,
 *    titre d'accueil, documents.
 * Chacune n'est déclarée qu'ici, une seule fois, en `font-display: swap` :
 * sans le fichier, le texte s'affiche dans la police système, rien ne
 * casse. (IBM Plex Sans reste celle du devis imprimé, qui la déclare.)
 */
@font-face {
  font-family: "Inter";
  src: url("/polices/inter-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Instrument Serif";
  src: url("/polices/instrument-serif-latin.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ======== 1. FONDATION ======== */

/* ============================================================
   SATELIS — bloc CSS v2 (brief révisé)
   Strate sécurité intacte : aucune ressource externe, échappement
   systématique, WCAG AA. Strate ergonomie assouplie : ombres en
   couches, transitions courtes, icônes SVG inline, JS moderne.
   ============================================================ */

/* ---------- 1. Jetons ---------- */
/* ---------- 2. Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  font-size: 100%;
  /* LE NAVIGATEUR N'A PAS LE DROIT DE REGROSSIR NOTRE TEXTE.
     Par défaut (`auto`), Chrome Android et Safari iOS appliquent un
     « text autosizer » : ils gonflent la police bloc par bloc, avec un
     facteur calculé sur la largeur du bloc. Nos tableaux mesurent
     1439 px de colonnes dans un cadre de 311 px — chaque colonne
     recevait donc un facteur DIFFÉRENT, et une même ligne s'affichait
     en quatre tailles. C'est exactement ce qu'on voyait sur le
     téléphone : « gros et pas homogène ». À 100 %, la taille affichée
     est celle que la feuille dit, et le zoom manuel reste intact. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
body {
  margin: 0;
  font-family: var(--police);
  font-size: var(--texte-m); line-height: 1.45;
  color: var(--texte); background: var(--fond);
  -webkit-font-smoothing: antialiased;
  /* Chiffres TABULAIRES partout (charte v3) : n° et montants s'alignent
     en colonne sans qu'aucun écran ait à le demander. */
  font-feature-settings: "tnum" 1, "cv11" 1;
}
::selection { background: var(--accent-clair); }
h1, h2, h3 { color: var(--marine); line-height: 1.25; margin: 0 0 var(--es-3); letter-spacing: -0.01em; }
h1 { font-size: var(--titre-1); font-weight: 700; }
h2 { font-size: var(--titre-2); font-weight: 700; }
h3 { font-size: var(--titre-3); font-weight: 700; }
p { margin: 0 0 var(--es-3); }
a { color: var(--marine-2); text-decoration-color: color-mix(in srgb, var(--marine-2) 35%, transparent); text-underline-offset: 2px; transition: color var(--transition); }
a:hover { color: var(--marine); text-decoration-color: currentColor; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--rayon-1); }
code, pre { font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace; }

/* ---------- 3. Armature ---------- */
.barre-laterale {
  position: fixed; inset: 0 auto 0 0; width: 15.5rem;
  background: linear-gradient(180deg, var(--marine) 0%, var(--marine-3) 100%);
  color: var(--sur-fonce); display: flex; flex-direction: column; overflow-y: auto;
  box-shadow: 1px 0 0 color-mix(in srgb, var(--encre) 6%, transparent);
}
.marque {
  display: flex; align-items: center; gap: var(--es-2);
  padding: var(--es-4) var(--es-4) var(--es-3);
  font-size: var(--texte-l); font-weight: 700; letter-spacing: 0.08em;
}
.marque svg { flex: none; }
.nav-section { padding: var(--es-2) var(--es-2) 0; }
.nav-section-titre {
  padding: var(--es-1) var(--es-2);
  font-size: var(--texte-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--side-texte-2);
}
.nav-lien {
  display: flex; align-items: center; gap: var(--es-2);
  padding: 0.375rem var(--es-2);
  margin: 1px 0;
  color: var(--sur-fonce); text-decoration: none;
  border-radius: var(--rayon-1);
  transition: background var(--transition);
}
.nav-lien svg { flex: none; opacity: .85; }
.nav-lien:hover { background: color-mix(in srgb, var(--sur-fonce) 9%, transparent); }
.nav-lien:focus-visible { outline-color: var(--side-focus); outline-offset: -2px; }
.nav-lien[aria-current="page"] {
  background: color-mix(in srgb, var(--sur-fonce) 15%, transparent);
  font-weight: 600;
  box-shadow: inset 3px 0 0 var(--side-focus);
}
.contenu { margin-left: 15.5rem; padding: var(--es-5) var(--es-5) var(--es-7); max-width: 90rem; }
@media (max-width: 75rem) {
  .barre-laterale { width: 13rem; }
  .contenu { margin-left: 13rem; padding: var(--es-4) var(--es-4) var(--es-6); }
}
.page-tete { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--es-3); margin-bottom: var(--es-5); }
.page-tete h1 { margin: 0; }
.page-tete .actions { margin-left: auto; display: flex; gap: var(--es-2); }

/* ---------- 4. Cartes ---------- */
.carte {
  background: var(--carte); border: var(--bordure); border-radius: var(--rayon-2);
  box-shadow: var(--ombre-1);
  padding: var(--es-4) var(--es-5); margin-bottom: var(--es-3);
}
.carte > h2:first-child, .carte > h3:first-child { margin-top: 0; }
.carte.compacte { padding: var(--es-3) var(--es-4); }

.grille-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: var(--es-3); margin-bottom: var(--es-4); }
.carte-stat {
  position: relative;
  background: var(--carte); border: var(--bordure); border-radius: var(--rayon-2);
  box-shadow: var(--ombre-1);
  padding: var(--es-3) var(--es-4); margin: 0; overflow: hidden;
  transition: box-shadow var(--transition), transform var(--transition);
}
.carte-stat::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px;
  background: var(--accent); opacity: .9;
}
.carte-stat:hover { box-shadow: var(--ombre-2); transform: translateY(-1px); }
.carte-stat .stat-valeur {
  display: block; font-size: var(--titre-2); font-weight: 700; color: var(--marine);
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em;
}
.carte-stat .stat-label { font-size: var(--texte-s); color: var(--texte-2); }
.carte-stat .stat-tendance { display: block; font-size: var(--texte-xs); margin-top: 2px; }

/* ---------- 5. Boutons ---------- */
.bouton {
  display: inline-flex; align-items: center; gap: var(--es-2);
  padding: 0.4375rem var(--es-4);
  font: inherit; font-weight: 600; font-size: var(--texte-m);
  border: 1px solid transparent; border-radius: var(--rayon-1);
  cursor: pointer; text-decoration: none; min-height: 2.125rem;
  transition: background var(--transition), box-shadow var(--transition), transform var(--transition), border-color var(--transition);
}
.bouton:active { transform: translateY(1px); }
.bouton.est-principal {
  background: linear-gradient(180deg, var(--accent-fonce) 0%, var(--accent) 100%);  /* 4,77:1 minimum, blanc dessus */
  color: var(--sur-fonce); box-shadow: 0 1px 2px color-mix(in srgb, var(--accent) 35%, transparent), inset 0 1px 0 color-mix(in srgb, var(--sur-fonce) 15%, transparent);
}
.bouton.est-principal:hover { background: linear-gradient(180deg, var(--accent) 0%, var(--accent-fonce) 100%); box-shadow: 0 2px 6px color-mix(in srgb, var(--accent) 40%, transparent); }
.bouton.est-secondaire { background: var(--carte); color: var(--marine); border-color: var(--ligne-forte); box-shadow: var(--ombre-1); }
.bouton.est-secondaire:hover { background: var(--fond); border-color: var(--marine-2); }
.bouton.est-discret { background: transparent; color: var(--accent); padding-left: var(--es-2); padding-right: var(--es-2); }
.bouton.est-discret:hover { text-decoration: underline; text-underline-offset: 2px; }
.bouton.est-destructeur { background: var(--rouge); color: var(--sur-fonce); box-shadow: 0 1px 2px color-mix(in srgb, var(--rouge) 30%, transparent); }
.bouton.est-destructeur:hover { background: var(--rouge-fonce); }
.bouton:disabled, .bouton[aria-disabled="true"] { opacity: .55; cursor: not-allowed; text-decoration: none; box-shadow: none; transform: none; }
.bouton:disabled:hover, .bouton[aria-disabled="true"]:hover { background: inherit; }
.bouton.est-principal:disabled:hover { background: var(--accent); }
.bouton.est-destructeur:disabled:hover { background: var(--rouge); }

/* ---------- 6. Formulaires ---------- */
.champ { margin-bottom: var(--es-4); max-width: 34rem; }
.champ-label { display: block; font-weight: 600; font-size: var(--texte-m); margin-bottom: var(--es-1); }
.champ-label .requis { color: var(--rouge); }
.champ-entree, select.champ-entree, textarea.champ-entree {
  width: 100%; padding: 0.4375rem var(--es-3);
  font: inherit; color: var(--texte); background: var(--carte);
  border: 1px solid var(--ligne-forte); border-radius: var(--rayon-1);
  transition: border-color var(--transition), box-shadow var(--transition);
}
.champ-entree:hover:not(:disabled) { border-color: var(--marine-2); }
.champ-entree:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent); }
.champ-entree[aria-invalid="true"] { border-color: var(--rouge); }
.champ-entree[aria-invalid="true"]:focus { box-shadow: 0 0 0 3px color-mix(in srgb, var(--rouge) 15%, transparent); }
.champ-entree:disabled { background: var(--fond); color: var(--texte-2); cursor: not-allowed; }
.champ-erreur { margin: var(--es-1) 0 0; font-size: var(--texte-s); color: var(--rouge); font-weight: 600; }
.aide { font-size: var(--texte-s); color: var(--texte-2); margin: var(--es-1) 0 0; }
.ligne-case { display: flex; align-items: flex-start; gap: var(--es-2); margin-bottom: var(--es-2); }
.ligne-case input[type="checkbox"], .ligne-case input[type="radio"] { margin-top: .2em; accent-color: var(--accent); width: 1rem; height: 1rem; }
.erreurs {
  border: 1px solid var(--rouge);
  background: var(--rouge-clair); color: var(--rouge);
  border-radius: var(--rayon-1); padding: var(--es-3) var(--es-4); margin-bottom: var(--es-4);
}
.erreurs ul { margin: var(--es-1) 0 0; padding-left: var(--es-4); }
fieldset { border: var(--bordure); border-radius: var(--rayon-2); padding: var(--es-4) var(--es-5); margin: 0 0 var(--es-4); background: var(--carte); box-shadow: var(--ombre-1); }
legend { font-weight: 700; color: var(--marine); padding: 0 var(--es-2); }

/* ---------- 7. Tableaux denses ---------- */
.tableau-cadre {
  overflow-x: auto; max-height: 32rem;
  border: var(--bordure); border-radius: var(--rayon-2);
  background: var(--carte); box-shadow: var(--ombre-1);
  margin-bottom: var(--es-4);
}
.tableau-cadre::-webkit-scrollbar { height: 10px; width: 10px; }
.tableau-cadre::-webkit-scrollbar-thumb { background: var(--ligne); border-radius: 999px; border: 2px solid var(--carte); }
.tableau-affaires {
  width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--texte-s);
  /* Chiffres TABULAIRES dans toute liste : numéros segmentés, montants et
     dates s'alignent en colonnes de chiffres — un identifiant-pivot mérite
     une typographie de pivot (revue de design, constat n° 2). */
  font-variant-numeric: tabular-nums;
}
.tableau-affaires th, .tableau-affaires td {
  padding: 0.375rem var(--es-2); text-align: left;
  border-top: var(--bordure); white-space: nowrap;
}
.tableau-affaires thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--surface); border-top: none; border-bottom: 1px solid var(--ligne-forte);
  color: var(--marine); font-size: var(--texte-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em;
}
.tableau-affaires tbody tr { transition: background 100ms ease; }
.tableau-affaires tbody tr:hover td { background: var(--surface-2); }
.tableau-affaires .num, .tableau-affaires th.num { text-align: right; font-variant-numeric: tabular-nums; }
.montant { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* UNE COLONNE DE PROSE dans un tableau dense. Par défaut aucune cellule ne
   renvoie à la ligne — les listes portent des valeurs courtes, et une
   colonne qui saute doublerait la hauteur de chaque rangée. Une phrase
   d'explication est l'exception : sans elle, la table sort de sa carte,
   puisque au-delà de 64 rem le cadre ne défile plus (c'est la zone de
   travail qui défile) et qu'un « overflow-x » visible ne coupe rien. */
.tableau-affaires th.prose, .tableau-affaires td.prose { white-space: normal; }

.col-fixe { position: sticky; left: 0; z-index: 1; background: var(--carte); box-shadow: 1px 0 0 var(--ligne); }
.tableau-affaires thead .col-fixe { z-index: 3; background: var(--surface); }
.tableau-affaires tbody tr:hover .col-fixe { background: var(--surface-2); }
.tableau-affaires .cellule-longue { white-space: normal; min-width: 12rem; }
tr.est-masquee { display: none; }

/* DANS UNE LISTE DENSE, L'ÉTAT SE DIT PAR SA PASTILLE (retour du
   directeur, 20/08). Écrits en toutes lettres derrière chaque nom,
   « Prospect » et « Inactif » coûtaient plus large que le nom qu'ils
   qualifient — et sur 244 lignes, la couleur suffit à lire la liste.
   La pastille se réduit donc à son point ; SON LIBELLÉ REVIENT AU
   SURVOL, là où on le cherche.

   Le texte n'est jamais retiré du document : il reste lu par les
   lecteurs d'écran et trouvé par la recherche du navigateur — il est
   seulement replié. Et la règle ne vaut QU'AU POINTEUR FIN : sur un
   écran tactile, où le survol n'existe pas, les libellés restent
   écrits. C'est la contrepartie assumée — au pointeur, un état ne se
   lit qu'à la couleur tant qu'on ne survole pas. */
@media (hover: hover) and (pointer: fine) {
  /* « NOUVEAU » ÉCHAPPE AU REPLI. Le repère ne dure qu'un jour et son rôle
     est précisément de SE VOIR sans qu'on le cherche : le replier en point
     le rendrait indistinguable d'un statut, ce qui annulerait sa raison
     d'être. */
  .tableau-affaires .badge-etude.nouvelle,
  /* CE QUI RESTE À FAIRE NE SE REPLIE PAS NON PLUS. Le repli en pastille
     vaut pour un STATUT : on ne le cherche pas, on le retrouve au survol.
     Une LACUNE, elle, est une consigne — « sans client », « à vérifier » —
     et réduite à un point ambre elle devient indistinguable d'un statut,
     c'est-à-dire invisible. Elle ne concerne d'ailleurs que quelques
     lignes : elle ne coûte pas la largeur d'une liste de deux cent
     quarante-quatre noms, qui est la raison d'être du repli. Et le survol
     n'existe pas sur un téléphone, où ces listes se lisent le plus. */
  .tableau-affaires .badge-etude.a-traiter {
    max-width: none; gap: 6px; padding: .125rem var(--es-2);
    font-size: var(--texte-xs);
  }
  .tableau-affaires .badge-etude {
    /* 6 px de point + 2 × 4 px de marge = 14 px : la largeur EXACTE de la
       pastille seule. Au pixel près, sinon une lettre dépasse. */
    /* `font-size: 0` plutôt qu'un plafond de largeur au pixel près : le
       texte ne peut PAS filtrer, quelle que soit la police ou son rendu.
       Un plafond calculé laissait passer un sliver de la première lettre. */
    max-width: .875rem; gap: 0; padding: .125rem .25rem; font-size: 0;
    overflow: hidden; vertical-align: -1px;
    transition: max-width var(--transition), padding var(--transition), font-size var(--transition);
  }
  /* Le point est un ÉLÉMENT FLEX : sans `flex: none` il se comprime à zéro
     sous le plafond de largeur, et c'est le texte qu'on voyait dépasser
     à sa place (« In » au lieu de la pastille). */
  .tableau-affaires .badge-etude::before { flex: none; }
  /* Dans le maître-détail, toute la fiche est un lien étiré (`.lien-fiche`,
     posé en absolu par-dessus) : sans ce relèvement, la pastille est
     RECOUVERTE et le survol ne l'atteint jamais — ni son infobulle.
     Trouvé en essayant de survoler la pastille pour de vrai, pas en
     relisant la feuille. Contrepartie : un clic pile sur la pastille ne
     sélectionne pas la fiche ; le reste de la carte, si. */
  .maitre-detail .tableau-affaires .badge-etude { position: relative; z-index: 2; }
  /* EXCEPTION NOMMÉE : la file d'entrée du tableau de bord. Le repli des
     pastilles économise la largeur d'une liste de 244 noms ; ici la liste
     tient en douze lignes, et le STATUT est l'une des deux choses qu'on y
     lit — avec l'échéance. Il s'écrit donc en clair, sans survol. */
  .tableau-entree .badge-etude {
    max-width: none; gap: 6px; padding: .125rem var(--es-2); font-size: var(--texte-xs);
  }
  .tableau-affaires .badge-etude:hover {
    max-width: 14rem; gap: 6px; padding: .125rem var(--es-2);
    font-size: var(--texte-xs);
  }
  /* La fiche et le volet ne sont pas des listes : l'état s'y écrit. */
  .volet-etude .badge-etude, .fiche-tete .badge-etude { max-width: none; }
  /* UN PLAN DE JALONS N'EST PAS UNE LISTE D'AFFAIRES. Dans une liste,
     l'état se réduit à son point de couleur parce que ce n'est pas ce
     qu'on y cherche. Dans un échéancier, l'ÉTAT EST L'INFORMATION —
     « prévu », « facturé », « bloqué » commandent la décision du mois.
     Réduits à un point, on ne lisait plus rien (vu sur capture, 22/08).
     LE MÊME ARGUMENT VAUT DANS TOUTE LA REVUE MENSUELLE, y compris pour
     les prestations ajoutées à la main qui s'y valident : on n'y parcourt
     pas une liste, on y tranche ligne par ligne, et un statut qu'il faut
     survoler pour lire n'aide pas à trancher (vu sur capture, 23/08).
     LES VERSIONS D'UNE OFFRE relèvent du même cas : deux ou trois lignes,
     et l'ÉTAT est précisément ce qu'on vient y lire — laquelle est partie,
     laquelle est remplacée, laquelle a été acceptée. Réduit à un point,
     « remplacée » n'était plus qu'une pastille grise (vu sur capture,
     28/08 — et la correction elle-même a d'abord été écrite APRÈS la
     fermeture du commentaire, ce qui la rendait sans effet ; c'est en
     mesurant le style calculé dans le navigateur, pas en relisant la
     feuille, qu'on s'en est aperçu). */
  [data-bloc="versions"] .badge-etude,
  .plan-jalons .badge-etude,
  .point-revue .badge-etude {
    max-width: none; gap: .4rem; padding: .1rem .5rem; font-size: var(--texte-xs);
    overflow: visible;
  }
}

/* UNE COLONNE DE TEXTE NE POUSSE JAMAIS DEHORS CE QUI DÉCIDE.
   Mesuré sur la base réelle : un libellé hérité du classeur atteint 89
   caractères ; comme les cellules interdisent le retour à la ligne, la
   colonne « Nom » réclamait 757 px, le tableau 1 345 px pour 1 095
   disponibles — et les compteurs, les actions, parfois le téléphone
   sortaient du cadre. C'est le défaut que le jeu de démonstration, avec
   ses noms courts, ne pouvait pas montrer.

   Le texte long se coupe donc par une ellipse. JAMAIS EN SILENCE : le
   serveur pose la valeur entière en infobulle, et la fiche la porte en
   entier. Le plafond vaut à partir de la tablette ; sur téléphone, la
   ligne est une carte qui a le droit de passer à la ligne (bloc final).

   Les cellules se reconnaissent par le NOM DE LEUR COLONNE (`data-libelle`,
   recopié du thead par `tableau-cartes.ts`) : un tableau ajouté demain en
   profite dès lors que ses colonnes portent ces noms-là. */
.tableau-affaires td[data-libelle="Nom"] > a,
.tableau-affaires td[data-libelle="Intitulé"],
.tableau-affaires td[data-libelle="Objet"] {
  display: inline-block; max-width: 20rem;
  overflow: hidden; text-overflow: ellipsis; vertical-align: bottom;
}
.tableau-affaires td[data-libelle="Client"],
.tableau-affaires td[data-libelle="Courriel"] {
  max-width: 14rem; overflow: hidden; text-overflow: ellipsis;
}
.tableau-affaires td[data-libelle="Ville"],
.tableau-affaires td[data-libelle="Activité"] {
  max-width: 11rem; overflow: hidden; text-overflow: ellipsis;
}

/* Dans une liste, c'est la LIGNE qui se clique, pas un mot bleu dedans :
   le lien d'une cellule est l'ancre — poids 600, couleur du texte, sans
   soulignement. Le survol le passe au marine. Les liens déjà habillés
   (boutons) gardent le leur. */
.tableau-affaires td a:not(.bouton):not(.bouton-2) {
  color: var(--texte); font-weight: 600;
  text-decoration: none; border-bottom: 0;
}
.tableau-affaires td a:not(.bouton):not(.bouton-2):hover { color: var(--marine-2); }

/* LES ACTIONS APPARAISSENT OÙ ON LES CHERCHE (décision du 20/08) : au
   pointeur fin, la colonne d'actions se révèle au survol de la ligne ET
   au focus clavier — la lecture d'abord. Un dépliant resté ouvert reste
   visible (:has). Un navigateur sans :has garde tout visible : la
   dégradation est l'affichage d'avant. */
@supports selector(td:has(details[open])) {
  @media (hover: hover) and (pointer: fine) {
    .tableau-affaires td.actions > * { opacity: 0; transition: opacity var(--transition); }
    .tableau-affaires tr:hover td.actions > *,
    .tableau-affaires tr:focus-within td.actions > *,
    .tableau-affaires td.actions:has(details[open]) > * { opacity: 1; }
    /* LÀ OÙ L'ON TRANCHE, LES BOUTONS NE SE CACHENT PAS, et c'est le sens
       même de ces écrans. Le repli au survol suppose qu'on vient LIRE une
       liste et qu'on agit par exception. Sur un plan de jalons c'est
       l'inverse : on vient décider — facturer, reporter, bloquer,
       encaisser, annuler — et le tableau n'existe QUE pour porter ces
       boutons. Repliés, ils rendaient la réunion de fin de mois et le plan
       d'une affaire indistinguables d'un tableau en lecture seule : on
       ouvrait la revue et on n'y voyait rien à faire (vu sur capture,
       23/08, DEUX FOIS — la seconde parce que l'exemption ne portait que
       sur la revue). `.plan-jalons` est la classe que les deux tableaux de
       décision partagent ; `.point-revue` y ajoute les prestations
       ajoutées à la main, qui se valident dans la même réunion. */
    .plan-jalons td.actions > *,
    .point-revue .tableau-affaires td.actions > * { opacity: 1; }
  }
}

/* ---------- 8. Badges pastilles ---------- */
.badge-etude {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 0.125rem var(--es-2);
  font-size: var(--texte-xs); font-weight: 600;
  border-radius: var(--rayon-3); white-space: nowrap;
}
.badge-etude::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.badge-etude.nouvelle { color: var(--accent); background: var(--accent-clair); font-weight: 700; }
.badge-etude.est-brouillon      { color: var(--texte-2); background: var(--surface); }
.badge-etude.est-en-etude       { color: var(--ambre); background: var(--ambre-clair); }
.badge-etude.est-offre          { color: var(--marine-2); background: var(--surface); }
.badge-etude.est-offre-validee  { color: var(--accent); background: var(--accent-clair); }
.badge-etude.est-transformee    { color: var(--marine); background: var(--accent-clair); }
.badge-etude.est-sans-suite     { color: var(--eteint); background: var(--eteint-clair); }

/* ---------- 9. Alertes ---------- */
/* Décision du 20/08 (retour du directeur sur maquettes) : la barre
   latérale de 4 px — le motif générique des gabarits d'admin — disparaît.
   Un message se dit par un LISERÉ UNIFORME de 1 px dans sa couleur d'état
   et un POINT devant son texte ; le fond teinté reste. Les deux
   orthographes de variantes cohabitent dans les pages (.alerte-attention
   et .alerte.attention) : la feuille couvre les deux. */
.alerte {
  border: 1px solid var(--ligne-forte);
  background: var(--carte); border-radius: var(--rayon-1);
  padding: var(--es-3) var(--es-4); margin-bottom: var(--es-4);
}
.alerte::before {
  content: ""; display: inline-block; width: 8px; height: 8px;
  border-radius: 50%; margin-right: .5rem; background: var(--texte-2);
}
.alerte-information, .alerte.info { border-color: var(--info-bord); background: var(--info-clair); }
.alerte-information::before, .alerte.info::before { background: var(--marine-2); }
.alerte-attention, .alerte.attention { border-color: var(--ambre-bord); background: var(--ambre-clair); }
.alerte-attention::before, .alerte.attention::before { background: var(--ambre); }
.alerte-erreur, .alerte.erreur { border-color: var(--rouge); background: var(--rouge-clair); }
.alerte-erreur::before, .alerte.erreur::before { background: var(--rouge); }
.alerte-succes, .alerte.calme { border-color: color-mix(in srgb, var(--accent) 25%, var(--carte)); background: var(--accent-clair); }
.alerte-succes::before, .alerte.calme::before { background: var(--accent); }
.alerte .alerte-titre { font-weight: 700; margin: 0 0 var(--es-1); }
.alerte p:last-child { margin-bottom: 0; }

/* ---------- 10. Fiche riche ---------- */
.fiche-tete {
  background: var(--carte); border: var(--bordure); border-radius: var(--rayon-2);
  box-shadow: var(--ombre-1);
  padding: var(--es-5); margin-bottom: var(--es-4);
  display: flex; flex-wrap: wrap; gap: var(--es-3); align-items: flex-start;
}
.fiche-tete .identite { min-width: 16rem; }
.fiche-tete h1 { margin: 0 0 var(--es-1); }
.fiche-tete .meta { color: var(--texte-2); font-size: var(--texte-s); margin: 0; }
.fiche-tete .actions { margin-left: auto; display: flex; gap: var(--es-2); flex-wrap: wrap; }
.detail { margin-bottom: var(--es-3); }
.detail .detail-terme { font-size: var(--texte-xs); color: var(--texte-2); text-transform: uppercase; letter-spacing: .05em; font-weight: 600; }
.detail .detail-valeur { font-size: var(--texte-m); margin-top: 1px; }
.grille-details { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: var(--es-4) var(--es-5); }
.grille-contacts { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
  min-width: 0; gap: var(--es-3); }
.contact {
  border: var(--bordure); border-radius: var(--rayon-2); padding: var(--es-3);
  background: var(--carte); box-shadow: var(--ombre-1);
  display: flex; gap: var(--es-3); align-items: flex-start;
  transition: box-shadow var(--transition), transform var(--transition);
}
.contact:hover { box-shadow: var(--ombre-2); transform: translateY(-1px); }
.contact .avatar {
  flex: none; width: 2.5rem; height: 2.5rem; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--marine); color: var(--sur-fonce); font-weight: 700; font-size: var(--texte-s);
}
.contact .contact-nom { font-weight: 700; }
.contact .contact-role { font-size: var(--texte-s); color: var(--texte-2); }
.contact p { margin: var(--es-1) 0 0; font-size: var(--texte-s); }
.chip-cat {
  display: inline-block; padding: 0.125rem var(--es-2);
  font-size: var(--texte-xs); font-weight: 600;
  color: var(--marine-2); background: var(--info-clair);
  border-radius: var(--rayon-3);
}

/* ---------- 11. Onglets ---------- */
.onglets { display: flex; gap: var(--es-1); border-bottom: 1px solid var(--ligne-forte); margin-bottom: var(--es-4); flex-wrap: wrap; }
.onglet {
  font: inherit; font-size: var(--texte-m);
  padding: var(--es-2) var(--es-3);
  background: none; border: none; border-bottom: 2px solid transparent;
  color: var(--texte-2); cursor: pointer; margin-bottom: -1px;
  transition: color var(--transition), border-color var(--transition);
}
.onglet:hover { color: var(--marine); }
.onglet[aria-selected="true"] { color: var(--marine); font-weight: 700; border-bottom-color: var(--accent); }

/* ---------- 12. Étapes, jauges, durées ---------- */
.etape { display: flex; gap: var(--es-2); align-items: flex-start; padding: var(--es-2) 0; border-top: var(--bordure); }
.etape:first-child { border-top: none; }
.etape .etape-marque {
  flex: none; width: 1.375rem; height: 1.375rem;
  border: 1px solid var(--ligne-forte); border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--texte-xs); color: var(--texte-2); background: var(--carte);
}
.etape.est-faite .etape-marque { background: var(--accent); border-color: var(--accent); color: var(--sur-fonce); }
.etape.est-courante .etape-marque { border-color: var(--accent); color: var(--accent); font-weight: 700; box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent); }
.jauge { background: var(--fond); border: var(--bordure); border-radius: 999px; height: .5rem; overflow: hidden; }
.progression { background: linear-gradient(90deg, var(--accent), var(--accent-fonce)); height: 100%; border-radius: 999px; }
.duree-ligne { display: flex; justify-content: space-between; gap: var(--es-3); font-size: var(--texte-s); padding: var(--es-1) 0; border-top: var(--bordure); }
.duree-ligne:first-child { border-top: none; }
.duree-ligne .duree-valeur { font-variant-numeric: tabular-nums; font-weight: 600; }

/* ---------- 13. États ---------- */
.vide {
  text-align: center; padding: var(--es-7) var(--es-4);
  color: var(--texte-2); background: var(--carte);
  border: 1px dashed var(--ligne-forte); border-radius: var(--rayon-2);
  margin-bottom: var(--es-4);
}
.vide svg { color: var(--ligne-forte); margin-bottom: var(--es-2); }
.vide .vide-titre { font-weight: 700; color: var(--texte); font-size: var(--texte-l); margin-bottom: var(--es-1); }
.chargement { display: flex; align-items: center; gap: var(--es-2); color: var(--texte-2); padding: var(--es-4); }
.chargement::before {
  content: ""; width: 1rem; height: 1rem; flex: none;
  border: 2px solid var(--ligne); border-top-color: var(--accent);
  border-radius: 50%; animation: satelis-tourne .8s linear infinite;
}
@keyframes satelis-tourne { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .chargement::before { animation: none; }
  *, *::before, *::after { transition-duration: 0.01ms !important; }
}

/* ---------- 14. Divers ---------- */
.intro { font-size: var(--texte-l); color: var(--texte-2); max-width: 46rem; }
.actions-fin { display: flex; gap: var(--es-2); justify-content: flex-end; flex-wrap: wrap; }
.texte-secondaire { color: var(--texte-2); }
.visuellement-cache { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
pre.code {
  background: var(--surface); border: var(--bordure); border-radius: var(--rayon-1);
  padding: var(--es-3); overflow-x: auto; font-size: var(--texte-s); line-height: 1.5;
  margin: var(--es-2) 0 var(--es-4);
}

/* ---------- 15. Impression A4 ---------- */
@page { size: A4; margin: 18mm 16mm; }



/* ======== 2. LIAISON ======== */
/*
 * La fondation stylise des CLASSES (`.bouton`, `.champ-entree`) ; nos
 * pages écrivent des ÉLÉMENTS nus. Plutôt que de réécrire vingt modules —
 * un risque pour aucun gain visible — cette strate applique la fondation
 * au balisage existant. Dans une application rendue par le serveur, styler
 * `button` plutôt qu'exiger une classe est PLUS SÛR : un bouton qu'on
 * oublie de classer reste correct, et un écran ajouté demain hérite du
 * style sans qu'on y pense.
 */
input[type="text"], input[type="number"], input[type="date"], input[type="month"],
input[type="search"], input[type="email"], input[type="tel"], input[type="password"],
input:not([type]), select, textarea {
  /* `width: 100%` ET `max-width: 100%` : sans la première, un champ garde
     sa largeur intrinsèque (une vingtaine de caractères) et deux colonnes
     de formulaire poussaient la page de Réglages à 475 px sur un écran de
     390. Sans la seconde, un `size` explicite reprendrait le dessus. */
  width: 100%; max-width: 100%;
  padding: 0.4375rem var(--es-3);
  font: inherit; color: var(--texte); background: var(--carte);
  border: 1px solid var(--ligne-forte); border-radius: var(--rayon-1);
  transition: border-color var(--transition), box-shadow var(--transition);
}
input:hover:not(:disabled):not([type="checkbox"]):not([type="radio"]),
select:hover:not(:disabled), textarea:hover:not(:disabled) { border-color: var(--marine-2); }
/* `:focus-within` aussi : dans un champ de date ou de mois, Tab peut poser
   le focus sur un composant INTERNE du champ (son sélecteur), et `:focus`
   ne s'allume plus — l'audit du 08/10 l'a trouvé, le champ n'avait alors
   aucun signe de focus. */
input:focus, input:focus-within, select:focus, textarea:focus {
  border-color: var(--accent); outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
input:disabled, select:disabled, textarea:disabled {
  background: var(--fond); color: var(--texte-2); cursor: not-allowed;
}
input[type="checkbox"], input[type="radio"] { accent-color: var(--accent); }

/* Les boutons : l'élément porte le style, les classes le nuancent. */
button, a.bouton {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--es-2);
  padding: 0.4375rem var(--es-4);
  font: inherit; font-weight: 600; line-height: 1.2;
  border-radius: var(--rayon-1); border: 1px solid transparent;
  background: var(--accent); color: var(--sur-fonce);
  cursor: pointer; text-decoration: none;
  transition: background var(--transition), border-color var(--transition);
}
button:hover:not(:disabled), a.bouton:hover { background: var(--accent-fonce); color: var(--sur-fonce); }
button:disabled { background: var(--ligne); color: var(--texte-2); cursor: not-allowed; }
button.secondaire, a.bouton.secondaire, .bouton-2 {
  background: var(--carte); color: var(--marine); border-color: var(--ligne-forte);
}
button.secondaire:hover:not(:disabled) { background: var(--surface); color: var(--marine); }
button.discret {
  background: transparent; color: var(--texte-2); border-color: var(--ligne);
}
button.discret:hover:not(:disabled) { background: var(--surface); color: var(--texte); }
button.mini { padding: 0.1875rem var(--es-3); font-size: var(--texte-xs); }
button.suppr, button.supprimer { background: var(--rouge); color: var(--sur-fonce); }
button.suppr:hover:not(:disabled), button.supprimer:hover:not(:disabled) { background: var(--rouge-fonce); }

/* Nos pastilles d'état n'ont pas le préfixe `est-` de la fondation. */
.badge-etude.brouillon      { color: var(--texte-2);  background: var(--surface); }
.badge-etude.en-etude       { color: var(--ambre);    background: var(--ambre-clair); }
.badge-etude.offre          { color: var(--marine-2); background: var(--surface); }
.badge-etude.offre-validee  { color: var(--accent);   background: var(--accent-clair); }
.badge-etude.transformee    { color: var(--marine);   background: var(--accent-clair); }
.badge-etude.sans-suite     { color: var(--texte-2);  background: var(--surface); }
/* La pastille des LACUNES : même ambre que « en étude » — la couleur de ce
   qui attend un geste — mais une classe à elle, parce que son comportement
   diffère (elle ne se replie jamais, voir plus haut). */
.badge-etude.a-traiter      { color: var(--ambre);    background: var(--ambre-clair); }


/* ======== 3. RÈGLES MÉTIER ======== */
/* Typo : l'interlettrage suit la taille — resserré sur les grands corps,
     neutre sur le texte courant (règle « optical sizing » du skill Apple). */
  h1 { font-size: var(--titre-2); color: var(--marine); margin: 0 0 .8rem; letter-spacing: -.012em; }
/* Réponse instantanée : le retour visuel vit sur l'appui, pas sur le
     relâchement — et seulement transform/opacité (compositeur). */
  button, a.bouton, .menu-item, a.puce, .filter-chip {
    transition: transform .1s ease-out, background-color .15s ease, box-shadow .18s ease,
      border-color .15s ease, color .15s ease;
  }
button:active, a.bouton:active { transform: scale(.97); }
.menu-item:active, a.puce:active { transform: scale(.98); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* ---- Coquille : barre latérale + barre haute (maquette du 15/08) ---- */
  .app { display: flex; min-height: 100vh; }
.lateral { width: var(--charpente-lat); background: linear-gradient(180deg, var(--marine), var(--marine-3)); color: var(--sur-fonce);
    position: fixed; top: 0; bottom: 0; left: 0; display: flex; flex-direction: column; z-index: 100; }
.lateral-tete { display: flex; align-items: center; gap: .7rem; padding: 1.05rem 1.1rem;
    border-bottom: 1px solid color-mix(in srgb, var(--sur-fonce) 10%, transparent); }
.logo-carre { width: 2.4rem; height: 2.4rem; background: color-mix(in srgb, var(--sur-fonce) 14%, transparent); color: var(--sur-fonce);
    border-radius: 10px; display: flex; align-items: center; justify-content: center;
    font-size: var(--texte-l); font-weight: 700; flex: none; }
.marque {
  /* La fondation met `.marque` en flex pour son logo en SVG ; notre marque
     porte un sous-titre en bloc, qui se retrouvait sur la même ligne et
     débordait de la barre. Ici, c'est une colonne. */
  display: block; padding: 0;
  font-weight: 700; letter-spacing: .14em; font-size: var(--texte-l); line-height: 1.25;
}
.marque span { display: block; font-weight: 400; font-size: .56rem; letter-spacing: .16em;
    color: var(--side-texte-2); text-transform: uppercase; }
.menu { flex: 1; overflow-y: auto; padding: .8rem .7rem; }
.menu-section { padding: .9rem .6rem .3rem; font-size: var(--texte-xs); text-transform: uppercase;
    letter-spacing: .12em; color: color-mix(in srgb, var(--sur-fonce) 45%, transparent); font-weight: 600; }
.menu-item { display: flex; align-items: center; gap: .65rem; padding: .58rem .7rem; border-radius: 9px;
    color: color-mix(in srgb, var(--sur-fonce) 78%, transparent); text-decoration: none; font-size: var(--texte-m); margin-bottom: 2px; }
.menu-item:hover { background: color-mix(in srgb, var(--sur-fonce) 9%, transparent); color: var(--sur-fonce); }
.menu-item.actif { background: color-mix(in srgb, var(--sur-fonce) 16%, transparent); color: var(--sur-fonce); }
.icone { width: 1.05rem; height: 1.05rem; flex: none; }
.lateral-pied { padding: .9rem 1rem; border-top: 1px solid color-mix(in srgb, var(--sur-fonce) 10%, transparent); }
.badge-utilisateur { display: flex; align-items: center; gap: .6rem; }
.avatar { width: 2.1rem; height: 2.1rem; border-radius: 50%; background: var(--accent); display: flex;
    align-items: center; justify-content: center; font-weight: 700; font-size: var(--texte-m); flex: none; }
.u-nom { font-size: var(--texte-s); font-weight: 600; }
.u-role { font-size: var(--texte-xs); color: color-mix(in srgb, var(--sur-fonce) 55%, transparent); }
a.sortir { display: flex; align-items: center; gap: .5rem; margin-top: .8rem;
    color: color-mix(in srgb, var(--sur-fonce) 65%, transparent); text-decoration: none; font-size: var(--texte-s); }
a.sortir:hover { color: var(--sur-fonce); }
.principal { flex: 1; margin-left: var(--charpente-lat); min-width: 0; display: flex; flex-direction: column; }
/* Matériau translucide : le contenu défile SOUS la barre (bord adouci,
     pas de trait dur) — hiérarchie par la matière, pas par la bordure. */
  /* Fond OPAQUE : le flou captait les couleurs du contenu qui défilait
     dessous et produisait des voiles colorés (audit du 16/08). */
  .barre-haute { height: var(--charpente-haut); background: var(--carte);
    border-bottom: 1px solid color-mix(in srgb, var(--marine) 8%, transparent); box-shadow: 0 1px 8px color-mix(in srgb, var(--encre) 4%, transparent);
    display: flex; align-items: center; gap: .8rem; padding: 0 1.4rem; position: sticky; top: 0; z-index: 50; }
/* ---- Liens du contenu ----------------------------------------------
     Sans cette règle, le navigateur les rendait bleu #0000EE puis violet
     une fois visités : une liste de 243 clients mi-bleue mi-violette.
     Correctif le plus rentable de l'audit du 16/08. */
  main a { color: var(--marine); text-decoration: none;
    border-bottom: 1px solid color-mix(in srgb, var(--marine) 22%, transparent); }
main a:hover { color: var(--accent); border-bottom-color: currentColor; }
main a:visited { color: var(--marine); }
/* Les liens déjà habillés (boutons, puces, menu, onglets) gardent le leur. */
  main a.bouton, main a.bouton-2, main a.puce, main a.menu-item, main a.doc,
  main a.lien-aide, main .sous-nav a, main .contact a, main .cs-detail a
    { border-bottom: 0; }
.titre-page { font-size: var(--texte-l); font-weight: 700; color: var(--marine); letter-spacing: -.01em; }
button.burger { display: none; background: none; border: 0; color: var(--marine); font-size: var(--titre-3);
    cursor: pointer; margin: 0; padding: .1rem .4rem; }
/* La BARRE D'ÉCRAN porte le titre, le compteur de résultats et l'action
   primaire : un écran, un titre, un endroit — le h1 dupliqué du corps a
   disparu (charpente, SYSTEME-DESIGN.md §2). */
  .barre-compteur { font-size: var(--texte-s); color: var(--texte-2);
    font-variant-numeric: tabular-nums; border-left: 1px solid var(--ligne);
    padding-left: .8rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* L'AVERTISSEMENT — une pastille qui s'ouvre, et qui se REFERME.
 *
 * Quatre écrans portaient un paragraphe ambré permanent au-dessus de leur
 * liste. Il se replie en pastille ; son texte s'ouvre d'un clic ou d'une
 * tape (`<details>`), et le survol l'ouvre aussi sur un poste à souris.
 *
 * LA PREMIÈRE VERSION SE DÉPLIAIT AU SURVOL SEUL, et s'écrivait en entier
 * là où le survol n'existe pas. Sur téléphone, le texte s'affichait donc
 * par-dessus l'écran — la barre a une hauteur fixe, il débordait — et
 * rien ne le refermait. Le panneau est maintenant TOUJOURS un panneau
 * posé au-dessus du contenu, et l'état ouvert/fermé appartient au
 * `<details>` : la même mécanique partout, quel que soit le doigt ou la
 * souris. */
.avertissement { position: relative; display: inline-block; flex: none; }
.avertissement > summary {
    display: inline-flex; align-items: center; gap: .3rem;
    padding: .1rem .5rem; border-radius: 999px; cursor: pointer;
    list-style: none; user-select: none;
    background: var(--ambre-clair); color: var(--ambre); border: 1px solid var(--ambre-bord);
    font-size: var(--texte-xs); font-weight: 600; white-space: nowrap; }
.avertissement > summary::-webkit-details-marker { display: none; }
.avertissement > summary::marker { content: ""; }
.avertissement > summary:hover { background: var(--ambre-survol); }
.avertissement .marque { font-size: .9em; }
.avertissement .texte {
    position: absolute; top: calc(100% + .4rem); left: 0; z-index: 200;
    width: max-content; max-width: min(38rem, 78vw);
    padding: .55rem .8rem; border-radius: var(--rayon-1);
    background: var(--carte); color: var(--texte); border: 1px solid var(--ambre-bord);
    box-shadow: var(--ombre-2); font-weight: 400; font-size: var(--texte-s);
    white-space: normal; text-align: left; }
/* PAS DE SURVOL : mesuré, pas supposé. Un navigateur masque le contenu
   d'un `<details>` fermé par `content-visibility`, que la feuille demande
   `display: block` ou non — le survol ne peut donc plus l'ouvrir. Plutôt
   qu'un demi-geste qui marche sur un poste et pas sur l'autre, un seul :
   on ouvre d'un clic, on referme du même. Le chevron le dit. */
.avertissement > summary::after {
    content: ""; width: .38em; height: .38em; flex: none; margin-left: .1rem;
    border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
    transform: rotate(-45deg) translate(-1px, -1px);
    transition: transform var(--transition); }
.avertissement[open] > summary::after { transform: rotate(45deg) translate(-2px, -2px); }
/* Sur téléphone la barre est étroite : le panneau s'aligne à DROITE pour
   ne pas sortir de l'écran. */
@media (max-width: 30rem) {
  .avertissement .texte { left: auto; right: 0; max-width: 88vw; }
}

.barre-haute .pousse { margin-left: auto; display: flex; gap: .5rem; align-items: center; flex: none; }
.barre-haute .pousse a.bouton, .barre-haute .pousse a.bouton-2 { margin-top: 0;
    padding: .35rem .9rem; font-size: var(--texte-s); }
a.lien-aide { font-size: var(--texte-s); color: var(--texte-2); text-decoration: none;
    border: 1px solid var(--ligne); border-radius: 999px; padding: .2rem .7rem; white-space: nowrap; }
a.lien-aide:hover { color: var(--marine); border-color: var(--marine); }
/* La barre d'OUTILLAGE : ce qui commande la liste — recherche, puces,
   sélecteurs — vit sous la barre d'écran, HORS de la zone qui défile.
   Sous 64rem la page défile : la barre se colle alors sous la barre
   d'écran ; sous 30rem elle devient la ligne qui défile du doigt. */
  .outillage { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap;
    padding: .55rem 1.4rem; background: var(--carte); border-bottom: 1px solid var(--ligne);
    position: sticky; top: var(--charpente-haut); z-index: 40; }
.outillage .barre-filtres, .outillage .puces, .outillage .sommaire-reglages { margin: 0; }
/* `flex-wrap: wrap` ET NON `nowrap`. Le `nowrap` d'origine voulait garder
   la recherche et ses déroulantes sur une ligne du ruban — mais il ne les y
   garde que là où elles TIENNENT déjà, et partout ailleurs il ne fait que
   forcer le débordement : 769 px de barre dans une tablette de 768, qui
   poussaient le document entier vers la droite. Autorisée à se replier,
   elle reste sur une ligne quand il y a la place, et passe à la ligne
   quand il n'y en a pas. On ne perd rien, on gagne les écrans étroits. */
.outillage .barre-filtres { flex: 1 1 auto; flex-wrap: wrap; }
.outillage input[type="search"], .outillage select { width: auto; }
.outillage .barre-filtres input[type="search"] { flex: 1 1 12rem; min-width: 9rem; }
.outillage button { margin-top: 0; padding: .4rem .9rem; font-size: var(--texte-s); }
.outillage .cherche-client { position: relative; flex: 1 1 18rem; }
.outillage .cherche-client input { padding: .5rem .7rem; border: 1px solid var(--ligne);
    border-radius: 8px; background: var(--carte); }
ol.aide-etapes { margin: 0; padding-left: 1.3rem; }
ol.aide-etapes li, ul.aide-regles li { font-size: var(--texte-m); margin: .25rem 0; }
ul.aide-regles { margin: 0; padding-left: 1.3rem; }
/* Accessibilité : trois signaux respectés (skill Apple §14). */
  @media (prefers-reduced-motion: reduce) {
    * { transition: none !important; animation: none !important; }
    html { scroll-behavior: auto; }
    button:active, a.bouton:active, .menu-item:active, a.puce:active { transform: none; }
    .carte-stat:hover { transform: none; }
  }
/* ---- Écran de connexion (carte centrée sur fond marine) ---- */
  body.plein { background: linear-gradient(135deg, var(--marine) 0%, var(--marine-3) 100%); }
.ecran-connexion { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 1rem; }
/* ---- Tableau de bord ---- */
  .grille-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: .9rem; margin-bottom: 1.3rem; }
.cs-valeur { font-size: var(--titre-2); font-weight: 700; color: var(--marine); line-height: 1.15;
    letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.cs-libelle { font-size: var(--texte-s); color: var(--texte-2); }
.cs-detail { font-size: var(--texte-xs); color: var(--texte-2); margin-top: .2rem; }
/* LA FILE « À TRAITER » : le travail du matin, en tête de tableau de
   bord — un point d'état, le fait, le lien pour y aller. */
  ul.file { list-style: none; margin: 0; padding: 0; }
ul.file li { display: flex; align-items: baseline; gap: .6rem; padding: .45rem 0;
    border-bottom: 1px solid var(--ligne); font-size: var(--texte-m); }
ul.file li:last-child { border-bottom: 0; }
ul.file .point { flex: none; width: 8px; height: 8px; border-radius: 50%;
    background: var(--ambre); align-self: center; }
ul.file .point.info { background: var(--marine-2); }
ul.file .point.calme { background: var(--accent); }
ul.file a.aller { margin-left: auto; font-size: var(--texte-s); font-weight: 600;
    white-space: nowrap; border-bottom: 0; color: var(--accent); }

/* LA BANDE DE CHIFFRES (décision du 20/08, planche « Variantes ») : un
   seul conteneur blanc, les chiffres séparés par de fins filets. L'état
   est porté par un JETON D'ÉTAT — point ambre + lien pour « agissant »,
   valeur grise pour « calme » — jamais par l'accent de la palette : la
   distinction survit à toutes les palettes. */
  .bande-stats { display: flex; background: var(--carte); border: 1px solid var(--ligne);
    border-radius: var(--rayon-2); box-shadow: var(--ombre-1); margin-bottom: 1.3rem; }
.bande-stats .stat { flex: 1; min-width: 0; padding: .5rem .9rem;
    border-left: 1px solid var(--ligne); }
.bande-stats .stat:first-child { border-left: 0; }
.stat-libelle { display: flex; align-items: center; gap: .4rem; font-size: var(--texte-s);
    color: var(--texte-2); }
.point-etat { width: 7px; height: 7px; border-radius: 50%; background: var(--ambre); flex: none; }
.stat.calme .cs-valeur { color: var(--texte-2); font-weight: 600; }
.bande-stats a { border-bottom: 0; color: var(--accent); font-weight: 600;
    font-size: var(--texte-xs); white-space: nowrap; }
.stat.agissant a { color: var(--ambre); }
ul.fil { margin: 0; padding: 0; list-style: none; }
ul.fil li { display: flex; gap: .9rem; padding: .45rem 0; border-bottom: 1px solid var(--ligne); font-size: var(--texte-m); }
ul.fil li:last-child { border-bottom: 0; }
ul.fil .quand { color: var(--texte-2); white-space: nowrap; font-size: var(--texte-xs); padding-top: .1rem;
    font-variant-numeric: tabular-nums; }
/* ---- Auto-complétion clients ---- */
  .cherche-client { position: relative; display: block; }
ul.suggestions { position: absolute; left: 0; right: 0; z-index: 60; margin: .2rem 0 0;
    padding: 0; list-style: none; background: var(--carte); border: 1px solid var(--ligne);
    border-radius: 8px; box-shadow: var(--ombre); max-height: 16rem; overflow-y: auto; }
ul.suggestions:empty { display: none; }
ul.suggestions li { padding: .5rem .8rem; cursor: pointer; font-size: var(--texte-m);
    transition: background-color .1s ease; }
ul.suggestions li:hover, ul.suggestions li:active { background: var(--accent-clair); }
ul.suggestions li.creer { color: var(--accent); font-weight: 600;
    border-top: 1px solid var(--ligne); }
/* ---- Tableaux : ils défilent DANS leur cadre, pas la page entière ----
     Un tableau plus large que son conteneur poussait tout le document vers
     la droite, barre supérieure comprise (audit du 16/08). */
  .tableau-cadre { overflow-x: auto; -webkit-overflow-scrolling: touch;
    border-radius: 10px; }
/* Un rapport d'import fait des centaines de lignes : il défile dans son
     cadre au lieu de repousser le bouton « Appliquer » hors de l'écran. */
  .tableau-cadre.tableau-long { max-height: 30rem; overflow-y: auto; }
/* Ce que le pied de page réglementaire donnera : montré avant d'imprimer. */
  .apercu-pied { margin-top: 1rem; padding: .8rem 1rem; border-radius: .4rem;
    background: var(--surface); border: 1px solid var(--ligne); }
.apercu-pied p { margin: .3rem 0 0; font-size: var(--texte-s); color: var(--marine); line-height: 1.5; }
/* Le classeur décrit une fiche sur plusieurs lignes : un filet marque le
     début de chaque colonne pour que l'œil suive les cases qui vont ensemble. */
  tr.bloc-debut td { border-top: 2px solid var(--ligne); }
/* Une colonne calculée n'est pas une destination : la ligne le montre
     sans la cacher — on doit pouvoir revenir en arrière d'un clic. */
  tr.case-calculee { background: var(--surface); color: var(--texte-2); font-style: italic; }
table.tableau-affaires { max-width: 100%; }
/* ---- Fiche client ---- */
  .fiche-tete { display: flex; align-items: flex-start; justify-content: space-between;
    gap: 1rem; flex-wrap: wrap; margin: 0 0 .9rem; }
.fiche-tete .identite { flex: 1 1 22rem; min-width: 0; }
.fiche-tete h1 { margin: 0; }
.etiquettes { display: flex; gap: .45rem; flex-wrap: wrap; align-items: center; margin-top: .4rem; }
.num-client { font-variant-numeric: tabular-nums; letter-spacing: .04em; font-weight: 600;
    font-size: var(--texte-xs); color: var(--texte-2); border: 1px solid var(--ligne);
    border-radius: 6px; padding: .1rem .45rem; }
.chip-cat { font-size: var(--texte-xs); color: var(--marine); background: var(--accent-clair);
    border-radius: 999px; padding: .12rem .6rem; }
.actions-tete { display: flex; gap: .5rem; flex-wrap: wrap; align-items: flex-start; }
.actions-tete a.bouton, .actions-tete a.bouton-2 { margin-top: 0; }
a.bouton-2 { display: inline-block; background: var(--carte); color: var(--marine);
    border: 1px solid var(--ligne); text-decoration: none; border-radius: 8px;
    padding: .5rem 1.1rem; font-size: var(--texte-m); }
a.bouton-2:hover { border-color: var(--marine); }
.grille-contacts { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
  min-width: 0;
    gap: .7rem; margin-top: .6rem; }
.contact { border: 1px solid var(--ligne); border-radius: 10px; padding: .75rem .9rem;
    background: var(--carte); }
.contact.principal { border-left: 3px solid var(--accent); background: var(--accent-clair); }
.contact .c-nom { font-weight: 600; color: var(--marine); }
.contact .c-role { font-size: var(--texte-xs); color: var(--texte-2); }
.contact ul { list-style: none; margin: .45rem 0 0; padding: 0; font-size: var(--texte-m); }
.contact li { display: flex; gap: .5rem; align-items: baseline; padding: .08rem 0; }
.contact li .etiq { color: var(--texte-2); font-size: var(--texte-xs); flex: 0 0 3.6rem;
    text-transform: uppercase; letter-spacing: .06em; }
.contact a { color: var(--accent); text-decoration: none; font-variant-numeric: tabular-nums; }
.contact a:hover { text-decoration: underline; }
.contact-edit { border-top: 1px solid var(--ligne); padding-top: .7rem; margin-top: .7rem; }
.ligne-case { display: flex; align-items: center; gap: .45rem; margin-top: .6rem; }
.ligne-case input { width: auto; }
.jauge.mince { height: 5px; margin: .45rem 0 .2rem; }
details.carte > summary { cursor: pointer; font-size: var(--texte-l); font-weight: 600;
    color: var(--marine); letter-spacing: -.008em; }
details.carte[open] > summary { margin-bottom: .7rem; }
/* ---- Sécurité & RGPD : mesures en place / à faire ---- */
  ul.mesures { list-style: none; margin: .6rem 0 0; padding: 0;
    display: flex; flex-direction: column; gap: .8rem; }
.mesure { display: flex; gap: .75rem; align-items: flex-start; }
.mesure > span { flex: 0 0 auto; margin-top: .1rem; }
.mesure p { margin: 0; }
.mesure p.aide { margin-top: .2rem; font-size: var(--texte-s); }
td.duree { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
.duree-ligne { margin-top: .7rem; }
.duree-ligne label { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.duree-ligne input { width: 5rem; }
.duree-ligne p.aide { margin: .15rem 0 0; }
/* ---- Mise en service : la checklist calculée ---- */
  ol.etapes-service { list-style: none; margin: 0; padding: 0;
    display: flex; flex-direction: column; gap: 1rem; }
.etape { display: flex; gap: .9rem; align-items: flex-start; }
.etape-numero { flex: 0 0 auto; width: 1.9rem; height: 1.9rem; border-radius: 50%;
    display: flex; align-items: center; justify-content: center; font-weight: 700;
    font-size: var(--texte-s); background: var(--surface); color: var(--texte-2); font-variant-numeric: tabular-nums; }
.etape.fait .etape-numero { background: var(--accent-clair); color: var(--accent); }
.etape.a-verifier .etape-numero { background: var(--ambre-clair); color: var(--ambre); }
.etape-corps { flex: 1; min-width: 0; }
.etape-titre { font-weight: 600; display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.etape-corps p.aide { margin: .25rem 0 .35rem; }
/* ---- Liste des affaires : filtres, tri, regroupement ---- */
  .barre-filtres { display: flex; gap: .5rem; flex-wrap: wrap; margin: 0 0 .8rem; }
.barre-filtres input[type=search] { flex: 1; min-width: 14rem; font: inherit; padding: .5rem .7rem;
    border: 1px solid var(--ligne); border-radius: 8px; background: var(--carte); }
.barre-filtres select { font: inherit; padding: .5rem .6rem; border: 1px solid var(--ligne);
    border-radius: 8px; background: var(--carte); }
.barre-filtres button { margin-top: 0; }
table.tableau-affaires tr.groupe td { background: var(--surface); border-top: 2px solid var(--ligne);
    font-size: var(--texte-m); }
table.tableau-affaires td.montant { text-align: right; white-space: nowrap; }
a.tri { color: inherit; text-decoration: none; }
a.tri:hover, a.tri.actif { color: var(--marine); }
/* ---- Études : filtres et statuts ---- */
  .puces { display: flex; gap: .5rem; flex-wrap: wrap; margin: 0 0 1rem; }
a.puce { padding: .32rem .85rem; border-radius: 999px; border: 1px solid var(--ligne);
    background: var(--carte); font-size: var(--texte-s); text-decoration: none; color: var(--texte); }
a.puce:hover { border-color: var(--marine); }
a.puce.active { background: var(--marine); color: var(--sur-fonce); border-color: var(--marine); }
.mission-veille { display: inline-block; padding: .12rem .55rem; border-radius: 6px;
    font-size: var(--texte-xs); font-weight: 600; background: var(--info-badge); color: var(--info); margin-right: .3rem; }
.avis-veille .v-actions { margin-top: .5rem; display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }
.avis-veille a.bouton { margin-top: 0; padding: .35rem .8rem; font-size: var(--texte-s); }
.echeance { font-size: var(--texte-xs); color: var(--texte-2); }
.echeance.urgente { color: var(--ambre); font-weight: 600; }
.echeance.depassee { color: var(--rouge); font-weight: 600; }
.echeance.proche { color: var(--accent); font-weight: 600; }
/* Indice de proposition — la convention du cabinet, lisible d'un coup d'œil. */
  .indice { display: inline-flex; align-items: center; justify-content: center;
    min-width: 1.5rem; height: 1.5rem; padding: 0 .3rem; border-radius: 6px;
    background: var(--marine); color: var(--sur-fonce); font-weight: 700; font-size: var(--texte-xs);
    font-variant-numeric: tabular-nums; }
td.actions { white-space: normal; }
td.actions button { margin: .1rem .15rem .1rem 0; }
.barre-mois { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; margin: 0 0 1rem; }
.entete-affaire { display: flex; justify-content: space-between; align-items: baseline;
    gap: .8rem; flex-wrap: wrap; }
details.agir { display: inline-block; margin: .1rem .3rem .1rem 0; vertical-align: top; }
details.agir summary { cursor: pointer; font-size: var(--texte-s); color: var(--marine); }
details.agir label { display: block; font-size: var(--texte-s); color: var(--texte-2); margin-top: .4rem; }
details.agir input, details.agir textarea { width: 100%; font: inherit; font-size: var(--texte-m);
    padding: .35rem .5rem; border: 1px solid var(--ligne); border-radius: 6px; }
.conformite .element { display: flex; align-items: baseline; gap: .55rem; padding: .3rem 0;
    border-bottom: 1px solid var(--ligne); font-size: var(--texte-m); }
.conformite .element:last-child { border-bottom: 0; }
.conformite .element.fait { color: var(--texte-2); text-decoration: line-through; }
.conformite .element.manquant { color: var(--ambre); }
.conformite input[type=checkbox] { accent-color: var(--accent); }
button.discret { background: var(--surface); color: var(--texte-2); }
details.transformer { margin: .3rem 0; }
details.transformer summary { cursor: pointer; font-size: var(--texte-s); color: var(--marine); }
details.transformer label { display: block; font-size: var(--texte-s); color: var(--texte-2); margin-top: .4rem; }
details.transformer input, details.transformer select { width: 100%; font: inherit;
    font-size: var(--texte-m); padding: .35rem .5rem; border: 1px solid var(--ligne); border-radius: 6px; }

/* UN SEUL IDIOME PAR ZONE (revue de design, constat n° 4). Dans une même
   cellule d'actions cohabitaient un dépliant nu (« ▶ Modifier ») et des
   boutons pleins (« Soumettre l'offre ») : le coût du clic était illisible
   — l'un ouvre un formulaire, les autres exécutent. Les DÉCLENCHEURS DE
   DÉPLIANT prennent la silhouette du bouton discret — même hauteur et même
   corps que `button.mini`, mais BORDÉS au lieu de pleins, et un chevron qui
   dit « ceci s'ouvre » et pivote à l'ouverture. Ce qui exécute reste plein ;
   ce qui ouvre est bordé : la différence se voit avant de cliquer. */
details.modifier > summary,
details.transformer > summary,
details.agir > summary,
details.rattachement-bloquees > summary,
details.supprimer-affaire > summary {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: 0.1875rem var(--es-3);
  border: 1px solid var(--ligne); border-radius: var(--rayon-1);
  background: var(--carte); color: var(--marine);
  font-size: var(--texte-xs); font-weight: 600;
  cursor: pointer; user-select: none;
  list-style: none;
}
details.modifier > summary::-webkit-details-marker,
details.transformer > summary::-webkit-details-marker,
details.agir > summary::-webkit-details-marker,
details.rattachement-bloquees > summary::-webkit-details-marker,
details.supprimer-affaire > summary::-webkit-details-marker { display: none; }
details.modifier > summary::before,
details.transformer > summary::before,
details.agir > summary::before,
details.rattachement-bloquees > summary::before,
details.supprimer-affaire > summary::before {
  content: ""; width: .38em; height: .38em; flex: none;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--transition);
}
details.modifier[open] > summary::before,
details.transformer[open] > summary::before,
details.agir[open] > summary::before,
details.rattachement-bloquees[open] > summary::before,
details.supprimer-affaire[open] > summary::before { transform: rotate(45deg); }
details.modifier > summary:hover,
details.transformer > summary:hover,
details.agir > summary:hover,
details.rattachement-bloquees > summary:hover,
details.supprimer-affaire > summary:hover { border-color: var(--marine-2); }
/* Le repli des études que le rattachement REFUSE : même pastille que les
   autres dépliants, un peu d'air au-dessus, et sa table reprend la largeur
   pleine une fois ouverte. */
details.rattachement-bloquees { margin-top: var(--es-3); }
details.rattachement-bloquees[open] > summary { margin-bottom: var(--es-3); }
main { width: 100%; max-width: 62rem; margin: 0 auto; padding: 1.5rem 1.4rem 4rem; }
.sous-nav { font-size: var(--texte-m); color: var(--texte-2); margin: -.3rem 0 1.2rem; }
.sous-nav a { color: var(--accent); text-decoration: none; }
.sous-nav a:hover { text-decoration: underline; }
h2.section { font-size: var(--titre-2); color: var(--marine); margin: 2.75rem 0 .35rem;
    display: flex; align-items: baseline; gap: .6rem; }
h2.section::after { content: ""; flex: 1; height: 1px; background: var(--ligne); }
.sous-section { color: var(--texte-2); font-size: var(--texte-m); margin: 0 0 1.1rem; }
/* Avancement */
  .lots { display: grid; grid-template-columns: repeat(auto-fill, minmax(15.5rem, 1fr)); gap: .8rem; }
.lot { background: var(--carte); border: 1px solid var(--ligne); border-radius: 10px; padding: .85rem 1rem;
    display: flex; flex-direction: column; gap: .3rem; }
.lot .entete { display: flex; align-items: center; gap: .55rem; }
.lot .code { font-size: var(--texte-xs); letter-spacing: .1em; color: var(--texte-2); text-transform: uppercase; }
.lot h3 { margin: 0; font-size: var(--texte-l); color: var(--marine); }
.lot p { margin: 0; font-size: var(--texte-s); color: var(--texte-2); line-height: 1.45; }
.pastille { margin-left: auto; font-size: var(--texte-xs); padding: .12rem .55rem; border-radius: 999px; white-space: nowrap; }
.pastille.fait, .pastille.valide { background: var(--accent-clair); color: var(--accent); border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--carte)); }
.pastille.en-cours, .pastille.remarques { background: var(--ambre-clair); color: var(--ambre); border: 1px solid var(--ambre-bord); }
.pastille.a-venir, .pastille.a-relire { background: var(--surface); color: var(--texte-2); border: 1px solid var(--ligne); }
.pastille.a-corriger { background: var(--rouge-clair); color: var(--rouge-fonce); border: 1px solid var(--rouge-bord); }
/* LES TROIS VERDICTS DE RECETTE partagent les teintes des trois verdicts de
   document — vert « ça va », ambre « ça va mais », rouge « non ». Un seul
   vocabulaire de couleur pour un seul geste : le cabinet regarde ce que
   nous avons livré et dit si ça convient. */
.pastille.conforme { background: var(--accent-clair); color: var(--accent); border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--carte)); }
.pastille.reserve  { background: var(--ambre-clair); color: var(--ambre); border: 1px solid var(--ambre-bord); }
.pastille.anomalie { background: var(--rouge-clair); color: var(--rouge-fonce); border: 1px solid var(--rouge-bord); }
/* Le titre de groupe de la recette : il sépare les écrans sans peser autant
   qu'un titre de section — on parcourt une liste, on ne navigue pas. */
.recette-ecran {
  margin: var(--es-5) 0 var(--es-3); font-size: var(--texte-l); color: var(--marine);
  border-bottom: 1px solid var(--ligne); padding-bottom: var(--es-2);
}
.lot.fait { border-left: 3px solid var(--accent); }
.lot.en-cours { border-left: 3px solid var(--ambre); }
/* Phases produit */
  .phases { display: flex; gap: .6rem; margin: .5rem 0 1.6rem; overflow-x: auto; padding-bottom: .3rem; }
.phase { flex: 1; min-width: 10.5rem; background: var(--carte); border: 1px solid var(--ligne);
    border-radius: 10px; padding: .75rem .9rem; }
.phase .entete { display: flex; align-items: center; gap: .5rem; }
.phase .num { width: 1.7rem; height: 1.7rem; border-radius: 50%; flex: none; display: flex;
    align-items: center; justify-content: center; background: var(--surface); color: var(--texte-2);
    font-weight: 600; font-size: var(--texte-s); }
.phase.fait .num { background: var(--accent); color: var(--sur-fonce); }
.phase.en-cours .num { background: var(--ambre); color: var(--sur-fonce); }
.phase.en-cours { border-color: var(--ambre); border-left: 3px solid var(--ambre); }
.phase.fait { border-left: 3px solid var(--accent); }
.phase h3 { margin: .4rem 0 .25rem; font-size: var(--texte-m); color: var(--marine); }
.phase p { margin: 0; font-size: var(--texte-xs); color: var(--texte-2); line-height: 1.45; }
/* Progression questions */
  .progression { display: flex; align-items: center; gap: 1rem; margin: .4rem 0 1.2rem; }
.jauge { flex: 1; height: 7px; background: var(--surface-2); border-radius: 999px; overflow: hidden; }
.jauge > div { height: 100%; background: var(--accent); border-radius: 999px; transition: width .3s; }
.progression .chiffre { font-size: var(--texte-m); color: var(--texte-2); white-space: nowrap; }
/* Questions */
  .question { position: relative; padding-left: 1.35rem; }
.question .numero { position: absolute; left: -1.05rem; top: 1.05rem; width: 2.1rem; height: 2.1rem;
    border-radius: 50%; background: var(--marine); color: var(--sur-fonce); display: flex; align-items: center;
    justify-content: center; font-size: var(--texte-s); font-weight: 600; }
.question.repondu { border-left: 3px solid var(--accent); }
.question.repondu .numero { background: var(--accent); }
.question h3 { margin: .1rem 0 .45rem; font-size: var(--texte-l); color: var(--marine); }
.badge-repondu { font-size: var(--texte-xs); vertical-align: middle; margin-left: .5rem; padding: .12rem .55rem;
    border-radius: 999px; background: var(--accent-clair); color: var(--accent); border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--carte)); }
.detail { color: var(--texte-2); font-size: var(--texte-m); margin: 0 0 .9rem; }
.reponse { border-left: 3px solid var(--accent); background: var(--accent-clair); border-radius: 0 8px 8px 0;
    padding: .6rem .9rem; margin: .55rem 0; font-size: var(--texte-m); }
.reponse .meta { color: var(--texte-2); font-size: var(--texte-xs); margin-top: .25rem; }
textarea { width: 100%; min-height: 5rem; font: inherit; font-size: var(--texte-m); padding: .6rem .7rem;
    border: 1px solid var(--ligne); border-radius: 8px; resize: vertical; background: var(--carte); }
textarea:focus, input:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: transparent; }
input[type=text], input[type=password] { font: inherit; padding: .55rem .7rem; border: 1px solid var(--ligne);
    border-radius: 8px; width: 100%; background: var(--carte); }
button { font: inherit; font-size: var(--texte-m); background: var(--accent); color: var(--sur-fonce); border: 0;
    border-radius: 8px; padding: .55rem 1.2rem; cursor: pointer; margin-top: .55rem; }
button:hover { background: var(--accent-fonce); }
/* PAS DE `button.secondaire` ICI. Une seconde définition vivait à cet
   endroit et n'imposait QUE le fond (marine) ; la couleur du texte restait
   celle de la règle d'origine (marine elle aussi), et le libellé
   disparaissait — « Relire avec ces réglages », « Tester la connexion »,
   « Scanner le Drive » n'étaient plus que des rectangles bleus. Vu sur
   capture le 22/08. La définition qui fait foi est plus haut, avec son
   fond clair ET sa couleur de texte. */
.ok { color: var(--accent); font-size: var(--texte-m); margin-left: .6rem; }
/* Documents */
  .docs { display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: .8rem; }
a.doc { display: block; background: var(--carte); border: 1px solid var(--ligne); border-radius: 10px;
    padding: .9rem 1.05rem; text-decoration: none; color: inherit; transition: border-color .15s, box-shadow .15s; }
a.doc:hover { border-color: var(--accent); box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 12%, transparent); }
a.doc .titre { color: var(--marine); font-weight: 600; font-size: var(--texte-m); }
a.doc .fichier { color: var(--texte-2); font-size: var(--texte-xs); margin-top: .2rem; }
a.doc .etat-doc { margin-top: .5rem; }
.valider-section { background: var(--fond); border: 1px solid var(--ligne); border-left: 3px solid var(--marine-2);
    border-radius: 8px; padding: .8rem 1.1rem; margin: 1.2rem 0 2rem; }
.valider-section .vs-entete { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.valider-section .vs-libelle { font-size: var(--texte-s); color: var(--texte-2); font-weight: 600;
    text-transform: uppercase; letter-spacing: .05em; }
.valider-section textarea { min-height: 3.2rem; }
.valider-section button { padding: .4rem .95rem; font-size: var(--texte-s); }
.choix-verdict { display: flex; gap: .6rem; flex-wrap: wrap; margin: .7rem 0; }
.choix-verdict label { border: 1px solid var(--ligne); border-radius: 999px; padding: .4rem .95rem;
    cursor: pointer; font-size: var(--texte-m); user-select: none; }
.choix-verdict input { margin-right: .4rem; accent-color: var(--accent); }
.choix-verdict label:has(input:checked) { border-color: var(--accent); background: var(--accent-clair); }
.doc-liste { padding-left: 1.1rem; margin: .6rem 0 0; }
.doc-liste li { margin: .3rem 0; font-size: var(--texte-m); }
.doc-liste a { color: var(--accent); }
/* Page de connexion */
  .connexion { max-width: 23rem; margin: 14vh auto 0; }
.connexion .marque-page { text-align: center; color: var(--marine); letter-spacing: .2em;
    font-size: var(--titre-2); margin-bottom: 1rem; }
.connexion .marque-page small { display: block; font-size: .6rem; letter-spacing: .3em; color: var(--texte-2); }
.erreur { color: var(--rouge-fonce); font-size: var(--texte-m); }
/* Article (document rendu) */
  article.document { background: var(--carte); border: 1px solid var(--ligne); border-radius: 12px;
    padding: 2.25rem 2.5rem; max-width: 50rem; margin: 1rem auto; }
article.document h1 { font-size: var(--titre-1); color: var(--marine); margin: .2rem 0 1rem;
    border-bottom: 3px solid var(--accent); padding-bottom: .6rem; }
article.document h2 { font-size: var(--titre-3); color: var(--marine); margin: 2rem 0 .6rem; }
article.document h3 { font-size: var(--texte-l); color: var(--marine-2); margin: 1.5rem 0 .4rem; }
article.document p, article.document li { font-size: var(--texte-m); }
article.document blockquote { margin: 1rem 0; padding: .7rem 1.1rem; border-left: 4px solid var(--ambre);
    background: var(--ambre-clair); border-radius: 0 8px 8px 0; }
article.document blockquote p { margin: 0; }
article.document code { background: var(--surface); border-radius: 4px; padding: .1rem .35rem; font-size: .86em; }
article.document pre { background: var(--marine); color: var(--side-texte-2); border-radius: 8px; padding: 1rem 1.2rem;
    overflow-x: auto; font-size: var(--texte-s); line-height: 1.5; }
article.document pre code { background: none; padding: 0; color: inherit; }
article.document .tableau { overflow-x: auto; margin: 1rem 0; }
article.document table { border-collapse: collapse; width: 100%; font-size: var(--texte-m); }
article.document th { background: var(--marine); color: var(--sur-fonce); text-align: left; padding: .5rem .7rem; }
article.document td { border-bottom: 1px solid var(--ligne); padding: .5rem .7rem; vertical-align: top; }
article.document tr:nth-child(even) td { background: var(--fond); }
article.document hr { border: 0; border-top: 1px solid var(--ligne); margin: 1.8rem 0; }
article.document a { color: var(--accent); }
.retour { display: inline-block; margin: .25rem 0 .5rem; color: var(--accent); text-decoration: none; font-size: var(--texte-m); }
.retour:hover { text-decoration: underline; }
/* Formulaire AD */
  .grille-2 {
    display: grid;
    /* `minmax(0, 1fr)` et non `1fr` : la taille MINIMALE d'une piste `1fr`
       est celle de son contenu, donc un placeholder long impose sa largeur
       et la grille refuse de rétrécir. Sur un écran de 390 px, la page
       enflait à 475 px et le navigateur dézoomait tout. */
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: .6rem 1.2rem; margin-top: .6rem;
  }
.grille-2 label, .carte > label { display: block; font-size: var(--texte-m); color: var(--texte-2); }
.grille-2 input, .grille-2 textarea, .carte input[type=text], .carte input[type=number],
  .carte input[type=date], .carte select, .carte textarea {
    width: 100%; font: inherit; font-size: var(--texte-m); padding: .4rem .55rem; margin-top: .15rem;
    border: 1px solid var(--ligne); border-radius: 6px; background: var(--carte); }
table.saisie-docs { width: 100%; border-collapse: collapse; margin: .6rem 0; }
table.saisie-docs th { text-align: left; font-size: var(--texte-xs); color: var(--texte-2); padding: .2rem .4rem; }
table.saisie-docs td { padding: .15rem .3rem; }
table.saisie-docs td:nth-child(1) { width: 24%; }
table.saisie-docs td:nth-child(3) { width: 14%; }
table.saisie-docs td:nth-child(4) { width: 18%; }
/* UN BOUTON QUI CHANGE SON FOND DÉCLARE SA COULEUR AVEC. C'est la
   troisième fois que la séparation coûte cher : le 22/08, `.secondaire`
   posait un fond marine sans toucher au texte, resté marine lui aussi —
   des rectangles bleus SANS LIBELLÉ sur plusieurs écrans. Ici, `.mini`
   imposait son fond marine par-dessus `.discret`, dont la couleur de
   texte grise restait : « supprimer » et « a quitté le cabinet »
   ressortaient à 1,9 de contraste sur l'écran Comptes. Un test refuse
   désormais qu'une règle de bouton pose un fond sans sa couleur. */
button.mini {
  font-size: var(--texte-xs); padding: .22rem .6rem;
  background: var(--marine); color: var(--sur-fonce); margin-top: 0;
}
/* La variante DISCRÈTE reprend SA paire ENTIÈRE, jamais une moitié. */
button.mini.discret { background: var(--surface); color: var(--texte-2); }
.obs-bloc { border-left: 3px solid var(--ligne); padding-left: .8rem; margin: .8rem 0; }
.barre-generer { position: sticky; bottom: 0; background: var(--marine); color: var(--sur-fonce);
    padding: .8rem 1rem; border-radius: 10px; display: flex; align-items: center; gap: 1rem;
    margin-top: 1.2rem; }
.barre-generer button { margin-top: 0; }
ul.erreurs { color: var(--rouge-fonce); font-size: var(--texte-m); }
/* Affaires */
  table.tableau-affaires { width: 100%; border-collapse: collapse; background: var(--carte);
    border: 1px solid var(--ligne); border-radius: 10px; overflow: hidden; }
table.tableau-affaires th { text-align: left; font-size: var(--texte-xs); color: var(--texte-2);
    padding: .55rem .8rem; background: var(--surface); }
/* DENSITÉ DE LA LIGNE (retour du directeur, 20/08) : la strate métier
   rendait la cellule à 14 px avec 8 px de marge haute et basse — 44 px
   par ligne, soit dix lignes de moins par écran que ce que le système
   prévoit. On revient aux valeurs de la maquette : 13 px, 6 px de marge.
   C'est la « densité travaillée » du brief, pas de la densité brute. */
table.tableau-affaires td { padding: .375rem .75rem; border-top: 1px solid var(--ligne);
    font-size: var(--texte-s); font-variant-numeric: tabular-nums; }
table.tableau-affaires tbody tr { transition: background-color .12s ease; }
table.tableau-affaires tbody tr:hover td { background: var(--surface-2); }
dl.fiche { display: grid; grid-template-columns: 8rem 1fr; gap: .3rem 1rem; margin: 0; }
dl.fiche dt { color: var(--texte-2); font-size: var(--texte-m); }
dl.fiche dd { margin: 0; }
a.bouton { display: inline-block; background: var(--accent); color: var(--sur-fonce); text-decoration: none;
    border-radius: 8px; padding: .5rem 1.1rem; font-size: var(--texte-m); margin-top: .8rem; }
/* ---- Le renseignement commercial d'une opération ----------------------
   Deux colonnes : ce qui est SAISI, ce qui est CALCULÉ. La frontière est
   la règle du modèle (docs/MODELE-OPERATION.md), elle se voit donc. */
.grille-operation {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  gap: 1.5rem;
  margin-top: .5rem;
}
table.tableau-operation { width: 100%; border-collapse: collapse; font-size: var(--texte-m); }
table.tableau-operation th {
  text-align: left; font-weight: 500; color: var(--texte-2);
  padding: .4rem .6rem .4rem 0; vertical-align: top;
  border-bottom: 1px solid var(--surface);
}
table.tableau-operation td {
  padding: .4rem 0; text-align: right; white-space: nowrap;
  font-variant-numeric: tabular-nums; border-bottom: 1px solid var(--surface);
}
/* Un chiffre calculé porte SA FORMULE : on doit pouvoir vérifier d'où il
   sort sans ouvrir le code — c'est ce que le tableur ne permettait plus. */
table.tableau-operation.calcule { background: var(--surface); }
table.tableau-operation.calcule th { padding-left: .6rem; }
table.tableau-operation.calcule td { padding-right: .6rem; }
.expression-formule { display: block; }
code.expression {
  font-size: var(--texte-xs); color: var(--texte-2); background: transparent; padding: 0;
}
.texte-operation { margin-top: 1rem; }
.texte-operation p { margin: .2rem 0 0; }
/* Corriger les saisies d'une opération : replié par défaut, parce que la
   lecture prime — mais à portée de clic devant une anomalie. */
details.corriger-operation { margin-top: 1.25rem; border-top: 1px solid var(--ligne); padding-top: .8rem; }
details.corriger-operation > summary {
  cursor: pointer; font-weight: 600; color: var(--marine); padding: .2rem 0;
}
details.corriger-operation > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Livrables par activité (Réglages) : une petite pile de cases par
   activité. Pas de tableau — le nombre d'activités et de générateurs reste
   petit, et un tableau à deux entrées coûterait plus qu'il ne rapporte. */
.livrables-activite {
  margin: .6rem 0;
  padding: .5rem .7rem;
  border: 1px solid var(--ligne);
  border-radius: 6px;
  background: var(--carte);
}
.livrables-activite strong { display: block; margin-bottom: .3rem; }
label.livrable {
  display: block;
  font-weight: 400;
  margin: .15rem 0;
}
label.livrable input { margin-right: .4rem; }
/* En-tête de colonne triable : le TRIANGLE annonce que la colonne se
   clique, et lequel commande le tri courant (plein contre creux). Sans
   lui, rien ne distingue un en-tête cliquable d'un libellé. */
th a.tri { color: inherit; text-decoration: none; white-space: nowrap; }
th a.tri:hover { text-decoration: underline; }
th a.tri .triangle { font-size: .8em; opacity: .45; }
th a.tri.actif { font-weight: 700; }
th a.tri.actif .triangle { opacity: 1; }
/* Une fiche archivée reste lisible mais recule d'un plan : elle n'est plus
   du champ courant. */
tr.archive td { opacity: .55; }
/* ---- Réglages : quatre familles, un sommaire ------------------------- */
/* Dix cartes à plat ne se lisent pas. Les h2 portent les familles, les
   cartes des h3, et le sommaire permet d'atteindre la bonne sans dérouler
   tout l'écran. */
.sommaire-reglages {
  display: flex; flex-wrap: wrap; gap: .5rem;
  margin: 0 0 1.5rem;
}
.sommaire-reglages a {
  padding: .3rem .8rem;
  border: 1px solid var(--ligne);
  border-radius: 999px;
  background: var(--carte);
  color: var(--marine);
  text-decoration: none;
  font-size: var(--texte-s);
  font-weight: 600;
}
.sommaire-reglages a:hover { border-color: var(--marine-2); }
/* Sur la page d'un module, le fil d'Ariane : le retour est un lien, le
   module courant n'en est pas un — on y est déjà. */
.sommaire-reglages .fil-actuel { align-self: center; color: var(--texte-2);
  font-size: var(--texte-s); }
.sommaire-reglages .fil-actuel::before { content: "/"; margin-right: .5rem; opacity: .5; }

/* LES ACTIVITÉS DU CABINET : les champs remplissent leur cellule. Laissés
   à leur largeur par défaut, ils coupaient « Vérification réglementaire
   (accréditation COFRAC) » en plein milieu — on ne relit pas un nom qu'on
   ne voit pas en entier. */
.activites-cabinet td { vertical-align: middle; }
.activites-cabinet input[type="text"] { width: 100%; margin: 0; }
.activites-cabinet th:first-child, .activites-cabinet td:first-child { width: 4rem; }
.activites-cabinet .ac-usage { white-space: nowrap; font-size: var(--texte-s); color: var(--texte-2); }

/* LA VUE D'ENSEMBLE DU CLASSEUR — dix onglets décrits d'un coup, dans un
   dépliant. OUVERT quand il manque des comptes : c'est un travail à faire,
   pas une information à aller chercher. Replié le reste du temps, pour ne
   pas repousser l'écran d'import hors de la page. */
.vue-classeur { margin-top: .8rem; border: 1px solid var(--ligne);
  border-radius: var(--rayon-2); background: var(--surface); padding: .6rem .9rem; }
.vue-classeur > summary { cursor: pointer; font-weight: 600; color: var(--marine); }
.vue-classeur[open] > summary { margin-bottom: .7rem; padding-bottom: .5rem;
  border-bottom: 1px solid var(--ligne); }
.vue-classeur .tableau-cadre { background: var(--carte); }
/* Les comptes à créer : un bloc d'action, séparé du tableau qui décrit. */
.comptes-manquants { margin-top: .9rem; padding-top: .8rem;
  border-top: 2px solid var(--ligne-forte); }
/* UNE PERSONNE, UNE LIGNE. Empilées, sept créations prenaient 600 px et
   repoussaient le bouton hors de l'écran — on validait sans avoir relu. */
.comptes-manquants .compte-manquant {
  display: grid; grid-template-columns: 3rem minmax(0, 1fr) auto;
  align-items: center; gap: .8rem; margin: 0 0 .35rem;
}
.comptes-manquants .compte-manquant > label { margin: 0; }
.comptes-manquants .compte-manquant .cm-nom { width: 100%; margin: 0; }
.comptes-manquants .compte-manquant .ligne-case { white-space: nowrap; }
@media (max-width: 48rem) {
  .comptes-manquants .compte-manquant { grid-template-columns: 3rem minmax(0, 1fr); }
  .comptes-manquants .compte-manquant .ligne-case { grid-column: 2; }
}

/* L'INDEX DES RÉGLAGES : une tuile par module, pas vingt-cinq cartes à
   dérouler. Chaque tuile dit ce qu'elle règle — sans quoi l'index ne
   ferait que déplacer le problème d'un cran. */
.modules-reglages {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: var(--es-3); margin-bottom: var(--es-2);
}
.module-reglage {
  display: flex; flex-direction: column; gap: .2rem;
  padding: var(--es-3) var(--es-4);
  background: var(--carte); border: 1px solid var(--ligne);
  border-radius: var(--rayon-2); box-shadow: var(--ombre-1);
  text-decoration: none; color: inherit;
  transition: border-color .12s ease, transform .12s ease;
}
main a.module-reglage { border-bottom: 1px solid var(--ligne); }
.module-reglage:hover { border-color: var(--marine-2); transform: translateY(-1px); }
.module-titre { font-weight: 700; color: var(--marine); }
.groupe-reglages { scroll-margin-top: 7.5rem; }
.groupe-reglages > h2 {
  margin-top: 2.2rem;
  padding-bottom: .35rem;
  border-bottom: 2px solid var(--ligne);
}
.groupe-reglages > .intro { margin-top: -.4rem; }
/* ---- Le choix de palette --------------------------------------------- */
/* Les nuances se MONTRENT : un nom de couleur ne dit pas de quoi l'écran
   aura l'air, et personne ne change une palette à l'aveugle. */
.palettes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
  min-width: 0;
  gap: .75rem;
  margin: .8rem 0 1rem;
}
label.palette {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "radio nuances" "radio nom" "radio aide";
  gap: .15rem .6rem;
  align-items: center;
  padding: .7rem .8rem;
  border: 1px solid var(--ligne);
  border-radius: 10px;
  background: var(--carte);
  cursor: pointer;
}
label.palette:hover { border-color: var(--marine-2); }
label.palette.actif { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-clair); }
label.palette input { grid-area: radio; accent-color: var(--accent); }
.palette-nuances { grid-area: nuances; display: flex; height: 1.4rem; border-radius: 5px; overflow: hidden; }
.palette-nuances span { flex: 1; }
.palette-nom { grid-area: nom; font-weight: 700; color: var(--marine); }
label.palette .aide { grid-area: aide; margin: 0; }

/* ---- Mise en page étroite : nos points de rupture ---- */
@media (max-width: 800px) {
    .lateral { transform: translateX(-100%); transition: transform .28s cubic-bezier(.32,.72,0,1); }
    .lateral.ouvert { transform: none; box-shadow: 0 0 40px color-mix(in srgb, var(--encre) 40%, transparent); }
    .principal { margin-left: 0; }
    button.burger { display: block; }
  }
@media (prefers-reduced-transparency: reduce) {
    .barre-haute { background: var(--carte); -webkit-backdrop-filter: none; backdrop-filter: none; }
  }
@media (prefers-contrast: more) {
    .carte, .carte-stat, table.tableau-affaires { border-color: var(--texte-2); }
    .barre-haute { background: var(--carte); -webkit-backdrop-filter: none; backdrop-filter: none;
      border-bottom-color: var(--texte-2); }
  }
@keyframes pulser { 0%, 100% { opacity: 1; } 50% { opacity: .65; } }
@media (max-width: 640px) {
    article.document { padding: 1.4rem 1.2rem; }
    .question { padding-left: .6rem; }
    .question .numero { display: none; }
    nav.onglets { gap: .3rem .8rem; font-size: var(--texte-s); margin-left: 0; width: 100%; }
  }


/* ---- Réglages : de l'air entre les familles et les cartes ------------ */
/* Les cartes sont blanches sur un fond très clair : sans respiration, deux
   cartes voisines se lisent comme un seul bloc. */
.groupe-reglages > .intro { margin: -.2rem 0 1rem; color: var(--texte-2); }
.groupe-reglages > .carte { margin-bottom: var(--es-5); }
.carte > h3 { margin-bottom: var(--es-2); color: var(--marine); }
.carte > h3 + .aide { margin-top: 0; }

/* Une liste d'erreurs VIDE n'est pas une erreur : elle ne se peint pas. */
.erreurs:empty { display: none; }

/* ======== MAÎTRE-DÉTAIL (études, grand écran) ========================== */
/*
 * Direction C de la revue « bureau » : le grand écran servait à afficher
 * du vide — 41 % de la largeur hors bandeau restait gris, et la liste ne
 * commençait qu'à 846 px sous le formulaire. Il sert désormais à voir
 * DEUX choses : la liste compacte à gauche (les fiches du téléphone), la
 * fiche complète de l'étude choisie à droite, sans navigation. La
 * sélection est un LIEN (`?etude=…`) rendu par le serveur — pas d'îlot.
 *
 * Sous 64 rem, rien de tout ceci n'existe : le tableau classique reste
 * (fenêtre moyenne), et sous 30 rem les fiches du téléphone gardent leur
 * clic et leur glissement, intacts.
 */
.volet-etude { display: none; }
.lien-fiche { display: none; }
/* UNE ACTION PRIMAIRE N'EXISTE QU'À UN SEUL ENDROIT : la barre d'écran
   (charpente §2). Ce dépliant portait le MÊME bouton vert que la barre du
   haut — deux « + Nouveau client » à trois centimètres l'un de l'autre,
   dont on ne pouvait pas deviner qu'ils font la même chose. Le bouton de
   la barre reste l'action ; le dépliant n'est plus que la poignée de son
   propre panneau, et le dit : ouvert, il propose de refermer. */
details.creer-etude > summary {
  display: inline-flex; align-items: center; gap: .45rem;
  background: var(--carte); color: var(--marine);
  border: 1px solid var(--ligne-forte);
  padding: .3rem var(--es-3); border-radius: var(--rayon-1);
  font-size: var(--texte-s); font-weight: 600;
  cursor: pointer; user-select: none; list-style: none;
  margin-bottom: var(--es-3);
}
details.creer-etude > summary::-webkit-details-marker { display: none; }
/* Replié, le dépliant n'affiche RIEN : son ouverture est le bouton de la
   barre d'écran, qui pointe sur son ancre. Déplié, sa poignée reste — il
   faut pouvoir refermer. Les deux écrans concernés ne rendent le dépliant
   que sous la même permission que le bouton : pas de panneau orphelin
   (garanti par `ecran-liste.test.ts`). */
details.creer-etude:not([open]) > summary { display: none; }
details.creer-etude > summary:hover { background: var(--surface); }
details.creer-etude[open] > summary::after {
  content: " — fermer"; color: var(--texte-2); font-weight: 400;
}
/* La barre de tri en puces ne sert que là où les EN-TÊTES manquent : sous
   30 rem (thead masqué) et en maître-détail (fiches sans colonnes). Entre
   les deux, le tableau classique a ses en-têtes triables. */
.barre-tri { display: none; gap: .5rem; flex-wrap: wrap; }
.barre-tri .tri-libelle { color: var(--texte-2); font-size: var(--texte-s); align-self: center; }
/* Le FILTRE D'ACTIVITÉ des études partage la rangée du tri : c'est la seule
   qui ait de la place — sept puces de statut remplissent la première à
   elles seules. Un filet le sépare du tri, parce que filtrer et trier ne
   sont pas le même geste. */
.filtre-activite { display: flex; align-items: center; margin: 0; }
/* Le filet est porté par le TRI, pas par le filtre : entre 480 et 1 024 px
   la rangée de tri est masquée, et un séparateur posé sur le filtre y
   restait seul, à séparer du vide. */
.filtre-activite + .barre-tri { padding-left: .7rem; margin-left: .3rem;
  border-left: 1px solid var(--ligne); }
.filtre-activite select { width: auto; margin: 0; padding: .25rem 1.6rem .25rem .6rem;
  font-size: var(--texte-s); }
.filtre-activite button { margin: 0 0 0 .4rem; padding: .25rem .7rem; font-size: var(--texte-s); }
@media (max-width: 30rem) {
  .barre-tri { display: flex; }
}
@media (min-width: 64rem) {
  .barre-tri { display: flex; }
  /* Le plafond de 62 rem est fait pour la prose ; une LISTE a le droit de
     prendre l'écran qu'on lui donne. Borné quand même : au-delà, les
     lignes de la fiche de droite deviendraient des câbles. */
  /* DEUX COLONNES QUI DÉFILENT CHACUNE POUR SON COMPTE.
     Auparavant la page entière défilait et le volet était collé
     (`position: sticky`) : une fiche plus haute que l'écran avait donc son
     BAS DÉFINITIVEMENT INATTEIGNABLE — les documents obligatoires d'une
     affaire se coupaient en plein milieu et rien ne permettait de
     descendre dedans (signalé le 22/08 : « la partie droite est figée »).
     Un volet collé ne peut pas montrer plus haut que la fenêtre ; c'est le
     principe même du collage. La liste et le volet sont donc devenus deux
     zones de défilement indépendantes — le geste attendu d'un
     maître-détail : on descend dans la fiche sans perdre la liste, et on
     descend dans la liste sans perdre la fiche. */
  main:has(.maitre-detail) {
    max-width: 100rem;
    display: flex; flex-direction: column;
    /* Le défilement passe AUX COLONNES : sans cela on en aurait deux, l'un
       dans l'autre, et la molette choisirait mal. */
    overflow: hidden;
  }
  .maitre-detail {
    display: grid;
    grid-template-columns: minmax(19rem, 24rem) minmax(0, 1fr);
    /* `minmax(0, 1fr)` et non `auto` : une piste `auto` se dimensionne sur
       son contenu et déborde du conteneur au lieu de s'y ajuster — les
       colonnes n'auraient alors rien à faire défiler. */
    grid-template-rows: minmax(0, 1fr);
    gap: var(--es-4);
    /* `stretch` (le défaut) et non `start` : chaque colonne doit recevoir
       la hauteur disponible pour avoir quelque chose à faire défiler. */
    flex: 1; min-height: 0;
  }
  /* `min-height: 0` sur les deux : sans lui, une piste de grille refuse de
     descendre sous la hauteur de son contenu et le débordement fuit vers
     le haut au lieu de rester dans la colonne. */
  .maitre-detail > .carte { min-height: 0; overflow-y: auto; }
  /* Le volet ÉPOUSE sa fiche (`align-self: start`) et ne défile qu'au-delà
     de la hauteur disponible : étiré, une fiche de quatre champs aurait
     produit une grande carte blanche à moitié vide. */
  .maitre-detail > .volet-etude { align-self: start; max-height: 100%; overflow-y: auto; }
  /* La liste garde de la place à droite pour son ascenseur, et les deux
     colonnes un peu d'air en bas pour que la dernière fiche ne colle pas
     au bord. */
  .maitre-detail > .carte {
    background: none; border: 0; box-shadow: none;
    padding: 0 var(--es-2) 0 0;
  }
  .maitre-detail > .carte::after { content: ""; display: block; height: var(--es-3); }
  /* `max-height: none` VOYAGE AVEC `overflow: visible` (voir le test
     `feuille-style`) : ici la colonne de gauche défile, pas le cadre. Le
     plafond tombait déjà, mais par une règle deux cents lignes plus bas, à
     spécificité ÉGALE — c'est-à-dire par ordre de source. Un accord qui
     tient à l'ordre des lignes finit par se défaire ; il est dit ici. */
  .maitre-detail .tableau-cadre { overflow: visible; max-height: none; border: 0; background: none; }
  .maitre-detail thead { display: none; }
  /* Les rangées deviennent les fiches du téléphone — même silhouette,
     même triplet, mêmes sélecteurs par libellé de colonne. La répétition
     avec le bloc téléphone est assumée : les deux contextes n'ont ni le
     même seuil ni le même périmètre (ici, les études seules). */
  .maitre-detail .tableau-affaires,
  .maitre-detail .tableau-affaires tbody,
  .maitre-detail .tableau-affaires tr,
  .maitre-detail .tableau-affaires td { display: block; width: auto; }
  .maitre-detail .tableau-affaires tr {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--es-3);
    row-gap: 0.2rem;
    align-items: baseline;
    background: var(--carte);
    border: 1px solid var(--ligne); border-radius: var(--rayon-2);
    box-shadow: var(--ombre-1);
    padding: var(--es-2) var(--es-4);
    margin-bottom: var(--es-2);
  }
  .maitre-detail .tableau-affaires tr.selectionnee {
    border: 2px solid var(--marine);
    /* Compense l'épaisseur : la fiche choisie ne « saute » pas. */
    padding: calc(var(--es-2) - 1px) calc(var(--es-4) - 1px);
  }
  .maitre-detail .tableau-affaires td { border: 0; padding: 0.15rem 0; }
  .maitre-detail .tableau-affaires td::before { content: none; }
  .maitre-detail .tableau-affaires td:first-child { grid-area: 1 / 1 / 2 / 2; font-weight: 700; font-size: var(--texte-s); }
  .maitre-detail .tableau-affaires td:nth-child(2) {
    grid-area: 2 / 1 / 3 / 3;
    color: var(--texte-2); font-size: var(--texte-xs);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .maitre-detail .tableau-affaires td:nth-child(n+3) { display: none; }
  .maitre-detail .tableau-affaires td[data-libelle="Montant"],
  .maitre-detail .tableau-affaires td[data-libelle="Honoraires"] {
    display: block; grid-area: 1 / 2 / 2 / 3;
    text-align: right; font-weight: 600; font-size: var(--texte-s);
  }
  .maitre-detail .tableau-affaires td[data-libelle="Statut"] {
    display: flex; flex-wrap: wrap; gap: var(--es-1) var(--es-2); align-items: center;
    grid-area: 3 / 1 / 4 / 3;
    color: var(--texte-2); font-size: var(--texte-xs);
  }
  /* DEUX CELLULES NE PARTAGENT JAMAIS UNE CASE. Le rang 3 de la fiche
     accueille l'ÉTAT ; les affaires n'ont pas de colonne « Statut », leur
     activité y prend donc place. Les études ont les DEUX — et les deux se
     retrouvaient superposées, texte sur texte (défaut signalé le 20/08 :
     « Coordination SPS » imprimé par-dessus « à rendre dans 40 j »).
     Quand la ligne porte un statut, c'est lui qui décide : l'activité se
     retire de la fiche compacte — elle reste dans le volet et dans le
     tableau. */
  .maitre-detail .tableau-affaires tr:has(td[data-libelle="Statut"]) td[data-libelle="Activité"] {
    display: none;
  }
  /* L'activité est un TEXTE, pas une suite de pastilles : elle reste un
     bloc, pour que la coupure porte son ellipse (une valeur tronquée
     doit se voir tronquée). Le plafond de la liste ne s'applique pas
     ici — la fiche a sa propre largeur. */
  .maitre-detail .tableau-affaires td[data-libelle="Activité"] {
    display: block; grid-area: 3 / 1 / 4 / 3;
    color: var(--texte-2); font-size: var(--texte-xs);
    max-width: 100%; overflow: hidden; text-overflow: ellipsis;
  }
  .maitre-detail .tableau-affaires td[data-libelle="Statut"] br,
  .maitre-detail .tableau-affaires td[data-libelle="Activité"] br { display: none; }
  /* Une ligne de regroupement n'est pas une fiche : un simple bandeau. */
  .maitre-detail .tableau-affaires tr.groupe {
    display: block; background: var(--surface); border: 0; box-shadow: none;
    padding: .3rem var(--es-3); border-radius: var(--rayon-1);
  }
  .maitre-detail .tableau-affaires tr.groupe td { display: inline; font-size: var(--texte-xs); }
  /* CLIENTS — l'identité d'un client est son NOM, pas son numéro (pour
     une affaire, c'est l'inverse : le numéro EST l'identité). Les rangs
     de la fiche compacte se déclarent donc par le NOM DE LA COLONNE :
     rang 1 = ce qui identifie et ce qui décide, rang 2 = le contexte,
     rang 3 = l'état.

     MAIS UN NOM DE COLONNE N'EST UNIQUE QUE DANS SA TABLE. « N° »
     désigne le numéro du client ici et le numéro d'affaire ailleurs :
     écrite sans garde, la règle ci-dessous déplaçait le n° d'affaire
     dans la case des honoraires, et les deux s'imprimaient l'un sur
     l'autre (défaut signalé le 20/08). Les rangées de clients se
     reconnaissent à leur colonne « Nom », que ni les affaires ni les
     études ne portent : c'est la garde qui rend le nommage par colonne
     sûr, et la même que pour l'état (« deux cellules ne partagent
     jamais une case »). Toute règle propre à un écran la porte. */
  .maitre-detail .tableau-affaires tr:has(td[data-libelle="Nom"]) td[data-libelle="Nom"] {
    grid-area: 1 / 1 / 2 / 2;
    font-weight: 700; font-size: var(--texte-s); color: var(--texte);
    max-width: none; overflow: hidden; text-overflow: ellipsis;
  }
  .maitre-detail .tableau-affaires tr:has(td[data-libelle="Nom"]) td[data-libelle="Nom"] > a {
    max-width: 100%; font-weight: 700;
  }
  .maitre-detail .tableau-affaires tr:has(td[data-libelle="Nom"]) td[data-libelle="N°"] {
    grid-area: 1 / 2 / 2 / 3; text-align: right;
    color: var(--texte-2); font-size: var(--texte-xs); font-variant-numeric: tabular-nums;
  }
  .maitre-detail .tableau-affaires tr:has(td[data-libelle="Nom"]) td[data-libelle="Courriel"] {
    display: block; grid-area: 2 / 1 / 3 / 3;
    color: var(--texte-2); font-size: var(--texte-xs);
    max-width: none; overflow: hidden; text-overflow: ellipsis;
  }
  /* Les compteurs ferment la fiche, et portent leur libellé : « 3 » tout
     seul ne dit pas de quoi il parle. */
  .maitre-detail .tableau-affaires tr:has(td[data-libelle="Nom"]) td[data-libelle="Affaires"],
  .maitre-detail .tableau-affaires tr:has(td[data-libelle="Nom"]) td[data-libelle="Études"] {
    display: block; font-size: var(--texte-xs); color: var(--texte-2);
  }
  .maitre-detail .tableau-affaires tr:has(td[data-libelle="Nom"]) td[data-libelle="Affaires"] { grid-area: 3 / 1 / 4 / 2; }
  .maitre-detail .tableau-affaires tr:has(td[data-libelle="Nom"]) td[data-libelle="Études"] { grid-area: 3 / 2 / 4 / 3; text-align: right; }
  .maitre-detail .tableau-affaires tr:has(td[data-libelle="Nom"]) td[data-libelle="Affaires"]::before,
  .maitre-detail .tableau-affaires tr:has(td[data-libelle="Nom"]) td[data-libelle="Études"]::before {
    content: attr(data-libelle) " "; color: var(--texte-2);
  }

  /* Une valeur ABSENTE ne prend pas un rang dans la fiche : « — » tout
     seul n'apprend rien et gonfle la ligne. Le serveur marque la cellule
     (`class="vide"`) ; le tableau, lui, garde son tiret pour aligner ses
     colonnes. */
  .maitre-detail .tableau-affaires td.vide,
  .maitre-detail .tableau-affaires tr:has(td[data-libelle="Nom"]) td.vide { display: none; }

  /* Le détail vit dans le volet : les annotations grises de la liste et la
     colonne d'actions n'ont rien à y faire. */
  .maitre-detail .tableau-affaires td:first-child .aide,
  .maitre-detail .tableau-affaires td:first-child br { display: none; }
  .maitre-detail .tableau-affaires td.actions { display: none; }
  /* La relance suit la même règle : la carte dit l'état (« À relancer »,
     l'âge de l'offre), le VOLET porte le geste. Le bouton posé dans la
     carte serait recouvert par le lien étiré — trouvé en cliquant pour de
     vrai dans Chromium, pas en relisant la feuille. */
  .maitre-detail .tableau-affaires .act-relance,
  .maitre-detail .tableau-affaires .act-relance-annuler { display: none; }
  /* Toute la fiche est le lien de sélection. */
  .maitre-detail .lien-fiche { display: block; position: absolute; inset: 0; z-index: 1; border-radius: var(--rayon-2); }
  /* UNE FICHE N'EST PAS UNE LIGNE DE TABLEAU. Le survol d'une liste peint
     ses CELLULES (`tr:hover td`) ; sur une fiche, les cellules sont des
     cases de grille séparées par des gouttières — on ne voyait donc pas
     une carte survolée, mais deux ou trois rectangles gris flottant
     dedans, et la structure du tableau ressortait là où elle devait
     disparaître. Le survol appartient à la carte. */
  .maitre-detail .tableau-affaires tbody tr:hover td,
  .maitre-detail .tableau-affaires tbody tr.selectionnee td { background: none; }
  .maitre-detail .tableau-affaires tr:hover { border-color: var(--marine-2); background: var(--surface-2); }
  .maitre-detail .tableau-affaires tr.selectionnee:hover { background: var(--carte); }

  /* Le volet : la fiche complète, dans sa propre zone de défilement (voir
     le commentaire de `.maitre-detail` — il était collé, et tout ce qui
     dépassait de la fenêtre était perdu). */
  .volet-etude {
    display: block;
    background: var(--carte); border: 1px solid var(--ligne);
    border-radius: var(--rayon-2); box-shadow: var(--ombre-1);
    padding: var(--es-5);
  }
  .volet-tete {
    display: flex; justify-content: space-between; align-items: baseline; gap: var(--es-4);
    border-bottom: var(--bordure); padding-bottom: var(--es-3); margin-bottom: var(--es-4);
  }
  .volet-ref { font-size: var(--titre-3); font-weight: 700; color: var(--marine); font-variant-numeric: tabular-nums; }
  .volet-ref .badge-etude { vertical-align: middle; margin-left: var(--es-2); }
  .volet-intitule { color: var(--texte-2); margin-top: 2px; }
  .volet-montant { font-size: var(--titre-2); font-weight: 700; color: var(--marine); font-variant-numeric: tabular-nums; white-space: nowrap; }
  .volet-champs {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--es-3) var(--es-4); margin-bottom: var(--es-4);
  }
  .volet-terme {
    font-size: var(--texte-xs); color: var(--texte-2);
    text-transform: uppercase; letter-spacing: .05em; font-weight: 600;
  }
  .volet-valeur { font-size: var(--texte-s); margin-top: 1px; overflow-wrap: break-word; }
  .volet-desc {
    background: var(--surface); border-radius: var(--rayon-1);
    padding: var(--es-3) var(--es-4); font-size: var(--texte-s); color: var(--texte-2);
    white-space: pre-line; margin-bottom: var(--es-4);
  }
  .volet-actions {
    display: flex; flex-wrap: wrap; gap: var(--es-2); align-items: center;
    border-top: var(--bordure); padding-top: var(--es-3);
  }
}


/* ======== CHARPENTE (grand écran) : SEULE LA ZONE DE TRAVAIL DÉFILE ==== */
/*
 * Le grief n° 2 : « la page fait 3 448 px et défile d'un seul bloc ».
 * À partir de 64rem, la colonne principale prend la hauteur de la fenêtre
 * et c'est `main` qui défile — barre d'écran, outillage et bandeau restent
 * en place, et l'en-tête de colonne (sticky) se colle au sommet de la zone.
 * Le cadre de 32rem des tableaux n'a plus de raison d'être ici : la liste
 * défile avec la zone de travail (sauf `.tableau-long`, dont le défilement
 * interne protège le bouton « Appliquer » d'un rapport d'import).
 * La restauration du défilement après un clic de sélection est l'îlot
 * déclaré dans fiches.js — sans script, comportement d'avant, rien ne casse.
 */
@media (min-width: 64rem) {
  .app { height: 100dvh; overflow: hidden; }
  .principal { height: 100dvh; }
  .principal > main { flex: 1; min-height: 0; overflow: auto; }
  .tableau-cadre:not(.tableau-long) { max-height: none; overflow: visible; }
  main:has(.tableau-cadre) { max-width: 100rem; }
  /* Ici l'outillage ne défile plus : l'ancre n'a plus à passer dessous. */
  .groupe-reglages { scroll-margin-top: 1rem; }
}

/* ======== 4. TÉLÉPHONE ======== */
/*
 * Vérifié sur un écran de 390 px, pas supposé. Trois maux, trois causes :
 *
 *  - les GRILLES exigeaient une largeur minimale de colonne que l'écran
 *    n'a pas ; la page enflait à 484 px et le navigateur dézoomait tout ;
 *  - les TABLEAUX denses (jusqu'à 1439 px de colonnes) obligeaient à
 *    défiler en largeur autant qu'en longueur ; chaque ligne est
 *    désormais une CARTE, et plus rien ne bouge horizontalement ;
 *  - les FILTRES prenaient sept lignes à eux seuls, repoussant le contenu
 *    hors de l'écran.
 */
@media (max-width: 30rem) {
  /* Aucune grille ne réclame plus que la largeur disponible. */
  .grille-2, .grille-operation, .palettes, .lots, .mesures, .totaux {
    grid-template-columns: 1fr !important;
  }

  /* ---- UNE LIGNE DEVIENT UNE CARTE ---------------------------------- */
  /*
   * On avait d'abord densifié les colonnes et annoncé le défilement par un
   * dégradé. Ça ne réglait rien : un tableau de sept colonnes ne se lit pas
   * sur 390 px, il se PARCOURT — on voyait la référence, on poussait
   * l'écran du doigt pour atteindre le montant, et on avait perdu la ligne
   * en revenant. Défiler en largeur ET en longueur, c'est ce que le
   * directeur a signalé, capture à l'appui.
   *
   * Sous ce seuil, chaque ligne devient donc une carte : l'identifiant en
   * tête, les colonnes l'une sous l'autre en « libellé / valeur », les
   * actions en pied. Plus rien ne défile horizontalement.
   *
   * Le libellé vient de `data-libelle`, que le serveur recopie depuis
   * l'en-tête (`tableau-cartes.ts`) : `thead` est masqué ici, et CSS ne
   * sait pas aller lire une autre cellule pour la citer.
   */
  /* `max-height: none` N'EST PAS COSMÉTIQUE — c'est le correctif du
     chevauchement signalé le 23/08 sur le cycle mensuel. La règle générale
     plafonne le cadre à 32 rem pour qu'un long tableau défile CHEZ LUI ;
     ici le cadre ne défile plus (les cartes s'empilent, c'est la page qui
     défile), et une boîte qui ne coupe rien mais reste plafonnée laisse
     son contenu peindre DEHORS pendant que la suite du document se pose
     après les 512 px. Résultat : la carte suivante recouvrait tout ce qui
     dépassait — treize échéances rendues, cinq lisibles.
     LA RÈGLE, plus large que ce cas : partout où le cadre cesse de couper,
     le plafond tombe avec lui. Un test le vérifie (`feuille-style`). */
  .tableau-cadre { overflow: visible; max-height: none; background: none; border: 0; }
  /* Une carte blanche dans une carte blanche ne dit rien de plus : la
     carte qui ne contient qu'une liste s'efface au profit de ses lignes.
     `:has()` manque à un très vieux navigateur — il verra alors le cadre
     d'avant, ce qui reste lisible. */
  .carte:has(> .tableau-cadre) {
    background: none; border: 0; box-shadow: none; padding: 0;
  }
  .tableau-affaires thead { display: none; }
  .tableau-affaires,
  .tableau-affaires tbody, .tableau-affaires tfoot,
  .tableau-affaires tr, .tableau-affaires td, .tableau-affaires th {
    display: block; width: auto;
  }
  .tableau-affaires tr {
    background: var(--carte);
    border: var(--bordure); border-radius: var(--rayon-2);
    box-shadow: var(--ombre-1);
    padding: var(--es-3) var(--es-4);
    margin-bottom: var(--es-3);
  }
  /* SUR UNE FICHE, AUCUNE CELLULE NE SE TEINTE. Le survol d'une liste
     peint ses CELLULES ; ici les cellules sont les lignes de la fiche, et
     un doigt qui touche laisse un « survol » collé : chaque donnée se
     retrouvait dans son propre rectangle gris aux coins arrondis, et la
     fiche montrait la structure du tableau qu'elle est censée cacher.
     Un écran tactile n'a pas de survol : sur une fiche dépliée, il n'y a
     donc RIEN à teinter — la carte se distingue déjà par son cadre.

     Le sélecteur porte `table` : sans lui, la règle métier
     `table.tableau-affaires tbody tr:hover td` reste plus spécifique et
     repasse devant (défaut constaté sur le téléphone du directeur, alors
     que le maître-détail, lui, était bien corrigé — sa règle porte deux
     classes). */
  table.tableau-affaires tbody tr:hover td,
  table.tableau-affaires tbody tr:hover .col-fixe { background: none; }
  .tableau-affaires tbody tr:hover { background: var(--carte); }
  /* Et une valeur ABSENTE ne prend pas une ligne : « Courriel — » suivi de
     « Téléphone — » faisait deux lignes vides dans une fiche qui tient
     dans un écran. Même règle qu'en maître-détail. */
  .tableau-affaires td.vide { display: none; }
  .tableau-affaires td {
    border: 0 !important;
    padding: 0.2rem 0 !important;
    text-align: left !important;
  }
  /* LE LIBELLÉ VA AU-DESSUS DE LA VALEUR, pas à côté. Une première version
     mettait la cellule en `flex` pour aligner deux colonnes ; le contenu
     de la cellule devenait alors lui-même une suite d'ÉLÉMENTS FLEX, et un
     intitulé suivi de sa référence et de son échéance se retrouvait
     éclaté en trois colonnettes de trois caractères. Une cellule contient
     ce qu'elle veut — du texte, des `<br>`, des `<span>`, un lien : la
     mise en page ne doit rien supposer de sa forme. */
  .tableau-affaires td[data-libelle]::before {
    content: attr(data-libelle);
    display: block;
    color: var(--texte-2); font-weight: 600;
    text-transform: uppercase; letter-spacing: .04em;
  }
  /* LA PREMIÈRE CELLULE EST LE TITRE de la carte. Elle ne répète pas son
     libellé : sur une carte, l'identifiant se lit d'un coup d'œil, pas
     précédé de « RÉF. ». */
  .tableau-affaires td:first-child {
    display: block;
    font-weight: 700; font-size: var(--texte-s) !important;
    padding-bottom: var(--es-2) !important;
    margin-bottom: var(--es-2);
    border-bottom: var(--bordure) !important;
  }
  .tableau-affaires td:first-child::before { content: none; }
  /* LES ACTIONS PASSENT EN PIED DE CARTE, sans étiquette : « ACTIONS :
     [Modifier] » n'apprend rien. Deux façons de les reconnaître, parce que
     nos tableaux font les deux — la colonne porte `class="actions"`, ou
     bien son en-tête est vide et la cellule n'a donc pas de libellé. */
  .tableau-affaires td.actions,
  .tableau-affaires td:not([data-libelle]):not(:first-child) {
    display: flex; flex-wrap: wrap; align-items: center;
    gap: var(--es-2);
    margin-top: var(--es-2);
  }
  .tableau-affaires td.actions::before { content: none; }
  /* Une cellule vide ne creuse pas un trou dans la carte. */
  .tableau-affaires td:empty { display: none; }

  /* ---- LA SAISIE N'EST PAS UNE FICHE --------------------------------
   *
   * Une ligne de LISTE se replie en carte : on la parcourt. Une ligne de
   * SAISIE — l'éditeur de devis — ne se replie pas : ses colonnes se lisent
   * ENSEMBLE (interventions × barème = heures = montant), et les empiler en
   * « libellé / valeur » ferait perdre le calcul de vue, chaque phase se
   * mélangeant à la suivante. Le tableau reste donc un tableau, et c'est le
   * CADRE qui défile en largeur — le geste attendu devant une grille.
   * `fiches.js` ignore ces tableaux de son côté (`:not(.saisie)`).
   */
  .tableau-cadre:has(.tableau-affaires.saisie) {
    overflow-x: auto;
    background: var(--carte); border: var(--bordure); border-radius: var(--rayon-2);
  }
  .carte:has(.tableau-affaires.saisie) {
    background: var(--carte); border: var(--bordure);
    box-shadow: var(--ombre-1); padding: var(--es-3);
  }
  .tableau-affaires.saisie { display: table; width: auto; min-width: 100%; }
  .tableau-affaires.saisie thead { display: table-header-group; }
  .tableau-affaires.saisie tbody { display: table-row-group; }
  .tableau-affaires.saisie tfoot { display: table-footer-group; }
  .tableau-affaires.saisie tr {
    display: table-row;
    background: none; border: 0; box-shadow: none; padding: 0; margin: 0;
  }
  .tableau-affaires.saisie th { display: table-cell; }
  .tableau-affaires.saisie td,
  .tableau-affaires.saisie td:first-child,
  .tableau-affaires.saisie td.actions,
  .tableau-affaires.saisie td:not([data-libelle]):not(:first-child) {
    display: table-cell;
    border: var(--bordure) !important;
    padding: 0.3rem 0.35rem !important;
    margin: 0;
    font-weight: 400;
    font-size: var(--texte-s) !important;
  }
  .tableau-affaires.saisie td::before { content: none !important; }
  .tableau-affaires.saisie td:empty { display: table-cell; }

  /* ---- FICHE REPLIÉE, CLIC POUR OUVRIR, SWIPE POUR AGIR -------------- */
  /*
   * 166 clients font 166 cartes : dépliées, la liste ne se parcourt plus.
   * Une fiche montre donc son identifiant et UN champ ; le reste vient au
   * clic. Les classes `.fiche`, `.ouverte` et `.tiroir` sont posées par
   * `public/fiches.js` — sans lui, aucune de ces règles ne s'applique et
   * les cartes restent entières, c'est-à-dire la mise en page d'avant.
   */
  .tableau-affaires tr.fiche { position: relative; overflow: hidden; }
  .tableau-affaires tr.fiche:not(.ouverte) td:nth-child(n+3):not(.fiche-actions) {
    display: none;
  }
  /* Le deuxième champ se lit sans son étiquette : sur une seule ligne de
     résumé, « NOM » avant le nom ne dit rien que le nom ne dise déjà. Et
     il se borne à deux lignes — un intitulé de mission en fait cinq, ce
     qui rendait la fiche « minimum » aussi haute qu'un paragraphe. */
  .tableau-affaires tr.fiche:not(.ouverte) td:nth-child(2)::before { content: none; }
  .tableau-affaires tr.fiche:not(.ouverte) td:nth-child(2) {
    color: var(--texte-2);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
    /* Le résumé s'arrête avant le chevron : replié, il passait dessous. */
    padding-right: 2.2rem !important;
  }
  /* Les annotations grises de l'identifiant (origine, canal, coordonnées)
     sont du détail : elles appartiennent à la fiche OUVERTE. */
  .tableau-affaires tr.fiche:not(.ouverte) td:first-child .aide,
  .tableau-affaires tr.fiche:not(.ouverte) td:first-child br { display: none; }

  /* Le chevron : la seule marque qu'une fiche s'ouvre — et un bouton réel,
     pour que le clavier et le lecteur d'écran y aient droit aussi. */
  .fiche-plier {
    position: absolute; top: var(--es-2); right: var(--es-2);
    width: 1.9rem; height: 1.9rem; padding: 0;
    background: none; border: 0; color: var(--texte-2);
    display: flex; align-items: center; justify-content: center;
  }
  .fiche-plier::before {
    content: ""; width: .5rem; height: .5rem;
    border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
    transition: transform var(--transition);
  }
  .fiche.ouverte .fiche-plier::before { transform: translateY(2px) rotate(-135deg); }
  /* Le titre s'arrête avant le chevron, il ne passe pas dessous. */
  .tableau-affaires tr.fiche > td:first-child { padding-right: 2.2rem !important; }

  /* LE TIROIR D'ACTIONS. Il n'existe que sur une fiche REPLIÉE : dépliée,
     les actions reprennent leur place en pied de carte, et un tiroir
     par-dessus ferait deux fois la même chose. */
  .tableau-affaires tr.fiche:not(.ouverte) td.fiche-actions {
    position: absolute; top: 0; right: 0; bottom: 0;
    margin: 0 !important;
    padding: 0 var(--es-3) !important;
    display: flex; align-items: center; gap: var(--es-2);
    background: var(--surface);
    border-left: var(--bordure) !important;
    transform: translateX(101%);
    transition: transform var(--transition);
  }
  .tableau-affaires tr.fiche:not(.ouverte).tiroir td.fiche-actions {
    transform: translateX(0);
  }
  /* Tiroir ouvert : le résumé s'efface. Il dépassait sous le tiroir coupé
     en plein mot, ce qui se lit comme un défaut d'affichage. L'identifiant
     reste, lui — c'est lui qui dit SUR QUELLE fiche on est en train d'agir,
     et l'effacer serait dangereux devant un bouton « Supprimer ». */
  .tableau-affaires tr.fiche.tiroir td:nth-child(2) { visibility: hidden; }

  /* Repliée, la fiche se resserre : le trait sous l'identifiant sépare des
     champs qui ne sont pas là, et deux lignes n'ont pas besoin d'air. */
  .tableau-affaires tr.fiche:not(.ouverte) { padding: var(--es-2) var(--es-4); }
  .tableau-affaires tr.fiche:not(.ouverte) > td:first-child {
    border-bottom: 0 !important;
    padding-bottom: 0 !important;
    margin-bottom: 0;
  }

  /* ---- LA FICHE REPLIÉE PORTE LE TRIPLET DE DÉCISION ----------------- */
  /*
   * Constat n° 1 de la revue de design : le « format minimum » prenait
   * mécaniquement les deux premières colonnes — référence et intitulé —
   * et taisait précisément ce qui décide : le montant et l'échéance. Pour
   * comparer deux études, il fallait les OUVRIR une à une.
   *
   * La fiche repliée devient une petite grille :
   *
   *     référence                montant   ← rang 1 : les deux ancres
   *     intitulé sur deux lignes           ← rang 2 : le contexte
   *     statut · échéance                  ← rang 3 : l'état et l'urgence
   *
   * QUI décide qu'une cellule est « le montant » ? Son EN-TÊTE. Chaque
   * cellule porte déjà le nom de sa colonne (`data-libelle`, recopié par
   * le serveur depuis le thead) : la feuille reconnaît « Montant »,
   * « Honoraires », « Montant HT », « HT » et « Statut ». Aucun écran n'a
   * été modifié pour ça — un tableau ajouté demain en profite dès lors
   * que ses colonnes portent ces noms-là, et un test le verrouille.
   */
  .tableau-affaires tr.fiche:not(.ouverte) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--es-3);
    row-gap: 0.2rem;
    align-items: baseline;
  }
  .tableau-affaires tr.fiche:not(.ouverte) > td:first-child { grid-area: 1 / 1 / 2 / 2; }
  .tableau-affaires tr.fiche:not(.ouverte) td:nth-child(2) { grid-area: 2 / 1 / 3 / 3; }
  /* Le montant remonte au rang 1, à droite — même corps que la référence,
     et un retrait qui le garde à gauche du chevron. */
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="Montant"],
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="Honoraires"],
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="Montant HT"],
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="HT"] {
    /* `!important` : la règle générale « toute cellule au-delà de la 2e est
       masquée » est plus SPÉCIFIQUE que ces sélecteurs par libellé — sans
       lui, le montant resterait caché. */
    display: block !important;
    grid-area: 1 / 2 / 2 / 3;
    text-align: right !important;
    font-size: var(--texte-s) !important;
    font-weight: 600;
    padding: 0 2rem 0 0 !important;
  }
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="Montant"]::before,
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="Honoraires"]::before,
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="Montant HT"]::before,
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="HT"]::before { content: none; }
  /* Le statut — et l'échéance qui vit dans sa cellule — ferme la fiche.
     « ÉTAT » EST LE MÊME RÔLE sous un autre nom : c'est ainsi que se
     nomment les colonnes de l'échéancier et de la revue mensuelle. Sans
     lui, une échéance repliée sur un téléphone perdait « En retard » —
     c'est-à-dire la seule chose qui appelait une décision, sur l'écran où
     le cabinet prend ses décisions. */
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="Statut"],
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="État"] {
    display: flex !important; flex-wrap: wrap; gap: var(--es-1) var(--es-2); align-items: center;
    grid-area: 3 / 1 / 4 / 3;
    padding: 0 !important;
  }
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="Statut"]::before,
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="État"]::before { content: none; }
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="Statut"] br,
  .tableau-affaires tr.fiche:not(.ouverte) td[data-libelle="État"] br { display: none; }
  /* ---- L'ÉCRAN COMPTES DIT QUI EST QUI, MÊME REPLIÉ -----------------
   *
   * Une carte repliée montre son identifiant, son nom, et le champ mis en
   * avant par sa colonne — sur les listes d'affaires, le montant et le
   * statut. Sur les COMPTES, ces deux-là ne veulent rien dire : ce qu'on
   * vient y lire, c'est ce que la personne FAIT (sa qualification) et ce
   * que son compte a le DROIT de faire (son rôle). Repliée, la carte n'en
   * montrait aucun — vu sur le téléphone du directeur le 23/08, l'heure
   * même où il demandait ces deux colonnes.
   *
   * On abandonne donc la grille « titre + montant » pour cet écran : les
   * trois faits tiennent sur une ligne qui se replie si besoin, et le reste
   * (initiales, boutons) attend le dépliage.
   */
  .tableau-comptes tr.fiche:not(.ouverte) { display: block; }
  .tableau-comptes tr.fiche:not(.ouverte) > td { display: none !important; }
  .tableau-comptes tr.fiche:not(.ouverte) > td:first-child,
  .tableau-comptes tr.fiche:not(.ouverte) > td:nth-child(2) { display: block !important; }
  .tableau-comptes tr.fiche:not(.ouverte) td[data-libelle="Qualification"],
  .tableau-comptes tr.fiche:not(.ouverte) td[data-libelle="Rôle"],
  .tableau-comptes tr.fiche:not(.ouverte) td[data-libelle="État"] {
    display: inline-flex !important; align-items: center;
    padding: 0 var(--es-3) 0 0 !important;
    margin: 0; border: 0;
    color: var(--texte-2); font-size: var(--texte-xs) !important;
  }
  .tableau-comptes tr.fiche:not(.ouverte) td[data-libelle="Qualification"]::before,
  .tableau-comptes tr.fiche:not(.ouverte) td[data-libelle="Rôle"]::before,
  .tableau-comptes tr.fiche:not(.ouverte) td[data-libelle="État"]::before { content: none; }
  /* La qualification se LIT ici, elle se change au dépliage : un sélecteur
     sur une carte repliée invite à un geste qu'on n'a pas voulu faire. */
  .tableau-comptes tr.fiche:not(.ouverte) td[data-libelle="Qualification"] select {
    border: 0; background: none; padding: 0; margin: 0;
    /* `!important` : la strate téléphone épingle la taille de TOUT ce que
       contient une cellule, et la déroulante sortait deux crans au-dessus
       du rôle placé juste à côté. */
    color: var(--texte-2); font-size: var(--texte-xs) !important;
    pointer-events: none; appearance: none;
  }

  /* Le tiroir recouvre le rang 1 : le montant s'efface avec le résumé,
     seule la référence — celle qu'on s'apprête à supprimer — reste lue. */
  .tableau-affaires tr.fiche.tiroir td[data-libelle="Montant"],
  .tableau-affaires tr.fiche.tiroir td[data-libelle="Honoraires"],
  .tableau-affaires tr.fiche.tiroir td[data-libelle="Montant HT"],
  .tableau-affaires tr.fiche.tiroir td[data-libelle="HT"],
  .tableau-affaires tr.fiche.tiroir td[data-libelle="Statut"],
  .tableau-affaires tr.fiche.tiroir td[data-libelle="État"] { visibility: hidden; }
  /* `!important` assumé DANS CE BLOC SEULEMENT : c'est la dernière strate,
     celle qui décide sur un écran étroit. Des règles métier plus
     spécifiques (`a.puce`, `.tableau-cadre .tableau-affaires td`) la
     débordaient sinon, et la mise en page téléphone n'était qu'à moitié
     appliquée — vérifié dans le navigateur, pas supposé. */
  /* UNE SEULE TAILLE DANS LE TABLEAU. Épingler `td` et `th` ne suffisait
     pas : ce qu'ils CONTIENNENT redéclare sa propre taille plus loin dans
     la feuille — `.aide` à 13 px, `.echeance` à 12,48 px, `button.mini`
     à 12,48 px. Une même ligne rendait donc en quatre tailles, et
     l'annotation `.aide` sortait PLUS GROSSE que la donnée qu'elle
     annote. La règle porte sur la cellule et sur tout son contenu ;
     l'exception est nommée juste en dessous. */
  .tableau-affaires,
  .tableau-affaires *:not(input):not(select):not(textarea):not(option) {
    font-size: var(--texte-xs) !important;
  }
  /* SAUF LES CHAMPS DE SAISIE — partout, pas seulement dans les tableaux —
     et pour une raison qui n'est pas esthétique : sous 16 px, Safari iOS
     ZOOME la page à la prise de focus et laisse l'utilisateur dézoomer à
     la main. 1rem est le seuil exact qui l'en empêche. Nos champs
     s'échelonnaient de 12 à 14,72 px selon le type de contrôle ; ils sont
     désormais tous à la même taille, celle qui ne déclenche rien.
     C'est la seule taille en dur du fichier : 16 px n'est pas un palier de
     notre échelle, c'est un seuil imposé par iOS. La lier à `--texte-l`
     ramènerait le zoom le jour où l'échelle bougerait. */
  input, select, textarea {
    font-size: 1rem !important;
  }
  /* La valeur va à la ligne plutôt que d'élargir la carte — et les
     plafonds de largeur des colonnes n'ont plus lieu d'être : une carte
     n'a pas de colonnes voisines à protéger. */
  .tableau-affaires td { white-space: normal !important; min-width: 0; }
  .tableau-affaires td, .tableau-affaires td > a { max-width: none; }

  /* Les filtres : compacts, et le libellé ne casse plus la ligne. */
  /* LES FILTRES NE REPOUSSENT PAS CE QU'ILS FILTRENT (constat n° 7) :
     sept puces prenaient trois lignes avant la liste. Une seule ligne,
     qui défile du doigt — le dégradé des tableaux n'est pas repris ici,
     la puce coupée au bord dit d'elle-même qu'il y a une suite. */
  .puces {
    gap: .35rem;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 2px;
  }
  .puces::-webkit-scrollbar { display: none; }
  /* UN RUBAN QUI DÉFILE NE COMPRIME PAS SES ENFANTS. La règle ne visait
     que les puces ; l'écran Études y a depuis ajouté une déroulante
     d'activité et une rangée de tri, qui n'étaient pas protégées : dans
     une rangée `nowrap`, elles se sont écrasées en colonnes de 90 px,
     hautes de 160, à moitié hors du cadre — d'où les grands vides
     constatés sur le téléphone du directeur. Tout enfant du ruban garde
     donc sa largeur, et c'est le ruban qui défile. */
  .puces > * { flex: none; }
  .puces .puce, .puces a.puce { flex: none; white-space: nowrap; }
  /* Une déroulante ne mange pas le ruban à elle seule. */
  .outillage .puces select { max-width: 13rem; }
  .puce, a.puce { padding: .25rem .6rem !important; font-size: var(--texte-xs) !important; }
  .barre-filtres { gap: .4rem; }
  .barre-filtres input[type=search] { min-width: 0; flex: 1 1 100%; }

  /* La bande de chiffres se replie en deux colonnes, mêmes filets. */
  .bande-stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .bande-stats .stat { padding: .45rem .7rem; }
  .bande-stats .stat:nth-child(odd) { border-left: 0; }
  .bande-stats .stat:nth-child(n+3) { border-top: 1px solid var(--ligne); }

  /* L'ACTION PRIMAIRE EXISTE AUSSI SUR TÉLÉPHONE.
     Cette règle la masquait, et elle avait ses raisons : le formulaire de
     création portait alors le MÊME bouton dans le corps de la page. Depuis
     que le doublon a disparu (« une action primaire n'existe qu'à un seul
     endroit »), la masquer ici revenait à la supprimer : sur téléphone, on
     ne pouvait plus créer ni étude ni client. Régression signalée par le
     directeur, écran Études.

     La barre passe donc sur DEUX lignes quand il le faut : titre et
     boutons d'abord, le compteur dessous, sur toute la largeur — c'est
     une information, elle cède le pas aux commandes sans disparaître. */
  .barre-haute {
    flex-wrap: wrap; height: auto; min-height: var(--charpente-haut);
    padding: .3rem .9rem; row-gap: .15rem;
  }
  /* LE GROUPE D'ACTIONS SE REPLIE LUI AUSSI. La barre passe à la ligne
     depuis le 22/08, mais `.pousse` gardait `flex: none` et ne repliait pas
     SES enfants : sur une fiche client, « Désigner un contact à appeler » +
     « + Nouvelle étude » + « ? Aide » faisaient 411 px dans un téléphone de
     390, et poussaient tout le document. Même invariant que le ruban : ce
     qui ne peut ni se replier ni défiler déborde. */
  .barre-haute .pousse {
    order: 2; flex-wrap: wrap; justify-content: flex-end;
    max-width: 100%; min-width: 0;
  }
  .barre-haute .pousse .bouton, .barre-haute .pousse .bouton-2,
  .barre-haute .pousse button {
    display: inline-flex; padding: .3rem .7rem; font-size: var(--texte-xs);
  }
  .barre-compteur { order: 3; flex: 1 1 100%; border-left: 0; padding-left: 0; }
  /* La barre n'a plus de hauteur connue d'avance : l'outillage ne peut
     plus se coller sous elle à une distance fixe, il rentre dans le flux.
     Sur téléphone c'est la PAGE qui défile, il n'y perd rien. */
  .outillage { position: static; }

  /* L'outillage : la recherche prend sa ligne, puces et sélecteurs
     défilent du doigt sur la leur. */
  .outillage { padding: .45rem .9rem; row-gap: .45rem; }
  .outillage .cherche-client, .outillage .barre-filtres input[type="search"] { flex: 1 1 100%; }
  .outillage input[type="search"] { width: 100%; }
  .outillage .puces, .outillage .sommaire-reglages, .outillage .barre-mois {
    flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; flex: 1 1 100%; }
  .outillage .puces::-webkit-scrollbar,
  .outillage .sommaire-reglages::-webkit-scrollbar { display: none; }
  /* LA BARRE DE FILTRES SE REPLIE, elle ne défile pas. Les puces défilent
     du doigt parce qu'elles sont une longue liste d'un seul axe ; trois
     commandes de formulaire, non — ce qui sort de l'écran ne se tape pas,
     et on ne sait même pas que ça existe. Or `flex-wrap: nowrap` lui était
     imposé pour le grand écran, sans rien pour rattraper ici : sur l'écran
     Affaires, elle mesurait 774 px dans un téléphone de 390 et poussait
     TOUT le document vers la droite, barre supérieure comprise. La
     recherche prend déjà sa ligne entière (règle au-dessus) : il ne
     manquait que l'autorisation de passer à la ligne. */
  .outillage .barre-filtres { flex-wrap: wrap; flex: 1 1 100%; max-width: 100%; min-width: 0; }
  /* AUCUNE COMMANDE DU RUBAN N'EST PLUS LARGE QUE LE RUBAN. Une déroulante
     se dimensionne sur sa PLUS LONGUE option : « Vérification réglementaire
     (COFRAC) » lui donnait 424 px dans un téléphone de 390, et un élément
     flexible plus large que son conteneur ne se replie pas — il déborde, et
     pousse le document. `min-width: 0` est indispensable : sans lui, un
     élément flex refuse de descendre sous sa largeur intrinsèque, et le
     `max-width` seul reste sans effet. Le texte de l'option choisie est
     alors tronqué par le navigateur ; c'est le bon compromis — on lit le
     début du libellé plutôt que de perdre l'écran entier. */
  .outillage select, .outillage input, .outillage button,
  .outillage .barre-filtres > * { max-width: 100%; min-width: 0; }

  /* Les cartes gagnent de la place utile en marge. */
  .carte { padding: var(--es-4); }
  .sommaire-reglages a { padding: .25rem .6rem; font-size: var(--texte-xs); }
}

/* Un `fieldset` a `min-inline-size: min-content` par défaut : il refuse de
   rétrécir et fait déborder toute la page. */
fieldset, .grille-2, .grille-operation { min-width: 0; }
fieldset > *, .grille-2 > * { min-width: 0; }

/* Une rangée flex qui ne se replie pas pousse ses enfants HORS du cadre :
   `.duree-ligne` (durées de conservation) faisait déborder toute la page
   de Réglages de 85 px sur un téléphone. Le repli est la valeur sûre — un
   texte d'aide passe à la ligne, il ne sort jamais de l'écran. */
.duree-ligne, .cons, .barre-haute, .actions-tete, .entete-affaire, .fiche-tete {
  flex-wrap: wrap;
}
.duree-ligne > .aide, .cons > .aide { flex: 1 1 100%; margin-top: .2rem; }

/* Le dépliant de suppression d'affaire : il doit se voir comme une zone à
   part, sans crier. Un bouton rouge suffit à dire le danger ; un cadre
   rouge partout ferait fuir l'œil de ce qui compte. */
details.supprimer-affaire { margin-top: 1.2rem; border-top: 1px solid var(--ligne); padding-top: .8rem; }
details.supprimer-affaire > summary { color: var(--rouge); font-weight: 600; cursor: pointer; }
details.supprimer-affaire[open] > summary { margin-bottom: .6rem; }
details.supprimer-affaire label { max-width: 26rem; }

/* La suppression d'une étude, au fond du dépliant « Modifier » : présente
   quand on la cherche, jamais sous le doigt quand on ne la cherche pas. */
.supprimer-etude {
  margin-top: .9rem; padding-top: .7rem;
  border-top: 1px solid var(--ligne);
}
.supprimer-etude .aide { margin-top: .4rem; }

/* ---------- L'ÉDITEUR DE DEVIS ----------
   Un tableau dont chaque cellule est un champ : sans réglage, les colonnes
   se partagent la largeur à parts égales et le LIBELLÉ — la seule colonne
   qui porte du sens — se retrouve tronqué à côté de champs numériques
   larges de dix centimètres. On donne donc la place à ce qui se lit, et on
   serre ce qui se compte. */
.tableau-affaires td .champ-entree { margin: 0; padding: 0.3rem var(--es-2); }
.tableau-affaires td.cellule-longue .champ-entree { min-width: 20rem; }
.tableau-affaires td.num .champ-entree { width: 6rem; text-align: right; }
/* Les colonnes calculées sont des CHIFFRES, pas des champs : elles se lisent
   d'un coup d'œil, alignées, et changent sous les doigts pendant la saisie. */
.tableau-affaires td[data-calc] { font-variant-numeric: tabular-nums; font-weight: 600; }
.tableau-affaires tfoot td { background: var(--surface); font-weight: 600; }
[data-bloc-phase] .d-ajouter { margin-top: var(--es-3); }

@media (max-width: 60rem) {
  /* Sous cette largeur, un champ de 20 rem pousse le tableau hors cadre ;
     le cadre défile déjà (`.tableau-cadre`), mais autant lui éviter. */
  .tableau-affaires td.cellule-longue .champ-entree { min-width: 12rem; }
}

/* ---------- LES BARÈMES DE DEVIS, EN RÉGLAGES ----------
   Une activité, un bloc : sans séparation, le titre de la suivante se
   lisait comme la légende de la zone précédente. Et la zone de saisie est
   en CHASSE FIXE, sans retour à la ligne automatique : un barème est un
   tableau déguisé, ses barres verticales doivent s'aligner pour qu'on
   repère d'un coup d'œil la ligne à quatre champs au milieu de celles à
   cinq. */
.modele-devis { margin-top: var(--es-4); padding-top: var(--es-3); border-top: 1px solid var(--ligne); }
.modele-devis:first-of-type { border-top: 0; }
/* La tête d'un modèle : son NOM prend la place — c'est lui qu'on lit pour
   reconnaître le bloc — et « Retirer » se range au bout, hors du chemin. */
.modele-tete { display: flex; align-items: center; gap: var(--es-3); margin-bottom: var(--es-2); }
.modele-tete .modele-nom { flex: 1; min-width: 12rem; font-weight: 700; }
.modele-tete .md-retirer { flex: none; color: var(--rouge); }
.modele-nombres { display: flex; flex-wrap: wrap; gap: var(--es-4); margin-bottom: var(--es-2); align-items: flex-end; }
.modele-nombres select { display: block; margin-top: 2px; }
.modele-nombres label { font-size: var(--texte-s); color: var(--texte-2); }
.modele-nombres input { width: 8rem; display: block; margin-top: 2px; }
.modele-lignes { display: block; font-size: var(--texte-s); color: var(--texte-2); }
.modele-lignes textarea {
  margin-top: 2px;
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-size: var(--texte-s); line-height: 1.5;
  white-space: pre; overflow-x: auto;
  color: var(--texte);
}

/* ---------- LE LOGO DU CLIENT, SUR L'ÉCRAN DEVIS ----------
   L'aperçu est BORNÉ comme sur le papier : un blason de mairie arrive
   parfois en 2 000 px de large, et sans plafond il pousserait le formulaire
   hors de l'écran. Le damier discret derrière montre la transparence d'un
   PNG — c'est ce qui dit, sans phrase, que le fond du devis sera blanc. */
.bloc-logo .apercu-logo {
  display: block; max-height: 6rem; max-width: 16rem; width: auto; height: auto;
  padding: var(--es-2); border: var(--bordure); border-radius: var(--rayon-1);
  background: var(--carte);
  background-image:
    linear-gradient(45deg, var(--surface-2) 25%, transparent 25%),
    linear-gradient(-45deg, var(--surface-2) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, var(--surface-2) 75%),
    linear-gradient(-45deg, transparent 75%, var(--surface-2) 75%);
  background-size: 12px 12px;
  background-position: 0 0, 0 6px, 6px -6px, -6px 0;
}
.bloc-logo .actions-logo { display: flex; flex-wrap: wrap; gap: var(--es-2); margin-top: var(--es-2); }
/* Le déclencheur est un LABEL : un champ « fichier » natif s'habille mal et
   ne se dessine pas pareil d'un navigateur à l'autre. */
.bloc-logo .actions-logo label { cursor: pointer; margin: 0; }

/* ---------- CE QUI REVIENT SOUVENT, PROPOSÉ AU CATALOGUE ----------
   Un bloc DISCRET sous la zone de saisie : c'est une suggestion, pas un
   avertissement. Le fond ambré la distingue sans crier — un cadre rouge
   ferait croire à un défaut là où il n'y a qu'une occasion. */
.promotions {
  margin-top: var(--es-3); padding: var(--es-3);
  background: var(--ambre-clair); border: 1px solid var(--ambre-bord); border-radius: var(--rayon-1);
}
.promotions-titre {
  font-size: var(--texte-xs); text-transform: uppercase; letter-spacing: .05em;
  font-weight: 700; color: var(--eteint); margin-bottom: var(--es-2);
}
.promotion { display: flex; align-items: center; flex-wrap: wrap; gap: var(--es-2); margin-bottom: var(--es-2); }
.promotion .promotion-ligne { font-weight: 600; font-size: var(--texte-s); }
.promotion .aide { margin: 0; }
.promotions > .aide { margin-top: var(--es-2); }

/* ======================================================================
 * L'IMPRESSION EST LA DERNIÈRE STRATE — et ce n'est pas une commodité.
 *
 * Ce bloc vivait au milieu du fichier. Les media queries n'ajoutent aucune
 * spécificité : à égalité, c'est l'ORDRE qui tranche, et toutes les règles
 * d'écran écrites plus bas passaient devant. La barre d'écran gardait donc
 * sa hauteur fixe sur le papier, et le texte d'un avertissement déplié
 * filait à 2 552 px de large, hors de la feuille. Mesuré, pas supposé.
 *
 * Le papier est le dernier mot : ce bloc reste EN FIN DE FICHIER.
 * ==================================================================== */
/* UNE FACTURE ANNULÉE RESTE LISIBLE, mais ne se confond plus avec les
   autres. Elle garde sa place au registre — la numérotation est sans trou,
   c'est une exigence comptable — et son numéro se barre : on doit voir en
   une seconde qu'elle ne compte pas dans le chiffre d'affaires. */
.facture-annulee { opacity: .72; }
.facture-annulee td[data-libelle="HT"],
.facture-annulee td[data-libelle="TTC"] { text-decoration: line-through; }
/* ---- LE DIALOGUE DU PORTAIL (D1) ----------------------------------------
   Il remplace confirm(), alert() et prompt() : un <dialog> natif, modal,
   qui piège le focus et se ferme par Échap (dialogue.ts). La question garde
   ses retours à la ligne. */
dialog.dialogue {
  border: 1px solid var(--ligne); border-radius: var(--rayon-2); padding: var(--es-4, 1.25rem);
  max-width: min(32rem, calc(100vw - 2rem)); width: 100%; background: var(--carte); color: var(--texte);
  box-shadow: var(--ombre-2);
}
dialog.dialogue::backdrop { background: color-mix(in srgb, var(--encre) 45%, transparent); }
.dialogue-message { margin: 0 0 1rem; white-space: pre-line; font-size: var(--texte-m); line-height: 1.5; }
.dialogue-champ { display: block; font-size: var(--texte-s); color: var(--texte-2); margin-bottom: 1rem; }
.dialogue-champ input { display: block; width: 100%; margin-top: .3rem; }
.dialogue-actions { display: flex; justify-content: flex-end; gap: .5rem; flex-wrap: wrap; }

/* ---- L'ANNONCE D'UN GESTE (D2) -------------------------------------------
   « Étude passée à Offre validée — Annuler » : en bas de l'écran, hors de la
   zone qui se rafraîchit, lue par les lecteurs d'écran (role=status). */
.annonces { position: fixed; left: 50%; bottom: 1.25rem; transform: translateX(-50%);
  z-index: 50; width: max-content; max-width: calc(100vw - 2rem); }
.annonce { display: flex; align-items: center; gap: .9rem; flex-wrap: wrap;
  background: var(--marine); color: var(--sur-fonce); border-radius: var(--rayon-2);
  padding: .6rem .7rem .6rem 1rem; box-shadow: var(--ombre-2); font-size: var(--texte-m); }
.annonce .bouton { margin: 0; background: transparent; color: var(--sur-fonce); border-color: color-mix(in srgb, var(--sur-fonce) 50%, transparent); }

/* ---- LA RECHERCHE ⌘K (lot F) ---------------------------------------------
   Le bouton de la barre l'annonce (et sert au doigt, qui n'a pas de ⌘K) ;
   la boîte s'ouvre en haut, comme une palette de commandes. */
.bouton-recherche { display: inline-flex; align-items: center; gap: .5rem; margin: 0;
  background: var(--carte); color: var(--texte-2); border: 1px solid var(--ligne);
  border-radius: var(--rayon-3); padding: .2rem .5rem .2rem .8rem; font-size: var(--texte-s); }
.bouton-recherche:hover:not(:disabled) { background: var(--surface); color: var(--texte); }
.bouton-recherche kbd { font: inherit; font-size: var(--texte-xs); color: var(--texte-2);
  border: 1px solid var(--ligne); border-radius: var(--rayon-1); padding: 0 .3rem; }
dialog.recherche { margin: 12vh auto auto; width: min(40rem, calc(100vw - 2rem)); padding: 0;
  border: 1px solid var(--ligne); border-radius: var(--rayon-2); background: var(--carte);
  color: var(--texte); box-shadow: var(--ombre-3); }
dialog.recherche::backdrop { background: color-mix(in srgb, var(--encre) 35%, transparent); }
.recherche-champ { width: 100%; border: 0; border-bottom: 1px solid var(--ligne); border-radius: 0;
  padding: .9rem 1rem; font-size: var(--texte-l); background: transparent; }
.recherche-champ:focus { box-shadow: none; outline: none; border-bottom-color: var(--accent); }
.recherche-liste { list-style: none; margin: 0; padding: .3rem; max-height: 55vh; overflow-y: auto; }
.recherche-liste li { display: grid; grid-template-columns: 4.5rem 1fr; column-gap: .75rem;
  padding: .5rem .7rem; border-radius: var(--rayon-1); cursor: pointer; }
.recherche-liste li[aria-selected="true"] { background: var(--accent-clair); }
.recherche-type { font-size: var(--texte-xs); color: var(--texte-2); text-transform: uppercase;
  letter-spacing: .06em; padding-top: .1rem; }
.recherche-titre { font-weight: 600; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.recherche-detail { grid-column: 2; font-size: var(--texte-s); color: var(--texte-2); overflow-wrap: anywhere; }
.recherche-liste li.recherche-vide { display: block; color: var(--texte-2); cursor: default; }
.recherche-pied { margin: 0; padding: .5rem 1rem; border-top: 1px solid var(--ligne);
  font-size: var(--texte-xs); color: var(--texte-2); }
/* Sur téléphone, le raccourci ne veut rien dire : la loupe parle seule. */
@media (max-width: 30rem) { .bouton-recherche kbd { display: none; } }

/* ======== 4. CHARTE v3 — LA COQUE (maquettes de la section 7) ========
   Une barre latérale CLAIRE de 248 px, une barre haute de 52 px avec le
   fil d'Ariane, et le contenu sur fond blanc. Posée APRÈS les strates
   d'avant pour les préciser, AVANT le bloc tactile et l'impression qui
   doivent garder le dernier mot. */
.lateral {
  width: var(--charpente-lat); background: var(--fond); color: var(--texte);
  border-right: 1px solid var(--ligne); padding: 14px 10px; gap: 2px;
}
.lateral-tete { padding: 4px 10px 14px; border-bottom: 0; gap: 10px; }
.lateral .logo-carre {
  width: 26px; height: 26px; border-radius: 7px; font-size: var(--titre-3); font-weight: 400;
  background: linear-gradient(145deg, var(--acier), var(--cobalt)); color: var(--sur-fonce);
  font-family: var(--police-marque);
}
.lateral .marque { font-size: 15px; font-weight: 600; letter-spacing: 0; color: var(--texte); }
.lateral .bouton-recherche {
  display: flex; width: 100%; height: 32px; margin: 0 0 8px; padding: 0 10px; gap: 8px;
  border: 1px solid var(--ligne); border-radius: var(--rayon-1); background: var(--carte);
  color: var(--texte-3); font-size: var(--texte-s); font-weight: 400; box-shadow: none;
}
.lateral .bouton-recherche:hover:not(:disabled) { background: var(--carte); color: var(--texte-2); border-color: var(--champ-bord); }
.lateral .bouton-recherche .icone { width: 14px; height: 14px; }
.bouton-recherche kbd, .barre-haute kbd, .liste-pied kbd {
  margin-left: auto; font: inherit; font-size: .85em; font-weight: 500; padding: 1px 5px;
  border-radius: 4px; border: 1px solid var(--champ-bord); background: var(--carte); color: var(--texte-3);
}
.lateral .menu {
  flex: 1; min-height: 0; padding: 0; display: flex; flex-direction: column; gap: 2px;
  overflow-y: auto; overflow-x: hidden;
}
.lateral .menu-item {
  height: 32px; min-height: 32px; padding: 0 10px; gap: 10px; margin: 0; border-radius: var(--rayon-1);
  color: var(--texte-nav); font-size: var(--texte-m); white-space: nowrap; flex: none;
}
.lateral .menu-item .icone { width: 16px; height: 16px; color: var(--texte-3); }
.lateral .menu-item:hover { background: var(--survol-menu); color: var(--texte); }
.lateral .menu-item.actif { background: var(--menu-actif); color: var(--texte); font-weight: 500; }
.lateral .menu-item.actif .icone { color: var(--accent); }
.lateral .menu-section {
  padding: 14px 10px 6px; font-size: var(--texte-xs); font-weight: 500; color: var(--texte-3);
  text-transform: none; letter-spacing: 0;
}
.lateral .menu-item .n {
  margin-left: auto; font-size: var(--texte-xs); font-weight: 400; color: var(--texte-3);
  font-variant-numeric: tabular-nums;
}
.vue-pastille { width: 8px; height: 8px; border-radius: 3px; margin: 0 4px; flex: none; }
.vue-pastille.est-relance { background: var(--etat-relance); }
.vue-pastille.est-retard { background: var(--etat-retard); }
.vue-pastille.est-etude { background: var(--accent); }
.menu-plus > summary { list-style: none; cursor: pointer; }
.menu-plus > summary::-webkit-details-marker { display: none; }
.menu-plus[open] > summary { color: var(--texte); }
.menu-plus > .menu-item { padding-left: 36px; }
.lateral .menu-pied { margin-top: auto; padding-top: 8px; display: flex; flex-direction: column; gap: 2px; }
.lateral .lateral-pied { padding: 10px; margin-top: 6px; border-top: 1px solid var(--ligne); }
.lateral .badge-utilisateur { gap: 10px; }
.lateral .u-texte { min-width: 0; line-height: 1.3; }
.lateral .avatar {
  width: 28px; height: 28px; background: var(--acier); color: var(--sur-fonce);
  font-size: var(--texte-xs); font-weight: 600;
}
.lateral .u-nom { font-size: var(--texte-s); font-weight: 500; color: var(--texte); }
.lateral .u-role { font-size: var(--texte-xs); color: var(--texte-3); }
.lateral a.sortir {
  margin: 0 0 0 auto; width: 28px; height: 28px; justify-content: center; border-radius: 6px;
  color: var(--texte-3);
}
.lateral a.sortir:hover { background: var(--survol-menu); color: var(--texte); }

.principal { background: var(--carte); }
.barre-haute {
  height: var(--charpente-haut); background: var(--carte); box-shadow: none;
  border-bottom: 1px solid var(--ligne-douce); padding: 0 20px; gap: 10px;
}
.barre-haute .fil { display: flex; align-items: center; gap: 10px; min-width: 0; font-size: var(--texte-m); }
.barre-haute .fil-parent { color: var(--texte-3); text-decoration: none; border: 0; }
.barre-haute .fil-parent:hover { color: var(--texte); }
.barre-haute .fil-sep { color: var(--separateur); }
.barre-haute .titre-page { font-size: var(--texte-m); font-weight: 500; color: var(--texte); letter-spacing: 0; }
.barre-haute .barre-compteur { font-size: var(--texte-s); color: var(--texte-3); border-left: 0; padding-left: 0; }
.barre-haute .pousse { gap: 8px; }
.barre-haute .pousse a.bouton, .barre-haute .pousse button.bouton {
  display: inline-flex; align-items: center; gap: 8px; height: 32px; padding: 0 14px;
  border: 0; border-radius: var(--rayon-1); background: var(--accent); color: var(--sur-fonce);
  font-size: var(--texte-s); font-weight: 600; text-decoration: none;
  box-shadow: 0 1px 2px color-mix(in srgb, var(--encre) 12%, transparent), inset 0 1px 0 color-mix(in srgb, var(--sur-fonce) 12%, transparent);
}
.barre-haute .pousse a.bouton:hover, .barre-haute .pousse button.bouton:hover { background: var(--accent-fonce); color: var(--sur-fonce); }
.barre-haute .pousse a.bouton kbd {
  background: color-mix(in srgb, var(--sur-fonce) 16%, transparent);
  border-color: color-mix(in srgb, var(--sur-fonce) 25%, transparent); color: var(--sur-fonce);
}
.bouton-fantome, .barre-haute a.lien-aide {
  display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 10px;
  border: 1px solid var(--ligne); border-radius: var(--rayon-1); background: var(--carte);
  font-size: var(--texte-s); color: var(--texte-nav); text-decoration: none; cursor: pointer;
}
.bouton-fantome:hover, .barre-haute a.lien-aide:hover { background: var(--survol-2); color: var(--texte); border-color: var(--ligne); }
/* La recherche du TÉLÉPHONE : la barre latérale y est un tiroir fermé. */
.barre-haute .recherche-mobile { display: none; }
@media (max-width: 800px) {
  .barre-haute .recherche-mobile { display: inline-flex; }
}

/* ======== 5. CHARTE v3 — LES COMPOSANTS PARTAGÉS ========
   Bouton plein (UN par écran), bouton fantôme, onglets soulignés, menus
   déroulants, pastilles d'état, avatars — tels que la maquette les
   dessine. Les autres écrans les reprendront (lot 5). */
.btnp {
  display: inline-flex; align-items: center; gap: 8px; height: 32px; padding: 0 14px; margin: 0;
  border: 0; border-radius: var(--rayon-1); background: var(--accent); color: var(--sur-fonce);
  font: inherit; font-size: var(--texte-s); font-weight: 600; text-decoration: none; cursor: pointer;
  box-shadow: 0 1px 2px color-mix(in srgb, var(--encre) 12%, transparent), inset 0 1px 0 color-mix(in srgb, var(--sur-fonce) 12%, transparent);
}
.btnp:hover:not(:disabled), main a.btnp:hover { background: var(--accent-fonce); color: var(--sur-fonce); border: 0; }
main a.btnp, main a.btnp:visited { color: var(--sur-fonce); border-bottom: 0; }
.btnp kbd, .barre-haute .pousse a.bouton kbd {
  background: color-mix(in srgb, var(--sur-fonce) 16%, transparent);
  border-color: color-mix(in srgb, var(--sur-fonce) 25%, transparent); color: var(--sur-fonce);
}
.ghost, summary.ghost {
  display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 10px; margin: 0;
  border: 1px solid var(--ligne); border-radius: var(--rayon-1); background: var(--carte);
  font: inherit; font-size: var(--texte-s); font-weight: 400; color: var(--texte-nav); cursor: pointer; list-style: none;
  white-space: nowrap;
}
.ghost:hover:not(:disabled) { background: var(--survol-2); color: var(--texte); }
.ghost svg, summary.ghost svg { width: 14px; height: 14px; fill: none; stroke: var(--texte-3); stroke-width: 1.4; }
.ghost .compte { font-weight: 600; color: var(--accent); }
button.danger { background: var(--rouge); color: var(--sur-fonce); border: 0; border-radius: var(--rayon-1); height: 32px; padding: 0 14px; font-size: var(--texte-s); font-weight: 600; }
button.danger:hover:not(:disabled) { background: var(--rouge-fonce); }
summary::-webkit-details-marker { display: none; }

.tab {
  display: inline-flex; align-items: baseline; padding: 0 2px 11px; font-size: var(--texte-m);
  color: var(--texte-2); white-space: nowrap; text-decoration: none; cursor: pointer; list-style: none;
}
main a.tab, main a.tab:visited { color: var(--texte-2); border-bottom: 0; }
.tab b { font-weight: 500; color: var(--texte-3); margin-left: 6px; }
.tab b.compte-alerte { color: var(--etat-retard); }
main a.tab:hover, .tab:hover { color: var(--texte); }
main a.tab.actif, .tab.actif { color: var(--texte); font-weight: 500; box-shadow: inset 0 -2px 0 var(--accent); }
.tab.plus { color: var(--texte-3); }

.menu-deroulant { position: relative; }
.menu-deroulant > summary { list-style: none; }
.menu-deroulant .menu-liste {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 60; min-width: 15rem; max-height: 60vh; overflow-y: auto;
  padding: 6px; background: var(--carte); border-radius: var(--rayon-carte); box-shadow: var(--ombre-2), 0 0 0 1px var(--ligne);
  display: flex; flex-direction: column;
}
.menu-deroulant.a-droite .menu-liste { left: auto; right: 0; }
.menu-liste a, main .menu-liste a {
  display: flex; align-items: center; gap: 8px; min-height: 32px; padding: 0 10px; border-radius: 6px;
  color: var(--texte); border: 0; text-decoration: none; font-size: var(--texte-m); white-space: nowrap;
}
.menu-liste a b { margin-left: auto; font-weight: 500; color: var(--texte-3); }
.menu-liste a:hover { background: var(--survol-2); color: var(--texte); }
.menu-liste a[aria-current] { background: var(--selection); font-weight: 500; }
.menu-titre { padding: 10px 10px 4px; font-size: var(--texte-xs); font-weight: 500; color: var(--texte-3); }

.pill {
  display: inline-flex; align-items: center; gap: 6px; height: 22px; padding: 0 9px; border-radius: var(--rayon-3);
  font-size: var(--texte-xs); font-weight: 500; white-space: nowrap; line-height: 1;
}
.pill i { width: 6px; height: 6px; border-radius: 50%; display: block; background: currentColor; }
.pill.est-signee { color: var(--etat-signee); background: var(--etat-signee-fond); }
.pill.est-etude { color: var(--etat-etude); background: var(--etat-etude-fond); }
.pill.est-valider { color: var(--etat-valider); background: var(--etat-valider-fond); }
.pill.est-valider i { background: var(--etat-valider-point); }
.pill.est-relance { color: var(--etat-relance); background: var(--etat-relance-fond); }
.pill.est-retard { color: var(--etat-retard); background: var(--etat-retard-fond); }
.pill.est-eteinte { color: var(--eteint); background: var(--eteint-clair); }

.av {
  width: 22px; height: 22px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  flex: none; font-size: .72em; font-weight: 600; color: var(--sur-fonce); background: var(--acier); vertical-align: middle;
}
.av.est-cobalt { background: var(--cobalt); }
.av.est-brume { background: var(--brume); }

/* ======== 6. CHARTE v3 — L'ÉCRAN ÉTUDES (maquette « 7 · Études ») ======== */
main:has(.espace-etudes) { max-width: none; padding: 0; margin: 0; }
.espace-etudes { display: grid; grid-template-columns: minmax(0, 1fr) 420px; min-height: 0; }
.espace-etudes.sans-fiche { grid-template-columns: minmax(0, 1fr); }
.colonne-liste { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.liste-tete { padding: 22px 24px 0; display: flex; flex-direction: column; gap: 18px; }
.liste-titre { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; }
.liste-titre h1 { margin: 0; font-size: var(--titre-2); font-weight: 600; letter-spacing: -.01em; color: var(--texte); }
.liste-resume { font-size: var(--texte-m); color: var(--texte-3); }
.vues { display: flex; align-items: flex-end; gap: 22px; border-bottom: 1px solid var(--ligne); min-width: 0; }
.vues .menu-deroulant > summary.tab { padding-bottom: 11px; }
/* Filtrer et Tri : sur la ligne du titre — la ligne des onglets n'a pas la
   place pour eux dès que les compteurs passent la centaine. */
.vues-outils { margin-left: auto; display: flex; gap: 8px; align-self: center; }
.liste-defile { flex: 1; min-height: 0; padding: 0 12px; }
table.liste-etudes { width: 100%; border-collapse: collapse; table-layout: fixed; font-size: var(--texte-m); }
table.liste-etudes col.c-num { width: 112px; }
table.liste-etudes col.c-statut { width: 140px; }
table.liste-etudes col.c-echeance { width: 92px; }
table.liste-etudes col.c-montant { width: 116px; }
table.liste-etudes col.c-qui { width: 44px; }
table.liste-etudes thead th {
  height: 38px; padding: 0 8px; text-align: left; font-size: var(--texte-xs); font-weight: 500; color: var(--texte-3);
  background: var(--carte); position: sticky; top: 0; z-index: 2; text-transform: none; letter-spacing: 0;
}
table.liste-etudes thead th:first-child { padding-left: 12px; }
table.liste-etudes tr.r { height: var(--ligne-tableau); cursor: pointer; }
table.liste-etudes tr.r td {
  padding: 0 8px; border-top: 1px solid var(--ligne-douce); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
table.liste-etudes tr.r td.col-num { padding-left: 12px; font-weight: 500; }
table.liste-etudes tr.r:hover td { background: var(--survol); }
table.liste-etudes tr.r.selectionnee td { background: var(--selection); }
table.liste-etudes tr.r.selectionnee td:first-child { box-shadow: inset 2px 0 0 var(--accent); }
table.liste-etudes a.lien-fiche, main table.liste-etudes a.lien-fiche {
  display: inline; position: static; color: var(--texte); border: 0; text-decoration: none; font: inherit;
}
table.liste-etudes a.lien-fiche:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
table.liste-etudes .intitule { font-weight: 500; }
table.liste-etudes .client { color: var(--texte-3); }
table.liste-etudes .col-echeance { color: var(--texte-2); }
table.liste-etudes .col-echeance.est-retard { color: var(--etat-retard); }
table.liste-etudes .col-montant { text-align: right; }
table.liste-etudes tr.vide td { padding: 32px 12px; color: var(--texte-3); text-align: center; white-space: normal; }
table.liste-etudes.simple { table-layout: auto; margin: 8px 0 16px; }
table.liste-etudes.simple th, table.liste-etudes.simple td { padding: 8px; border-top: 1px solid var(--ligne-douce); text-align: left; }
.vue-rattachement { padding: 16px 12px 32px; max-width: 60rem; }
.vue-rattachement h2 { font-size: var(--titre-3); font-weight: 600; color: var(--texte); margin: 16px 0 4px; }
.liste-pied {
  height: 40px; flex: none; display: flex; align-items: center; gap: 16px; padding: 0 24px;
  border-top: 1px solid var(--ligne-douce); font-size: var(--texte-xs); color: var(--texte-3);
}

.fiche-etude { border-left: 1px solid var(--ligne); display: flex; flex-direction: column; min-height: 0; background: var(--carte); }
.fiche-entete { padding: 18px 22px 0; display: flex; flex-direction: column; gap: 12px; }
.fiche-ligne { display: flex; align-items: center; gap: 10px; }
.fiche-numero { font-size: var(--texte-s); font-weight: 500; color: var(--texte-2); }
main a.fiche-fermer, a.fiche-fermer {
  margin-left: auto; width: 28px; height: 28px; border-radius: 6px; display: inline-flex; align-items: center;
  justify-content: center; border: 0; color: var(--texte-3);
}
a.fiche-fermer:hover { background: var(--survol-2); }
a.fiche-fermer svg { width: 15px; height: 15px; fill: none; stroke: var(--texte-3); stroke-width: 1.4; }
.fiche-etude h2 { margin: 0; font-size: var(--titre-3); font-weight: 600; line-height: 1.35; letter-spacing: -.01em; color: var(--texte); }
.titre-editable { display: inline; border-radius: 6px; outline: none; padding: 0 2px; margin: 0 -2px; }
.titre-editable:hover { background: var(--survol-2); }
.titre-editable:focus { background: var(--carte); box-shadow: 0 0 0 1.5px var(--accent), 0 0 0 4px var(--anneau); }
.fiche-onglets { display: flex; gap: 20px; border-bottom: 1px solid var(--ligne); margin-top: 4px; }
.fiche-corps { flex: 1; min-height: 0; overflow-y: auto; padding: 16px 22px 24px; }
.fiche-volet { display: flex; flex-direction: column; gap: 18px; }
.fiche-volet[hidden] { display: none; }
.suggestion { border-radius: var(--rayon-carte); padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; }
.suggestion p { margin: 0; font-size: var(--texte-m); line-height: 1.5; }
.suggestion p b { font-weight: 600; }
.suggestion p span { color: var(--texte-2); }
.suggestion.est-relance { border: 1px solid var(--etat-relance-bord); background: color-mix(in srgb, var(--etat-relance-fond) 55%, var(--carte)); }
.suggestion.est-etude { border: 1px solid var(--anneau); background: color-mix(in srgb, var(--etat-etude-fond) 60%, var(--carte)); }
.suggestion-gestes { display: flex; gap: 8px; flex-wrap: wrap; }
.props { display: flex; flex-direction: column; }
.prop { display: grid; grid-template-columns: 132px minmax(0, 1fr); align-items: center; min-height: 34px; font-size: var(--texte-m); }
.prop-terme { color: var(--texte-3); }
.prop-valeur { padding: 5px 8px; margin-left: -8px; overflow-wrap: anywhere; }
.prop-aide { color: var(--texte-3); font-size: var(--texte-xs); }
.prop-champ, input.prop-champ, select.prop-champ, textarea.prop-champ {
  width: 100%; min-width: 0; margin: 0 0 0 -8px; padding: 5px 8px; border: 1px solid transparent; border-radius: 6px;
  background: transparent; font: inherit; font-size: var(--texte-m); color: var(--texte); box-shadow: none;
}
.prop-champ:hover:not(:disabled) { background: var(--survol-2); border-color: transparent; }
.prop-champ:focus { background: var(--carte); border-color: var(--accent); box-shadow: 0 0 0 3px var(--anneau); outline: none; }
.prop-champ[data-retard] { color: var(--etat-retard); }
.prop-champ:disabled { color: var(--texte-2); cursor: not-allowed; }
select.prop-champ { appearance: none; -webkit-appearance: none; cursor: pointer; }
.prop-notes { display: flex; flex-direction: column; gap: 4px; }
.prop-notes textarea.prop-champ { margin: 0; min-height: 3rem; resize: vertical; }
.recents h3 { margin: 0 0 10px; font-size: var(--texte-xs); font-weight: 500; color: var(--texte-3); }
.fil-activite { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.fil-activite li { display: flex; gap: 10px; font-size: var(--texte-s); line-height: 1.45; }
.fil-activite .qui { font-weight: 500; }
.fil-activite .quoi { color: var(--texte-2); }
.fil-activite .quand { color: var(--texte-3); font-size: var(--texte-xs); }
.fil-activite .motif { color: var(--texte-2); font-style: italic; }
.fiche-gestes { display: flex; flex-wrap: wrap; gap: 8px; padding-top: 4px; border-top: 1px solid var(--ligne-douce); padding-top: 14px; }
details.transformer, details.supprimer-etude { border-top: 1px solid var(--ligne-douce); padding-top: 12px; }
details.transformer > summary, details.supprimer-etude > summary { cursor: pointer; font-size: var(--texte-s); color: var(--accent); list-style: none; }
details.supprimer-etude > summary { color: var(--texte-3); }
details.transformer[open], details.supprimer-etude[open] { display: flex; flex-direction: column; gap: 10px; }
details.transformer label, details.supprimer-etude label { display: flex; flex-direction: column; gap: 4px; font-size: var(--texte-s); color: var(--texte-2); }

/* LE PANNEAU DE CRÉATION, par-dessus la liste. */
.voile-creation { position: fixed; inset: 0; z-index: 200; background: var(--voile); backdrop-filter: blur(1.5px); }
.voile-creation[hidden], .panneau-creation[hidden] { display: none; }
.panneau-creation {
  position: fixed; top: 12px; right: 12px; bottom: 12px; z-index: 201; width: min(560px, calc(100vw - 24px));
  background: var(--carte); border-radius: var(--rayon-panneau); box-shadow: var(--ombre-3);
  display: flex; flex-direction: column; overflow: hidden;
}
.creation-tete { padding: 20px 24px 16px; display: flex; align-items: center; gap: 10px; border-bottom: 1px solid var(--ligne-douce); font-size: var(--texte-s); }
.creation-tete .fil-parent { color: var(--texte-3); }
.creation-tete .fil-sep { color: var(--separateur); }
.creation-tete #titre-creation { font-weight: 500; }
.creation-brouillon { margin-left: auto; font-size: var(--texte-xs); color: var(--texte-3); }
.creation-tete a.fiche-fermer { margin-left: 0; }
.creation-corps { flex: 1; min-height: 0; overflow-y: auto; padding: 22px 24px; display: flex; flex-direction: column; gap: 20px; }
.creation-intitule { display: flex; flex-direction: column; gap: 6px; font-size: var(--texte-s); color: var(--texte-3); }
.creation-intitule input, .creation-intitule input:focus {
  font: inherit; font-size: var(--titre-2); font-weight: 600; letter-spacing: -.015em; color: var(--texte);
  border: 0; border-bottom: 2px solid var(--ligne); border-radius: 0; padding: 0 0 6px; background: transparent;
  box-shadow: none; outline: none;
}
.creation-intitule input:focus { border-bottom-color: var(--accent); }
.creation-grille { display: grid; grid-template-columns: 1fr 1fr; gap: 14px 16px; }
.creation-champ { display: flex; flex-direction: column; gap: 6px; min-width: 0; margin: 0; padding: 0; border: 0; }
.creation-champ.pleine { grid-column: 1 / -1; }
.creation-champ > span:first-child, .creation-champ legend { font-size: var(--texte-xs); font-weight: 500; color: var(--texte-2); padding: 0; }
.creation-champ input, .creation-champ select, .creation-champ textarea {
  height: 38px; border: 1px solid var(--champ-bord); border-radius: var(--rayon-2); padding: 0 12px; font: inherit;
  font-size: var(--texte-m); background: var(--carte); color: var(--texte); width: 100%; box-shadow: none;
}
.creation-champ textarea { height: auto; padding: 8px 12px; }
.creation-champ input:focus, .creation-champ select:focus, .creation-champ textarea:focus {
  border-color: var(--accent); box-shadow: 0 0 0 3px var(--anneau); outline: none;
}
.champ-lu {
  height: 38px; border: 1px solid var(--champ-bord); border-radius: var(--rayon-2); padding: 0 12px;
  display: flex; align-items: center; gap: 8px; font-weight: 500; background: var(--fond);
}
.champ-numero { position: relative; display: block; }
.champ-numero input { font-weight: 500; padding-right: 11rem; }
.champ-numero .numero-etat { position: absolute; right: 12px; top: 50%; transform: translateY(-50%); pointer-events: none; }
.numero-etat { margin-left: auto; font-size: var(--texte-xs); font-weight: 500; }
.numero-etat.est-libre { color: var(--etat-signee); }
.numero-etat.est-pris { color: var(--etat-retard); }
.creation-aide { font-size: var(--texte-xs); color: var(--texte-3); }
.segments { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); background: var(--etat-valider-fond); border-radius: var(--rayon-2); padding: 3px; gap: 2px; }
.segment { min-width: 0; }
.segment input { position: absolute; opacity: 0; pointer-events: none; }
.segment span {
  display: block; text-align: center; padding: 7px 6px; border-radius: var(--rayon-1); font-size: var(--texte-s);
  color: var(--texte-2); cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.segment input:checked + span { background: var(--carte); color: var(--texte); font-weight: 500; box-shadow: var(--ombre-1); }
.segment input:focus-visible + span { box-shadow: 0 0 0 2px var(--accent); }
.cherche-client { position: relative; }
.cherche-client .suggestions {
  position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 3; list-style: none; margin: 0;
  background: var(--carte); border-radius: var(--rayon-carte); padding: 6px;
  box-shadow: 0 12px 32px color-mix(in srgb, var(--encre) 16%, transparent), 0 0 0 1px var(--ligne); max-height: 15rem; overflow-y: auto;
}
.cherche-client .suggestions[hidden] { display: none; }
.cherche-client .suggestions li {
  display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 10px; border-radius: var(--rayon-1); cursor: pointer;
}
.cherche-client .suggestions li .nom { font-weight: 500; }
.cherche-client .suggestions li .detail { font-size: var(--texte-xs); color: var(--texte-3); }
.cherche-client .suggestions li[aria-selected="true"] { background: var(--selection); }
.cherche-client .suggestions li.creer { color: var(--texte-2); }
.creation-info {
  display: flex; align-items: center; gap: 10px; margin: 0; font-size: var(--texte-s); color: var(--texte-2);
  background: var(--fond); border-radius: var(--rayon-2); padding: 10px 12px;
}
.creation-pied { padding: 14px 24px; border-top: 1px solid var(--ligne-douce); display: flex; align-items: center; gap: 10px; }
.creation-autre { display: flex; align-items: center; gap: 8px; font-size: var(--texte-s); color: var(--texte-2); margin-right: auto; }
.creation-pied kbd { margin-left: 2px; }

/* Grand écran : la page tient dans la fenêtre, UN défilement par colonne. */
@media (min-width: 64rem) {
  main:has(.espace-etudes) { overflow: hidden; display: flex; flex-direction: column; }
  .espace-etudes { flex: 1; height: 100%; }
  .liste-defile { overflow-y: auto; }
}
/* Plus étroit : la fiche ne s'ouvre que demandée, en plein écran. */
@media (max-width: 63.99rem) {
  .espace-etudes { display: block; }
  .espace-etudes .fiche-etude { display: none; }
  .espace-etudes.fiche-demandee .fiche-etude {
    display: flex; position: fixed; inset: 0; z-index: 150; border-left: 0;
  }
  .vues { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; gap: 18px; }
}
/* Téléphone : la liste en fiches, la création en plein écran. */
@media (max-width: 48rem) {
  .liste-tete { padding: 16px 16px 0; }
  .liste-defile { padding: 0 8px; }
  table.liste-etudes, table.liste-etudes tbody { display: block; }
  table.liste-etudes thead, table.liste-etudes colgroup { display: none; }
  table.liste-etudes tr.r {
    display: grid; grid-template-columns: 1fr auto; gap: 4px 8px; height: auto; padding: 12px 8px;
    border-top: 1px solid var(--ligne-douce);
  }
  table.liste-etudes tr.r td, table.liste-etudes tr.r:hover td, table.liste-etudes tr.r.selectionnee td {
    border: 0; padding: 0; height: auto; background: transparent; box-shadow: none;
  }
  table.liste-etudes tr.r.selectionnee { background: var(--selection); box-shadow: inset 2px 0 0 var(--accent); }
  /* La fiche : n° et statut, puis l'étude, puis l'échéance et le montant. */
  table.liste-etudes tr.r td.col-num { grid-area: 1 / 1; padding: 0; color: var(--texte-2); font-size: var(--texte-s); }
  table.liste-etudes tr.r td.col-statut { grid-area: 1 / 2; justify-self: end; }
  table.liste-etudes tr.r td.col-etude { grid-area: 2 / 1 / 3 / 3; white-space: normal; }
  table.liste-etudes tr.r td.col-echeance { grid-area: 3 / 1; font-size: var(--texte-s); }
  table.liste-etudes tr.r td.col-montant { grid-area: 3 / 2; justify-self: end; font-weight: 500; }
  table.liste-etudes tr.r td.col-qui { display: none; }
  .segments { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .liste-pied { display: none; }
  .panneau-creation { inset: 0; width: 100%; border-radius: 0; }
  .creation-grille { grid-template-columns: 1fr; }
  .creation-pied kbd { display: none; }
}

/* ======== 7. CHARTE v3 — L'ACCUEIL « AUJOURD'HUI » (maquette « 7 · Accueil ») ======== */
main:has(.accueil) { max-width: none; padding: 36px 48px 48px; }
.accueil { display: flex; flex-direction: column; gap: 28px; max-width: 86rem; }
.accueil-tete { display: flex; flex-direction: column; gap: 6px; }
.accueil-date { font-size: var(--texte-s); color: var(--texte-3); }
.accueil-titre {
  margin: 0; font-family: var(--police-marque); font-weight: 400; font-size: var(--marque-1); line-height: 1.05;
  letter-spacing: -.01em; color: var(--texte);
}
.accueil-titre em { color: var(--accent); font-style: italic; }
.chiffres-cles { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 16px; }
.chiffre { border: 1px solid var(--ligne); border-radius: 14px; padding: 18px 20px; display: flex; flex-direction: column; gap: 6px; background: var(--carte); }
.chiffre-libelle { font-size: var(--texte-s); color: var(--texte-2); }
.chiffre-valeur { font-size: var(--titre-1); font-weight: 600; letter-spacing: -.02em; color: var(--texte); }
.chiffre-valeur small { font-size: var(--texte-l); font-weight: 500; color: var(--texte-2); }
.chiffre-detail { font-size: var(--texte-s); color: var(--texte-3); }
.accueil-grille { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: 24px; align-items: start; }
.a-faire { border: 1px solid var(--ligne); border-radius: 14px; overflow: hidden; background: var(--carte); }
.a-faire-tete { display: flex; align-items: center; gap: 12px; padding: 14px 18px; border-bottom: 1px solid var(--ligne-douce); }
.a-faire-tete h2 { margin: 0; font-size: var(--texte-l); font-weight: 600; color: var(--texte); }
.a-faire-tete span { font-size: var(--texte-s); color: var(--texte-3); }
.a-faire-tete a, main .a-faire-tete a { margin-left: auto; font-size: var(--texte-s); color: var(--accent); border: 0; }
.gestes { list-style: none; margin: 0; padding: 0; }
.geste { display: flex; align-items: center; gap: 12px; padding: 12px 18px; border-bottom: 1px solid var(--ligne-douce); }
.geste:last-child { border-bottom: 0; }
.geste .pill { flex: none; }
.geste-texte { flex: 1; min-width: 0; }
.geste-titre, main a.geste-titre {
  display: block; font-size: var(--texte-m); font-weight: 500; color: var(--texte); border: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.geste-detail { font-size: var(--texte-xs); color: var(--texte-3); }
.geste.fait { opacity: .55; }
main a.ghost { color: var(--texte-nav); border: 1px solid var(--ligne); text-decoration: none; }
.accueil-cote { display: flex; flex-direction: column; gap: 16px; }
.en-bref {
  position: relative; overflow: hidden; border-radius: 14px; padding: 20px; color: var(--sur-fonce);
  background: linear-gradient(150deg, var(--acier) 0%, var(--accent) 45%, var(--cobalt) 100%);
  display: flex; flex-direction: column; gap: 10px;
}
.en-bref::before {
  content: ""; position: absolute; inset: 0;
  background: repeating-linear-gradient(90deg, color-mix(in srgb, var(--pervenche) 10%, transparent) 0 10px, transparent 10px 34px);
}
.en-bref-titre { position: relative; font-size: var(--texte-xs); font-weight: 500; letter-spacing: .08em; text-transform: uppercase; opacity: .85; }
.en-bref p { position: relative; margin: 0; font-family: var(--police-marque); font-size: var(--marque-3); line-height: 1.25; }
.carte-v3 { border: 1px solid var(--ligne); border-radius: 14px; padding: 16px 18px; display: flex; flex-direction: column; gap: 12px; background: var(--carte); }
.carte-v3 h2 { margin: 0; font-size: var(--texte-l); font-weight: 600; color: var(--texte); }
.accueil-detail { border-top: 1px solid var(--ligne); padding-top: 16px; }
.accueil-detail > summary { cursor: pointer; font-size: var(--texte-s); color: var(--accent); list-style: none; }
.accueil-detail[open] > summary { margin-bottom: 16px; }
@media (max-width: 64rem) {
  main:has(.accueil) { padding: 20px 16px 32px; }
  .accueil-grille { grid-template-columns: 1fr; }
  .accueil-titre { font-size: var(--marque-2); }
}

/* ======== 8. CHARTE v3 — LA CONNEXION (maquette « 7 · Connexion ») ======== */
body.plein { background: var(--fond); }
body.plein main.pleine { max-width: none; padding: 0; margin: 0; }
.ecran-connexion { min-height: 100vh; display: flex; align-items: stretch; justify-content: stretch; padding: 0; }
.connexion-marque {
  flex: 1 1 56%; min-width: 0; position: relative; overflow: hidden; color: var(--sur-fonce);
  background: linear-gradient(160deg, var(--acier) 0%, var(--accent) 38%, var(--cobalt) 72%, var(--encre) 130%);
  display: flex; flex-direction: column; justify-content: space-between; padding: 48px 56px;
}
.connexion-marque::before {
  content: ""; position: absolute; inset: 0;
  background: repeating-linear-gradient(90deg, color-mix(in srgb, var(--pervenche) 10%, transparent) 0 14px, transparent 14px 46px),
    linear-gradient(180deg, transparent 40%, color-mix(in srgb, var(--pervenche) 22%, transparent) 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, var(--encre) 55%); mask-image: linear-gradient(180deg, transparent 0%, var(--encre) 55%);
}
.connexion-marque::after {
  content: ""; position: absolute; right: -120px; top: -120px; width: 520px; height: 520px; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--pervenche) 35%, transparent) 0%, transparent 70%);
}
.connexion-marque > * { position: relative; z-index: 1; }
.connexion-logo { display: flex; align-items: baseline; gap: 12px; }
.connexion-nom { font-family: var(--police-marque); font-size: var(--marque-2); }
.connexion-portail, .connexion-surtitre { font-size: var(--texte-xs); font-weight: 500; letter-spacing: .2em; text-transform: uppercase; opacity: .88; }
.connexion-accroche { display: flex; flex-direction: column; gap: 18px; max-width: 520px; }
.connexion-titre { margin: 0; font-family: var(--police-marque); font-size: var(--marque-0); line-height: 1.08; letter-spacing: -.01em; }
.connexion-trait { width: 64px; height: 1px; background: color-mix(in srgb, var(--sur-fonce) 60%, transparent); }
.connexion-texte { margin: 0; font-size: var(--titre-3); line-height: 1.6; opacity: .92; }
.connexion-pied { margin: 0; font-size: var(--texte-s); opacity: .8; }
.connexion-formulaire { flex: 1 1 44%; min-width: 0; display: flex; align-items: center; justify-content: center; padding: 48px; }
.carte-connexion { width: 100%; max-width: 400px; display: flex; flex-direction: column; gap: 28px; background: transparent; box-shadow: none; padding: 0; text-align: left; }
.connexion-entete { display: flex; flex-direction: column; gap: 8px; }
.carte-connexion h1 { margin: 0; font-family: var(--police-marque); font-weight: 400; font-size: var(--marque-1b); color: var(--texte); letter-spacing: 0; }
.carte-connexion .sous-titre { margin: 0; font-size: var(--texte-l); color: var(--texte-2); }
.carte-connexion form { display: flex; flex-direction: column; gap: 18px; }
.carte-connexion label { display: flex; flex-direction: column; gap: 8px; }
.connexion-etiquette { font-size: var(--texte-xs); font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--texte-2); }
.carte-connexion select, .carte-connexion input {
  width: 100%; border: 1px solid var(--champ-bord); border-radius: var(--rayon-2); padding: 12px 14px;
  font: inherit; font-size: var(--texte-l); background: var(--carte); color: var(--texte); box-shadow: none; height: auto;
}
.carte-connexion select:focus, .carte-connexion input:focus { border-color: var(--accent); box-shadow: 0 0 0 4px var(--anneau); outline: none; }
.connexion-code { position: relative; display: block; }
.connexion-code input { padding-right: 6rem; }
button.connexion-afficher, .carte-connexion button.connexion-afficher {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%); margin: 0; background: transparent; border: 0;
  color: var(--accent); font-size: var(--texte-m); padding: 6px 8px; min-height: 0; box-shadow: none;
}
button.connexion-afficher:hover:not(:disabled) { background: var(--survol-2); color: var(--accent-fonce); }
button.connexion-entrer {
  margin: 4px 0 0; width: 100%; border: 0; border-radius: var(--rayon-2); padding: 14px 18px; font: inherit;
  font-size: var(--texte-l); font-weight: 600; background: var(--accent); color: var(--sur-fonce); box-shadow: var(--ombre-1); cursor: pointer;
}
button.connexion-entrer:hover:not(:disabled) { background: var(--accent-fonce); }
.carte-connexion .erreur { margin: 0; padding: 10px 12px; border-radius: var(--rayon-2); background: var(--etat-retard-fond); color: var(--etat-retard); font-size: var(--texte-m); }
.connexion-note { margin: 0; font-size: var(--texte-s); color: var(--texte-2); line-height: 1.6; border-top: 1px solid var(--ligne); padding-top: 18px; }
/* Téléphone : le panneau bleu devient un bandeau court. */
@media (max-width: 48rem) {
  .ecran-connexion { flex-direction: column; }
  .connexion-marque { flex: none; padding: 20px 20px 22px; gap: 10px; }
  .connexion-accroche { gap: 6px; }
  .connexion-surtitre, .connexion-trait, .connexion-texte, .connexion-pied { display: none; }
  .connexion-titre { font-size: var(--marque-3); }
  .connexion-formulaire { padding: 28px 20px 40px; align-items: flex-start; }
}

/* ======== 9. CHARTE v3 — LES ÉCRANS D'AVANT (Affaires, Clients, Cycle,
   Facturation, Import, Réglages, Aide, Veille) ========
   Mêmes composants que l'écran Études, posés sur le balisage existant :
   onglets de vues soulignés au lieu de pilules, tableaux denses de 44 px,
   cartes à filet sans ombre, fiche à droite au lieu d'une carte flottante. */
.outillage { background: var(--carte); border-bottom: 1px solid var(--ligne); padding: 10px 24px 0; gap: 18px; box-shadow: none; }
.outillage .puces { gap: 22px; margin: 0; align-items: flex-end; }
a.puce, .outillage a.puce, main a.puce {
  background: none; border: 0; border-radius: 0; padding: 0 2px 11px; color: var(--texte-2);
  font-size: var(--texte-m); text-decoration: none; white-space: nowrap; box-shadow: none;
}
a.puce:hover, main a.puce:hover { color: var(--texte); background: none; border: 0; }
a.puce.active, main a.puce.active { background: none; color: var(--texte); font-weight: 500; box-shadow: inset 0 -2px 0 var(--accent); }
.outillage .barre-filtres, .outillage .barre-tri, .outillage form { padding-bottom: 8px; }
.outillage input[type="search"], .outillage select, .outillage .barre-filtres input[type="search"] {
  height: 30px; border: 1px solid var(--ligne); border-radius: var(--rayon-1); font-size: var(--texte-s); padding: 0 10px; background: var(--carte);
}
.outillage button { height: 30px; padding: 0 12px; border-radius: var(--rayon-1); font-size: var(--texte-s); }

.carte { border: 1px solid var(--ligne); border-radius: var(--rayon-carte); box-shadow: none; }
.carte h2, .carte > h3 { font-size: var(--texte-l); font-weight: 600; color: var(--texte); }
main h1 { font-size: var(--titre-2); font-weight: 600; color: var(--texte); }
main h2 { font-weight: 600; color: var(--texte); }

table.tableau-affaires { font-size: var(--texte-m); border: 0; }
table.tableau-affaires thead th {
  background: var(--carte); color: var(--texte-3); font-size: var(--texte-xs); font-weight: 500;
  text-transform: none; letter-spacing: 0; border-bottom: 1px solid var(--ligne);
}
table.tableau-affaires tbody td { border-top: 1px solid var(--ligne-douce); border-bottom: 0; }
table.tableau-affaires tbody tr:hover td { background: var(--survol); }
.tableau-cadre { border: 0; border-radius: 0; }

button.mini, button.secondaire, a.bouton-2, button.discret {
  background: var(--carte); color: var(--texte-nav); border: 1px solid var(--ligne); border-radius: var(--rayon-1); box-shadow: none;
}
button.mini:hover:not(:disabled), button.secondaire:hover:not(:disabled), button.discret:hover:not(:disabled) { background: var(--survol-2); color: var(--texte); }
button, a.bouton { border-radius: var(--rayon-1); }

.badge-etude { border-radius: var(--rayon-3); font-weight: 500; }
.badge-etude.est-en-etude, .badge-etude.en-etude { color: var(--etat-etude); background: var(--etat-etude-fond); }
.badge-etude.est-offre, .badge-etude.offre, .badge-etude.brouillon, .badge-etude.est-brouillon { color: var(--etat-valider); background: var(--etat-valider-fond); }
.badge-etude.est-offre-validee, .badge-etude.offre-validee { color: var(--etat-etude); background: var(--etat-etude-fond); }
.badge-etude.est-transformee, .badge-etude.transformee { color: var(--etat-signee); background: var(--etat-signee-fond); }
.badge-etude.non-signe { color: var(--etat-retard); background: var(--etat-retard-fond); }

/* LES RÉGLAGES v3 : un sommaire fixe à gauche (familles et modules), le
   contenu à droite ; l'index range ses modules en LIGNES denses, la
   mosaïque de tuiles d'avant ne se parcourait qu'au défilement. */
main:has(> .reglages-v3) { max-width: none; padding: 0; margin: 0; }
.reglages-v3 { display: grid; grid-template-columns: 232px minmax(0, 1fr); min-height: 100%; }
.reglages-v3 .sommaire-reglages {
  display: flex; flex-direction: column; flex-wrap: nowrap; gap: 1px; margin: 0;
  padding: 18px 12px; border-right: 1px solid var(--ligne); background: var(--carte);
  position: sticky; top: 0; align-self: start; max-height: calc(100vh - var(--charpente-haut)); overflow-y: auto;
}
.reglages-v3 .sr-famille { padding: 14px 10px 6px; font-size: var(--texte-xs); font-weight: 500; color: var(--texte-3); }
.reglages-v3 .sr-famille:first-child { padding-top: 0; }
.reglages-v3 .sommaire-reglages a {
  display: block; padding: 6px 10px; border: 0; border-radius: var(--rayon-1); background: none;
  color: var(--texte-nav); font-size: var(--texte-s); font-weight: 400; text-decoration: none;
}
.reglages-v3 .sommaire-reglages a:hover { background: var(--survol-menu); color: var(--texte); }
.reglages-v3 .sommaire-reglages a.actif { background: var(--menu-actif); color: var(--texte); font-weight: 500; }
.reglages-v3 .reglages-contenu { padding: 22px 32px 40px; max-width: 64rem; min-width: 0; }
.reglages-v3 .reglages-contenu > h1 { margin: 0 0 6px; font-size: var(--titre-2); font-weight: 600; letter-spacing: -.01em; }
.reglages-v3 .groupe-reglages > h2 { margin: 28px 0 2px; padding: 0; border: 0; font-size: var(--texte-l); }
.reglages-v3 .groupe-reglages > .intro { margin: 0 0 10px; color: var(--texte-3); font-size: var(--texte-s); }
.reglages-v3 .modules-reglages {
  display: flex; flex-direction: column; gap: 0; margin: 0;
  border: 1px solid var(--ligne); border-radius: var(--rayon-carte); background: var(--carte); overflow: hidden;
}
.reglages-v3 .module-reglage, main .reglages-v3 a.module-reglage {
  display: grid; grid-template-columns: 14rem minmax(0, 1fr) 1rem; align-items: center; gap: 16px;
  min-height: var(--ligne-tableau); padding: 8px 16px; border: 0; border-bottom: 1px solid var(--ligne-douce);
  border-radius: 0; box-shadow: none; transform: none;
}
.reglages-v3 .module-reglage:last-child { border-bottom: 0; }
.reglages-v3 .module-reglage:hover { background: var(--survol); transform: none; }
.reglages-v3 .module-titre { font-weight: 500; color: var(--texte); }
.reglages-v3 .module-reglage .aide { margin: 0; color: var(--texte-3); font-size: var(--texte-s); }
.reglages-v3 .module-fleche { color: var(--texte-3); text-align: right; }
@media (max-width: 64rem) {
  .reglages-v3 { grid-template-columns: minmax(0, 1fr); }
  .reglages-v3 .sommaire-reglages { display: none; }
  .reglages-v3 .reglages-contenu { padding: 16px; }
  .reglages-v3 .module-reglage, main .reglages-v3 a.module-reglage { grid-template-columns: minmax(0, 1fr) 1rem; gap: 2px 12px; }
  .reglages-v3 .module-reglage .aide { grid-column: 1; }
  .reglages-v3 .module-fleche { grid-row: 1 / span 2; grid-column: 2; }
}

/* L'AIDE v3 : le même sommaire fixe que les Réglages, et une colonne de
   lecture (le texte est long : ~75 caractères par ligne). */
main:has(> .aide-v3) { max-width: none; padding: 0; margin: 0; }
.aide-v3 { display: grid; grid-template-columns: 232px minmax(0, 1fr); }
.aide-v3 .sommaire-aide {
  display: flex; flex-direction: column; gap: 1px; padding: 18px 12px; border-right: 1px solid var(--ligne);
  background: var(--carte); position: sticky; top: 0; align-self: start;
  max-height: calc(100vh - var(--charpente-haut)); overflow-y: auto;
}
.aide-v3 .sr-famille { padding: 14px 10px 6px; font-size: var(--texte-xs); font-weight: 500; color: var(--texte-3); }
.aide-v3 .sr-famille:first-child { padding-top: 0; }
.aide-v3 .sommaire-aide a {
  display: block; padding: 6px 10px; border-radius: var(--rayon-1); color: var(--texte-nav);
  font-size: var(--texte-s); text-decoration: none;
}
.aide-v3 .sommaire-aide a:hover { background: var(--survol-menu); color: var(--texte); }
main .aide-v3 .sommaire-aide a, main .reglages-v3 .sommaire-reglages a { border: 0; }
.aide-v3 .sommaire-aide, .reglages-v3 .sommaire-reglages { min-height: calc(100vh - var(--charpente-haut)); box-sizing: border-box; }
.aide-v3 .aide-contenu { padding: 22px 40px 48px; max-width: 48rem; min-width: 0; }
.aide-v3 .aide-contenu > h1 { margin: 0 0 6px; font-size: var(--titre-2); font-weight: 600; letter-spacing: -.01em; }
.aide-v3 .section-aide { padding: 24px 0; border-top: 1px solid var(--ligne); scroll-margin-top: 12px; }
.aide-v3 .section-aide:target > h2 { color: var(--accent); }
.aide-v3 .section-aide > h2 { margin: 0 0 6px; font-size: var(--titre-3); }
.aide-v3 .section-aide > .detail { margin: 0 0 12px; color: var(--texte-2); }
@media (max-width: 64rem) {
  .aide-v3 { grid-template-columns: minmax(0, 1fr); }
  .aide-v3 .sommaire-aide { display: none; }
  .aide-v3 .aide-contenu { padding: 16px; }
}

/* LES ÉCRANS DE TRAVAIL v3 (Facturation, Cycle mensuel) : la même tête que
   les Études — titre, résumé, onglets soulignés — et un tableau dense
   pleine largeur, lignes de 44 px. */
main:has(> .ecran-v3) { max-width: none; padding: 0; margin: 0; }
.ecran-v3 .ecran-corps { padding: 8px 24px 32px; display: flex; flex-direction: column; gap: 16px; }
.ecran-v3 .ecran-corps > .aide { margin: 0; }
table.liste-dense { width: 100%; border-collapse: collapse; font-size: var(--texte-m); }
table.liste-dense thead th {
  height: 38px; padding: 0 8px; text-align: left; font-size: var(--texte-xs); font-weight: 500;
  color: var(--texte-3); border-bottom: 1px solid var(--ligne); white-space: nowrap; background: var(--carte);
}
table.liste-dense td {
  height: var(--ligne-tableau); padding: 6px 8px; border-bottom: 1px solid var(--ligne-douce);
  color: var(--texte); vertical-align: middle;
}
table.liste-dense th:first-child, table.liste-dense td:first-child { padding-left: 12px; }
table.liste-dense .montant { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
table.liste-dense td.action { text-align: right; white-space: nowrap; width: 1%; }
table.liste-dense tbody tr:hover td { background: var(--survol); }
table.liste-dense tr.vide td { padding: 32px 12px; text-align: center; color: var(--texte-3); }
table.liste-dense tr.facture-annulee td { color: var(--texte-3); }
.ecran-v3 .mois-voisins { margin-left: auto; display: flex; gap: 16px; font-size: var(--texte-s); }
.ecran-v3 .mois-voisins a { color: var(--texte-2); text-decoration: none; }
.ecran-v3 .mois-voisins a:hover { color: var(--accent); }
.ecran-v3 .tab-fait { color: var(--etat-signee); }
.ecran-v3 .etat-vide { margin: 24px 0; padding: 32px; text-align: center; color: var(--texte-3);
  border: 1px dashed var(--ligne); border-radius: var(--rayon-carte); }
.revue-ouverte .revue-nom { margin: 0; font-size: var(--texte-l); }
.ajout-replie > summary { list-style: none; cursor: pointer; align-self: flex-start; display: inline-flex; }
.ajout-replie > summary::-webkit-details-marker { display: none; }
.ajout-replie[open] > summary { margin-bottom: 10px; }
@media (max-width: 40rem) {
  .ecran-v3 .ecran-corps { padding: 8px 16px 24px; }
}

/* L'ACTION EN LOT, EN BARRE : une ligne collée au pied de la liste
   (affectation des affaires affichées), au lieu d'une carte sous le tableau. */
.barre-lot {
  position: sticky; bottom: 0; z-index: 4; display: flex; align-items: center; flex-wrap: wrap;
  gap: 8px 10px; padding: 8px 12px; margin: 0 -12px; background: var(--carte);
  border-top: 1px solid var(--ligne); font-size: var(--texte-s); color: var(--texte-2);
}
.barre-lot b { color: var(--texte); font-weight: 600; }
.barre-lot select { width: auto; max-width: 18rem; min-height: 32px; padding: 4px 8px; }
.barre-lot button { min-height: 32px; padding: 4px 14px; }
.barre-lot .ok:empty, .barre-lot .erreurs:empty { display: none; }
.barre-lot .erreurs { flex-basis: 100%; margin: 0; }
/* Sur téléphone, la barre d'onglets du bas tient déjà le pied de l'écran :
   la barre d'action reprend sa place dans le flux, après la liste. */
@media (max-width: 64rem) {
  .barre-lot { position: static; margin: 12px 0 0; border: 1px solid var(--ligne); border-radius: var(--rayon-carte); }
}

/* LE MAÎTRE-DÉTAIL D'AVANT (Affaires, Clients) DEVIENT CELUI DES ÉTUDES :
   un tableau dense à gauche, la fiche à droite sur toute la hauteur. Les
   sélecteurs portent `main` en tête : ils doivent l'emporter sur les règles
   qui faisaient des lignes des cartes, sans dépendre de l'ordre du fichier. */
@media (min-width: 64rem) {
  main:has(.maitre-detail) { max-width: none; padding: 0; margin: 0; }
  main .maitre-detail { grid-template-columns: minmax(0, 1fr) 420px; gap: 0; }
  main .maitre-detail > .carte { padding: 0 12px; border: 0; border-radius: 0; }
  main .maitre-detail thead { display: table-header-group; }
  main .maitre-detail .tableau-affaires { display: table; width: 100%; table-layout: fixed; }
  main .maitre-detail .tableau-affaires thead th { position: sticky; top: 0; z-index: 3; height: 38px; padding: 0 8px; white-space: normal; overflow-wrap: anywhere; line-height: 1.2; }
  main .maitre-detail .tableau-affaires thead th:first-child { width: 120px; padding-left: 12px; }
  main .maitre-detail .tableau-affaires thead th:nth-child(2) { width: 30%; }
  main .maitre-detail .tableau-affaires tbody { display: table-row-group; }
  main .maitre-detail .tableau-affaires tr,
  main .maitre-detail .tableau-affaires tr.selectionnee {
    display: table-row; position: relative; height: var(--ligne-tableau); padding: 0; margin: 0;
    border: 0; border-radius: 0; box-shadow: none; background: none; grid-template-columns: none;
  }
  main .maitre-detail .tableau-affaires td,
  main .maitre-detail .tableau-affaires td:first-child,
  main .maitre-detail .tableau-affaires td:nth-child(2),
  main .maitre-detail .tableau-affaires td:nth-child(n+3),
  main .maitre-detail .tableau-affaires td[data-libelle],
  main .maitre-detail .tableau-affaires tr:has(td[data-libelle="Statut"]) td[data-libelle="Activité"],
  main .maitre-detail .tableau-affaires tr:has(td[data-libelle="Nom"]) td[data-libelle] {
    display: table-cell; grid-area: auto; padding: 0 8px; height: var(--ligne-tableau); vertical-align: middle;
    border: 0; border-top: 1px solid var(--ligne-douce); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    text-align: left; font-size: var(--texte-m); font-weight: 400; color: var(--texte); max-width: none;
    -webkit-line-clamp: unset;
  }
  main .maitre-detail .tableau-affaires td:first-child { font-weight: 500; padding-left: 12px; }
  main .maitre-detail .tableau-affaires td.montant,
  main .maitre-detail .tableau-affaires td[data-libelle="Montant"],
  main .maitre-detail .tableau-affaires td[data-libelle="Honoraires"] { text-align: right; }
  main .maitre-detail .tableau-affaires td::before,
  main .maitre-detail .tableau-affaires tr:has(td[data-libelle="Nom"]) td[data-libelle]::before { content: none; display: none; }
  main .maitre-detail .tableau-affaires td.actions { display: none; }
  /* AFFAIRES : la ville et l'activité se lisent dans la fiche ; la liste
     garde le n° entier et les honoraires lisibles. */
  main .maitre-detail .tableau-affaires:has(td[data-libelle="Honoraires"]) thead th:first-child { width: 136px; }
  main .maitre-detail .tableau-affaires:has(td[data-libelle="Honoraires"]) thead th:nth-child(4),
  main .maitre-detail .tableau-affaires:has(td[data-libelle="Honoraires"]) thead th:nth-child(5),
  main .maitre-detail .tableau-affaires:has(td[data-libelle="Honoraires"]) td[data-libelle="Ville"],
  main .maitre-detail .tableau-affaires:has(td[data-libelle="Honoraires"]) td[data-libelle="Activité"] { display: none; }
  main .maitre-detail .tableau-affaires:has(td[data-libelle="Honoraires"]) thead th:nth-child(7) { width: 112px; }
  main .maitre-detail .tableau-affaires tbody tr:hover td { background: var(--survol); }
  main .maitre-detail .tableau-affaires tbody tr.selectionnee td { background: var(--selection); }
  main .maitre-detail .tableau-affaires tbody tr.selectionnee td:first-child { box-shadow: inset 2px 0 0 var(--accent); }
  main .maitre-detail .lien-fiche { border-radius: 0; }
  main .maitre-detail > .volet-etude, main .maitre-detail > aside {
    align-self: stretch; max-height: none; height: 100%; overflow-y: auto; border: 0; border-left: 1px solid var(--ligne);
    border-radius: 0; box-shadow: none; padding: 18px 22px 24px; background: var(--carte);
  }
}
.volet-ref, .volet-tete .volet-ref { font-size: var(--texte-s); font-weight: 500; color: var(--texte-2); }
.volet-intitule { font-size: var(--titre-3); font-weight: 600; color: var(--texte); }
.volet-montant { font-size: var(--titre-3); font-weight: 600; color: var(--texte); }
.volet-terme, .detail .detail-terme { font-size: var(--texte-xs); color: var(--texte-3); text-transform: none; letter-spacing: 0; font-weight: 400; }

/* ======== 10. CHARTE v3 — LE TÉLÉPHONE : la barre d'onglets en bas ======== */
.onglets-bas { display: none; }
@media (max-width: 800px) {
  .onglets-bas {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 120; height: 64px;
    padding-bottom: env(safe-area-inset-bottom); background: var(--carte); border-top: 1px solid var(--ligne);
    justify-content: space-around; align-items: stretch;
  }
  .onglet-bas, button.onglet-bas {
    flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    background: none; border: 0; border-radius: 0; margin: 0; padding: 0; box-shadow: none; min-height: 0;
    color: var(--texte-3); font-size: var(--texte-xs); text-decoration: none;
  }
  .onglet-bas .icone { width: 20px; height: 20px; }
  .onglet-bas.actif { color: var(--accent); font-weight: 600; }
  button.onglet-bas:hover:not(:disabled) { background: none; color: var(--texte); }
  .principal { padding-bottom: 64px; }
  /* La barre haute se replie au lieu de déborder sur l'outillage. */
  .barre-haute { height: auto; min-height: var(--charpente-haut); flex-wrap: wrap; padding: 6px 12px; }
  .panneau-creation, .espace-etudes.fiche-demandee .fiche-etude { z-index: 210; }
}

/* ---- C3 : AU DOIGT, UNE CIBLE FAIT 44 PX ---------------------------------
   Audit du 08/10 : au téléphone, les entrées du menu faisaient 39 px, les
   puces 26, les « mini » boutons 24 — sous le seuil où un pouce vise juste
   (WCAG 2.5.5, 44 × 44). La règle ne vaut QU'AU POINTEUR GROSSIER : à la
   souris, la densité d'une liste de 244 affaires reste ce qu'elle est.
   Elle est posée ici, une fois, en fin de feuille, pour que nulle règle
   d'écran ne la défasse par mégarde. */
@media (pointer: coarse) {
  button, summary, select, a.bouton, a.bouton-2, a.puce, a.menu-item, a.sortir, a.lien-aide,
  input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):not([type="range"]) {
    min-height: 44px;
  }
  /* Un lien-bouton en ligne ignore min-height : il devient une boîte. Une
     boîte flex ABSORBE l'espace entre deux enfants — « Sans ingénieur 1 »
     devenait « Sans ingénieur1 » au téléphone (vu le 08/10) : le `gap`
     rend l'espace que le texte portait. */
  a.puce, a.lien-aide, a.bouton, a.bouton-2 { display: inline-flex; align-items: center; gap: .35em; }
  /* Le chevron d'une fiche : la cible grandit, le dessin reste le même. */
  .fiche-plier { width: 44px; height: 44px; top: 0; right: 0; }
  /* LES LIENS DANS LE FLUX — « les rendre → », « ← Affaires », le nom
     d'un client dans sa fiche : leur ZONE DE FRAPPE grandit, pas leur
     place. Le rembourrage vertical est rendu par une marge négative, et
     rien ne bouge à l'écran. */
  a.aller, a.retour, .tableau-affaires td a:not(.lien-fiche) {
    display: inline-block; padding-block: 14px; margin-block: -14px;
  }
  /* La case reste une case ; c'est son <label> qui fait la cible. */
  input[type="checkbox"], input[type="radio"] { width: 1.25rem; height: 1.25rem; }
}


/* ======== L'ÉCRAN SUR PAPIER ========
 *
 * Les mêmes règles que les documents du cabinet (`generation/impression.ts`),
 * appliquées à une page de l'application. Trois défauts constatés en
 * imprimant réellement l'écran Affaires, pas déduits du code :
 *
 *  1. LA MOITIÉ DROITE DU TABLEAU MANQUAIT. La liste vit dans un cadre qui
 *     défile horizontalement (1 055 px de tableau dans 749 px de cadre) :
 *     à l'écran on fait glisser, sur le papier la colonne des honoraires
 *     est simplement absente. Un cadre qui défile n'a pas de sens sur une
 *     feuille — il redevient visible, et le tableau se replie sur la
 *     largeur de la page.
 *  2. LES CADRES DISPARAISSAIENT. L'ancienne règle retirait la bordure des
 *     cartes et des cadres de tableau « pour faire propre » ; elle enlevait
 *     justement ce qui donne sa forme au document. On ne retire que l'ombre,
 *     qui, elle, ne veut rien dire sur du papier.
 *  3. TOUT CE QUI COMMANDE S'IMPRIMAIT — recherche, puces de filtre, tri,
 *     boutons. La règle de la charpente dit : ce qui commande ne défile
 *     pas, ce qui est commandé défile. Sur le papier elle devient : CE QUI
 *     COMMANDE NE S'IMPRIME PAS. Reste la liste, et ce qui la qualifie.
 */
@media print {
  /* Les aplats portent du sens (bandes d'en-tête, pastilles d'état) : ils
     s'impriment, sans dépendre de la case « Graphiques d'arrière-plan ». */
  *, *::before, *::after { -webkit-print-color-adjust: exact; print-color-adjust: exact; }

  /* Ce qui commande. */
  .barre-laterale, .outillage, .actions, .onglets, .bouton, .chargement,
  .pas-impression, .bascule-menu, .barre-haute .pousse, .barre-haute a,
  .barre-haute button, form.filtres, .puces-tri, .tableau-affaires td.actions,
  input, select, textarea, button, summary, details.creer-etude { display: none !important; }

  /* SAUF L'AVERTISSEMENT : une feuille ne s'ouvre pas. Son titre ET son
     texte s'impriment en entier, à plat. `::details-content` lève le
     masquage du contenu replié ; là où ce sélecteur n'existe pas encore,
     le titre s'imprime seul — dégradé, jamais muet. */
  /* Il prend sa propre ligne dans la barre : sans base 100 %, la boîte
     flex se dimensionne sur son contenu et le texte file hors de la page. */
  .avertissement { display: block !important; }
  .avertissement > summary {
    display: inline-flex !important; border: 0; background: none;
    padding: 0; font-size: 9pt; }
  .avertissement > summary::after { display: none; }
  .avertissement::details-content { content-visibility: visible; }
  /* `!important` assumé : le bloc d'impression est déclaré AVANT les règles
     d'écran de l'avertissement, et un panneau flottant sur du papier se
     poserait par-dessus le tableau. */
  .avertissement .texte {
    position: static !important; display: block !important;
    width: auto !important; max-width: 100% !important;
    border: 0; box-shadow: none; background: none; padding: .2rem 0 0; font-size: 9pt; }

  body { background: #fff; font-size: 11pt; }
  .contenu { margin: 0; padding: 0; max-width: none; }
  /* La charpente n'a plus lieu d'être : rien ne défile sur une feuille. */
  .app, .principal, .principal > main, main:has(.maitre-detail) {
    display: block; height: auto; max-height: none; overflow: visible; max-width: none;
  }
  /* La barre d'écran perd sa hauteur fixe : sur du papier elle porte le
     titre ET l'avertissement déplié, et rien ne doit déborder dessous. */
  /* La barre redevient un simple bloc : titre, compteur et avertissement
     s'y empilent au lieu de se disputer une rangée flex de hauteur fixe. */
  .barre-haute { position: static; display: block; height: auto; padding: 0 0 6pt; }
  .tableau-affaires thead th { position: static; }
  /* Le triangle de tri est un bouton déguisé : il ne s'imprime pas, le nom
     de la colonne reste. */
  .triangle { display: none; }
  /* LA PASTILLE REPLIÉE S'ÉCRIT EN TOUTES LETTRES. Dans une liste, l'état
     se réduit à son point de couleur et son libellé revient au survol —
     un geste que le papier n'a pas. Imprimée telle quelle, la pastille
     n'était plus qu'un point sans légende. */
  .tableau-affaires .badge-etude {
    max-width: none; font-size: 8pt; gap: 4px; padding: .5pt 3pt; overflow: visible;
  }
  .carte, .fiche-tete, .tableau-cadre, fieldset {
    box-shadow: none; max-height: none; overflow: visible; margin-bottom: 12pt;
  }
  /* Le tableau se replie sur la page : plus rien ne dépasse à droite. Le
     texte revient à la ligne au lieu d'être coupé — CE QUI COÛTE DU PAPIER
     (l'annuaire des clients passe de 9 à 18 pages) et le vaut : une valeur
     tronquée par des points de suspension ne se retrouve pas sur une
     feuille, alors qu'à l'écran il suffit d'élargir. Le rembourrage se
     resserre pour en rendre une partie. */
  .tableau-affaires { font-size: 9pt; width: 100%; }
  .tableau-affaires td, .tableau-affaires th {
    white-space: normal; max-width: none; padding: 2.5pt 3pt;
  }
  /* La colonne d'actions n'a plus ni cellules ni raison d'avoir un titre. */
  .tableau-affaires th:empty { display: none; }
  /* Une ligne ne se coupe pas en deux pages, un en-tête se répète. */
  thead { display: table-header-group; break-after: avoid; }
  tr { break-inside: avoid; }
  a { color: var(--texte); text-decoration: none; }
  .rapport-a4 h1 { font-size: 16pt; }
  .rapport-a4 h2 { font-size: 13pt; break-after: avoid; }
  .rapport-a4 table, .rapport-a4 tr { break-inside: avoid; }
}

