/* ═══════════════════════════════════════════════════════════════════════════════
   RAIL ALLYO — LE fichier canonique, UNIQUE pour toutes les surfaces (23/07/2026,
   « j'en ai marre » des copies qui divergent). Servi par www.allyo.group/rail.css :
   le socle, dashboard.allyo.space, la marque blanche (même docroot) et les apps
   Next (app.allyo.pro…) le chargent — PLUS AUCUNE app ne garde sa copie locale.
   Toute évolution du rail se fait ICI et nulle part ailleurs.
   Variables attendues de l'hôte : --accent (couleur société). Tout le reste a un
   défaut intégré — le rail rend pareil quel que soit le thème de l'app hôte.
   ═══════════════════════════════════════════════════════════════════════════════ */

/* Hauteur : le rail S'ÉTEND sur TOUTE la hauteur de la page (Agentation Mathieu 27/07 :
   « s'il y a un scroll vertical, la navbar doit s'étendre pour que le bouton utilisateur
   et le + soient toujours en bas de page ») — align-self:stretch + min-height:100vh,
   jamais un height:100vh figé qui laisse une colonne vide sous le premier écran. */
/* Filet DÉFINITIF contre la colonne navy qui s'arrête avant le bas (signalé encore le
   03/08). `align-self:stretch` seul ne suffit pas : selon la page, la hauteur retenue par
   le navigateur pour un élément `sticky` étiré laisse une bande claire sous le rail. On
   peint donc la colonne sur le FOND DE LA PAGE, en `fixed` : cette bande navy couvre
   toujours toute la fenêtre, quoi que fasse la mise en page. Le rail se pose par-dessus,
   exactement aligné (mêmes 64 px) — la jointure est invisible.
   Ciblé par `:has(.rail)` : une page sans rail (webapp Chat, monitoring) reste intacte.
   Désactivé sous 641px, où le rail devient un tiroir hors-écran. */
