/* OTICAD — feuille de style unique de l'editeur.

   Palette de la maquette V2 : le TEAL est la couleur de marque et celle
   des actions principales ; le bleu reste la couleur du DESSIN (symboles,
   cadres de selection), parce que c'est celle qu'on lit sur un plan. Les
   deux ne se disputent donc jamais le meme role. */

:root{
    --teal:#0f766e; --tealClair:#e6f4f2;
    --bleu:#1E5AA8; --bleuClair:#eef4fc;
    --rouge:#C0392B; --encre:#1c2530; --gris:#5b6875;
    --trait:#d5dbe2; --fond:#f4f6f8; --papier:#fff; --accent:#0f7b6c;
    --guide:#e2711d;
    /* Lot M2 — la palette de la marque, pour les pages HORS editeur.
       Neuf couleurs fournies, plus cinq derivees. Une derivee est une
       OMBRE ou une TEINTE d'une des neuf : meme teinte, meme saturation,
       autre luminosite. Aucune couleur etrangere.
       Mesure : la plus foncee des neuf, #046C6C, plafonne a 6,2:1 sur
       blanc. C'est insuffisant pour du texte courant — d'ou --encreForte,
       qui est le #347478 ramene a 17,5 % de luminosite : 11,9:1. */
    --encreForte:#1b3c3e;   /* ombre de #347478 — titres, 11,9:1 */
    --texte:#347478;        /* palette —  5,4:1 */
    --grisBleu:#4c748c;     /* palette —  5,0:1 */
    --action:#046c6c;       /* palette — boutons et liens, 6,2:1 */
    --actionDoux:#ecf5f5;   /* teinte de #046C6C */
    --vif:#049c9c;          /* palette — filets, JAMAIS du texte (3,4:1) */
    --signal:#94c31c;       /* palette — un seul emploi, JAMAIS du texte */
    --fondDoux:#f5f8f8;     /* teinte de #347478 */
    --traitDoux:#e6eced;    /* teinte de #347478 — le contraste faible */
    --traitAccent:#bddbdb;  /* teinte de #046C6C */
    --bande1:#253844;       /* ombre de #4C748C */
    --bande2:#183537;       /* ombre de #347478 */
    --surBande:#7dd4d4;     /* teinte de #049C9C — 7,6:1 sur --bande2 */
    --surBandeDoux:#b7cbd7; /* teinte de #4C748C — 7,3:1 sur --bande1 */
    --barreH:41px;      /* hauteur de la barre de menus */
    --regle:22px;       /* epaisseur des regles graduees */
    --barre:13px;       /* epaisseur des barres de defilement */
    --fondBarre:#f2f5f8;  /* piste des barres de defilement */
  }
  *{box-sizing:border-box}
  /* `hidden` veut dire CACHÉ, partout et sans discussion.
     Le piège s'est produit quatre fois dans ce fichier : une règle
     `display:flex` ou `display:grid` posée plus loin l'emporte sur
     l'attribut, et l'élément marqué caché reste à l'écran — le groupe Trait
     du ruban, le bloc d'identité du compte, une ligne du formulaire. Chaque
     fois on ajoutait une règle de plus. Celle-ci les rend toutes inutiles.
     `!important` est ici à sa place : il n'existe aucun cas où un élément
     porte `hidden` et doit rester visible. */
  [hidden]{display:none !important}

  html,body{margin:0;height:100%;font:14px/1.45 system-ui,-apple-system,"Segoe UI",sans-serif;
            color:var(--encre);overflow:hidden}
  body{display:flex;flex-direction:column;background:var(--fond)}

  /* Une seule bande de tête depuis le lot 46 : menus, onglets de plans,
     commandes du plan, compte. `nowrap` est délibéré — la bande doit garder
     sa hauteur quoi qu'elle porte ; ce sont les onglets qui se rétrécissent
     et défilent, parce qu'ils sont la seule partie dont le nombre varie. */
  #barreMenus{display:flex;align-items:center;gap:10px;padding:0 10px;
         height:var(--barreH);flex-wrap:nowrap;min-width:0;
         background:var(--papier);border-bottom:1px solid var(--trait);flex:none}
  #retourPlan{border:0;background:none;padding:4px 6px;border-radius:7px}
  #retourPlan:hover{background:#eef2f6}
  #barreMenus h1{font-size:15px;margin:0;font-weight:700;letter-spacing:-.2px;color:var(--encre)}
  #barreMenus h1 span{color:var(--teal)}
  .sep{width:1px;height:22px;background:var(--trait)}
  .mini{font-size:12px;color:var(--gris)}
  select,input,button{font:inherit;color:inherit}
  select,input[type=text],input[type=number]{padding:5px 8px;border:1px solid var(--trait);
        border-radius:6px;background:var(--papier)}
  button{padding:6px 10px;border:1px solid var(--trait);border-radius:6px;background:var(--papier);
         cursor:pointer}
  button:hover:not(:disabled){background:#eef2f6}
  button:disabled{opacity:.4;cursor:default}
  button.primaire{background:var(--teal);border-color:var(--teal);color:#fff}
  button.primaire:hover{filter:brightness(1.08)}
  button.danger{color:var(--rouge);border-color:#f0c8c3}
  button.actif{background:var(--tealClair);border-color:var(--teal);color:var(--teal)}

  main{flex:1;display:flex;min-height:0}
  aside{width:234px;background:var(--papier);border-right:1px solid var(--trait);
        padding:11px;overflow:auto;flex:none}
  aside h2{font-size:11px;text-transform:uppercase;letter-spacing:.7px;color:var(--gris);margin:0 0 8px}
  .palette{display:flex;flex-direction:column;gap:6px}
  /* Cent-vingt-sept symboles ne se parcourent pas a l'oeil : ils se
     cherchent, et se rangent par famille. */
  .recherche{width:100%;box-sizing:border-box;margin-bottom:8px;padding:5px 8px;
             border:1px solid var(--trait);border-radius:7px;font-size:12.5px}
  .recherche:focus{outline:none;border-color:var(--bleu)}
  .famille{display:flex;align-items:center;gap:6px;width:100%;margin:6px 0 1px;
           padding:2px 0;border:0;background:none;cursor:pointer;text-align:left;
           font:600 10.5px system-ui;text-transform:uppercase;letter-spacing:.6px;
           color:var(--gris)}
  .famille:first-child{margin-top:0}
  /* `display:flex` l'emporte sur l'attribut `hidden` du HTML — meme piege
     que `main[hidden]` au lot 8. Sans cette regle, « Favoris » et
     « Récents » restent affichés alors qu'ils n'ont rien à montrer. */
  .famille[hidden]{display:none}
  .famille .compte{margin-left:auto;font-weight:400;opacity:.75}
  .famille .fleche{display:inline-block;width:8px;transition:transform .12s}
  .famille.replie .fleche{transform:rotate(-90deg)}
  .vide{font-size:12px;color:var(--gris);margin:6px 2px}
  /* Vignettes COMPACTES : a 127 symboles, une fiche de trois lignes par
     entree transformait la colonne en interminable rouleau. Le libelle tient
     sur une ligne et se coupe proprement — le nom complet reste dans
     l'infobulle, et l'identifiant est juste dessous. */
  /* La palette en MATRICE, comme une planche de symboles normalisee.
     Une ligne par symbole coutait toute la largeur de la colonne : huit
     clapets occupaient l'ecran. `auto-fill` remplit la largeur disponible,
     donc la palette suit la fenetre au lieu d'imposer un nombre de
     colonnes. */
  .grilleSymboles{display:grid;gap:4px;
                  grid-template-columns:repeat(auto-fill,minmax(46px,1fr))}
  .sym{position:relative;display:flex;align-items:center;justify-content:center;
       aspect-ratio:1;padding:4px;border:1px solid var(--trait);
       border-radius:7px;cursor:pointer;background:var(--papier)}
  .sym:hover{border-color:var(--bleu)}
  .sym.actif{border-color:var(--bleu);background:#eef4fc;box-shadow:inset 0 0 0 1px var(--bleu)}
  .sym svg{width:100%;height:100%;display:block}

  #zone{flex:1;position:relative;min-width:0}
  #plan{width:100%;height:100%;display:block;background:var(--papier);outline:none}
  #plan.placement{cursor:crosshair}

  .equip{cursor:move}
  /* La couleur vient du calque ; la selection la recouvre. */
  /* Lot M4. Le repli n'est plus le bleu mais l'encre du plan. Mesure sur un
     plan de 220 equipements : 218 n'ont AUCUNE couleur de calque et tombaient
     donc sur ce repli. Le PDF, lui, dessinait deja ces memes equipements en
     noir (`NOIR` dans `cad/pdf.py`) — l'ecran et le papier se contredisaient,
     et c'est l'ecran qui avait tort. Un calque qui PORTE une couleur la garde,
     evidemment : c'est un choix, pas un defaut. */
  .equip .forme{fill:none;stroke:var(--couleur-calque,var(--encrePlan));stroke-width:2.4;
                vector-effect:non-scaling-stroke;stroke-linejoin:round;stroke-linecap:round}
  .equip.selection .forme{stroke:var(--accent);stroke-width:3.4}
  .equip.verrouille{cursor:not-allowed}
  .equip.verrouille .forme{stroke-dasharray:7 3;opacity:.75}
  .equip .halo{fill:transparent;stroke:none;pointer-events:all}
  .port{fill:#fff;stroke:var(--gris);stroke-width:1.5;vector-effect:non-scaling-stroke;cursor:pointer}
  /* Toutes les accroches se valent : plus de code couleur entree/sortie,
     qui laissait croire a une regle qui n'existe plus. */
  .port.arme{fill:var(--rouge);stroke:var(--rouge)}
  .port:hover{fill:var(--accent);stroke:var(--accent)}
  /* Cible de clic large et invisible : viser le cercle de 5 mm au pixel pres
     etait la principale source d'agacement au tracage des liaisons. */
  .port-zone{fill:transparent;stroke:none;pointer-events:all;cursor:crosshair}
  .port.cible{fill:var(--accent);stroke:var(--accent);r:7}
  .cadre.zoom{fill:rgba(30,90,168,.08);stroke:var(--bleu);stroke-dasharray:6 3}
  /* L'epaisseur et la couleur viennent du fluide, posees en attributs par
     le rendu : la feuille ne fixe plus que le comportement commun. */
  .liaison{fill:none;stroke-linejoin:round;stroke-linecap:round;
           pointer-events:none}
  /* Un LIEN d'instrumentation. Meme trait que les tuyauteries, mais ce n'en
     est pas une : ni tag, ni DN, ni numero de ligne. */
  .lien{fill:none;stroke-linejoin:round;stroke-linecap:round;
        pointer-events:none}
  .priseLien{fill:none;stroke:transparent;stroke-width:14;
             pointer-events:stroke;cursor:pointer}
  .marqueur{pointer-events:none}
  /* Le cartouche du tag KKS d'une conduite. Trait fin et non mis a
     l'echelle : c'est un repere de dessin, pas une conduite. */
  .cartoucheLigne{fill:none;stroke:var(--gris);stroke-width:1.2;
                  vector-effect:non-scaling-stroke;pointer-events:none}
  .tagGroupe.selection .cartoucheLigne{stroke:var(--accent);stroke-width:2}
  /* Le texte du cartouche est en MILLIMETRES, pas en pixels d'ecran : il
     doit grandir avec sa boite au zoom, sinon il en deborde. D'ou une
     classe distincte de `.tag`, qui elle fige une taille d'ecran. */
  .tagCartouche{text-anchor:middle;font-family:system-ui;font-weight:600;
                fill:var(--gris);user-select:none;pointer-events:none}
  /* La taille des tags est une VARIABLE, reglee sur `body` par le profil.
     Demande d'Ermin : « les etiquettes de tag sont encombrantes, meme dans
     les dessins faits a la main ». Trois crans plutot qu'une taille libre :
     ils se nomment, se retiennent et se discutent. `normal` reproduit
     exactement ce qui existait — 11 px pour un tag, 12 pour un tag de ligne.
     Les deux tailles gardent leur ecart : un tag de ligne s'ecrit par-dessus
     le tuyau et a besoin d'un peu plus de corps. */
  body{--tagPx:11px;--tagLignePx:12px}
  body.tagsReduits{--tagPx:9px;--tagLignePx:10px}
  body.tagsMinuscules{--tagPx:7px;--tagLignePx:8px}
  .tag{font:600 var(--tagPx) system-ui;fill:var(--gris);text-anchor:middle;user-select:none;pointer-events:none}
  /* Le tag de ligne s'ecrit PAR-DESSUS le tuyau : un lisere de la couleur
     du papier le detache sans masquer le motif. Regle posee apres `.tag`,
     sinon la taille de police de celle-ci l'emporterait. */
  .tagLigne{font-size:var(--tagLignePx);fill:var(--encre);paint-order:stroke;
               stroke:var(--papier);stroke-width:4px;stroke-linejoin:round}
  /* Le tag appartient a l'equipement : il se prend a la souris, mais dans
     un rayon limite, et un trait le rattache des qu'il s'ecarte. */
  .priseTag{fill:transparent;cursor:move}
  .tagGroupe:hover .priseTag{fill:#eef4fc;stroke:var(--bleu);stroke-width:1;
                                   vector-effect:non-scaling-stroke;rx:3}
  .tagGroupe.selection .tag{fill:var(--bleu)}
  .tagGroupe.verrouille .priseTag{cursor:not-allowed}
  .lienTag{stroke:var(--gris);stroke-width:1;stroke-dasharray:3 3;opacity:.55;
              vector-effect:non-scaling-stroke;pointer-events:none}
  /* Poignees d'angle : redimensionnement homothetique. */
  .cadreRedim{fill:none;stroke:var(--bleu);stroke-width:1;stroke-dasharray:4 3;
              opacity:.5;vector-effect:non-scaling-stroke;pointer-events:none}
  .poignee{fill:#fff;stroke:var(--bleu);stroke-width:1.5;
           vector-effect:non-scaling-stroke;cursor:nwse-resize}
  .poignee:hover{fill:var(--bleu)}
  .cadre{fill:rgba(15,123,108,.08);stroke:var(--accent);stroke-width:1;
         vector-effect:non-scaling-stroke;stroke-dasharray:4 3;pointer-events:none}
  .guide{stroke:var(--guide);stroke-width:1;vector-effect:non-scaling-stroke;
         stroke-dasharray:6 4;pointer-events:none}

  #aligner{position:absolute;left:50%;transform:translateX(-50%);top:12px;
        display:none;gap:3px;background:var(--papier);border:1px solid var(--trait);
        border-radius:9px;padding:4px;box-shadow:0 6px 20px rgba(20,30,45,.09)}
  #aligner.ouvert{display:flex}
  #aligner button{padding:5px 8px;font-size:12px;line-height:1}
  #aligner .groupe{width:1px;background:var(--trait);margin:2px 3px}

  .calques{display:flex;flex-direction:column;gap:2px;margin-top:6px}
  .calque{display:flex;align-items:center;gap:7px;padding:4px 5px;border-radius:6px;
          font-size:12.5px;cursor:pointer}
  .calque:hover{background:#eef2f6}
  .calque .pastille{width:11px;height:11px;border-radius:3px;flex:none;
                    border:1px solid rgba(0,0,0,.15)}
  .calque.masque{opacity:.45}
  .calque .oeil{margin-left:auto;font-size:12px;color:var(--gris)}
  .calque input[type=color]{width:18px;height:18px;padding:0;border:none;background:none;
                            cursor:pointer}

  .annot{fill:none;stroke:var(--couleur-calque,var(--gris));stroke-width:2;
         vector-effect:non-scaling-stroke;cursor:pointer}
  .annot:hover{stroke:var(--bleu)}
  /* Selection : meme vert accent que pour les equipements, pour qu'il n'y ait
     qu'un seul code visuel a apprendre. */
  .annot.selection{stroke:var(--accent);stroke-width:3}
  /* Contour epais et invisible : on vise le trait, pas le pixel. */
  .priseAnnot{fill:none;stroke:transparent;stroke-width:14;
              pointer-events:stroke;cursor:move}
  .priseLiaison{fill:none;stroke:transparent;stroke-width:16;
                pointer-events:stroke;cursor:pointer}
  /* Liaison de longueur nulle : un losange rouge, la ou il n'y a rien a
     tracer. Il est plein, donc cliquable, contrairement au tuyau qu'il
     remplace. */
  .liaisonNulle{fill:#fdecea;stroke:var(--rouge);stroke-width:1.6;
                vector-effect:non-scaling-stroke;pointer-events:none}
  .liaisonNulle.selection{fill:#fbd5d0;stroke-width:2.6}
  .priseNulle{fill:transparent;pointer-events:all;cursor:pointer}
  .alerte{margin:0 0 8px;padding:6px 8px;border-radius:6px;font-size:11.5px;
          line-height:1.35;background:#fdecea;border:1px solid #f3bdb6;
          color:#8c2f22}
  /* Bandeau des calques masques : flottant au-dessus du plan, toujours
     visible, jamais dans le chemin du dessin. */
  #bandeauMasques{position:absolute;top:8px;left:50%;transform:translateX(-50%);
                  z-index:6;display:flex;align-items:center;gap:10px;
                  padding:5px 8px 5px 11px;border-radius:8px;font-size:12px;
                  background:#fff6e5;border:1px solid #e8c88a;color:#7a5312;
                  box-shadow:0 3px 12px rgba(20,30,45,.12)}
  #bandeauMasques[hidden]{display:none}
  .compte.alerte-compte{color:#b0632b;font-weight:600}
  /* Fenêtre à deux colonnes : formulaire large, aperçu à droite. */
  .grilleNum{display:grid;grid-template-columns:1fr 1fr;gap:5px 8px;margin-bottom:2px}
  .grilleNum label{display:flex;flex-direction:column;gap:2px;font-size:11px;
                   color:var(--gris)}
  .grilleNum input{width:100%;box-sizing:border-box}
  .case{display:flex;align-items:center;gap:6px;font-size:12px;margin:4px 0}
  #apercuFeuille{width:100%;height:100%;min-height:240px;max-height:520px;
                 background:var(--papier);border:1px solid var(--trait);
                 border-radius:8px}
  /* Cadre et cartouche. Pas de `vector-effect` : leurs épaisseurs sont des
     cotes normalisées, en millimètres, et doivent suivre le zoom comme le
     reste du dessin. */
  /* `pointer-events:none` sur les TRAITS aussi, pas seulement sur les
     textes : un cadre couvre tout le plan, et sans cette regle il
     interceptait les clics — poser une annotation ou selectionner un
     symbole devenait impossible des que la feuille etait affichee. */
  .traitFeuille{stroke:var(--couleur-cartouche,#1c2530);fill:none;
                stroke-linecap:square;pointer-events:none}
  .texteFeuille{fill:var(--couleur-cartouche,#1c2530);font-family:system-ui;
                user-select:none;pointer-events:none}
  .texteFeuille.gras{font-weight:700}
  /* Zone de PRISE du cadre (lot 26). Une bande le long du cadre, et rien
     d'autre : le reste de la feuille reste traversant, sinon le cadre de
     sélection à la souris ne fonctionnerait plus au milieu du plan.
     `non-scaling-stroke` : la bande fait toujours la même largeur À
     L'ÉCRAN, quel que soit le zoom — une bande en millimètres deviendrait
     inattrapable dès qu'on dézoome. */
  .priseFeuille{fill:transparent;stroke:none;cursor:move}
  .priseFeuille:hover{fill:var(--accent);fill-opacity:.10}
  .priseFeuille.selection{fill:var(--accent);fill-opacity:.22}
  /* Le cartouche s'attrape par sa surface : c'est la seule partie de la
     feuille qui n'est pas un trait fin. Il est dessiné SOUS le plan, donc
     un symbole posé dessus reste cliquable — c'est la même règle que pour
     le fond d'un tableau. */
  .priseCartouche{fill:transparent;cursor:move}
  .annot-texte.selection{fill:var(--accent)}
  /* Pas de font-size ici : une regle CSS l'emporte sur l'attribut de
     presentation, et le texte se retrouvait dessine en 1 px. La taille est
     posee en style inline, qui gagne sur la feuille. */
  /* Le texte ECRIT DANS un rectangle ou un cercle. Ancre par son SOMMET et
     centre horizontalement : la meme convention que le DXF (`VAlignTop`,
     `HAlignCenter`) et que le PDF, sans quoi les trois sorties ne
     poseraient pas le texte au meme endroit. Pas de `font-size` ici : une
     regle CSS l'emporterait sur l'attribut, la taille est posee en style
     inline. */
  .texteForme{fill:var(--couleur-calque,var(--gris));font-weight:600;
              font-family:system-ui,sans-serif;text-anchor:middle;
              dominant-baseline:text-before-edge;
              user-select:none;pointer-events:none}
  body.sombre .texteForme{fill:var(--couleur-calque,#9fb0c2)}
  .annot-texte{fill:var(--couleur-calque,var(--gris));font-weight:600;
               font-family:system-ui,sans-serif;user-select:none;cursor:pointer}
  .apercu{fill:none;stroke:var(--accent);stroke-width:2;stroke-dasharray:6 3;
          vector-effect:non-scaling-stroke;pointer-events:none}
  .mesure{stroke:var(--guide);stroke-width:2;vector-effect:non-scaling-stroke;
          pointer-events:none}
  .mesure-point{fill:var(--guide);pointer-events:none}

  /* Les trois inspecteurs ne flottent plus au-dessus du dessin : ils sont
     les trois contenus possibles du panneau Proprietes, ancre a droite.
     Ils gardent leur identifiant et leur classe « ouvert » — c'est ce qui
     rend le changement invisible pour inspector.js. */
  #inspecteur,#inspAnnot,#inspLiaison,#inspLien{display:none}
  #inspecteur.ouvert,#inspAnnot.ouvert,#inspLiaison.ouvert,
  #inspLien.ouvert{display:block}
  /* Les trois aperçus de motif : conduite tracée, tronçon posé,
     raccordement. Même cadre, parce que c'est la même chose qu'on montre. */
  #apercuFluide,#apercuFluideTroncon,#apercuLien{
                width:100%;height:34px;margin:2px 0 6px;background:var(--papier);
                border:1px solid var(--trait);border-radius:6px}
  #inspAnnot h3,#inspLiaison h3,#inspLien h3{margin:0 0 8px;font-size:12px;text-transform:uppercase;
        letter-spacing:.6px;color:var(--gris)}
  #inspecteur h3{margin:0 0 8px;font-size:12px;text-transform:uppercase;letter-spacing:.6px;color:var(--gris)}
  .ligne{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}
  .ligne label{font-size:12px;color:var(--gris)}
  .ligne input{width:100px}

  #barre{flex:none;display:flex;align-items:center;gap:10px;
         padding:4px 12px;background:var(--papier);border-top:1px solid var(--trait);
         font-size:12px;color:var(--gris)}
  #barre .pousse{margin-left:auto}
  .sepEtat{width:1px;height:13px;background:var(--trait);flex:none}
  /* Les indicateurs de la SURFACE DE DESSIN. `contents` pour qu'ils restent
     des elements de la barre — l'espacement ne bouge pas. */
  #etatDessin{display:contents}
  /* Hors de l'editeur, il n'y a pas de dessin : ils annonceraient l'etat
     d'une chose qu'on ne regarde pas. Meme regle que le ruban juste
     au-dessus, qui parle lui aussi du plan ouvert — elle existait, elle
     n'avait pas ete etendue jusqu'ici. */
  body.horsEditeur #etatDessin{display:none}
  /* Les reglages d'ECRAN, venus du ruban au lot I13. Plus petits que des
     boutons de ruban — ils vivent dans une barre de 12 px — et sans fond
     tant qu'ils sont au repos : la barre d'etat s'annonce, elle ne crie
     pas. Un reglage ACTIF se colore, comme dans le ruban. */
  #reglagesEcran{display:flex;align-items:center;gap:4px}
  body.horsEditeur #reglagesEcran{display:none}
  .regleEcran{display:flex;align-items:center;gap:4px;padding:2px 7px;
              font-size:12px;line-height:1.4;color:var(--gris);
              background:none;border:1px solid transparent;border-radius:5px}
  .regleEcran:hover:not(:disabled){background:#eef2f6;color:inherit}
  .regleEcran.actif{background:var(--tealClair);border-color:var(--teal);
                    color:var(--teal)}
  .regleEcran .ico{font-size:13px;line-height:1}
  body.sombre .regleEcran:hover:not(:disabled){background:#243040}

  #etat.erreur{color:var(--rouge);font-weight:600}
  #etat.ok{color:var(--accent)}
  /* Lot F2 : une consigne qui reste affichee sans etre une erreur —
     l'organisation vide qui n'a pas encore d'affaire. */
  #etat.invite{color:var(--teal);font-weight:600}

  #aide{position:absolute;left:12px;bottom:12px;background:rgba(255,255,255,.96);
        border:1px solid var(--trait);border-radius:8px;font-size:12px;color:var(--gris);
        max-width:400px;overflow:hidden}
  /* Le panneau n'est plus POSÉ sur le dessin en permanence : sa poignée
     occupait le coin bas gauche, exactement là où l'on cadre une pompe.
     Il s'ouvre depuis la barre d'état — « ? Raccourcis clavier » — et
     depuis le menu Aide, qui étaient déjà là tous les deux. */
  #aide:not([open]){border:0;background:none;pointer-events:none}
  #aide summary{cursor:pointer;padding:7px 11px;font-weight:600;color:var(--encre);list-style:none}
  #aide:not([open]) > summary{display:none}
  #aide summary::-webkit-details-marker{display:none}
  #aide summary::before{content:"？ ";color:var(--bleu)}
  #aide .corps{padding:0 11px 10px;display:grid;grid-template-columns:max-content 1fr;
               gap:4px 12px;align-items:baseline}
  #aide .corps > :nth-child(odd){justify-self:start;white-space:nowrap}
  #aide kbd{background:#eef2f6;border:1px solid var(--trait);border-bottom-width:2px;
            border-radius:4px;padding:0 5px;font:600 11px system-ui;color:var(--encre);white-space:nowrap}

  /* ---------- Bibliotheque de symboles ---------- */
  .voile{position:fixed;inset:0;background:rgba(20,30,45,.42);display:none;
         align-items:center;justify-content:center;z-index:50}
  .voile.ouvert{display:flex}
  .fenetre{background:var(--papier);border-radius:12px;width:min(1340px,96vw);
           height:min(760px,92vh);display:flex;flex-direction:column;
           box-shadow:0 18px 50px rgba(20,30,45,.28);overflow:hidden}
  .fenetre .entete{display:flex;align-items:center;gap:12px;padding:12px 16px;
                   border-bottom:1px solid var(--trait)}
  .fenetre .entete h2{margin:0;font-size:15px}
  /* L'apercu est PLAFONNE et ce sont les champs qui s'etalent. Avant, il
     prenait tout l'espace disponible : un symbole de 30 mm flottait au
     milieu d'un panneau de mille pixels pendant que le formulaire etait
     serre a droite. */
  .fenetre .corps,#biblio .corps,#fluides .corps{flex:1;display:grid;
                  grid-template-columns:238px minmax(220px,400px) minmax(400px,1fr);
                  min-height:0}
  /* Fenêtre à DEUX colonnes (le cartouche) : formulaire large à gauche,
     aperçu à droite. Posée APRÈS la règle à trois colonnes, sinon celle-ci
     l'emporte à spécificité égale et la fenêtre garde une colonne vide. */
  .fenetre .corps2{grid-template-columns:minmax(440px,1fr) minmax(340px,620px)}
  .colonneListe{border-right:1px solid var(--trait);padding:10px;overflow:auto;
                display:flex;flex-direction:column}
  .colonneListe > div:first-of-type{flex:1;min-height:0;overflow:auto}
  /* Les cinq actions sont en PIED : c'est la liste qui défile, le pied ne
     bouge pas. Sans `hidden` ici, la colonne entière défilerait et le pied
     descendrait hors de vue avec elle. */
  #biblio .colonneListe{overflow:hidden}
  /* Le pied est COMPACT, et c'est là qu'est le gain : les cinq boutons
     pleine hauteur plus leur note prenaient 272 px des 750 de la colonne.
     Les libellés ne sont PAS raccourcis — la FAQ les cite mot pour mot,
     « Importer un DXF… » et « Ranger les importés… », et une aide qui
     nomme un bouton qui n'existe plus est pire qu'une aide absente. */
  #actionsBiblio{flex:none;display:flex;flex-direction:column;gap:3px;
                 margin-top:8px;padding-top:8px;
                 border-top:1px solid var(--trait)}
  #actionsBiblio button{width:100%;padding:5px 9px;font-size:12.5px}
  #actionsBiblio .mini{margin:3px 2px 0;font-size:11px;line-height:1.3}
  .colonneApercu{display:flex;flex-direction:column;justify-content:center;
                 padding:12px;border-right:1px solid var(--trait);min-width:0}
  .colonneChamps{padding:10px 14px;overflow:auto}
  /* Un bloc RESERVE (lot G6) : rendu inerte par `appliquerDroits`, et il
     doit se VOIR — un ecran qui ne repond pas sans avoir l'air different se
     lit comme une panne. Le mot « lecture seule » reste hors du bloc, donc
     lisible et annonce. */
  [data-reserve].reserve{opacity:.55}
  .lectureSeule{color:var(--gris);margin:0 0 8px;font-style:italic}
  .colonneChamps h3{font-size:11px;text-transform:uppercase;letter-spacing:.7px;
                    color:var(--gris);margin:11px 0 5px}
  /* L'inspecteur du plan impose des champs de 100 px, largement suffisants
     pour une coordonnee. Ici on saisit des identifiants et des libelles :
     a 100 px, « Pompe centrifuge » s'affichait « Pompe cent ». */
  .colonneChamps .ligne label{width:96px;flex:0 0 auto}
  .colonneChamps .ligne input{flex:1;width:auto;min-width:0}

  /* Intervenants : une case par entreprise, le logo au centre. La vignette
     garde les proportions du cartouche (large et basse) pour qu'on voie
     tout de suite ce que donnera l'impression. */
  #listeIntervenants{display:grid;grid-template-columns:1fr 1fr;gap:10px}
  .intervenant{border:1px solid var(--trait);border-radius:8px;padding:8px;
               display:flex;flex-direction:column;gap:6px}
  .intervenant > label{font-size:11px;text-transform:uppercase;
                       letter-spacing:.6px;color:var(--gris)}
  .vignetteLogo{height:56px;display:flex;align-items:center;
                justify-content:center;background:var(--papier);
                border:1px dashed var(--trait);border-radius:6px;
                font-size:11px;color:var(--gris);overflow:hidden}
  .vignetteLogo img{max-width:100%;max-height:100%;object-fit:contain}
  /* Tableaux posés sur le plan. Le fond est OPAQUE : un tracé qui passerait
     dessous traverserait les cases et rendrait la datasheet illisible.
     C'est aussi lui qui donne une surface à attraper — sans fond, un tableau
     ne se prendrait que par ses traits, larges de deux pixels. */
  .fondTableau{fill:var(--papier);stroke:none}
  .traitTableau{stroke:var(--couleur-calque,var(--encre));fill:none;
                stroke-linecap:square}
  .texteTableau{font:400 1px system-ui;fill:var(--encre);user-select:none}
  .texteTableau.gras{font-weight:700}
  .tableauPlan{cursor:move}
  .tableauPlan.selection .fondTableau{stroke:var(--accent);stroke-width:2;
                                      vector-effect:non-scaling-stroke}
  /* La grille d'édition : des colonnes étroites pour les largeurs, larges
     pour le texte. */
  #grilleTableau input{width:100%;box-sizing:border-box}
  #grilleTableau input.court{width:64px}
  #grilleTableau .ligneLargeurs td{padding-bottom:6px}
  #grilleTableau .ligneLargeurs input{color:var(--gris);font-size:11px}

  .actionsLogo{display:flex;gap:6px}
  /* Invisible mais present : c'est le bouton au-dessus qui le declenche. */
  .fichierLogo{position:absolute;width:1px;height:1px;opacity:0;
               pointer-events:none}
  .actionsLogo button{flex:1}
  .nomIntervenant{width:100%;box-sizing:border-box}
  /* Le logo pose sur le plan ne se prend pas a la souris, comme le reste du
     cadre : cliquer dessus doit selectionner ce qu'il y a en dessous. */
  .logoFeuille{pointer-events:none}

  .symLigne{display:flex;align-items:center;gap:8px;padding:3px 7px;border-radius:6px;
            cursor:pointer;font-size:12px}
  .symLigne:hover{background:#eef2f6}
  .symLigne.actif{background:#eef4fc;box-shadow:inset 0 0 0 1px var(--bleu)}
  .symLigne > span{min-width:0;flex:1}
  .symLigne b{display:block;font-weight:600;line-height:1.2;
              white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .symLigne small{display:block;color:var(--gris);font-size:10px;line-height:1.15}
  /* Lot 51 : ce qui s'ecarte du catalogue livre se voit dans la liste.
     Deux marques et non une : « modifie chez vous » est un etat normal,
     « une version corrigee a ete livree depuis » est une invitation. */
  .marqueSurcharge{color:var(--bleu);font-size:14px;line-height:1;flex:none}
  .marqueOrigine{color:#c47f00;font-size:13px;line-height:1;flex:none}
  /* Lot E : les membres de l'organisation, et le code d'entree. */
  .tableauMembres{width:100%;border-collapse:collapse;margin:6px 0 10px;
                  font-size:12px}
  .tableauMembres th{text-align:left;font-weight:600;color:var(--gris);
                     padding:3px 6px;border-bottom:1px solid #e2e8f0}
  .tableauMembres td{padding:4px 6px;border-bottom:1px solid #f1f5f9;
                     vertical-align:middle}
  .tableauMembres select{font-size:12px;padding:1px 4px}
  /* Le code se LIT et se recopie : chasse fixe, et assez gros pour etre
     dicte sans confondre un l et un 1. */
  .codeInscription{font-family:ui-monospace,monospace;font-size:15px;
                   letter-spacing:.06em;background:#f1f5f9;border-radius:5px;
                   padding:3px 8px;user-select:all}
  /* `lienTexte` et non `lien` : `.lien` designe DEJA un lien
     d'instrumentation sur le dessin (lot 42), et cette regle-la porte
     `pointer-events:none`. Le bouton etait donc parfaitement visible et
     inclickable — trouve au navigateur, invisible a la lecture. */
  button.lienTexte{background:none;border:none;color:var(--bleu);
                   cursor:pointer;padding:0;font:inherit;
                   text-decoration:underline}

  #apercuMotif{width:100%;height:100%;min-height:200px;background:var(--papier);
               border:1px solid var(--trait);border-radius:8px}
  .flLigne{display:flex;align-items:center;gap:8px;padding:3px 7px;border-radius:6px;
           cursor:pointer;font-size:12px}
  .flLigne:hover{background:#eef2f6}
  .flLigne.actif{background:#eef4fc;box-shadow:inset 0 0 0 1px var(--bleu)}
  .flLigne .pastille{width:11px;height:11px;border-radius:3px;flex:none;
                     border:1px solid rgba(0,0,0,.15)}
  .flLigne > span:last-child{min-width:0;flex:1}
  .flLigne b{display:block;font-weight:600;line-height:1.2}
  .flLigne small{display:block;color:var(--gris);font-size:10px;line-height:1.15;
                 white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #messageFluide{margin-top:10px;font-size:12px;line-height:1.4}
  #messageFluide .erreur{color:var(--rouge);font-weight:600}
  /* Plafonne : un symbole garde ses proportions, donc etirer le cadre sur
     toute la hauteur de la fenetre n'agrandit pas le dessin — ca ne fait
     qu'ajouter du vide de part et d'autre. */
  #apercuSymbole{width:100%;height:100%;min-height:240px;max-height:440px;
                 background:repeating-linear-gradient(0deg,#eef2f6 0 1px,transparent 1px 20px),
                            repeating-linear-gradient(90deg,#eef2f6 0 1px,transparent 1px 20px),#fff;
                 border:1px solid var(--trait);border-radius:8px}
  /* `--encre` et non `--encrePlan` : cette vignette est sur un panneau
     BLANC, qui ne bascule pas avec le fond sombre du plan. */
  #apercuSymbole .forme{fill:none;stroke:var(--encre);stroke-width:2;
                        vector-effect:non-scaling-stroke;stroke-linejoin:round}
  #apercuSymbole .port{cursor:grab}
  #apercuSymbole .port.attrape{cursor:grabbing}

  .tableau{width:100%;border-collapse:collapse;font-size:12px}
  .tableau th{text-align:left;font-weight:600;color:var(--gris);font-size:10.5px;
              text-transform:uppercase;letter-spacing:.5px;padding:2px 3px}
  .tableau td{padding:1px 2px}
  .tableau input,.tableau select{width:100%;padding:3px 5px;font-size:12px;
                                 border:1px solid var(--trait);border-radius:4px}
  .tableau input.court{width:52px}
  /* Nom et type de port : lisibles sans etre tronques (« aspiration »,
     « refoulement » sont les cas courants). */
  #tPorts td:nth-child(1) input{min-width:104px}
  #tPorts td:nth-child(2) select{min-width:78px}
  #tGeo td:nth-child(1){color:var(--gris);white-space:nowrap;padding-right:6px}
  /* Sans cela, la regle « .tableau input{width:100%} » etirait aussi la case
     a cocher « fermee » sur toute la largeur de la colonne. */
  .tableau input[type=checkbox]{width:auto;min-width:0;margin:0 4px 0 0}
  .tableau label{display:inline-flex;align-items:center;white-space:nowrap;
                 margin-left:8px;color:var(--gris)}
  .tableau .suppr{color:var(--rouge);cursor:pointer;padding:0 4px;font-weight:700}
  .petit{padding:3px 8px !important;font-size:11.5px}
  .rangeeBoutons{display:flex;gap:5px;flex-wrap:wrap;margin-top:5px}
  #messageBiblio{margin-top:10px;font-size:12px;line-height:1.4}
  #messageBiblio .erreur{color:var(--rouge);font-weight:600}
  #messageBiblio ul{margin:4px 0 0 16px;padding:0;color:var(--gris);font-weight:400}

  /* ===================== Pages ===================== */
  /* Trois pages plutôt qu'une pile de fenêtres : on gère ses plans dans une
     vue où l'on reste, pas dans une modale qui se ferme au premier Échap. */
  #pages{display:flex;gap:3px;margin-left:4px}
  #pages .page{padding:5px 11px;border:1px solid transparent;background:none;
               font-size:13px;color:var(--gris);border-radius:7px}
  #pages .page:hover{background:#eef2f6;color:var(--encre)}
  #pages .page.actif{background:#eef4fc;border-color:var(--bleu);
                     color:var(--bleu);font-weight:600}
  /* Les outils de dessin ne concernent que l'éditeur : les laisser visibles
     ailleurs inviterait à cliquer sur des boutons sans effet. Depuis le lot
     9b la question ne se pose plus barre par barre : la barre de commande
     et le ruban parlent du PLAN OUVERT, et il n'y en a pas hors de
     l'éditeur. Les deux disparaissent en bloc. */
  body.horsEditeur #barreCommande{display:none}
  /* Le RUBAN, lui, ne disparaît plus en bloc : il ne garde que le groupe
     « Affaire ». Les outils de dessin n'ont rien à faire sur la page
     Ingénierie — mais les onglets de plans y sont le chemin du retour, et
     c'est justement ce qu'on avait gagné en les sortant du dessin. Les
     descendre dans le ruban ne doit pas le reprendre. */
  body.horsEditeur #ruban > .rubanGroupe:not(#groupeAffaire){display:none}

  /* `main` porte `display:flex` : sans cette regle, l'attribut `hidden` du
     HTML est ignore et l'editeur reste visible SOUS la page ouverte. */
  main[hidden]{display:none}
  .page-plein[hidden]{display:none}
  .page-plein{flex:1;min-height:0;overflow:auto;background:var(--fond);
              padding:16px 20px}
  .entetePage{display:flex;align-items:center;gap:12px;margin:0 0 14px}
  .entetePage h2{font-size:17px;margin:0}

  /* --- Documents --- */
  .grilleDocuments{display:grid;gap:12px;
                   grid-template-columns:repeat(auto-fill,minmax(310px,1fr))}
  /* Deux niveaux : l'affaire, puis ses planches. Le liseré à gauche du bloc
     est ce qui rattache visuellement les cartes à leur en-tête ; sans lui,
     deux affaires côte à côte se lisent comme une seule longue liste. */
  .listeAffaires{display:flex;flex-direction:column;gap:18px}
  .affaire{border-left:3px solid var(--trait);padding-left:12px}
  .affaireEntete{display:flex;align-items:center;gap:9px;margin-bottom:9px;
                 flex-wrap:wrap}
  .affaireNom{margin:0;font-size:14.5px;letter-spacing:.2px}
  .affaireCompte{white-space:nowrap}
  .affaireActions{display:flex;gap:6px;margin-left:auto}
  .chevronAffaire{padding:1px 7px;line-height:1.1}
  .document{display:flex;gap:12px;padding:11px;background:var(--papier);
            border:1px solid var(--trait);border-radius:10px;min-width:0}
  .document.courant{border-color:var(--bleu);box-shadow:inset 0 0 0 1px var(--bleu)}
  .document .croquis{flex:none;width:92px;height:74px;background:var(--fond);
                     border:1px solid var(--trait);border-radius:7px}
  .croquisBoite{fill:none;stroke:var(--encre);stroke-width:6;
                vector-effect:non-scaling-stroke;opacity:.8}
  .croquisVide{font:9px system-ui;fill:var(--gris)}
  .docCorps{min-width:0;flex:1;display:flex;flex-direction:column;gap:2px}
  .docCorps h3{margin:0;font-size:13.5px;line-height:1.25;
               white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .docCorps > p{margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .docMeta,.docCompteurs{font-size:11px;color:var(--gris)}
  .docActions{display:flex;gap:4px;margin-top:auto;padding-top:7px;flex-wrap:wrap}
  .docActions button{padding:3px 8px;font-size:11.5px}

  /* --- Mon compte --- */
  .corpsCompte{display:grid;gap:20px;align-items:start;max-width:1100px;
               grid-template-columns:minmax(320px,1fr) minmax(300px,1fr)}
  .corpsCompte .colonneChamps{background:var(--papier);border-radius:10px;
                              border:1px solid var(--trait);padding:14px 16px;
                              overflow:visible}
  .corpsCompte .ligne{display:flex;align-items:center;gap:8px;margin:4px 0}
  /* Le journal (lot J1) : une seule colonne, pleine largeur. Il reutilise
     la carte de `.colonneChamps` plutot que d'en inventer une — deux cartes
     qui se ressemblent finissent par diverger. */
  #cpBlocJournal{grid-template-columns:1fr;max-width:1250px}
  /* `display:grid` l'emporterait sur `hidden` : sans cette ligne, un
     concepteur arrive sur cette page verrait le cadre vide du journal. */
  #cpBlocJournal[hidden]{display:none}
  /* Un refus se LIT comme un refus. C'est la ligne qu'on vient chercher. */
  .tableauMembres tr.refuse td{color:#9a3412;background:#fff7ed}
  .tableauMembres td.quand{white-space:nowrap;color:var(--gris)}
  /* Un avertissement se lit ; il ne se déguise pas en note de bas de page. */
  .avertissement{background:#fdf6e3;border:1px solid #e8d9a8;border-radius:7px;
                 padding:7px 9px;margin:6px 0 0;color:#6b5518}

  /* =================================================================
     LOT 9b — LA COQUILLE

     Trois barres empilées, une colonne d'outils à gauche, un panneau de
     propriétés à droite, et le dessin au milieu. Chaque barre a un rôle
     et un seul ; c'est ce qui permet d'y trouver quelque chose sans
     lire les vingt boutons.
     ================================================================= */

  /* ---------- 1. Menus ---------- */
  /* `flex:none` et `nowrap` : la navigation ne se dedouble jamais. Dans la
     bande fondue, la laisser flexible faisait passer « Aide » sur deux
     lignes des que les commandes s'allongeaient, et la bande grandissait
     de neuf pixels — exactement ce qu'on venait de gagner. */
  #menus{display:flex;align-items:center;gap:2px;height:100%;
         flex:none;flex-wrap:nowrap}
  .menu{position:relative;display:flex;align-items:center;flex:none}
  .menuTitre{padding:5px 10px;border:1px solid transparent;background:none;
             font-size:13.5px;color:var(--gris);border-radius:7px;cursor:pointer;
             white-space:nowrap}
  .menuTitre:hover{background:#eef2f6;color:var(--encre)}
  /* La page ouverte est soulignée en teal, comme dans la maquette : un
     onglet actif se lit à son trait, pas à un fond de couleur qui entre en
     concurrence avec les boutons d'action. */
  .menuTitre.actif{color:var(--teal);font-weight:600;
                   box-shadow:inset 0 -2px 0 var(--teal)}
  .menu[data-ouvert] > .menuTitre{background:#eef2f6;color:var(--encre)}

  .menuListe{position:absolute;top:calc(100% + 4px);left:0;z-index:60;
             display:none;flex-direction:column;min-width:232px;padding:5px;
             background:var(--papier);border:1px solid var(--trait);
             border-radius:9px;box-shadow:0 10px 30px rgba(20,30,45,.16)}
  .menuListe.aDroite{left:auto;right:0}
  .menu[data-ouvert] > .menuListe{display:flex}
  .menuListe button{display:block;width:100%;text-align:left;border:0;
                    background:none;padding:6px 9px;border-radius:6px;
                    font-size:13px}
  .menuListe button:hover:not(:disabled){background:var(--tealClair)}
  .menuListe button.primaire{background:none;color:inherit;border:0}
  .menuListe button.primaire:hover{background:var(--tealClair);filter:none}
  .menuListe button b{display:block;font-weight:600;line-height:1.25}
  .menuListe button small{display:block;color:var(--gris);font-size:11px;
                          line-height:1.3;white-space:normal}
  .menuSep{height:1px;background:var(--trait);margin:4px 2px}

  /* Le compte ferme la bande. Il ne pousse plus : ce sont les onglets qui
     prennent le mou, et les commandes qui se collent à droite avant lui. */
  /* Lot M1. Une RANGÉE, et non une suite d'éléments en ligne. Mesuré avant :
     ce bloc faisait 60 px dans une bande de tête de 41 px — il commençait
     donc à −10 px et ses boutons étaient rognés par le haut de la fenêtre,
     pour les trois rôles et à toutes les largeurs. La cause n'était pas la
     place : sans `display:flex`, les boutons se posaient sur une LIGNE DE
     TEXTE, dont l'interligne ajoutait une hauteur que rien ne demandait.
     `align-items:center` les recentre dans la bande, et `flex:none` garde le
     bloc collé à droite sans qu'il s'étire. */
  #blocCompte{margin-left:0;flex:none;display:flex;align-items:center;gap:6px}
  #menuCompte{display:flex;align-items:center;gap:8px;padding:3px 8px 3px 3px;
              border:1px solid transparent;background:none;border-radius:20px}
  #menuCompte:hover{background:#eef2f6}
  #menuCompte.actif{border-color:var(--teal)}
  .pastilleCompte{width:27px;height:27px;flex:none;border-radius:50%;
                  background:var(--teal);color:#fff;display:flex;
                  align-items:center;justify-content:center;
                  font:700 11px system-ui;letter-spacing:.4px;text-transform:uppercase}
  /* `display:flex` l'emporte sur l'attribut `hidden` : sans cette règle, le
     nom et la fonction resteraient dans la bande. Une pastille suffit —
     l'infobulle et la page Compte disent le reste, et les quatre-vingt-quinze
     pixels rendus sont ce qui permet à la bande fondue de tenir sur une
     ligne. */
  .identiteCompte[hidden]{display:none}
  .identiteCompte{display:flex;flex-direction:column;text-align:left;line-height:1.15}
  .identiteCompte b{font-size:12.5px;font-weight:600}
  .identiteCompte small{font-size:10.5px;color:var(--gris)}

  /* ---------- 2. Commandes du plan, DANS la bande de tête ----------
     Ce n'est plus une bande mais un groupe : pas de fond propre, pas de
     bordure, pas de retour à la ligne. Il garde son identifiant parce que
     c'est lui que `body.horsEditeur` masque — le geste est le même, seule
     sa place a changé. */
  #barreCommande{display:flex;align-items:center;gap:6px;padding:0;
                 background:none;border-bottom:0;
                 flex:none;flex-wrap:nowrap;margin-left:auto}
  #barreCommande button{padding:4px 8px;font-size:12.5px;white-space:nowrap}
  #barreCommande select{max-width:118px}
  /* Sous 1440 px, les libelles cedent AVANT que la bande ne se dedouble :
     l'icone et l'infobulle disent la meme chose, et la bande garde sa
     hauteur. Au-dessus, tout est ecrit. */
  @media (max-width:1439px){ #barreCommande .mot{display:none} }
  #barreCommande .pousse{margin-left:0}
  #barreCommande .menuTitre.bouton{border:1px solid var(--trait);
                                   background:var(--papier);color:inherit;
                                   border-radius:6px;padding:4px 8px;font-size:12.5px}
  #barreCommande .menuTitre.bouton.primaire{background:var(--teal);
                                            border-color:var(--teal);color:#fff}
  #barreCommande .menuTitre.bouton:hover{background:#eef2f6}
  #barreCommande .menuTitre.bouton.primaire:hover{background:var(--teal);
                                                  filter:brightness(1.08)}

  /* ---------- 3. Ruban ---------- */
  #ruban{display:flex;align-items:stretch;gap:0;padding:4px 12px 2px;
         background:var(--papier);border-bottom:1px solid var(--trait);
         flex:none;overflow-x:auto}
  /* `flex:none` : un groupe ne se comprime PAS. Sans cela, l'arrivee du
     groupe Affaire a rogne le groupe Affichage de quatre pixels, ses deux
     boutons sont passes sur deux lignes, et le ruban a grandi de treize —
     que le dessin a perdus. Le seul groupe elastique est Affaire, dont le
     contenu varie avec le nombre de plans ouverts. */
  /* 6 px et non 12 : dix groupes a deux cotes, c'est 120 px de ruban rendus
     au dessin sans qu'un seul bouton retrecisse ni disparaisse (lot I13). */
  .rubanGroupe{display:flex;flex-direction:column;justify-content:space-between;
               flex:none;padding:0 6px;border-right:1px solid var(--trait)}
  .rubanGroupe:last-child{border-right:0}
  /* `display:flex` l'emporte sur l'attribut `hidden` : sans cette règle, le
     groupe Trait resterait visible une fois masqué. */
  .rubanGroupe[hidden]{display:none}

  /* ---------- Groupe « Affaire », à la fin du ruban ----------
     Le seul groupe dont le contenu VARIE : trente plans ouverts ne doivent
     ni faire grandir le ruban, ni pousser les autres groupes hors de
     l'écran. Il prend donc le mou, et c'est la bande d'onglets qui défile
     — comme elle le faisait dans la bande de tête. */
  #groupeAffaire{flex:1 1 auto;min-width:130px;align-items:flex-start;
                 border-right:0;padding-left:14px}
  #outilsAffaire{display:flex;align-items:center;gap:7px;
                 min-width:0;width:100%;padding-top:3px}
  /* Hors de l'éditeur, le groupe est SEUL dans le ruban : le laisser
     élastique étalerait deux onglets sur seize cents pixels, avec le
     sélecteur perdu à l'autre bout et le titre au milieu de rien. Il se
     range alors à gauche, à sa taille. */
  body.horsEditeur #groupeAffaire{flex:none;padding-left:12px}
  body.horsEditeur #outilsAffaire{width:auto}
  #groupeAffaire .rubanTitre{align-self:center}
  /* Le sélecteur CÈDE la place aux onglets : ce sont eux qu'on lit, lui
     sert à ouvrir une planche qui n'est pas encore ouverte. */
  #outilsAffaire select{flex:0 1 130px;min-width:78px;font-size:12.5px;
                        padding:2px 5px}
  /* Le groupe doit tenir dans la HAUTEUR des autres : un onglet plus haut
     qu'un bouton d'outil ferait grandir le ruban de quatorze pixels, et le
     dessin descendrait d'autant — la même faute qu'avec le groupe Trait.
     `#ruban button` empile son icône AU-DESSUS de son libellé : appliquée à
     un onglet, la règle mettait la croix sous le nom du plan et doublait la
     hauteur. Un onglet se lit en LIGNE, et garde sa largeur. */
  #outilsAffaire .ongletPlan{flex-direction:row;align-items:center;gap:6px;
                             min-width:0;padding:2px 8px;font-size:12px}
  #outilsAffaire #ongletPlus{flex-direction:row;min-width:0;
                             padding:1px 8px;font-size:13px}
  .rubanGroupe:first-child{padding-left:0}
  /* 3 px entre deux boutons d'un meme groupe : ils se touchent presque,
     et c'est voulu — ce qui separe deux groupes est le trait vertical, pas
     l'air entre les boutons. Vingt boutons, vingt pixels rendus. */
  .rubanOutils{display:flex;gap:3px;align-items:flex-start;flex-wrap:nowrap}
  /* Le titre du groupe est SOUS les boutons, en petit : il nomme
     l'intention sans prendre la place de l'outil. */
  .rubanTitre{text-align:center;font:400 10px system-ui;color:var(--gris);
              letter-spacing:.5px;padding:1px 0 2px}
  .rubanSeul{align-self:center}
  #ruban button{display:flex;flex-direction:column;align-items:center;gap:2px;
                min-width:58px;padding:5px 7px;border:1px solid transparent;
                background:none;border-radius:7px;font-size:11.5px;
                color:var(--encre);line-height:1.2}
  #ruban button:hover:not(:disabled){background:#eef2f6}
  #ruban button.actif{background:var(--tealClair);border-color:var(--teal);
                      color:var(--teal)}
  #ruban button.danger{color:var(--rouge)}
  #ruban .ico{font-size:17px;line-height:1.05}
  /* La règle générique `.outil` fixait une largeur de 30 px pour l'ancienne
     barre d'icônes seules. Dans le ruban, un outil porte AUSSI son nom. */
  #ruban .outil{width:auto;padding:5px 7px !important;font-size:11.5px}

  /* Couleur et style de trait : des grilles de pastilles, posées à même le
     ruban. Un menu déroulant y serait rogné — `#ruban` défile en `auto`,
     ce qui rogne aussi en hauteur — et il faudrait deux clics là où le
     choix tient en un seul. */
  .choixTrait{display:grid;gap:3px;align-content:start}
  /* Cinq pastilles par rangee, et non trois : neuf couleurs tenaient sur
     TROIS rangees, ce qui rendait le groupe Trait plus haut que tous les
     autres et faisait grandir le ruban de quatorze pixels a son ouverture.
     Deux rangees, et le ruban ne bouge plus. */
  #choixCouleur{grid-template-columns:repeat(5, 18px)}
  #choixStyle{grid-template-columns:repeat(2, 30px)}
  #ruban .choixTrait button{display:block;min-width:0;padding:0;
                            border:1px solid var(--trait);border-radius:4px;
                            height:18px;line-height:0;overflow:hidden}
  #ruban #choixCouleur button{width:18px}
  #ruban #choixStyle button{width:30px}
  #ruban .choixTrait button:hover{border-color:var(--gris)}
  #ruban .choixTrait button.actif{border-color:var(--teal);
                                  box-shadow:0 0 0 1.5px var(--teal);
                                  background:none}
  /* « Couleur du calque » : une pastille barrée, la convention du « sans ». */
  #ruban .choixTrait button.sansCouleur{
    background:linear-gradient(to top right,
      transparent calc(50% - 1px), var(--rouge) calc(50% - 1px),
      var(--rouge) calc(50% + 1px), transparent calc(50% + 1px)),
      var(--papier)}
  .choixTrait svg{display:block;width:100%;height:100%}

  /* ---------- Colonne centrale : onglets puis dessin ----------
     `main` est une RANGÉE : bibliothèque | centre | propriétés. Le centre,
     lui, est une COLONNE : les onglets des plans ouverts, puis la zone de
     dessin. C'est ce qui met les onglets au-dessus du seul dessin, et non
     au-dessus du panneau de propriétés. */
  #centre{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0}
  #ongletsPlans{display:none}   /* posé en flex par onglets.js quand il y a matière */
  #ongletPlus{flex:none}

  /* ---------- Règles graduées ----------
     Elles vivent dans `#cadreDessin`, pas dans `#zone` : `cadrer()` mesure
     `#zone` pour calculer l'échelle, et vingt-deux pixels de règle
     comptés dans cette mesure décaleraient le centrage à chaque cadrage. */
  #cadreDessin{flex:1;position:relative;min-height:0}
  /* La zone de dessin laisse la place aux deux barres, en bas et a droite.
     Quand les barres sont masquees, `body.sansBarres` la rend au dessin. */
  #barreH{position:absolute;left:var(--regle);right:var(--barre);bottom:0;
          height:var(--barre);background:var(--fondBarre);
          border-top:1px solid var(--trait);z-index:3}
  #barreV{position:absolute;top:var(--regle);right:0;bottom:var(--barre);
          width:var(--barre);background:var(--fondBarre);
          border-left:1px solid var(--trait);z-index:3}
  #coinDefil{position:absolute;right:0;bottom:0;width:var(--barre);
             height:var(--barre);background:var(--fondBarre);z-index:3}
  .curseurDefil{position:absolute;background:#b9c4cf;border-radius:7px;
                cursor:grab}
  #curseurH{top:2px;height:calc(var(--barre) - 5px)}
  #curseurV{left:2px;width:calc(var(--barre) - 5px)}
  .curseurDefil:hover{background:#9aa7b4}
  .curseurDefil.attrape{background:var(--teal);cursor:grabbing}
  body.sansBarres #barreH,body.sansBarres #barreV,
  body.sansBarres #coinDefil{display:none}
  body.sombre .curseurDefil{background:#4a5763}
  body.sombre .curseurDefil:hover{background:#5d6b78}

  #cadreDessin > #zone{position:absolute;top:var(--regle);left:var(--regle);
                       right:0;bottom:0}
  #regleH{position:absolute;top:0;left:var(--regle);right:0;height:var(--regle);
          background:var(--papier);border-bottom:1px solid var(--trait);
          overflow:hidden;z-index:4}
  #regleV{position:absolute;top:var(--regle);left:0;bottom:var(--barre);width:var(--regle);
          background:var(--papier);border-right:1px solid var(--trait);
          overflow:hidden;z-index:4}
  #coinRegles{position:absolute;top:0;left:0;width:var(--regle);height:var(--regle);
              background:var(--papier);border-right:1px solid var(--trait);
              border-bottom:1px solid var(--trait);z-index:5}
  #regleH canvas,#regleV canvas{display:block}

  /* ---------- Panneau Propriétés ---------- */
  /* `overflow:auto` valait pour les DEUX axes, et un `<select>` prend par
     défaut la largeur de son option la plus longue : celui de « Grandeur
     mesurée » liste vingt libellés DIN, dont le plus long dépassait les
     246 px du panneau. Une barre de défilement HORIZONTALE s'installait
     donc sur toute la hauteur, pour un champ qu'on ouvre au clic et qui
     n'a jamais eu besoin d'être fait glisser. Le panneau ne défile plus
     que verticalement, et ses champs tiennent dans sa largeur — la liste
     déroulée, elle, reste entière : c'est le navigateur qui la pose,
     par-dessus le panneau et non dedans. */
  #proprietes{width:246px;flex:none;background:var(--papier);
              border-left:1px solid var(--trait);padding:11px;
              overflow-x:hidden;overflow-y:auto;
              display:flex;flex-direction:column}
  #proprietes select,#proprietes input,#proprietes textarea{
              max-width:100%;min-width:0}
  #proprietes .ligne{min-width:0}
  #proprietes .ligne > label{min-width:0;overflow-wrap:anywhere}
  #proprietes .ligne > select{flex:0 1 132px}
  #proprietes[hidden]{display:none}
  .propEntete{display:flex;align-items:center;gap:8px;margin:0 0 10px}
  .propEntete h2{font-size:11px;text-transform:uppercase;letter-spacing:.7px;
                 color:var(--gris);margin:0}
  #fermerProprietes{margin-left:auto;line-height:1;padding:1px 7px !important;
                    font-size:14px}
  #propIdentite{display:flex;align-items:center;gap:9px;margin-bottom:10px;
                padding-bottom:10px;border-bottom:1px solid var(--trait)}
  #propIdentite[hidden]{display:none}
  .propVignette{width:42px;height:42px;flex:none;border:1px solid var(--trait);
                border-radius:8px;background:var(--fond);display:flex;
                align-items:center;justify-content:center;overflow:hidden}
  #propApercu{width:100%;height:100%}
  #propApercu .forme{fill:none;stroke:var(--encre);stroke-width:5;
                     vector-effect:non-scaling-stroke;stroke-linejoin:round}
  .propNoms{min-width:0}
  .propNoms b{display:block;font-size:13px;line-height:1.25;
              white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* Une seule ligne, coupee proprement : « Pompe centrifuge · PMP-CEN-001 »
     sur trois lignes pousserait tout le formulaire vers le bas. Le texte
     entier reste dans l'infobulle. */
  .propNoms small{display:block;color:var(--gris);font-size:11px;
                  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* Quatre onglets sur UNE ligne dans un panneau de 223 px. Mesure : a
     11,5 px et 4 px de marge interne, les quatre occupent 219 px — ca
     passe, mais de peu, et une police un peu plus large ailleurs suffirait
     a faire deborder.
     D'ou `nowrap` PLUS `text-overflow` sur les boutons : la rangee reste
     sur une ligne quoi qu'il arrive, et si la place manque un jour, c'est
     le libelle qui se raccourcit — pas la rangee qui se dedouble ni un
     onglet qui sort de l'ecran. Un onglet qu'on ne voit pas est un onglet
     qui n'existe pas. */
  #propOnglets{display:flex;flex-wrap:nowrap;gap:2px;margin-bottom:10px;
               border-bottom:1px solid var(--trait)}
  #propOnglets[hidden]{display:none}
  .propOnglet{border:0;background:none;padding:5px 4px;font-size:11.5px;
              color:var(--gris);border-radius:0;white-space:nowrap;
              min-width:0;overflow:hidden;text-overflow:ellipsis}
  .propOnglet:hover{background:none;color:var(--encre)}
  .propOnglet.actif{color:var(--teal);font-weight:600;
                    box-shadow:inset 0 -2px 0 var(--teal)}
  #propRien{margin:2px 0}
  #proprietes .ligne input{width:96px}
  #proprietes h3{margin:0 0 8px;font-size:12px;text-transform:uppercase;
                 letter-spacing:.6px;color:var(--gris)}

  /* ---------- Favoris et récents ---------- */
  #blocFavoris,#blocRecents{margin-bottom:4px}
  #blocFavoris[hidden],#blocRecents[hidden]{display:none}
  /* L'etoile ne s'affiche qu'au survol, ou en permanence si le symbole EST
     un favori : sur une tuile de 44 px, une etoile toujours visible
     mangerait le dessin qu'on cherche a reconnaitre. */
  .sym .etoile{position:absolute;top:-2px;right:0;font-size:11px;line-height:1;
               opacity:0;transition:opacity .1s;z-index:1}
  .sym:hover .etoile,.sym:focus-visible .etoile,.sym .etoile.pleine{opacity:1}
  .etoile{margin-left:auto;flex:none;color:var(--trait);cursor:pointer;
          font-size:12px;line-height:1;padding:0 1px}
  .etoile.pleine{color:#e0a412}
  .rangeeRecherche{display:flex;gap:5px;align-items:flex-start}
  .rangeeRecherche .recherche{flex:1}

  /* ---------- Onglets de plans ---------- */
  #centreColonne{flex:1;display:flex;flex-direction:column;min-width:0}
  /* Dans le groupe « Affaire » du ruban : c'est la partie qui prend le mou,
     et la seule qui défile. */
  #ongletsPlans.ouvert{display:flex;align-items:center;gap:3px;
                       flex:1 1 auto;min-width:0;padding:0;background:none;
                       border-bottom:0;overflow-x:auto;overflow-y:hidden;
                       scrollbar-width:none}
  /* La barre de défilement de la bande d'onglets n'est PAS affichée. Dans
     une rangée de 26 px elle ajoutait quinze pixels de hauteur au ruban
     entier — mesuré — et le dessin descendait d'autant. Elle est inutile :
     l'onglet actif est ramené dans la vue par le code, et le « + » ouvre
     les planches que la bande ne montre pas. */
  #ongletsPlans.ouvert::-webkit-scrollbar{display:none}
  /* Un onglet garde sa LARGEUR : comprimé, son libellé et sa croix passent
     sur deux lignes et la bande grandit. C'est la bande qui défile, pas
     l'onglet qui se plie. */
  #listeOnglets{display:flex;gap:3px;flex:none}
  .ongletPlan{flex:none}
  .ongletPlan{display:flex;align-items:center;gap:7px;padding:4px 9px;
              border:1px solid transparent;
              border-radius:7px;background:none;font-size:12.5px;
              color:var(--gris);white-space:nowrap;cursor:pointer}
  .ongletPlan:hover{background:#eef2f6;color:var(--encre)}
  .ongletPlan.actif{background:var(--fond);border-color:var(--trait);
                    color:var(--encre);font-weight:600;
                    box-shadow:inset 0 -2px 0 var(--teal)}
  .ongletPlan .fermer{color:var(--gris);font-size:13px;line-height:1;
                      padding:0 2px;border-radius:4px}
  .ongletPlan .fermer:hover{background:var(--trait);color:var(--encre)}
  #ongletPlus{padding:3px 9px;border:1px dashed var(--trait);background:none;
              color:var(--gris);font-size:14px;line-height:1.1;border-radius:7px}

  /* ---------- Identification (lot 49) ---------- */
  /* Le bandeau d'installation : il DIT que la porte n'est pas posée. Ambre
     et non rouge — ce n'est pas une panne, c'est un état de départ qu'on
     traverse, et un rouge permanent finit par ne plus se voir. */
  #bandeauInstallation{display:flex;align-items:center;gap:12px;flex:none;
                       padding:7px 14px;font-size:13px;
                       background:#fdf3e0;color:#7a4d06;
                       border-bottom:1px solid #e6cf9e}
  #bandeauInstallation[hidden]{display:none}
  #bandeauInstallation button{padding:3px 10px;font-size:12.5px;
                              border-color:#dcc08a;background:#fff}
  body.sombre #bandeauInstallation{background:#2e2413;color:#e0b871;
                                   border-bottom-color:#4a3a1c}

  /* L'écran de connexion COUVRE tout : derrière, il n'y a rien à voir. */
  #voileConnexion{position:fixed;inset:0;z-index:200;display:none;
                  align-items:center;justify-content:center;
                  background:var(--fond)}
  #voileConnexion.ouvert{display:flex}
  .fenetreConnexion{width:min(380px,92vw);background:var(--papier);
                    border:1px solid var(--trait);border-radius:12px;
                    padding:26px 26px 20px;
                    box-shadow:0 18px 50px rgba(20,30,45,.18)}
  .fenetreConnexion h1{font-size:22px;margin:0 0 4px;font-weight:700;
                       letter-spacing:-.3px}
  .fenetreConnexion h1 span{color:var(--teal)}
  .fenetreConnexion .ligne{display:block;margin:14px 0 0}
  .fenetreConnexion .ligne label{display:block;font-size:12px;
                                 color:var(--gris);margin-bottom:3px}
  .fenetreConnexion input{width:100%}
  .fenetreConnexion button{width:100%;margin-top:16px;padding:8px}
  .fenetreConnexion .mini{margin:10px 0 0;line-height:1.4}
  .fenetreConnexion .mini.erreur{color:var(--rouge);min-height:1.2em;margin:8px 0 0}
  /* Le lien « J'ai un code d'organisation » est un BOUTON, pour rester
     atteignable au clavier — mais la regle ci-dessus donne 100 % de largeur
     et 16 px de marge haute a tout bouton de cette fenetre. Il debordait
     alors de son paragraphe, que le suivant recouvrait : le lien etait
     VISIBLE et inclickable. Defaut trouve au navigateur, pas a la lecture. */
  .fenetreConnexion button.lienTexte{width:auto;margin:0;padding:0;
                                     display:inline}
  #seDeconnecter[hidden]{display:none}

  /* ---------- Aperçu avant export ---------- */
  #voileApercu .fenetre{width:min(1180px,94vw);height:min(900px,94vh)}
  #apercuCorps{flex:1;min-height:0;background:var(--fond);padding:10px}
  #apercuCadre{width:100%;height:100%;border:1px solid var(--trait);
               border-radius:8px;background:#fff;display:block}
  #apercuZone button{padding:4px 10px;font-size:12.5px}
  #apercuZone button.actif{background:var(--tealClair);
                           border-color:var(--teal);color:var(--teal)}
  #apercuInfo{white-space:nowrap}

  /* ---------- Page Ingénierie ---------- */
  #ongletsIngenierie{display:flex;gap:2px;margin-bottom:12px;
                     border-bottom:1px solid var(--trait)}
  .ongIng{border:0;background:none;padding:6px 12px;font-size:13px;
          color:var(--gris);border-radius:0}
  .ongIng:hover{background:none;color:var(--encre)}
  .ongIng.actif{color:var(--teal);font-weight:600;
                box-shadow:inset 0 -2px 0 var(--teal)}
  .voletIng[hidden]{display:none}
  /* Bibliothèque et Fluides étaient des fenêtres : elles gardent leur mise
     en page à trois colonnes, mais dans un cadre de page — plus de voile
     sombre, plus de fermeture au premier Échap. */
  #biblio,#fluides{background:var(--papier);border:1px solid var(--trait);
                   border-radius:12px;overflow:hidden;display:flex;
                   flex-direction:column;height:calc(100vh - 190px);
                   min-height:420px}
  #biblio .corps,#fluides .corps{min-height:0}

  /* ---------- Outil de tags, dans le panneau Propriétés ----------
     Deux étages : la codification de l'affaire en haut, séparée par un
     trait du tag de l'objet en dessous. Le trait n'est pas décoratif — il
     dit que le premier vaut pour tout le dossier et le second pour un seul
     objet. */
  #propTag[hidden]{display:none}
  #propTag{padding:2px 0 10px}
  .tagSchema{padding-bottom:10px;margin-bottom:10px;
             border-bottom:1px solid var(--trait)}
  .tagSchemas{display:flex;gap:4px;margin:4px 0 6px}
  .tagSchemas button{flex:1;padding:5px 4px;font-size:12px;
                     border:1px solid var(--trait);background:var(--papier)}
  .tagSchemas button.actif{background:var(--tealClair);border-color:var(--teal);
                           color:var(--teal);font-weight:600}
  .tagOrigine{font-style:italic}
  .tagSchema .petit{width:100%;margin-top:4px}
  .tagCases .ligne{margin-bottom:5px}
  .tagCases select,.tagCases input{width:104px}
  .tagCases > .petit{width:100%;margin:2px 0 6px}
  /* L'aperçu est le point de mire du volet : c'est la seule chose qu'on
     regarde en tapant. Il est donc gros, monospace, et ne bouge pas. */
  .tagApercu{font-family:ui-monospace,monospace;font-size:17px;
             font-weight:600;letter-spacing:.5px;text-align:center;
             padding:9px 6px;margin:8px 0 6px;border-radius:8px;
             background:var(--tealClair);color:var(--teal);
             word-break:break-all}
  .tagApercu.vide{background:var(--fond);color:var(--gris);font-weight:400}
  .tagConstats p{margin:0 0 5px}
  .tagSens{color:var(--teal);font-weight:600}
  /* Ce que l'application PROPOSE, et pourquoi. Ton neutre : c'est une
     aide, pas un constat d'erreur — les alertes, elles, sont rouges. */
  /* Numeroter la planche : la barre de commande, la grille de serie et
     le tableau d'apercu. Ton neutre — c'est une proposition tant qu'on n'a
     pas clique sur Ecrire. */
  .codNumBarre{display:flex;gap:8px;align-items:end;margin:8px 0;flex-wrap:wrap}
  .codNumSerie{display:flex;gap:10px;flex-wrap:wrap;margin:8px 0}
  .codNumSerie label{display:flex;flex-direction:column;font-size:12px;gap:2px}
  .codNumSerie input,.codNumSerie select{width:130px}
  #codNumResultat table{border-collapse:collapse;width:100%;font-size:12px}
  #codNumResultat th{text-align:left;padding:4px 8px;border-bottom:1px solid var(--bord);
                     color:var(--gris);font-weight:600}
  #codNumResultat td{padding:3px 8px;border-bottom:1px solid #f0f0f0}
  #codNumResultat tr.inchange td{color:var(--gris);opacity:.7}
  #codNumResultat td.neuf{font-weight:600;color:var(--bleu)}
  #codNumResultat .renvoi{color:#8a6d00;background:#fff8e1;border-left:2px solid #e0b400;
                          padding:4px 8px;margin:6px 0;border-radius:2px;font-size:12px}
  .tagProposition{color:var(--gris);opacity:.85;margin:2px 0}
  .tagAConfirmer{color:#8a6d00;background:#fff8e1;border-left:2px solid #e0b400;
                 padding:3px 6px;margin:3px 0;border-radius:2px}
  #tagAppliquer{width:100%;margin-top:4px}
  #tagAppliquer:disabled{opacity:.45;cursor:default}
  .propOngletSeul{width:100%;margin:6px 0;font-size:12px}
  .propOngletSeul[hidden]{display:none}

  /* ---------- Page Aide ----------
     Une aide se LIT : la colonne est bornée en largeur, parce qu'une ligne
     de texte qui court sur 1800 px se relit mal. Les tableaux, eux, ne sont
     pas bornés — un tableau de codes se parcourt du regard, pas ligne à
     ligne. */
  #ongletsAide{display:flex;gap:2px;margin-bottom:14px;
               border-bottom:1px solid var(--trait)}
  .ongAide{border:0;background:none;padding:6px 12px;font-size:13px;
           color:var(--gris);border-radius:0}
  .ongAide:hover{background:none;color:var(--encre)}
  .ongAide.actif{color:var(--teal);font-weight:600;
                 box-shadow:inset 0 -2px 0 var(--teal)}
  .aideVolet{max-width:900px;padding-bottom:40px}
  .aideVolet h3{font-size:15px;margin:26px 0 10px;color:var(--teal)}
  .aideVolet h3:first-child{margin-top:0}
  .aideVolet h4{font-size:13px;margin:16px 0 6px;color:var(--gris)}
  .aideVolet p{line-height:1.55;margin:0 0 9px}
  .aideVolet .mini{color:var(--gris)}
  .aideFaq,.aideFamille{border:1px solid var(--trait);border-radius:9px;
                        background:var(--papier);margin-bottom:7px;
                        overflow:hidden}
  .aideFaq > summary,.aideFamille > summary{
      padding:9px 13px;cursor:pointer;font-weight:600;font-size:13.5px;
      list-style:none}
  .aideFaq > summary::-webkit-details-marker,
  .aideFamille > summary::-webkit-details-marker{display:none}
  .aideFaq > summary::before,.aideFamille > summary::before{
      content:"›";display:inline-block;width:14px;color:var(--teal);
      transition:transform .12s}
  .aideFaq[open] > summary::before,.aideFamille[open] > summary::before{
      transform:rotate(90deg)}
  .aideFaq > summary:hover,.aideFamille > summary:hover{background:var(--fond)}
  .aideReponse{padding:2px 13px 11px 27px;border-top:1px solid var(--trait)}
  .aideTable{width:100%;border-collapse:collapse;margin:8px 0 14px;
             font-size:12.5px;background:var(--papier)}
  .aideTable th{text-align:left;padding:6px 9px;font-weight:600;
                color:var(--gris);border-bottom:1px solid var(--trait);
                background:var(--fond);position:sticky;top:0}
  .aideTable td{padding:5px 9px;border-bottom:1px solid var(--trait);
                vertical-align:top}
  .aideTable td.codeCell{font-family:ui-monospace,monospace;font-weight:600;
                         color:var(--teal);white-space:nowrap}
  .aideTable tr[hidden]{display:none}
  .aideTable[hidden]{display:none}
  /* Un tag découpé en cases : c'est la SEULE façon de montrer qu'un tag
     KKS se lit case par case et non comme une chaîne de caractères. */
  .aideDecoupe{display:flex;flex-wrap:wrap;gap:4px;margin:9px 0 12px}
  .aideCase{border:1px solid var(--trait);border-radius:7px;
            background:var(--papier);padding:6px 10px;min-width:64px;
            text-align:center}
  .aideCase b{display:block;font-family:ui-monospace,monospace;font-size:15px;
              color:var(--teal)}
  .aideCase small{display:block;color:var(--gris);font-size:10.5px;
                  margin-top:2px;max-width:150px}
  .aideExemple{margin:0 0 16px}
  .aideTag{font-family:ui-monospace,monospace;font-size:17px;
           font-weight:600;letter-spacing:.5px}
  .aideExemple[hidden],.aideFaq[hidden],.aideFamille[hidden]{display:none}

  .grilleNomenclature{display:grid;gap:10px;margin-bottom:16px;
                      grid-template-columns:repeat(auto-fill,minmax(178px,1fr))}
  .carteNom{display:flex;align-items:center;gap:11px;padding:12px 13px;
            background:var(--papier);border:1px solid var(--trait);
            border-radius:10px}
  .carteNom svg{width:34px;height:30px;flex:none}
  .carteNom .forme{fill:none;stroke:var(--gris);stroke-width:4;
                   vector-effect:non-scaling-stroke;stroke-linejoin:round}
  .carteNom .txt{min-width:0}
  .carteNom b{display:block;font-size:12.5px;font-weight:600;line-height:1.25;
              white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .carteNom .nb{font-size:21px;font-weight:700;color:var(--teal);line-height:1.1}

  /* Les colonnes du bilan : famille et symbole se lisent, les nombres se
     comparent. Sans largeurs, le tableau s'etale sur toute la page et
     l'oeil doit traverser un mètre de blanc entre « Bride » et « 2 ». */
  #tNomenclature{max-width:920px}
  #tNomenclature td{padding:3px 6px;border-bottom:1px solid var(--trait)}
  #tNomenclature th{padding:3px 6px}
  #tNomenclature td:nth-child(4){text-align:right;font-weight:600;width:60px}
  #tNomenclature td:nth-child(3){color:var(--gris);width:130px}
  #tNomenclature td:nth-child(1){width:190px}

  #revisions .petiteFenetre{width:min(720px,94vw);height:min(560px,88vh)}
  .corpsSimple{flex:1;overflow:auto;padding:14px 16px}
  #tListeRevisions td{padding:4px 3px;border-bottom:1px solid var(--trait)}
  #tListeRevisions .quand{color:var(--gris);white-space:nowrap}
  #messageRevision{font-size:12px;line-height:1.4;margin-bottom:8px}
  #messageRevision .erreur{color:var(--rouge);font-weight:600}

  /* =================================================================
     LOT 10 — LES LISTES D'INGÉNIERIE

     Un tableau d'ingénierie se lit en diagonale : on cherche une ligne
     dans deux cents. D'où l'en-tête figée, l'alternance de fond, et les
     nombres alignés à droite — les seuls réglages qui font vraiment la
     différence à la lecture.
     ================================================================= */
  .tableListe{background:var(--papier);border:1px solid var(--trait);
              border-radius:10px;overflow:auto;max-height:calc(100vh - 320px)}
  .tableau.grille{border-collapse:separate;border-spacing:0;font-size:12.5px}
  .tableau.grille th{position:sticky;top:0;z-index:2;background:var(--papier);
                     padding:8px 10px;border-bottom:1px solid var(--trait);
                     white-space:nowrap}
  /* Une colonne modifiable se signale : sinon on clique au hasard pour
     savoir laquelle accepte une saisie. */
  .tableau.grille th.editable::after{content:" ✎";color:var(--teal);
                                     font-weight:400}
  .tableau.grille td{padding:3px 6px;border-bottom:1px solid #eef2f6;
                     vertical-align:middle}
  .tableau.grille tr:last-child td{border-bottom:0}
  .tableau.grille tr:hover td{background:#f7fafb}
  .tableau.grille td.nb,.tableau.grille th.nb{text-align:right}
  .tableau.grille td.vide{color:var(--trait)}
  .tableau.grille td input[type=text],
  .tableau.grille td input[type=number]{width:100%;box-sizing:border-box;
        border:1px solid transparent;background:none;padding:3px 5px;
        border-radius:5px;font-size:12.5px}
  /* Le champ ne se dessine qu'au survol ou à la saisie : deux cents cadres
     de saisie empilés font un formulaire, pas une liste. */
  .tableau.grille td input:hover{border-color:var(--trait);background:var(--papier)}
  .tableau.grille td input:focus{outline:none;border-color:var(--teal);
                                 background:var(--papier)}
  .tableau.grille td input[type=number]{text-align:right}
  .tableau.grille td input[type=checkbox]{margin:0}

  #barreListe[hidden]{display:none}
  #listePortee[hidden]{display:none}

  #vuesNomenclature{display:flex;gap:4px;margin-bottom:14px}
  .ongVue{padding:4px 11px;border:1px solid var(--trait);background:var(--papier);
          border-radius:20px;font-size:12.5px;color:var(--gris)}
  .ongVue.actif{background:var(--tealClair);border-color:var(--teal);
                color:var(--teal);font-weight:600}
  /* Le groupe « Non renseigné » se distingue : c'est un manque, pas une
     catégorie de matériel. */
  .carteNomVide{border-style:dashed}
  .carteNomVide .nb{color:var(--gris)}
  .carteNom .txt small{display:block;margin-top:1px}
  .mini.avertissement{background:#fff6e5;border:1px solid #e8c88a;
                      color:#7a5312;border-radius:8px;padding:7px 10px;
                      margin:0 0 12px}
  .mini.avertissement[hidden]{display:none}

  /* =================================================================
     LOT 11 — FOND SOMBRE

     UNIQUEMENT l'affichage. Le DXF et le PDF ne lisent rien de ceci :
     on n'imprime pas des traits blancs sur du papier blanc. Seule la
     ZONE DE DESSIN bascule — les barres, les panneaux et les pages
     restent clairs, parce que c'est du texte qu'on lit, pas un plan
     qu'on regarde.

     Ce qui n'a pas de couleur propre suit `--encrePlan` ; ce qui en a
     une (un fluide rouge, un calque bleu) la garde. La règle
     d'éclaircissement vit dans `affichage.js` et ne touche que le trop
     sombre — voir `encreEcran`.
     ================================================================= */
  body.sombre{
    --papierPlan:#141a21;      /* le fond de la zone de dessin */
    --encrePlan:#e8eef5;       /* ce qui était noir s'affiche clair */
  }
  :root{ --papierPlan:#fff; --encrePlan:#1c2530 }

  #plan{background:var(--papierPlan)}
  /* Le cadre ISO et le cartouche : leur encre suit le fond. Ils gardent
     leur couleur de calque quand elle en a une. */
  .traitFeuille{stroke:var(--couleur-cartouche,var(--encrePlan))}
  .texteFeuille{fill:var(--couleur-cartouche,var(--encrePlan))}
  .texteTableau{fill:var(--encrePlan)}
  .traitTableau{stroke:var(--couleur-calque,var(--encrePlan))}
  /* Le fond d'un tableau reste OPAQUE — c'est ce qui empêche un tracé de
     traverser ses cases — mais opaque avec la couleur du fond courant. */
  .fondTableau{fill:var(--papierPlan)}
  /* Le liseré qui détache le tag de ligne du tuyau : il doit être de la
     couleur du FOND, sinon il dessine un halo blanc sur du noir. */
  .tagLigne{stroke:var(--papierPlan)}

  body.sombre .tag{fill:#9fb0c2}
  body.sombre .tagLigne{fill:var(--encrePlan)}
  body.sombre .port{fill:var(--papierPlan);stroke:#8fa0b3}
  body.sombre .annot{stroke:var(--couleur-calque,#9fb0c2)}
  body.sombre .annot-texte{fill:var(--couleur-calque,#9fb0c2)}
  body.sombre .lienTag{stroke:#7b8b9c}
  body.sombre .cadreRedim{stroke:#5f86c4}
  body.sombre .poignee{fill:var(--papierPlan);stroke:#5f86c4}
  body.sombre .poignee:hover{fill:#5f86c4}
  body.sombre #aide{background:rgba(20,26,33,.96);color:#9fb0c2;
                    border-color:#2b3542}
  body.sombre #aide summary{color:var(--encrePlan)}
  body.sombre #aide kbd{background:#232b35;border-color:#2b3542;
                        color:var(--encrePlan)}
  body.sombre #aligner{background:#1b222b;border-color:#2b3542}
  body.sombre #aligner button{background:#232b35;border-color:#2b3542;
                              color:var(--encrePlan)}
  /* Les règles graduées encadrent le dessin : elles suivent son fond, pas
     celui des barres. */
  body.sombre #barreH,body.sombre #barreV,body.sombre #coinDefil{
    background:#1a212a;border-color:#2b3542}
  body.sombre #regleH,body.sombre #regleV,body.sombre #coinRegles{
    background:#1b222b;border-color:#2b3542}
  /* L'entrée de menu cochée. Un réglage qui bascule doit dire dans quel
     état il est — sinon on clique pour voir. */
  .menuListe button.coche{color:var(--teal);font-weight:600}

  /* ================= LOT 12 — RAPPORT DE CONTRÔLE =================
     Posé EN SURIMPRESSION du plan, dans `#zone` : glissé dans la colonne
     centrale, il rétrécirait la zone de dessin et le plan sauterait sous le
     curseur à chaque ouverture. */
  #controle{position:absolute;left:10px;bottom:10px;z-index:7;
            width:min(470px,54%);max-height:52%;display:flex;
            flex-direction:column;border:1px solid var(--trait);
            border-radius:10px;background:var(--papier);
            box-shadow:0 6px 24px rgba(20,30,45,.18);overflow:hidden}
  #controle[hidden]{display:none}
  #controleEntete{display:flex;align-items:center;gap:8px;padding:7px 9px;
                  border-bottom:1px solid var(--trait);font-size:12.5px}
  /* Le titre ne se coupe pas en deux lignes : c'est le résumé chiffré qui
     cède la place, pas le nom du panneau. Mais il doit pouvoir RÉTRÉCIR :
     un titre qui porte le nom d'un plan importé — « PT1802_VEF_CIT_P_D_00_
     1003_RevA PID - LUBE OIL SYSTEM 1 2 » — poussait la croix de fermeture
     hors du panneau, et le rapport ne se fermait plus qu'à la touche Échap.
     `min-width:0` est ce qui l'autorise : sans lui, un élément de rangée
     flex refuse de descendre sous la largeur de son texte. */
  #controleEntete strong{white-space:nowrap;overflow:hidden;
                         text-overflow:ellipsis;min-width:0;flex:0 1 auto}
  /* Le pousse-boutons n'était défini que dans la barre du haut : ici il ne
     poussait rien, et les boutons restaient collés au titre. */
  #controleEntete .pousse{margin-left:auto}
  /* Et les boutons ne se laissent jamais comprimer : c'est le titre qui
     cède, jamais la sortie. */
  #controleEntete button{flex:none}
  #controleEntete .gris{color:var(--gris);font-size:11.5px}
  #controleFiltres{display:flex;gap:5px;padding:6px 9px;
                   border-bottom:1px solid var(--trait)}
  .filtreGravite{border:1px solid var(--trait);background:var(--papier);
                 color:var(--gris);border-radius:20px;padding:2px 9px;
                 font-size:11px;cursor:pointer}
  .filtreGravite.actif{border-color:var(--teal);color:var(--teal);
                       background:var(--tealClair);font-weight:600}
  #controleListe{overflow:auto;padding:5px}
  .controleVide{margin:10px;color:var(--gris);font-size:12px}
  /* Chaque constat est un BOUTON : il se clique, se tabule et s'annonce
     comme cliquable. Un `div` avec un `onclick` ne fait aucun des trois. */
  .anomalie{display:flex;flex-direction:column;gap:1px;width:100%;
            text-align:left;border:0;border-left:3px solid var(--trait);
            background:none;padding:6px 8px;border-radius:0 6px 6px 0;
            cursor:pointer;font-size:12.5px;color:var(--encre)}
  .anomalie:hover{background:var(--fond)}
  .anomalie small{color:var(--gris);font-size:11px;line-height:1.35}
  .anomalie.erreur{border-left-color:var(--rouge)}
  .anomalie.avertissement{border-left-color:#e2a03f}
  .anomalie.information{border-left-color:#7f93a8}
  /* La pastille du ruban porte un NOMBRE : « 3 » se lit de loin, un point
     de couleur oblige à ouvrir pour savoir s'il y en a un ou vingt. */
  /* La pastille est posée EN ABSOLU sur le bouton, et c'est structurel :
     dans le flux, elle rendait le bouton plus haut, le ruban passait de 67
     à 84 px, et les 17 px perdus par la zone de dessin faisaient sauter le
     plan sous le curseur au premier contrôle. Un indicateur ne doit rien
     déplacer. */
  #rbControle{position:relative}
  #pastilleControle{position:absolute;top:1px;right:1px;padding:0 4px;
                    border-radius:9px;background:#e2a03f;color:#fff;
                    font-size:9.5px;font-weight:700;line-height:14px;
                    display:inline-block}
  #pastilleControle[hidden]{display:none}
  #pastilleControle.grave{background:var(--rouge)}

  body.sombre #controle{background:#1b222b;border-color:#2b3542;
                        color:var(--encrePlan)}
  body.sombre #controleEntete,body.sombre #controleFiltres{
    border-color:#2b3542}
  body.sombre .filtreGravite{background:#232b35;border-color:#2b3542;
                             color:#9fb0c2}
  body.sombre .filtreGravite.actif{background:#12332e;border-color:#2f7d70;
                                   color:#5fd3c0}
  body.sombre .anomalie{color:var(--encrePlan);border-left-color:#2b3542}
  body.sombre .anomalie:hover{background:#232b35}
  body.sombre .anomalie small{color:#9fb0c2}

  /* ================= LOT 13 — RAPPORT D'IMPORT =================
     Même règle que le rapport de contrôle : posé PAR-DESSUS le plan, il ne
     rétrécit pas la zone de dessin. */
  #rapportImport{position:absolute;left:50%;top:16px;transform:translateX(-50%);
                 z-index:8;width:min(470px,64%);max-height:78%;display:flex;
                 flex-direction:column;border:1px solid var(--trait);
                 border-radius:10px;background:var(--papier);
                 box-shadow:0 8px 30px rgba(20,30,45,.22);overflow:hidden}
  #rapportImport[hidden]{display:none}
  #rapportImportCorps{overflow:auto;padding:8px 11px 11px}
  .ligneRapport{display:flex;align-items:baseline;gap:10px;padding:3px 0;
                font-size:12.5px;border-bottom:1px dotted var(--trait)}
  .ligneRapport span{color:var(--gris)}
  .ligneRapport b{margin-left:auto;font-variant-numeric:tabular-nums}
  .ligneRapport.fort b{color:var(--teal);font-size:14px}
  /* Ce qui n'a PAS pu être importé se lit comme un avertissement, pas comme
     une ligne de plus : un import qui perd du contenu doit le dire fort. */
  .rapportAlerte{margin:9px 0 0;padding:7px 9px;border-radius:7px;
                 background:#fff6e5;border:1px solid #e8c88a;color:#7a5312;
                 font-size:11.5px;line-height:1.4}
  .rapportNote{margin:8px 0 0;font-size:11.5px;color:var(--gris);line-height:1.4}
  /* Une ressemblance soupçonnée se TRANCHE : deux boutons au bout de la
     ligne, à la place du nombre qu'il n'y a pas. */
  .ligneDecision b{display:flex;gap:5px;align-items:center;font-weight:600}
  .ligneDecision button{padding:2px 7px;font-size:11.5px;line-height:1.5}
  body.sombre #rapportImport{background:#1b222b;border-color:#2b3542;
                             color:var(--encrePlan)}
  body.sombre .ligneRapport{border-bottom-color:#2b3542}
  body.sombre .ligneRapport span,body.sombre .rapportNote{color:#9fb0c2}
  body.sombre .rapportAlerte{background:#3a2f16;border-color:#6b5528;
                             color:#e8c88a}

  /* ================= LOT 14 — CODIFICATION DES TAGS ================= */
  #codCorps{padding:12px 16px;overflow:auto}
  #codSchemas{display:flex;align-items:center;gap:8px;margin-bottom:12px}
  .codSchema{padding:5px 14px;border:1px solid var(--trait);border-radius:20px;
             background:var(--papier);cursor:pointer;font-size:12.5px}
  .codSchema.actif{border-color:var(--teal);background:var(--tealClair);
                   color:var(--teal);font-weight:600}
  #codCategories{display:grid;gap:14px}
  .codBloc{border:1px solid var(--trait);border-radius:10px;padding:10px 12px;
           background:var(--papier)}
  .codBloc header{display:flex;align-items:center;gap:12px;margin-bottom:6px}
  .codBloc h3{margin:0;font-size:14px}
  .codSep{display:flex;align-items:center;gap:5px;font-size:11.5px;
          color:var(--gris)}
  /* `auto` et non `100%` : a pleine largeur, la colonne « Source » s'etirait
     sur trois cents pixels de vide entre deux champs de saisie. */
  .codTable{width:auto;border-collapse:collapse;font-size:12px}
  .codTable th{text-align:left;font-weight:600;color:var(--gris);
               font-size:11px;padding:2px 6px 4px;border-bottom:1px solid var(--trait)}
  .codTable td{padding:2px 6px}
  .codTable input[type=number]{width:52px}
  .codActions button{border:1px solid var(--trait);background:var(--papier);
                     border-radius:6px;padding:1px 6px;cursor:pointer}
  .codActions button.danger{color:var(--rouge)}
  /* L'aperçu est ce qui rend un format lisible : une liste de colonnes ne se
     juge pas, un tag assemblé si. */
  .codApercu{margin-top:8px;padding:7px 9px;border-radius:8px;
             background:var(--fond);display:grid;gap:3px}
  .codApercu div{display:flex;align-items:baseline;gap:10px}
  .codApercu b{font-family:ui-monospace,Consolas,monospace;font-size:14px;
               color:var(--teal);min-width:190px}
  .codApercu b.codVide{color:var(--rouge);font-style:italic}
  .codApercu small{color:var(--gris);font-size:11px}
  #codTables{margin-top:14px}
  #codTables summary{cursor:pointer;font-size:12.5px;color:var(--gris)}
  .codDeuxTables{display:grid;grid-template-columns:1fr 1fr;gap:20px;
                 margin-top:10px}
  .codDeuxTables h4{margin:0 0 2px;font-size:12.5px}
  .codLigneTable{display:flex;align-items:center;gap:8px;padding:2px 0;
                 font-size:12px;border-bottom:1px dotted var(--trait)}
  .codLigneTable span{flex:1}
  #codFautes{margin:0 16px 12px}
  body.sombre .codBloc,body.sombre .codSchema{background:#1b222b;
                                              border-color:#2b3542}
  body.sombre .codApercu{background:#232b35}

  /* ============ LOT 15 — CE QU'UN INSTRUMENT ÉCRIT ============
     Le code fonctionnel et le tag vivent DANS le cartouche, les seuils à
     côté. Ils suivent l'encre du calque comme le reste du dessin. */
  /* `text-before-edge` et non `middle` : la position que calcule
     `domain/instruments.py` est le HAUT du texte, parce que c'est ce que
     le DXF en fait (code 73 = 3, relevé dans un fichier produit). Centré,
     l'écran écrivait une demi-hauteur trop haut par rapport au fichier
     livré — écart invisible dans un cartouche de 67 mm, mais qui sortait
     le code fonctionnel hors d'un ballon de 40. */
  .texteInstrument{fill:var(--couleur-calque,var(--encrePlan));
                   font-family:system-ui,sans-serif;
                   dominant-baseline:text-before-edge}
  .texteInstrument.code{font-weight:700}
  .texteInstrument.seuil{font-size:inherit}
  body.sombre .texteInstrument{fill:var(--couleur-calque,#9fb0c2)}

  /* ---- Déclaration d'un instrument, dans le panneau Propriétés ---- */
  .declInstrument{display:grid;gap:7px;margin-bottom:6px}
  /* `min-width:0` sur les enfants du bloc de declaration.
     Sans lui, la rangee des dix lettres de la Table 2 ne se replie PAS : le
     `<div>` qui la porte est un element de grille, sa `min-width` vaut donc
     `auto` — « au moins aussi large que mon contenu » — et il mesurait
     464 px dans un panneau de 246. Les deux dernieres fonctions, X et Y,
     sortaient de l'ecran : deux des dix fonctions de traitement etaient
     litteralement inatteignables a la souris. Meme piege, et meme
     correctif, que pour `.seuil select` quelques lignes plus bas. */
  .declInstrument > *{min-width:0}
  .lettresFonctions{display:flex;flex-wrap:wrap;gap:3px;margin-top:3px}
  .lettresFonctions button{width:26px;height:24px;border:1px solid var(--trait);
                           background:var(--papier);border-radius:6px;
                           font-size:12px;cursor:pointer}
  .lettresFonctions button.actif{border-color:var(--teal);
                                 background:var(--tealClair);color:var(--teal);
                                 font-weight:700}
  .listeSeuils{display:grid;gap:3px;margin:3px 0}
  .seuil{display:flex;gap:4px;align-items:center}
  /* `min-width:0` : sans lui, un <select> refuse de retrecir sous la
     largeur de son option la plus longue, et la seconde liste sortait du
     panneau. */
  .seuil select{flex:1;min-width:0}
  .seuil button.danger{border:1px solid var(--trait);background:var(--papier);
                       color:var(--rouge);border-radius:6px;cursor:pointer}
  /* Ce que la déclaration DONNE : un format ne se juge pas sur des champs. */
  .apercuInstrument{font-family:ui-monospace,Consolas,monospace;font-size:14px;
                    font-weight:700;color:var(--teal);background:var(--fond);
                    border-radius:7px;padding:6px 9px;text-align:center;
                    overflow-wrap:anywhere}
  .sepDecl{border:0;border-top:1px solid var(--trait);margin:8px 0}
  body.sombre .lettresFonctions button{background:#232b35;border-color:#2b3542}
  body.sombre .apercuInstrument{background:#232b35}

  /* Bandeau d'interface perimee. Il occupe toute la largeur, EN HAUT, et
     pousse le reste vers le bas plutot que de se poser par-dessus : ce
     qu'il annonce est qu'on ne regarde pas la bonne application, et cela ne
     se glisse pas dans un coin. Masque tant que les versions concordent. */
  #bandeauObsolete{background:#fdecea;color:var(--rouge);font-weight:600;
                   padding:8px 14px;border-bottom:1px solid #f0c8c3;
                   font-size:13px;text-align:center}
  body.sombre #bandeauObsolete{background:#3a2422;border-bottom-color:#5a3330}

  /* Le SENS de sortie d'une bride, dessine sur l'apercu du symbole. Discret
     quand tout va bien, ROUGE quand il ne correspond pas a l'endroit ou la
     bride est posee : c'est le defaut qu'on ne voyait pas, et qui faisait
     sortir le tuyau de cote. */
  .sensPort{fill:none;stroke:var(--gris);stroke-width:2.2;
            vector-effect:non-scaling-stroke}
  .sensPort.douteux{stroke:var(--rouge);stroke-width:3}
  .corrigerSens{margin-left:6px;color:var(--rouge);border-color:#f0c8c3}
  body.sombre .sensPort{stroke:#9aa7b4}

  /* Onglet Documentation : le champ prend la place, le bouton « ouvrir »
     ne parait que si la saisie s'ouvre vraiment. */
  .ligneDoc input{flex:1;min-width:0}
  .ouvrirDoc{margin-left:6px;white-space:nowrap;text-decoration:none;
             border:1px solid var(--trait);border-radius:6px;padding:2px 7px;
             color:var(--gris)}
  .ouvrirDoc[hidden]{display:none}

  /* L'assistant (lot G4). Dans le panneau de droite, sous les proprietes :
     il ne depend d'aucune selection et doit rester atteignable quand rien
     n'est choisi — c'est-a-dire au moment ou l'on ouvre un plan vide. */
  /* L'assistant, fenetre FLOTTANTE (lot G9).
     `position:fixed` et non `absolute` : la fenetre ne doit pas defiler avec
     le plan sous elle. Elle n'a PAS la classe `voile` des trois fenetres
     modales — pas de fond qui couvre l'ecran, pas de capture du clavier —
     parce que la selection part avec la demande et qu'il faut pouvoir
     cliquer le plan pendant qu'elle est ouverte.
     `resize:both` est natif : le coin en bas a droite suffit, sans une ligne
     de JavaScript. Il demande `overflow:auto`, qui sert de toute facon quand
     le journal des tournures est deplie. */
  #fenAssistant{position:fixed;z-index:60;width:340px;min-width:260px;
                min-height:200px;max-width:92vw;max-height:88vh;
                display:flex;flex-direction:column;overflow:hidden;
                background:var(--papier);border:1px solid var(--trait);
                border-radius:8px;box-shadow:0 10px 30px rgba(0,0,0,.22)}
  #asBarre{display:flex;align-items:center;gap:8px;padding:6px 6px 6px 10px;
           background:var(--fondBarre,var(--papier));
           border-bottom:1px solid var(--trait);cursor:move;user-select:none}
  #asBarre .titre{font-size:12px;text-transform:uppercase;letter-spacing:.6px;
                  color:var(--gris);font-weight:600}
  #asFermer{margin-left:auto;border:0;background:none;font-size:16px;
            line-height:1;padding:2px 6px;cursor:pointer;color:var(--gris)}
  #asFermer:hover{color:var(--encre)}
  /* Le CORPS porte le redimensionnement, et non la fenetre : sur la fenetre,
     la poignee native se pose sous l'ombre portee et devient introuvable. */
  #asCorps{padding:10px 12px 12px;overflow:auto;resize:vertical;flex:1}
  #fenAssistant textarea{width:100%;resize:vertical;font:inherit;font-size:12px;
                      padding:5px 6px;border:1px solid var(--trait);
                      border-radius:4px;background:var(--papier)}
  #fenAssistant .ligne{display:flex;align-items:center;gap:8px}
  #asChoix{display:flex;flex-wrap:wrap;gap:4px;margin:8px 0 0}
  #asChoix button{max-width:100%;text-align:left}
  #asFaites{margin:6px 0 0;padding-left:16px}
  #asFaites li{margin:2px 0}
  #asEtat{margin:8px 0 0;min-height:1em}
  #asCouches{margin:10px 0 0;color:var(--gris)}
  /* Le journal des tournures non comprises (lot G5). Replie, discret, et
     gris : c'est une liste d'echecs, elle doit etre consultable sans etre
     mise sous le nez de quelqu'un a chaque geste. */
  #asJournal{margin-top:8px;color:var(--gris)}
  #asJournal summary{cursor:pointer;user-select:none}
  #asRefus{margin:6px 0 0;padding-left:16px}
  #asRefus li{margin:2px 0}

  /* =================================================================
     LOT M2 — L'HABILLAGE DES PAGES HORS ÉDITEUR

     Toutes les règles de ce bloc sont portées par `.page-plein`,
     `body.horsEditeur` ou l'écran de connexion. Ce n'est pas une
     précaution de style : c'est la garantie, vérifiable au grep, que
     rien ici ne peut atteindre l'éditeur. Les tokens de l'éditeur —
     `--teal`, `--bleu`, `--encre`, `--trait` — gardent leurs valeurs ;
     ce bloc n'emploie que les tokens NOUVEAUX déclarés en tête.

     Le bleu du dessin (`--bleu`, teinte 214°, saturation 70 %) et le
     bleu des pages (`--grisBleu`, 202°, 30 %) ne se confondent pas :
     moins de la moitié de saturation. La règle « teal = action,
     bleu = dessin » tient sans aménagement.

     Sept procédés, et pas un de plus :
       1. des bordures à très faible contraste ;
       2. des ombres RARES — une seule sorte, large, sur les cartes ;
       3. le rayon par rôle : 0 partout, 14 px les cartes, 99 px les
          pilules. Un arrondi dit « objet séparé » ; partout, il ne
          dit plus rien ;
       4. un accent, deux emplois : `--action` remplit les boutons ET
          écrit les sur-titres, rien d'autre ne le fait ;
       5. des sur-titres en capitales espacées ;
       6. de l'interlettrage négatif sur les gros titres ;
       7. du blanc vertical.
     ================================================================= */

  /* ---- Le fond, l'encre, le rythme ---- */
  /* Lot M4. La couleur du texte est celle de l'EDITEUR, `--encre`, et non
     `--texte`. Defaut du lot M2, signale par Ermin capture a l'appui :
     `--texte` vaut #347478, un teal, et `color` s'HERITE — tout ce qui ne
     fixe pas la sienne dans ces pages devenait vert, jusqu'aux noms de
     symboles de la bibliotheque. Mesure : 218 elements de la page
     Bibliotheque le portaient.
     Regle tiree de la : le lot M2 garde ses FORMES — bordures faibles,
     ombres rares, rayon par role, rythme — et rend les COULEURS de texte
     a ce qu'elles etaient. */
  .page-plein{background:var(--fondDoux);color:var(--encre);
              padding:26px 30px 40px}
  .page-plein h2{color:var(--encre);font-size:23px;font-weight:700;
                 letter-spacing:-.025em;line-height:1.2}
  .page-plein h3{color:var(--encre);letter-spacing:-.012em}
  /* Le sur-titre ne décore pas : il nomme la rubrique à laquelle la page
     appartient. C'est le titre lui-même qui la porte, en attribut — une
     page sans attribut n'affiche aucun sur-titre, et rien à corriger. */
  .page-plein h2[data-rubrique]::before{content:attr(data-rubrique);
             display:block;font-size:10.5px;font-weight:700;
             letter-spacing:.12em;text-transform:uppercase;
             color:var(--action);margin-bottom:5px}
  /* `flex-end` et non `center` : le sur-titre fait grandir le titre par
     le haut, et ce sont les LIGNES DE BASE du bas qui doivent s'aligner. */
  .page-plein .entetePage{align-items:flex-end;margin-bottom:22px}

  /* ---- Les cartes : la bordure presque invisible, l'ombre unique ---- */
  .page-plein .colonneChamps,
  .page-plein .document,
  .page-plein .carte{border-color:var(--traitDoux);border-radius:14px}
  .page-plein .colonneChamps{padding:20px 22px;
             box-shadow:0 10px 30px rgba(27,60,62,.05)}
  .page-plein .document:hover{border-color:var(--traitAccent)}
  .page-plein .affaire{border-left-color:var(--traitAccent)}
  .page-plein .document .croquis{background:var(--fondDoux);
             border-color:var(--traitDoux)}

  /* ---- Un accent, deux emplois ---- */
  .page-plein button{border-color:var(--traitDoux);border-radius:99px;
             color:var(--encre)}
  .page-plein button:hover:not(:disabled){background:var(--actionDoux);
             border-color:var(--traitAccent)}
  .page-plein button.primaire{background:var(--action);
             border-color:var(--action);color:#fff;font-weight:600;
             padding:7px 16px}
  .page-plein button.actif{background:var(--actionDoux);
             border-color:var(--traitAccent);color:var(--action)}
  .page-plein a,.page-plein .lienTexte{color:var(--action)}
  .page-plein input,.page-plein select,.page-plein textarea{
             border-color:var(--traitDoux);border-radius:9px}
  .page-plein input:focus-visible,.page-plein select:focus-visible,
  .page-plein textarea:focus-visible{outline:2px solid var(--action);
             outline-offset:1px}
  .page-plein .codeInscription{color:var(--action);background:var(--actionDoux);
             border:1px solid var(--traitAccent);border-radius:8px;
             padding:4px 10px}

  /* ---- Tableaux : l'en-tête devient une étiquette, pas un titre ---- */
  .page-plein .tableauMembres th{font-size:10.5px;font-weight:700;
             letter-spacing:.11em;text-transform:uppercase;
             color:var(--gris);background:var(--fondDoux);
             border-color:var(--traitDoux)}
  .page-plein .tableauMembres td{border-color:var(--traitDoux)}

  /* ---- Le seul emploi du vert acide ----
     #94C31C est la plus voyante des neuf et la moins lisible : 2,1:1 sur
     blanc. Elle ne porte donc JAMAIS de texte. Ici elle est un point de
     8 px devant le code d'entrée — et cette ligne n'existe que lorsque
     les inscriptions sont OUVERTES. C'est son unique emploi dans toute
     l'application : le dépenser ailleurs le rendrait muet.
     L'ambre de `.avertissement` reste l'ambre : une couleur qui dit
     « attention » n'est pas une couleur de marque, et les deux ne se
     remplacent pas. */
  .page-plein #ligneCodeInscription::before{content:"";flex:none;
             width:8px;height:8px;border-radius:50%;background:var(--signal);
             box-shadow:0 0 0 4px rgba(148,195,28,.20)}

  /* ---- L'écran d'entrée ----
     Le voile portait le fond des pages ; il porte maintenant l'ombre du
     bleu ardoise qui glisse vers celle du teal ardoise, avec un halo de
     `--vif` — la couleur qui ne sait pas écrire mais qui sait éclairer.
     La fenêtre, elle, reste claire : c'est un formulaire, il se lit. */
  /* `position:fixed` est REPETE, et ce n'est pas une redite : la regle
     d'origine le pose, celle-ci vient plus loin dans le fichier et
     l'ecraserait avec un `relative` — le voile cessait alors de couvrir la
     fenetre et se posait SOUS la page. Defaut vu a la capture, pas a la
     lecture. */
  #voileConnexion{position:fixed;overflow:hidden;
                  background:linear-gradient(150deg,var(--bande1) 0%,
                  #1f3a3d 55%,var(--bande2) 100%)}
  #voileConnexion::before{content:"";position:absolute;right:-12%;top:-22%;
                  width:56vmax;height:56vmax;border-radius:50%;pointer-events:none;
                  background:radial-gradient(circle,rgba(4,156,156,.26),transparent 66%)}
  #voileConnexion .fenetreConnexion{position:relative;border-color:var(--traitDoux);
                  border-radius:16px;padding:28px 28px 22px;
                  box-shadow:0 26px 70px rgba(10,25,28,.42)}
  #voileConnexion .fenetreConnexion h1{letter-spacing:-.025em;
                  color:var(--encreForte)}
  #voileConnexion .fenetreConnexion h1 span{color:var(--action)}
  #voileConnexion .fenetreConnexion .ligne label{color:var(--grisBleu);
                  font-weight:600}
  #voileConnexion .fenetreConnexion input{border-color:var(--traitDoux);
                  border-radius:10px}
  #voileConnexion .fenetreConnexion input:focus-visible{
                  outline:2px solid var(--action);outline-offset:1px}
  #voileConnexion .fenetreConnexion button{border-radius:99px;
                  background:var(--action);border-color:var(--action);
                  color:#fff;font-weight:600}
  #voileConnexion .fenetreConnexion button.lienTexte{background:none;
                  border:0;color:var(--action);font-weight:400}
  #voileConnexion .fenetreConnexion .mini{color:var(--grisBleu)}

  /* =================================================================
     LOT M3 — L'ÉCRAN D'ENTRÉE

     Trois portes d'égale légitimité — un compte, un code, la découverte —
     et un panneau qui dit ce qu'est OTICAD à qui arrive sans le savoir.
     Avant, les deux dernières portes étaient des liens en bas du premier
     formulaire : un lien sous un formulaire annonce une exception, pas une
     entrée.

     Les trois fenêtres ne changent NI de structure NI d'identifiant : le
     basculeur de `session.js` les pilote comme avant, et les liens de bas
     de page continuent de marcher. Ce lot ajoute une coquille autour.
     ================================================================= */
  #cadreEntree{display:grid;grid-template-columns:minmax(0,1.02fr) minmax(0,.98fr);
               width:min(880px,94vw);border-radius:16px;overflow:hidden;
               background:var(--papier);
               box-shadow:0 26px 70px rgba(10,25,28,.42)}

  /* Le panneau sombre : l'ombre du bleu ardoise glisse vers celle du teal
     ardoise, et le halo est en `--vif` — la couleur qui ne sait pas écrire
     mais qui sait éclairer. Le texte y est en `--surBandeDoux` (7,3:1) et
     l'accent en `--surBande` (7,6:1) : mesurés, pas choisis à l'oeil. */
  /* DEUX heritages a defaire, et ils viennent de l'editeur : `aside` y
     designe la colonne d'outils, donc `width:234px` et un liseré a droite ;
     et `aside h2` y met les titres en CAPITALES de 11 px. Les deux
     s'appliquaient ici — vu a la capture : un panneau de 234 px avec
     « UN P&ID SE DESSINE ICI » en petites capitales. On garde `aside`, qui
     est le bon element pour ce panneau, et on defait explicitement. */
  #argumentaire{position:relative;overflow:hidden;padding:32px 30px 26px;
                width:auto;border-right:0;
                display:grid;align-content:space-between;gap:24px;
                background:linear-gradient(145deg,var(--bande1) 0%,#1f3a3d 55%,
                           var(--bande2) 100%)}
  #argumentaire::after{content:"";position:absolute;right:-120px;bottom:-140px;
                width:320px;height:320px;border-radius:50%;pointer-events:none;
                background:radial-gradient(circle,rgba(4,156,156,.30),transparent 68%)}
  #argumentaire > *{position:relative}
  .marqueEntree{margin:0;font-size:23px;font-weight:700;letter-spacing:-.025em;
                color:#fff}
  .marqueEntree span{color:var(--surBande)}
  #argumentaire h2{margin:22px 0 0;font-size:23px;font-weight:700;
                   text-transform:none;letter-spacing:-.025em;line-height:1.28;
                   color:#fff;max-width:19ch}
  #argumentaire h2 em{font-style:normal;color:var(--surBande)}
  .argus{list-style:none;margin:18px 0 0;padding:0;display:grid;gap:11px}
  .argus li{position:relative;padding-left:23px;font-size:13.5px;line-height:1.5;
            color:var(--surBandeDoux)}
  /* La coche est dessinee en CSS et non ecrite en caractere : « ✓ » n'existe
     pas dans toutes les polices systeme, et la ou il manque, le navigateur
     en emprunte une autre — la puce change alors de graisse d'une machine
     a l'autre. Deux traits en bordure ne changent jamais. */
  .argus li::before{content:"";position:absolute;left:1px;top:4px;width:5px;
            height:9px;border:solid var(--surBande);border-width:0 2px 2px 0;
            transform:rotate(43deg)}
  .basEntree{margin:0;font-size:11.5px;line-height:1.5;color:#8fa9b8;
             border-top:1px solid rgba(255,255,255,.11);padding-top:14px}

  /* La colonne des formulaires. C'est ELLE qui defile si la fenetre est
     basse : le panneau de gauche n'a rien a faire suivre. */
  #voletsEntree{padding:24px 28px 22px;overflow:auto;max-height:88vh}
  #ongletsEntree{display:flex;gap:3px;padding:3px;margin:0 0 18px;
                 background:var(--fondDoux);border:1px solid var(--traitDoux);
                 border-radius:99px}
  #ongletsEntree button{flex:1;border:0;background:none;border-radius:99px;
                 padding:6px 10px;font-size:12.5px;color:var(--grisBleu);
                 white-space:nowrap;cursor:pointer}
  #ongletsEntree button[aria-selected="true"]{background:var(--papier);
                 color:var(--encreForte);font-weight:600;
                 box-shadow:0 1px 3px rgba(27,60,62,.12)}

  /* Dans la coquille, une fenetre n'est plus une carte : la coquille en est
     une. Sans cela on aurait un cadre dans un cadre, et deux ombres. */
  #cadreEntree .fenetreConnexion{width:auto;border:0;border-radius:0;padding:0;
                 box-shadow:none;background:none}
  /* Le titre de chaque fenetre faisait DOUBLON avec la marque du panneau de
     gauche : trois fois « OTICAD » sur le meme ecran. Il reste dans le HTML
     — il porte le nom quand le panneau n'est pas la — et disparait ici. */
  #cadreEntree .fenetreConnexion h1{display:none}
  #cadreEntree .fenetreConnexion > .mini:first-of-type{margin-top:0;
                 font-size:14px;color:var(--encreForte);font-weight:600}

  @media (max-width:820px){
    #cadreEntree{grid-template-columns:1fr;width:min(460px,94vw)}
    #argumentaire{padding:24px 22px 20px}
    #argumentaire h2{font-size:20px;margin-top:16px}
    /* Sous cette largeur, l'argumentaire coute plus qu'il ne rapporte : on
       garde la marque et la promesse, on laisse tomber la liste. */
    .argus,.basEntree{display:none}
    #voletsEntree{padding:20px 20px 18px;max-height:none}
  }

  /* =================================================================
     LOT M5 — CHOISIR CE QU'ON RANGE

     Le rangement des importes retirait tout ou rien. Le serveur, lui,
     acceptait deja une liste de noms quelconque et recoupe chacun a la
     confirmation : choisir lesquels ne demandait donc aucune route de
     plus, et aucune garde en moins. Un symbole pose sur un plan n'entre
     pas dans la liste — il est annonce plus bas, avec sa raison.
     ================================================================= */
  .listeRangement{margin:8px 0 0;max-height:210px;overflow:auto;
                  border:1px solid var(--traitDoux);border-radius:10px;
                  background:var(--papier)}
  .ligneRangement{display:flex;align-items:center;gap:9px;padding:6px 10px;
                  border-bottom:1px solid var(--traitDoux);cursor:pointer;
                  font-size:13px;color:var(--encre)}
  .ligneRangement:last-child{border-bottom:0}
  .ligneRangement:hover{background:var(--fondDoux)}
  /* `flex:none` : sans lui la case se comprime quand un nom est long, et
     une case de trois pixels ne se coche plus. */
  .ligneRangement input{margin:0;flex:none;accent-color:var(--action)}
  .ligneRangement b{font-weight:600}
  .ligneRangement small{display:block;color:var(--gris);font-size:11.5px;
                        font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
  .barreRangement{display:flex;gap:6px;margin-top:6px}

  /* =================================================================
     LOT M7 — LE MONTAGE EN COURS

     Une conversation de six echanges a besoin d'une ligne qui dit ou
     l'on en est, et d'une porte de sortie. Les deux tiennent dans une
     bande : le resume a gauche, « Abandonner » a droite. Elle ne
     s'affiche que pendant un montage — une bande vide en permanence
     prendrait la place de ce qu'on est venu lire.
     ================================================================= */
  #asMontage{display:flex;align-items:center;gap:8px;margin:6px 0;
             padding:5px 8px;border-radius:8px;
             background:var(--actionDoux);border:1px solid var(--traitAccent)}
  /* `hidden` perd contre `display:flex` : sans cette ligne, la bande
     resterait visible et vide hors montage. */
  #asMontage[hidden]{display:none}
  #asResume{flex:1;min-width:0}
  /* Retour d'Ermin : la liste des robinets compte vingt-six boutons, et la
     fenetre, posee en bas a droite, grandissait SOUS le bord de l'ecran —
     les propositions suivantes, celles des capacites comprises, tombaient
     hors de vue. Les choix defilent dans leur propre boite : la question
     reste lisible au-dessus, quelle que soit la longueur de la liste. */
  #asChoix{max-height:34vh;overflow:auto}

  /* =================================================================
     LOT N1 — LE CIRCUIT DE VALIDATION

     Une fenetre ETROITE : ce sont trois lignes de visa et quelques
     boutons, pas un editeur. La pleine largeur des autres fenetres
     laisserait les trois noms perdus au milieu d'un ecran vide.
     ================================================================= */
  #circuit .fenetre{width:min(720px,94vw);height:auto;max-height:92vh}
  .corpsCircuit{padding:14px 18px 18px;overflow:auto}
  .corpsCircuit h3{font-size:12.5px;margin:18px 0 6px;color:var(--encre)}
  .ciEtat{display:flex;align-items:baseline;gap:10px;font-size:14px}
  .ciEtat b{font-size:15px}
  .ciPuce{display:inline-block;padding:1px 9px;border-radius:10px;
          font-size:12px;background:var(--fondDoux);border:1px solid var(--trait)}
  .ciPuce.en_verification,.ciPuce.en_approbation{background:#fff4e0;
          border-color:#e2a03f}
  .ciPuce.approuve{background:var(--actionDoux);border-color:var(--traitAccent)}
  .ciVisas{width:100%;border-collapse:collapse;margin:12px 0;font-size:13px}
  .ciVisas td{padding:5px 8px;border-bottom:1px solid var(--traitDoux)}
  .ciVisas td:first-child{color:var(--gris);width:120px}
  #ciAgir{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
  #ciAgir select,#ciAgir textarea{font:inherit;font-size:12.5px}
  #ciAgir textarea{flex-basis:100%;min-height:44px}
  .ciListe{margin:0;padding-left:18px;font-size:12.5px}
  .ciListe li{margin:2px 0}
  .ciNotice{margin-top:16px}
  #ciVerrou{background:#fff4e0;border:1px solid #e2a03f;border-radius:8px;
            padding:6px 10px;color:var(--encre)}
  #rbCircuit{position:relative}
  #pastilleCircuit{position:absolute;top:1px;right:1px;padding:0 4px;
                   border-radius:9px;background:var(--action);color:#fff;
                   font-size:9.5px;font-weight:700;line-height:14px;
                   display:inline-block}
  #pastilleCircuit[hidden],#etatCircuit[hidden]{display:none}
  #etatCircuit{padding:0 8px;border-radius:8px;background:#fff4e0;
               color:var(--encre);font-size:12px;cursor:pointer}

  /* =================================================================
     LOT N2 — LES REMARQUES DE VERIFICATION

     Une pastille numerotee, de taille constante a l'ecran. Orange tant
     qu'elle attend — c'est la couleur de ce qui bloque le circuit —,
     verte une fois traitee, grise refusee : on voit d'un coup d'oeil ce
     qui reste a faire sans ouvrir la liste.
     ================================================================= */
  .pastilleCom{cursor:pointer}
  .pastilleCom circle{fill:#e2a03f;stroke:#fff;stroke-width:2;
                      vector-effect:non-scaling-stroke}
  .pastilleCom.traite circle{fill:var(--action)}
  .pastilleCom.refuse circle{fill:#9aa5ae}
  .pastilleCom text{fill:#fff;font:700 11px system-ui,sans-serif;
                    pointer-events:none}
  #boiteCommentaire{position:fixed;z-index:70;width:300px;padding:8px;
                    background:var(--papier);border:1px solid var(--trait);
                    border-radius:8px;box-shadow:0 10px 30px rgba(0,0,0,.2)}
  #boiteCommentaire[hidden]{display:none}
  #boiteCommentaire textarea{width:100%;box-sizing:border-box;font:inherit;
                             font-size:12.5px;resize:vertical}
  #boiteCommentaire .ligne{display:flex;gap:6px;align-items:center;margin-top:6px}
  #boiteCommentaire .ligne .mini{flex:1;color:var(--rouge)}
  .ciComs{list-style:none;padding-left:0}
  .ciComs li.com{padding:6px 8px;border-left:3px solid #e2a03f;
                 background:var(--fondDoux);margin:4px 0;border-radius:4px}
  .ciComs li.com.traite{border-left-color:var(--action)}
  .ciComs li.com.refuse{border-left-color:#9aa5ae}
  .ciComs li.com.vise{outline:2px solid var(--traitAccent)}
  .ciComs .gestes{display:flex;gap:6px;margin-top:4px;align-items:center}
  .ciComs .gestes input{flex:1;font:inherit;font-size:12px}
  .ciBloque{flex-basis:100%;color:#9a5b00}
  #ciCommenter{margin-left:10px;vertical-align:middle}
  #ciAnciennes[hidden]{display:none}
  #ciAnciennes summary{cursor:pointer;margin:6px 0}
  .ciGroupe{margin:8px 0 2px;font-weight:600}

  /* =================================================================
     LOT N3 — CE QUI A CHANGE

     Un anneau autour de chaque objet touche, de taille constante a
     l'ecran : vert ajoute, orange modifie, rouge retire (en pointilles,
     a sa derniere place — il n'y est plus). Des anneaux et non des
     aplats : l'objet reste lisible dessous.
     ================================================================= */
  .anneauDiff circle{fill:none;stroke-width:3;vector-effect:non-scaling-stroke}
  .anneauDiff.ajoute circle{stroke:#2e8b57}
  .anneauDiff.modifie circle{stroke:#e2a03f}
  .anneauDiff.retire circle{stroke:var(--rouge);stroke-dasharray:4 3}
  .ciBoutonDiff{margin-left:8px}
  .ciDiffTete{margin:8px 0 4px;font-size:12.5px}
  li.diff.ajoute{color:#1f6b41}
  li.diff.retire{color:var(--rouge)}
  #ciDiff .gestes{display:flex;gap:6px;margin-top:6px}
  #etatDiff[hidden]{display:none}
  #etatDiff{padding:0 8px;border-radius:8px;background:#fff4e0;
            color:var(--encre);font-size:12px;cursor:pointer}