@media (min-width:641px){
  body:has(> .app > .rail){
    background-image:linear-gradient(to right,var(--navy,#0c1c39) 0 64px,transparent 64px);
    background-repeat:no-repeat;background-attachment:fixed}
  /* Le rail étant `fixed`, il ne pousse plus le contenu : on lui réserve ses 64 px
     ici. Même sélecteur que la bande de fond — une page sans rail reste intacte, et
     sous 641px le rail est un tiroir hors-écran, sans place à réserver. */
  body:has(> .app > .rail) > .app{box-sizing:border-box;padding-left:64px}
}
/* ── LE RAIL EST FIXE, SUR LA HAUTEUR DE L'ÉCRAN (01/09, demande Mathieu) ──────────
   Il était `sticky` + `align-self:stretch` : sur une page longue il s'étirait à la
   hauteur du CONTENU, donc plus haut que la fenêtre — et un élément sticky plus haut
   que la fenêtre défile avec la page. Le pied avait été plaqué en `fixed` pour
   compenser ; ce rustine n'a plus lieu d'être. Le rail vaut désormais exactement une
   hauteur d'écran (100dvh sur mobile : barres d'URL rétractables) et ne bouge plus.
   Sorti du flux, il ne réserve plus sa largeur : c'est `.app` qui la réserve, juste
   en dessous, sous la MÊME condition que la bande de fond. */
.rail{
  /* ── TOKENS LOCAUX DU RAIL (03/09) ─────────────────────────────────────────
     Le rail est TOUJOURS navy, sur toutes les surfaces. Or ses filets, ses
     popovers et ses libellés lisaient --line / --card / --ink / --muted de la
     PAGE HÔTE : sur allyo.group/space (--line:rgba(12,28,57,.11)) le filet sous
     le switcher devenait invisible, alors qu'il se voyait très bien sur le CRM
     (--line clair). Même composant, deux rendus — d'où l'écart constaté d'un
     module à l'autre. Le rail redéfinit donc ses propres jetons ici : la teinte
     de la page ne le traverse plus. Seul --accent reste celui du tenant, il
     porte la marque (carré de marque, item actif, anneau d'avatar).

     ⚠ 03/09 bis — la liste OUBLIAIT --surf, --faint et --mint, que le rail lit
     pourtant pour TOUS ses fonds de survol (.swpop-item, .upop a, .swi, .swnb,
     .mailic). Sur une page hôte en thème clair, --surf valait #e9edf6 : le fond
     du survol passait au blanc pendant que --ink restait clair, et le libellé
     disparaissait — item du switcher et « Mon entreprise » du menu profil rendus
     vides, seule l'icône survivait (elle est en --accent). Tout jeton lu ici doit
     être défini ici. */
  --line:rgba(255,255,255,.14);--card:#111a2e;--ink:#e6edf7;--muted:#8ea2c8;
  --surf:#16213a;--faint:#5f7099;--mint:#4fe3c1;
  /* ⚠ 03/09 ter — L'ACCENT DU TENANT NE PEUT PAS SERVIR D'ENCRE ICI (MAYAx : « svg
     illisibles »). Il porte la marque et convient en FOND (carré de marque, item
     actif, texte blanc dessus) ; en couleur de TRAIT sur le navy du rail, il dépend
     entièrement du tenant — Earth a choisi #05070d, un quasi-noir : les icônes du
     switcher devenaient invisibles sur --surf #16213a. On en dérive donc une encre
     toujours claire, qui garde la teinte de la marque sans dépendre de sa luminosité :
     58 % de blanc, quel que soit l'accent. Les fonds, eux, gardent --accent tel quel. */
  --accent-encre:color-mix(in srgb, var(--accent,#4fe3c1) 42%, #eaf0fb);
  position:fixed;top:0;left:0;flex:0 0 auto;width:64px;height:100vh;height:100dvh;background:var(--navy,#0c1c39);display:flex;flex-direction:column;align-items:center;padding:14px 0 16px;gap:6px;z-index:40;font-family:'Plus Jakarta Sans',system-ui,sans-serif}
.rail .brand{width:42px;height:42px;border-radius:13px;display:grid;place-items:center;background:var(--accent,#0c1c39);color:#fff;margin-bottom:14px;box-shadow:0 8px 20px -8px rgba(0,0,0,.5);text-decoration:none}
.rail .brand svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.rail .brand img{width:34px;height:34px;object-fit:contain;display:block}
/* ── Témoin d'état du serveur (26/08) ──────────────────────────────────────────
   Un anneau fin AUTOUR DE MAYA — le bouton flottant, pas le logo du tenant (demande
   Mathieu 26/08) : vert = fluide, ambre = chargé, rouge = saturé. La marque du client
   reste la marque du client, elle n'a pas à porter l'état de nos machines.
   Anneau en box-shadow et non en ::after : le bouton est en overflow:hidden (l'avatar
   est un fond rond), un pseudo-élément débordant serait rogné.
   Sélecteur porté par l'attribut : tant qu'aucune mesure n'est revenue, rien ne s'affiche. */
#mayaFab[data-sante]{transition:box-shadow .6s ease}
/* !important OBLIGATOIRE : maya-fab.js pose le bouton avec un style INLINE qui porte déjà
   son box-shadow — sans cela l'anneau ne s'est jamais affiché, la règle perdait contre
   l'attribut style (constat 27/08). */
#mayaFab[data-sante="ok"]{box-shadow:0 0 0 3px rgba(79,227,193,.85),0 10px 26px -8px rgba(12,28,57,.55)!important}
#mayaFab[data-sante="charge"]{box-shadow:0 0 0 3px rgba(251,191,36,.9),0 10px 26px -8px rgba(12,28,57,.55)!important}
#mayaFab[data-sante="sature"]{box-shadow:0 0 0 3px rgba(226,96,78,.95),0 10px 26px -8px rgba(12,28,57,.55)!important;
  animation:mayaSante 2.4s ease-in-out infinite}
@keyframes mayaSante{0%,100%{opacity:1}50%{opacity:.55}}
/* Aucune infobulle : la couleur suffit (26/08). Le détail vit dans « Statuts ». */
.rail .nav,.rail .rnav{display:flex;flex-direction:column;align-items:center;gap:6px;width:100%}
/* Fenêtre courte (28/08, Agentation Mathieu : 14 entrées à la console) : la zone centrale
   se COMPRIME au lieu de laisser les dernières entrées passer sous le pied fixe (fond
   navy → invisibles ET inatteignables, aucun ascenseur). Ses items
   cèdent de la hauteur à parts égales, plancher 30 px. PAS d'overflow ici : un ascenseur
   couperait les infobulles, qui sortent du rail par la droite. Quand tout tient, rien ne bouge.

   ⚠ MAYAx 02/09 — la borne s'écrivait `calc(100vh - 252px)`, 252 px valant « marque +
   switcher + thème + avatar ». Ce compte OUBLIAIT le bloc d'outils du pied (Rechercher,
   Drive, Chat, Mail, Signaler un bug), soit 306 px de plus : le centre s'autorisait
   253 px de trop, à toute hauteur de fenêtre. Le rail débordait, et comme rien dans le
   pied n'interdisait de rétrécir, ses icônes s'écrasaient à leur tour — les items ne
   tombaient plus sur le même rythme vertical (constaté sur
   app.allyo.solar/<slug>/bureau-etude.php, MAYAx « problème d'alignement sur la hauteur »).
   Plus de constante : le centre prend CE QUI RESTE (`flex:1 1 auto` + `min-height:0`,
   sans quoi un conteneur flex refuse de passer sous la hauteur de son contenu) et le pied
   ne cède rien (`flex:0 0 auto`). Le compte se refait tout seul le jour où une entrée
   s'ajoute au pied — ce qu'un nombre écrit à la main ne saura jamais faire. */
.rail .nav{flex:1 1 auto;min-height:0}
.rail .nav .r-item{flex:0 1 46px;height:auto;min-height:30px}
/* Le pied garde sa taille : c'est le centre qui absorbe, jamais l'inverse. */
.rail .foot .r-item,.rail .foot .twrap{flex:0 0 auto}
.rail .foot{flex:0 0 auto;display:flex;flex-direction:column;align-items:center;gap:5px;width:100%;margin-top:auto;
  /* EN BAS DU RAIL — et le rail fait une hauteur d'écran, donc en bas de l'écran.
     Le `position:fixed` posé le 03/08 compensait un rail étiré plus haut que la
     fenêtre ; depuis que le rail est lui-même `fixed` sur 100dvh, `margin-top:auto`
     suffit et le pied redevient solidaire du tiroir mobile sans règle dédiée. */
  background:var(--navy,#0c1c39);padding-bottom:16px;z-index:41}
.r-item{position:relative;width:46px;height:46px;border:0;background:transparent;border-radius:13px;display:grid;place-items:center;color:#8a98b5;cursor:pointer;text-decoration:none;transition:background .15s,color .15s}
.r-item svg{width:21px;height:21px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;transition:transform .22s cubic-bezier(.34,1.56,.64,1)}
.r-item:hover{color:#fff;background:rgba(255,255,255,.08)}
.r-item.on{color:#fff;background:var(--accent,#0c1c39);box-shadow:0 8px 20px -10px rgba(0,0,0,.6)}
.r-item .tip{position:absolute;left:calc(100% + 11px);top:50%;transform:translateY(-50%) translateX(-5px);background:var(--navy,#0c1c39);color:#fff;font-size:.76rem;font-weight:600;white-space:nowrap;padding:6px 10px;border-radius:8px;opacity:0;pointer-events:none;transition:opacity .14s,transform .14s;box-shadow:0 10px 26px -8px rgba(0,0,0,.55);z-index:50}
.r-item .tip:after{content:"";position:absolute;right:100%;top:50%;transform:translateY(-50%);border:5px solid transparent;border-right-color:var(--navy,#0c1c39)}
.r-item:hover .tip,.r-item:focus-visible .tip{opacity:1;transform:translateY(-50%) translateX(0)}
.r-item:hover svg,.r-item:focus-visible svg{transform:scale(1.18)}
.r-item:active svg{transform:scale(.9);transition-duration:.08s}
@media (prefers-reduced-motion: reduce){
  .r-item svg{transition:none}
  .r-item:hover svg,.r-item:focus-visible svg,.r-item:active svg{transform:none}
}
.r-item .rbadge{position:absolute;top:5px;right:5px;background:#ef4444;color:#fff;font-size:.6rem;font-weight:800;min-width:15px;height:15px;border-radius:999px;display:grid;place-items:center;padding:0 3px}
/* Séparateur du rail SUPPRIMÉ (Agentation Mathieu 03/08 « ce trait blanc horrible ») :
   le <span class="sep"> reste dans le balisage de toutes les surfaces (socle, tenant,
   Supply, Support…) mais ne dessine plus rien — un simple espace avant le pied. */
.rail .sep{display:block;width:0;height:0;margin:5px 0;background:none}
/* Cercle autour de la miniature (Agentation 26/08) : l'anneau à la couleur d'accent se
   confondait avec le fond du rail, souvent de la même famille. On garde ce liseré comme
   séparation, et on pose par-dessus un anneau clair, lui toujours visible. */
.r-ava{width:34px;height:34px;border-radius:50%;object-fit:cover;display:block;
  box-shadow:0 0 0 2px var(--navy,#0c1c39),0 0 0 3.5px rgba(255,255,255,.34)}
.r-item:hover .r-ava,.r-item[aria-expanded="true"] .r-ava{
  box-shadow:0 0 0 2px var(--navy,#0c1c39),0 0 0 3.5px rgba(255,255,255,.72)}
.r-ava.ph{display:grid;place-items:center;background:var(--accent,#0c1c39);color:#fff;font-size:.8rem;font-weight:800}
img.r-ava{background:#fff}

/* ── Switcher de modules (sous la marque) ── */
/* Tailles en px (base 16), PAS en rem : le switcher doit rester identique au tenant
   (référence) même dans les apps qui montent la racine html en clamp (Support, Espace
   client, allyo.cloud). Ne pas repasser en rem, sinon le menu regrossit sur ces hôtes. */
.swwrap{position:relative;width:100%;display:flex;justify-content:center;margin-bottom:6px;padding-bottom:8px}
/* Filet sous le switcher (Agentation 24/08) : il ferme le bloc « marque + switcher » et
   le sépare des modules. Volontairement PLUS ÉTROIT que le rail — 60 % de sa largeur,
   centré — pour rester un séparateur discret, pas une barre pleine. */
.swwrap::after{content:"";position:absolute;left:50%;bottom:0;transform:translateX(-50%);
  width:60%;height:1px;background:var(--line,rgba(255,255,255,.10))}
.swpop{position:absolute;left:calc(100% + 11px);top:0;width:230px;background:var(--card,#111a2e);border:1px solid var(--line,rgba(255,255,255,.10));border-radius:14px;box-shadow:0 18px 50px -12px rgba(0,0,0,.45);padding:11.2px;opacity:0;visibility:hidden;transform:translateY(-6px);transition:.16s;z-index:60}
.swpop.open{opacity:1;visibility:visible;transform:none}
.swpop-head{font-size:11.2px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--muted,#8ea2c8);padding:3.2px 6.4px 8.8px;border-bottom:1px solid var(--line,rgba(255,255,255,.10));margin-bottom:6.4px}
/* Titre de SECTION dans le switcher (« Outils », 02/09) : même typographie que l'en-tête,
   mais le trait passe AU-DESSUS — il sépare des modules au lieu d'ouvrir le panneau. */
.swpop-head.sec{border-bottom:0;border-top:1px solid var(--line,rgba(255,255,255,.10));
  margin:8px 0 4.8px;padding:9.6px 6.4px 4.8px}
.swpop-empty{font-size:12.8px;color:var(--muted,#8ea2c8);text-align:center;padding:16px 8px;line-height:1.5}
.swpop-item{display:flex;align-items:center;gap:10.4px;padding:8.8px 8px;border-radius:10px;color:var(--ink,#eaf0fb);text-decoration:none;transition:background .13s}
.swpop-item+.swpop-item{margin-top:2.4px}
.swpop-item:hover{background:var(--surf,#16213a)}
.swpop-item .swi{flex:0 0 auto;width:34px;height:34px;border-radius:9px;display:grid;place-items:center;background:var(--surf,#16213a);
  color:#cfd9ee;color:var(--accent-encre,#4fe3c1)}
.swpop-item .swi svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.swpop-item b{display:block;font-size:13.76px;font-weight:700;line-height:1.2}
/* Description du module MASQUÉE (Agentation Mathieu 27/07 : « juste le nom ») —
   le markup <em> reste dans les hôtes, la règle canonique le cache partout. */
.swpop-item em{display:none}
.swpop-item.off{opacity:.55;cursor:default}
/* Tout petit coin « nouvel onglet » : discret, visible au survol de la ligne. */
.swnb{flex:0 0 auto;margin-left:auto;width:20px;height:20px;border-radius:6px;display:grid;place-items:center;color:var(--faint,#5f7099);opacity:0;transition:.13s}
.swpop-item:hover .swnb{opacity:1}
.swnb:hover{color:var(--mint,#4fe3c1);background:var(--surf,#16213a)}
.swnb svg{width:12px;height:12px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

/* ── Menu MAIL du rail (01/09) : « menu horizontal », ICÔNES SEULES (Mathieu) — Boîte
   mail et Annuaire côte à côte, sans libellé, comme les outils du rail. Même coquille
   .swpop (position, ombre, ouverture) : seule la disposition interne change. ── */
.mailpop{width:auto;padding:6.4px}
.mailpop .mailrow{display:flex;align-items:center;gap:4.8px}
.mailpop .mailic{position:relative;flex:0 0 auto;width:40px;height:40px;border-radius:10px;display:grid;place-items:center;
  color:var(--muted,#8ea2c8);background:transparent;transition:background .13s,color .13s}
.mailpop .mailic:hover{background:var(--surf,#16213a);color:var(--ink,#eaf0fb)}
/* Entrée de nav repliée (.tnav) : la destination courante est marquée dans le menu,
   sinon rien ne dit où l'on est une fois les entrées repliées. */
.rail .nav .tnav{position:relative}
.mailpop .mailic.on{color:#fff;background:var(--accent,#0c1c39)}
.mailpop .mailic svg{width:19px;height:19px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.mailpop .mailic .tcnb{position:absolute;bottom:2.4px;right:2.4px}

/* ── Fiche utilisateur (bas du rail) ── */
.uwrap{position:relative;width:100%;display:flex;justify-content:center}
.upop{position:absolute;left:calc(100% + 11px);bottom:0;width:230px;background:var(--card,#111a2e);border:1px solid var(--line,rgba(255,255,255,.10));border-radius:14px;box-shadow:0 18px 50px -12px rgba(0,0,0,.45);padding:.7rem;opacity:0;visibility:hidden;transform:translateY(6px);transition:.16s;z-index:60}
.upop.open{opacity:1;visibility:visible;transform:none}
.upop .uhead{display:flex;align-items:center;gap:.6rem;padding:.3rem .4rem .6rem;border-bottom:1px solid var(--line,rgba(255,255,255,.10));margin-bottom:.4rem}
.upop .uhead .av{width:38px;height:38px;border-radius:50%;object-fit:cover;flex:0 0 auto;background:var(--accent,#0c1c39);color:#fff;display:grid;place-items:center;font-weight:800;font-size:.85rem}
.upop .uhead b{font-size:.85rem;color:var(--ink,#eaf0fb);display:block;line-height:1.2}
.upop .uhead span{font-size:.72rem;color:var(--muted,#8ea2c8)}
.upop a,.upop button.upop-item{display:flex;align-items:center;gap:.55rem;width:100%;padding:.5rem .55rem;border-radius:9px;font-size:.84rem;font-weight:600;color:var(--ink,#eaf0fb);background:none;border:0;cursor:pointer;text-align:left;font-family:inherit}
.upop a:hover,.upop button.upop-item:hover{background:var(--surf,#16213a)}
.upop a svg,.upop button svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.upop .danger{color:#dc2626}
.upop-sep{display:block;height:1px;background:var(--line,rgba(255,255,255,.10));margin:.4rem .3rem}
/* Entrée réservée titulaire/Superadmin (menu OU rail) : icône dans l'accent, pour
   la distinguer d'un coup d'œil des entrées ouvertes à tous (demande Mathieu 27/07). */
.upop .priv,.r-item.priv{color:#cfd9ee;color:var(--accent-encre,#4fe3c1)}

/* ── Chat (pied du rail) : panneau flottant, jamais de navigation — on reste dans le
   module où l'on est (demande Mathieu 27/07). Même mécanique que .upop (position,
   transition), mais plus large/haut pour accueillir l'iframe du chat. ── */
.chwrap{position:relative;width:100%;display:flex;justify-content:center}
.chpop{position:absolute;left:calc(100% + 11px);bottom:0;width:380px;height:min(600px,80vh);
  display:flex;flex-direction:column;background:var(--card,#111a2e);border:1px solid var(--line,rgba(255,255,255,.10));
  border-radius:14px;box-shadow:0 18px 50px -12px rgba(0,0,0,.45);opacity:0;visibility:hidden;
  transform:translateY(6px);transition:.16s;z-index:60;overflow:hidden}
.chpop.open{opacity:1;visibility:visible;transform:none}
.chpop-head{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:.5rem;
  padding:.65rem .8rem;border-bottom:1px solid var(--line,rgba(255,255,255,.10));font-size:.85rem;
  font-weight:700;color:var(--ink,#eaf0fb)}
.chpop-nb{display:grid;place-items:center;width:26px;height:26px;border-radius:8px;color:var(--muted,#8ea2c8)}
.chpop-nb:hover{color:var(--mint,#4fe3c1);background:var(--surf,#16213a)}
.chpop-nb svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.chpop-frame{flex:1;width:100%;border:0;background:var(--card,#111a2e)}
.r-item.priv:hover{color:#cfd9ee;color:var(--accent-encre,#4fe3c1)}

/* ── Un SEUL gabarit de rail, à toutes les largeurs d'écran (demande Mathieu 27/07 :
   le rail doit être identique partout, la règle mobile ≤560px qui le resserrait
   créait un « rail différent » selon la fenêtre — supprimée, ne pas la remettre). ── */

/* ── Dérouleur d'outils (pied de rail) : Drive · Chat · Boîte mail · Thème repliés
   derrière UN bouton (demande Mathieu 27/07 — gain de place). Témoin rouge sur le
   bouton fermé s'il y a du nouveau (chat ou mail). Dépliage HORIZONTAL (27/07 :
   « rail horizontal pas vertical ») : les icônes jaillissent en rangée à DROITE du
   bouton, à ressort et en cascade, dans une pastille navy flottante. Chaque icône
   (sauf Thème) s'ouvre en _parent au clic, ou en _blank via le mini-bouton .rnb au
   survol (même esprit que .swnb du switcher). ── */
.twrap{position:relative;width:100%;display:flex;justify-content:center}
/* ── Outils À PLAT (Agentation 24/08 « comme dans le module CRM ») : plus de dérouleur,
   les icônes s'empilent dans le rail. Le conteneur .tpanel reste (le poll le cible) mais
   redevient un simple bloc en flux, sans habits de panneau flottant. */
.twrap.plat{flex-direction:column;gap:6px}
.twrap.plat .tpanel{position:static;flex-direction:column;gap:6px;opacity:1;visibility:visible;
  transform:none;background:none;border:0;box-shadow:none;padding:0;width:100%;align-items:center}
/* Info-bulles : à DROITE de l'icône comme le reste du rail, plus au-dessus. */
.twrap.plat .tpanel .r-item .tip{left:calc(100% + 9px);top:50%;bottom:auto;transform:translateY(-50%) translateX(-4px)}
.twrap.plat .tpanel .r-item:hover .tip,.twrap.plat .tpanel .r-item:focus-visible .tip{transform:translateY(-50%) translateX(0)}
.twrap.plat .tpanel .r-item .tip:after{left:-5px;right:auto;top:50%;transform:translateY(-50%);
  border:5px solid transparent;border-right-color:var(--navy,#0c1c39);border-top-color:transparent}
/* Ouverture/fermeture pilotée par GSAP (Agentation 03/08) — le JS de rail-tools.php anime
   le panneau et chaque icône en cascade. Le CSS ne pose que l'état FERMÉ ; sans GSAP
   (fichier bloqué, connexion coupée), la classe .open suffit à tout afficher. */
.tpanel{position:absolute;left:calc(100% + 11px);bottom:0;display:flex;flex-direction:row;
  align-items:center;gap:6px;padding:6px;background:var(--navy,#0c1c39);border-radius:14px;
  box-shadow:0 14px 34px -10px rgba(0,0,0,.6);border:1px solid rgba(255,255,255,.08);
  opacity:0;visibility:hidden;z-index:60}
.twrap.open .tpanel{opacity:1;visibility:visible}
/* Infobulles : au-DESSUS des icônes (à droite elles chevaucheraient l'icône suivante). */
.tpanel .r-item .tip{left:50%;top:auto;bottom:calc(100% + 9px);
  transform:translateX(-50%) translateY(4px)}
.tpanel .r-item:hover .tip,.tpanel .r-item:focus-visible .tip{transform:translateX(-50%) translateY(0)}
/* Dérouleur ouvert : l'infobulle « Outils » du bouton + n'a plus lieu d'être (le panneau la recouvre). */
.tbtn .tip{display:none}
.tpanel .r-item .tip:after{right:auto;left:50%;top:100%;
  transform:translateX(-50%);border:5px solid transparent;border-top-color:var(--navy,#0c1c39);border-right-color:transparent}
.tbtn svg{transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
.twrap.open .tbtn svg{transform:rotate(45deg)}
/* Notifications du dérouleur (Agentation 03/08) : le « + » replié porte le TOTAL, tous
   canaux confondus (Drive, Chat, Boîte mail, réponses aux bugs) ; une fois ouvert,
   l'ICÔNE concernée passe en rouge ET porte son propre compte (badge .tcnb, Agentation
   24/08 « le nombre de notif sur chaque icône concernée »). Le badge vit en BAS à
   droite : le haut à droite est réservé au mini-bouton « nouvel onglet » (.rnb) —
   c'est ce chevauchement qui avait tué l'ancienne pastille .tdot. */
/* Bouton du dérouleur : un CERCLE (le trait, pas un disque plein — Agentation 03/08).
   Le rouge des notifications ne touche QUE LE TRAIT : le chiffre garde la couleur du
   rail. Jamais de fond. */
.tball{width:22px;height:22px;border-radius:50%;border:1.7px solid currentColor;
  background:none;display:grid;place-items:center;font:800 10px/1 system-ui,sans-serif;
  transition:border-color .15s}
.tball.on{border-color:#ef4444}
/* Contenu du rond : la clé à molette au repos, le CHIFFRE à sa place dès qu'une
   notification tombe (Agentation 03/08) — les deux ne coexistent jamais. */
.tball>*{grid-area:1/1}
.tball .tico{width:12px;height:12px;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round}
.tball .tnum{display:none;font:inherit}
.tball.on .tico{display:none}
.tball.on .tnum{display:block}
.tpanel .r-item.neuf{color:#ef4444}
.tpanel .r-item.neuf:hover{color:#fff;background:#ef4444}
/* Badge « nombre de notifications » d'une icône du panneau — vide = absent (le poll
   écrit '' quand le compteur retombe à zéro). Anneau navy pour se détacher de l'icône. */
.tcnb{position:absolute;bottom:1px;right:1px;min-width:14px;height:14px;padding:0 3px;
  box-sizing:border-box;border-radius:7px;background:#ef4444;color:#fff;
  font:800 9px/14px system-ui,sans-serif;text-align:center;pointer-events:none;
  box-shadow:0 0 0 2px var(--navy,#0c1c39)}
.tcnb:empty{display:none}
/* .tdot conservé pour les surfaces pas encore migrées — plus posé par ggRailTools. */
.tdot{position:absolute;top:5px;right:5px;width:9px;height:9px;border-radius:50%;
  background:#ef4444;box-shadow:0 0 0 2px var(--navy,#0c1c39)}
.twrap.open .tbtn .tdot{display:none}
.rnb{position:absolute;top:2px;right:2px;width:16px;height:16px;border-radius:5px;
  display:grid;place-items:center;color:#aab7d4;background:rgba(255,255,255,.14);
  opacity:0;transition:opacity .13s;cursor:alias}
.tpanel .r-item:hover .rnb{opacity:1}
.rnb:hover{color:#fff;background:rgba(255,255,255,.28)}
.rnb svg{width:10px;height:10px;fill:none;stroke:currentColor;stroke-width:2.2;
  stroke-linecap:round;stroke-linejoin:round;transform:none !important}
@media (prefers-reduced-motion: reduce){
  .tpanel,.tpanel .r-item,.tbtn svg{transition:none}
}

/* ── Repasse mobile (27/07 soir). Le GABARIT du rail ne bouge PAS (64px partout —
   décision ci-dessus, intacte) : on borne seulement ce qui en SORT pour que plus
   aucun panneau ne dépasse de l'écran d'un téléphone (360-430px, moins le rail). ── */
@media (max-width:640px){
  .swpop,.upop{width:min(230px,calc(100vw - 86px));max-height:min(72vh,540px);overflow-y:auto}
  .chpop{width:min(380px,calc(100vw - 86px))}
  .tpanel{max-width:calc(100vw - 86px);flex-wrap:wrap;justify-content:flex-start}
}
/* Tactile (pas de survol) : les infobulles hover restent collées après un tap (état
   hover rémanent iOS/Android) → neutralisées ; les mini-boutons « nouvel onglet »
   révélés au survol seraient des cibles invisibles → visibles en permanence. */
@media (hover:none){
  .r-item .tip,.tpanel .r-item .tip{display:none}
  .swnb,.rnb{opacity:.7}
  /* Cibles tactiles (audit tablette 10" du 08/09) : les entrees des menus du rail
     mesuraient 30 a 33 px de haut — sous le minimum de 44 px exigible au doigt, ce
     qui produit les taps a cote ressentis comme des "bugs d'affichage". On releve
     la hauteur SANS toucher au dessin : meme fonds, memes rayons, meme typo. Au
     survol (souris) rien ne change — la regle est confinee aux pointeurs tactiles. */
  .swpop-item,
  .upop a,.upop button.upop-item,
  .mailpop .swpop-item{min-height:var(--touch-min,44px)}
  /* Les mini-boutons "nouvel onglet" gardent leur taille dessinee mais recoivent une
     zone de contact pleine hauteur, sinon ils restent des cibles de 16 a 20 px. */
  .swnb,.rnb,.chpop-nb{position:relative}
  .swnb::after,.rnb::after,.chpop-nb::after{content:"";position:absolute;
    top:50%;left:50%;transform:translate(-50%,-50%);
    width:var(--touch-min,44px);height:var(--touch-min,44px)}
}

/* ── SMARTPHONE (<8", demande Mathieu 27/07 soir) : le rail n'est PLUS fixe — il
   devient un TIROIR. Un bouton flottant en bas à gauche (à la place de l'icône user)
   l'ouvre en SURVOL de la page ; un clic sur un lien du rail charge la page pleine
   largeur et replie le tiroir. Le bouton/backdrop sont injectés par le JS de chaque
   surface (classes .rail-mtoggle / .rail-mbg) — desktop strictement inchangé. ── */
@media (max-width:640px){
  .rail{position:fixed;left:0;top:0;bottom:0;height:100dvh;z-index:85;
    transform:translateX(-102%);transition:transform .22s ease;
    box-shadow:0 0 60px rgba(0,0,0,.5)}
  .rail.mob-open{transform:none}
  /* Le tiroir mobile réclamait DÉJÀ ce comportement (100dvh, pied en flux) — il est
     devenu la règle de base le 02/09, cette surcharge n'a plus lieu d'être. */
  .rail-mtoggle{position:fixed;left:12px;bottom:calc(12px + env(safe-area-inset-bottom,0px));
    z-index:86;width:50px;height:50px;border-radius:16px;border:0;cursor:pointer;
    background:var(--accent,#0c1c39);color:#fff;display:grid;place-items:center;
    box-shadow:0 10px 28px -8px rgba(0,0,0,.55)}
  .rail-mtoggle svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.8;
    stroke-linecap:round;stroke-linejoin:round}
  .rail-mbg{position:fixed;inset:0;z-index:84;background:rgba(3,8,20,.45);
    opacity:0;pointer-events:none;transition:opacity .2s}
  .rail-mbg.on{opacity:1;pointer-events:auto}
}
@media (min-width:641px){.rail-mtoggle,.rail-mbg{display:none}}
@media (prefers-reduced-motion:reduce){.rail,.rail-mbg{transition:none}}
/* Pastille de compteur sur une entrée du rail (29/08) — litiges en cours, et tout
   compteur du même genre à venir. Le rail est un composant PARTAGÉ : une seule règle. */
.r-item .r-badge{position:absolute;top:4px;right:4px;min-width:16px;height:16px;padding:0 4px;border-radius:999px;background:#dc2626;color:#fff;font-size:10px;font-weight:800;line-height:16px;text-align:center;pointer-events:none}
