/* ═══════════════════════════════════════════════════════════════════════
   RS WP Maintenance — design system « A2 Relief »
   Fichier statique (pas de build) chargé via <link> par le layout.
   Source de vérité visuelle : design/propositions/a2-relief.html
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Fontes locales (Clash Display — l'intégrateur copie les woff2 dans public/fonts/) ── */
@font-face{font-family:'Clash Display';src:url('../fonts/clash-display-400.woff2') format('woff2');font-weight:400;font-display:swap}
@font-face{font-family:'Clash Display';src:url('../fonts/clash-display-500.woff2') format('woff2');font-weight:500;font-display:swap}
@font-face{font-family:'Clash Display';src:url('../fonts/clash-display-600.woff2') format('woff2');font-weight:600;font-display:swap}

/* ═══ Tokens ═══ */
:root{
  --surface:#edf0f6;
  --ink:#1c2740;
  --ink-2:#66748d;
  --ink-3:#a2adc0;
  --accent:#00ffa7;
  --accent-ink:#03583e;
  --tongue:#0af0a0;
  --tongue-deep:#013a27;
  --warn:#e3a02a;
  --danger:#e85a74;

  /* Quatre noms écrits dans les règles sans avoir jamais été définis. Une var()
     non résolue rend la déclaration INVALIDE — la propriété ne s'applique pas
     du tout. Conséquences mesurées au navigateur le 03/08/2026 : aucun anneau
     de focus clavier sur les lignes de la Flotte (outline-style:none), aucun
     filet entre les sites de /monitoring, entre les .run et dans les .wk
     (border-top-style:none), cases à cocher en bleu navigateur.
     Ce sont des alias, pas des couleurs neuves : chacun dit l'intention de
     l'usage avec le token qui existait déjà. */
  --ink-1:var(--ink);          /* titres et textes forts */
  --acc:var(--accent-ink);     /* survols et accent-color lisibles */
  --accent-deep:var(--accent-ink);
  --hair:rgba(28,39,64,.09);   /* filet séparateur, même encre que les ombres */

  /* La matière posée : un seul dégradé pour tout ce qui est en relief. Il était
     recopié 45 fois sur 7 valeurs à un point d'écart — « améliorer le relief »
     voulait dire 45 modifications. */
  --posed:linear-gradient(150deg,#f1f4f9,#eaeef5);

  /* ── L'ENTRÉE EN SCÈNE N'A LIEU QU'UNE FOIS ──────────────────────────────
     Le hub compte 21 animations d'entrée — `fade` sur les cartes, les KPI et
     l'entête, `gooIn` sur le menu, `railIn` sur la gouttière, `tabin` sur les
     panneaux — échelonnées par des délais qui vont jusqu'à 0,7 s. Elles
     donnent au premier chargement sa mise en place.
     Mais `wire:navigate` remplace le <body> : à chaque clic d'onglet, tous ces
     éléments sont neufs, et les 21 animations REJOUENT. C'est ce qui donnait
     l'impression que le menu, la gouttière et l'entête « se rechargeaient »,
     et ces 700 ms écrasaient la transition de 420 ms qui, elle, tournait bien.
     Ces animations passent donc toutes par cette variable. `hub.js` marque le
     document après la première navigation, et elles se taisent — le shell
     devient réellement persistant. Une animation d'entrée ajoutée plus tard
     doit s'écrire `animation:var(--entree,son-nom)` pour suivre la règle. */
  --entree:initial;

  /* Le chiffre gravé. L'ombre est INVERSÉE — sombre en haut-gauche, claire en
     bas : c'est elle qui creuse au lieu de soulever, et c'est tout ce qui fait
     l'effet. Purement verticale, comme le reste de la lumière du hub.
     Ce que la recette d'origine ajoute et qu'on écarte : `color:transparent` +
     `background-clip:text`, et `filter:blur(.45px)`. Les deux se paient en
     lisibilité, et ces chiffres-là sont des DONNÉES — un score de santé, un
     uptime, un nombre de failles — pas de la décoration. L'ombre seule ne coûte
     aucun contraste : l'encre du chiffre ne bouge pas. */
  --grave:0 -1px 1px rgba(28,39,64,.2), 0 1px 1px rgba(255,255,255,.9);

  /* ─────────────────────────────────────────────────────────────────────────
     Le relief, refondu le 03/08/2026 sur la recette du codepen de référence.

     Ce qui a changé et pourquoi — arbitré par Raphaël sur prototype, en
     comparant les deux recettes sur le vrai tableau de bord :

     1. LA LUMIÈRE PASSE À LA VERTICALE. Elle venait du haut-GAUCHE (`-14px
        -14px` de blanc contre `16px 18px` d'ombre). Le codepen éclaire d'aplomb
        par le haut, et c'est ce qui rend son creux crédible : la lèvre du haut
        projette DANS le trou, celle du bas renvoie la lumière. Le creux et le
        relief partagent désormais le même axe — deux axes différents sur un même
        écran, c'est deux soleils.

     2. LE CONTRASTE MONTE. Les ombres étaient à .07 d'opacité, elles vont à .4
        sur le creux. C'est le facteur qui sépare le plat du réaliste, mesuré
        en comparant les deux : quatre à cinq fois.

     3. LA LUEUR EXTÉRIEURE. C'est ce que Raphaël a repéré à l'œil — « une lueur
        d'ombre supplémentaire autour du rectangle arrondi ». Le creux n'avait
        que des `inset` : rien ne disait que la matière remontait autour du trou.
        Les deux `0 -4px 15px 2px` (blanc) et `0 -1px 15px 2px` (sombre) la
        posent, et le relief reçoit la même en blanc.

     Le fond ne bouge pas : `--surface` reste #edf0f6. L'hypothèse d'un fond
     neutre #efefef a été testée sur prototype et écartée — les deux ont la même
     clarté (0,870 contre 0,863), ils ne diffèrent que par la teinte. Ce n'était
     pas le fond, c'était le contraste des ombres.
     ───────────────────────────────────────────────────────────────────────── */

  /* Le creux : la structure du codepen, son ombre interne atténuée. Le codepen
     la pose à .4 — sur un objet unique c'est juste, mais répétée 95 fois sur des
     écrans de données elle plombait. Descendue à .19 en deux passes (Raphaël,
     03/08), pour ÉQUILIBRER avec le relief : un creux à .28 contre un relief à
     .15 se lisait deux fois plus lourd que lui, sur la même page. L'écart tient
     maintenant en dessous de 1,3 — la lèvre haute projette toujours, sans que le
     trou tire l'œil plus que l'objet posé à côté. */
  --carve:
    inset 0 -2px 8px #fff, inset 0 -2px 4px #fff,
    0 2px 4px rgba(255,255,255,.8),
    inset 0 5px 8px rgba(18,30,58,.19), inset 0 2px 2px rgba(18,30,58,.19),
    0 -1px 4px rgba(18,30,58,.15),
    0 -4px 15px 2px #fff, 0 -1px 15px 2px rgba(18,30,58,.11);

  /* Le creux SANS ses lueurs extérieures. `--carve` en porte deux — un halo
     blanc de 15 px et son ombre — qui font remonter la matière autour d'un grand
     trou. Sur une petite pièce COLORÉE (la rainure verte d'un interrupteur), ce
     halo blanc déborde sur la couleur et la rend floue au lieu de la creuser.
     Ici, rien que les faces internes. */
  --carve-net:
    inset 0 4px 7px rgba(18,30,58,.3),
    inset 0 1px 2px rgba(18,30,58,.26),
    inset 0 -2px 4px rgba(255,255,255,.5);

  /* Le relief : même axe vertical, contraste modéré — un objet posé se lit à
     son contact au sol, pas à la profondeur d'un trou. La lueur blanche
     extérieure est la même que celle du creux. */
  --raise:
    inset 0 2px 0 rgba(255,255,255,.75),
    0 -3px 8px rgba(255,255,255,.9),
    0 -4px 15px 2px rgba(255,255,255,.75),
    0 4px 8px rgba(18,30,58,.15),
    0 10px 24px rgba(18,30,58,.13);
  --raise-sm:
    inset 0 1px 0 rgba(255,255,255,.7),
    0 -2px 6px rgba(255,255,255,.88),
    0 -3px 11px 1px rgba(255,255,255,.7),
    0 2px 5px rgba(18,30,58,.14),
    0 6px 14px rgba(18,30,58,.11);
}

/* ═══ Base + grain céramique ═══ */
*{margin:0;padding:0;box-sizing:border-box}
html{-webkit-font-smoothing:antialiased}
body{
  font-family:'Atkinson Hyperlegible',sans-serif;font-size:14px;color:var(--ink);
  min-height:100vh;overflow-x:hidden;
  background:
    radial-gradient(1400px 700px at 10% -12%, rgba(255,255,255,.6), transparent 55%),
    radial-gradient(1000px 600px at 110% 115%, rgba(163,178,203,.14), transparent 60%),
    var(--surface);
}
/* grain céramique très léger */
body::after{
  content:"";position:fixed;inset:0;z-index:99;pointer-events:none;opacity:.5;
  mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.14'/%3E%3C/svg%3E");
}
.mono{font-family:'Spline Sans Mono',monospace}

/* ═══ Menu goo : une seule forme SVG, plate et fluide ═══ */
.goo{
  view-transition-name:menu;
  position:fixed;left:0;top:50%;transform:translateY(-50%);z-index:50;
  width:88px;height:640px;
  animation:var(--entree,gooIn) 1s cubic-bezier(.22,1,.36,1) both;
}
/* Après la première navigation, plus aucune entrée en scène : c'est `--entree`
   qui les éteint toutes d'un coup, et pas seulement le temps d'une transition
   comme le faisait `:active-view-transition` — les animations reprenaient juste
   après elle. */
html[data-navigue]{--entree:none}
@keyframes gooIn{from{opacity:0;transform:translate(-60px,-50%)}to{opacity:1;transform:translate(0,-50%)}}
.goo-svg{
  position:absolute;left:0;top:0;pointer-events:none;overflow:visible;
  filter:drop-shadow(6px 12px 28px rgba(10,45,48,.28)) drop-shadow(2px 4px 10px rgba(10,45,48,.16));
}
.goo-items{
  position:absolute;left:0;top:0;bottom:0;width:100%;
  /* Menu replié : les libellés sont en opacity:0 mais gardent leur largeur.
     Sans ce rognage ils débordaient de la forme et attrapaient les clics
     dans le vide, à droite du menu. */
  overflow:hidden;
  /* Les congés rétrécissent la forme en haut et en bas : sans ce retrait,
     les premières et dernières icônes sortaient de la matière. La valeur
     est calculée par le JS et suit l'échelle de la forme (--goo-inset). */
  padding:calc(var(--goo-inset, 126px) * .86) 15px;
  display:flex;flex-direction:column;justify-content:center;gap:3px;
  transition:padding .1s linear;
}
.goo a{
  position:relative;
  display:flex;align-items:center;gap:13px;height:46px;flex:none;
  padding:0 14px;border-radius:999px;text-decoration:none;
  color:rgba(255,255,255,.72);
  transition:color .25s;white-space:nowrap;
}
/* La bille avait été essayée ici, en puce sur l'entrée active. Écartée par
   Raphaël le 03/08/2026 : l'entrée est déjà en vert accent et en gras, la puce
   ne faisait que redire la même chose. */
.goo a svg{width:19px;height:19px;flex:none;stroke:currentColor;fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;
  transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
.goo a:hover{color:#fff}
.goo a:hover svg{transform:scale(1.12)}
.goo a.on{color:var(--accent)}
/* Les libellés sont visibles au repos (revue d'interface 29/07 : « huit
   icônes sans un mot au repos »). Ils ne s'effacent que si Raphaël replie
   le menu lui-même — jamais au survol, jamais tout seuls. */
.goo a .lb{
  font-size:13px;font-weight:600;letter-spacing:.01em;
  opacity:1;transform:none;
  transition:opacity .3s .06s, transform .4s .06s cubic-bezier(.22,1,.36,1);
}
.goo a .lb i{font-style:normal;font-family:'Spline Sans Mono';font-size:10.5px;font-weight:400;
  opacity:.5;margin-left:7px}
/* Menu replié : seules les icônes restent. */
.goo:not(.is-open) a .lb,
.goo:not(.is-open) .soon .lb,
.goo:not(.is-open) .fold .lb{opacity:0;transform:translateX(-8px)}

/* Entrées pas encore branchées : même place, même rythme, mais visiblement
   inertes — et sans compteur. Un lien mort qui affiche un chiffre laisse
   croire qu'il y a quelque chose derrière. */
.goo .soon{
  display:flex;align-items:center;gap:13px;height:46px;flex:none;
  padding:0 14px;border-radius:999px;white-space:nowrap;cursor:default;
  color:rgba(255,255,255,.3);
}
.goo .soon svg{width:19px;height:19px;flex:none;stroke:currentColor;fill:none;
  stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.goo .soon .lb{
  font-size:13px;font-weight:600;letter-spacing:.01em;
  opacity:1;transform:none;
  transition:opacity .3s .06s, transform .4s .06s cubic-bezier(.22,1,.36,1);
}
.goo .soon .lb em{font-style:normal;font-size:9.5px;font-weight:600;letter-spacing:.08em;
  text-transform:uppercase;margin-left:8px;padding:2px 7px;border-radius:999px;
  background:rgba(255,255,255,.09);color:rgba(255,255,255,.45)}
/* La poignée de repli : même gabarit qu'une entrée, mais ce n'est pas une
   destination — d'où le retrait de couleur et la flèche qui se retourne. */
.goo .fold{
  display:flex;align-items:center;gap:13px;height:46px;flex:none;margin-top:6px;
  padding:0 14px;border:0;border-radius:999px;background:transparent;
  color:rgba(255,255,255,.4);cursor:pointer;white-space:nowrap;
  font-family:inherit;transition:color .25s;
}
.goo .fold:hover{color:#fff}
.goo .fold svg{width:19px;height:19px;flex:none;stroke:currentColor;fill:none;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round;transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
.goo:not(.is-open) .fold svg{transform:rotate(180deg)}
.goo .fold .lb{
  font-size:13px;font-weight:600;letter-spacing:.01em;
  opacity:1;transform:none;
  transition:opacity .3s .06s, transform .4s .06s cubic-bezier(.22,1,.36,1);
}

.goo .gap{height:14px;flex:none;position:relative;margin:0 16px}
.goo .gap::after{content:"";position:absolute;inset:auto 0 6px;height:1px;border-radius:2px;
  background:rgba(255,255,255,.16)}

/* ═══ Dock droit : actions, tâches, notifications ═══ */
/* ⚠️ Jamais de `margin-top:auto` sur le PREMIER enfant de ce rail. Sur le
   premier enfant d'une colonne flex, il absorbe tout l'espace au-dessus et
   refoule le rail entier vers le bas de l'écran — régression vécue le
   29/07/2026 avec `.lvl{margin-top:auto}`. La mise en garde vivait dans le
   bloc `.lvl`, supprimé le 03/08 avec la bascule Simple/Avancé ; elle est
   ici parce que c'est le rail qu'elle protège, pas le bloc qui l'a révélée. */
/* Persistant d'un écran à l'autre : la gouttière ne change pas quand on passe
   d'un onglet à un autre, elle n'a aucune raison de se refondre. */
.rail{
  view-transition-name:rail;
  position:fixed;right:0;top:0;bottom:0;width:296px;z-index:40;
  background:linear-gradient(200deg,#f2f5fa,#e9edf4);
  border-radius:30px 0 0 30px;
  box-shadow:-16px 0 44px rgba(28,39,64,.10), inset 1px 0 0 rgba(255,255,255,.8);
  padding:28px 26px 24px;display:flex;flex-direction:column;gap:30px;
  overflow-y:auto;
  animation:var(--entree,railIn) 1s .15s cubic-bezier(.22,1,.36,1) both;
}
@keyframes railIn{from{opacity:0;transform:translateX(60px)}to{opacity:1;transform:none}}
.rail h3{font-family:'Clash Display';font-size:11px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-2);margin-bottom:14px;display:flex;align-items:baseline;gap:8px}
.rail h3 .mono{margin-left:auto;font-size:10px;color:var(--ink-3);letter-spacing:0;text-transform:none}
/* Un titre du dock peut être un lien (« Tâches » mène à /travail). `hub.css`
   n'a aucun reset sur `a` : sans cette règle il sortait en bleu souligné du
   navigateur, au milieu d'un dock en encre — constaté par Raphaël le 03/08.
   Un titre reste un titre, qu'il mène quelque part ou non. */
.rail h3 a{color:inherit;text-decoration:none;transition:color .25s}
.rail h3 a:hover{color:var(--accent-ink)}
.qa-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.qa{display:flex;flex-direction:column;align-items:flex-start;gap:9px;padding:13px 14px;
  border-radius:16px;background:var(--posed);
  box-shadow:var(--raise-sm);cursor:pointer;text-decoration:none;color:var(--ink-2);
  transition:transform .25s, box-shadow .3s, color .25s}
.qa svg{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.qa b{font-size:11.5px;font-weight:600;line-height:1.25}
.qa:hover{transform:translateY(-2px);color:var(--accent-ink);box-shadow:var(--raise)}
.qa:active{transform:none;box-shadow:var(--carve)}
.task{margin-bottom:15px;display:block;color:inherit;text-decoration:none;
  padding:2px 0;border-radius:8px;transition:background .2s}
.task:hover{background:rgba(143,157,182,.06)}
.task:last-child{margin-bottom:0}
.task .t{display:flex;align-items:baseline;gap:8px;min-width:0}
.task .t{min-width:0}
.task .t b{font-size:12.5px;font-weight:600;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;min-width:0}
.task .t>span{font-size:10.5px;color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.task .t .pc{margin-left:auto;flex:none;font-family:'Spline Sans Mono';font-size:10.5px;color:var(--accent-ink)}
.bar{height:5px;border-radius:999px;background:var(--surface);box-shadow:var(--carve);margin-top:8px;overflow:hidden}
.bar i{display:block;height:100%;border-radius:999px;
  background:linear-gradient(90deg,#00d68c,var(--accent));
  box-shadow:0 0 8px rgba(0,255,167,.5)}
.bar i.run{animation:barpulse 2.2s ease-in-out infinite}
@keyframes barpulse{50%{filter:brightness(1.15)}}
.task.queued .t b{color:var(--ink-2);font-weight:500}
.task.queued .t .pc{color:var(--ink-3)}
/* Une tâche cassée est du travail qui attend, pas du travail terminé. */
.task.failed .t .pc{color:#c13a54;font-weight:600}
/* Une tâche qui attend une DÉCISION est ce que le dock doit crier le plus
   fort : elle ne bougera jamais toute seule. Elle garde donc le titre pleine
   graisse (contrairement à `.queued`, volontairement effacée) et sa mention
   passe en accent. Ajouté le 07/09/2026 après l'audit du dock, qui comptait
   cinq tâches et n'en montrait qu'une. */
.task.waiting .t .pc{color:var(--accent-ink);font-weight:600}
.bar i.bad{background:var(--danger);opacity:.5;animation:none}
/* Une part qui n'est ni bonne ni mauvaise. Les deux remplissages ci-dessus
   portent un verdict : vert « ça avance », rouge « c'est cassé ». La part de
   trafic marqué campagne n'est ni l'un ni l'autre — la teinter reviendrait à
   juger la stratégie du client à sa place. Ajouté le 04/08/2026 (perfseo).
   `--ink-3` à .55 avait été le premier essai : mesuré au navigateur, le
   remplissage ne se distinguait plus de son rail — une barre qu'on ne lit pas
   ne dit rien. `--ink-2` opaque garde la neutralité et rend la proportion. */
.bar i.neutre{background:var(--ink-2);opacity:1;box-shadow:none;animation:none}
.notif{display:flex;gap:11px;padding:11px 0;position:relative}
.notif + .notif::before{content:"";position:absolute;top:0;left:18px;right:0;height:1px;
  background:linear-gradient(180deg, rgba(28,39,64,.05), rgba(255,255,255,.7))}
.notif .nd{width:7px;height:7px;border-radius:50%;flex:none;margin-top:5px}
.notif .nd.a{background:#00d68c;box-shadow:0 0 8px rgba(0,230,150,.5)}
.notif .nd.w{background:var(--warn)}
.notif .nd.d{background:var(--danger)}
.notif .nt{min-width:0}
.notif .nt b{font-size:12px;font-weight:600;display:block;line-height:1.35}
.notif .nt span{font-size:11px;color:var(--ink-3)}
.notif .ok-x{margin-left:auto;display:flex;gap:7px;align-self:center;flex:none}
.notif .ok-x a{width:30px;height:30px;border-radius:50%;display:grid;place-items:center;
  text-decoration:none;font-size:12px;font-weight:700;
  background:var(--posed);box-shadow:var(--raise-sm);
  transition:transform .2s, box-shadow .3s}
.notif .ok-x a.y{color:var(--accent-ink)}
.notif .ok-x a.n{color:var(--ink-3)}
.notif .ok-x a:hover{transform:translateY(-1px)}
.notif .ok-x a:active{box-shadow:var(--carve);transform:none}
.rail-empty{font-size:11.5px;color:var(--ink-3);padding:4px 0}

/* ═══ Page ═══ */
/* Le retrait de gauche suit la largeur réelle du menu (--goo-w, posée par
   le JS à chaque image) : quand le menu s'ouvre, le contenu se décale au
   lieu d'être recouvert. */
.page{padding:30px 336px 56px calc(var(--goo-w, 88px) + 50px)}

/* ── Entête ── */
/* `view-transition-name` doit être UNIQUE dans la page. Vérifié au navigateur
   sur quatre écrans : il n'y a jamais qu'un seul `header.top` rendu — celui de
   l'écran de gestion vit dans la branche non encastrée, les deux ne coexistent
   pas. Deux éléments de même nom feraient annuler la transition entière. */
.top{view-transition-name:entete;
  display:flex;align-items:center;gap:20px;margin-bottom:30px;
  animation:var(--entree,fade) .9s .1s cubic-bezier(.22,1,.36,1) both}
/* L'entête est persistant : il ne se réintroduit pas à chaque navigation. Son
   `fade` d'entrée ne sert qu'au premier chargement, et rejouait à chaque clic —
   c'est ce clignotement qu'on retire. Pendant une transition, le navigateur
   l'interpole d'un écran à l'autre ; l'animation ferait un fondu DANS le
   fondu. */
h1{font-family:'Clash Display';font-size:29px;font-weight:600;letter-spacing:.05em;text-transform:uppercase}
.top .sub{color:var(--ink-3);font-size:12.5px;margin-top:4px;letter-spacing:.01em}
.top .sub b{color:var(--ink-2);font-weight:500}
.search{
  margin-left:auto;display:flex;align-items:center;gap:10px;width:290px;
  background:var(--surface);
  border-radius:999px;padding:11px 18px;color:var(--ink-3);font-size:13px;
  box-shadow:var(--carve);
}
.search svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round}
.search .mono{margin-left:auto;font-size:10px;color:var(--ink-3);opacity:.8}
.search input{flex:1;min-width:0;background:transparent;border:0;outline:none;
  font:inherit;color:var(--ink)}
.search input::placeholder{color:var(--ink-3)}
.search input::-webkit-search-cancel-button{display:none}
.night{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--ink-2)}
.night i{width:6px;height:6px;border-radius:50%;background:#00d68c;
  box-shadow:0 0 8px 1px rgba(0,230,150,.55);animation:pulse 3s infinite}
@keyframes pulse{50%{opacity:.45}}

/* ── Bandeau KPI : une pièce, sculptée doucement ── */
.kpi-bar{
  display:grid;grid-template-columns:1.3fr 1fr 1fr 1fr 1fr;
  background:var(--posed);
  border-radius:28px;box-shadow:var(--raise);
  margin-bottom:22px;
  animation:var(--entree,fade) .9s .18s cubic-bezier(.22,1,.36,1) both;
}
.kpi{padding:26px 28px 24px;position:relative}
.kpi + .kpi::before{
  content:"";position:absolute;left:0;top:20%;bottom:20%;width:1.5px;border-radius:2px;
  background:linear-gradient(90deg, rgba(28,39,64,.06), rgba(255,255,255,.9));
}
.kpi .lbl{font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3);font-weight:500}
.kpi .val{font-family:'Clash Display';font-size:34px;font-weight:500;letter-spacing:-.02em;
  margin-top:9px;line-height:1;font-variant-numeric:tabular-nums;text-shadow:var(--grave)}
.kpi .val small{font-size:14px;color:var(--ink-3);font-weight:400;margin-left:1px}
/* padding:0 explicite : `.foot` seul (le pied de page de la Flotte, sans
   rapport) déclare `padding:0 26px`, et la valeur descendait dans les ~19 pieds
   de KPI qui ont déjà leur propre padding. Les vues contournaient en patchant
   le margin en inline. */
.kpi .foot{font-size:12px;color:var(--ink-2);margin-top:10px;padding:0;display:flex;align-items:center;gap:7px}
.dot{width:5px;height:5px;border-radius:50%;flex:none}
.dot.ok{background:#00c583}
.dot.warn{background:var(--warn)}
/* « On ne sait pas » : une pastille grise, jamais une verte. */
.dot.mute{background:var(--ink-3);opacity:.5}
.kpi.hero{display:flex;align-items:center;gap:20px}
.hero-ring{position:relative;width:66px;height:66px;flex:none;border-radius:50%;
  background:var(--surface);box-shadow:var(--carve);
  --bille:#00c583;--bille-deep:#007a4e}
/* Le cercle de progrès est retiré : la bille porte le signal à elle seule, et
   le chiffre dit le reste. Le <svg> de l'arc, son dégradé `#ga` dans le layout
   et le keyframes qui l'animait sont supprimés avec lui — masquer du DOM mort
   l'aurait seulement rendu invisible.

   La bille, montée comme celle du codepen de référence : un corps coloré qui
   porte les ombres, et un vernis métallique par-dessus en `mix-blend-mode`.
   C'est le blend sur un dégradé clair→sombre→clair qui fait le métal — sans
   lui, on n'a qu'un rond coloré.
   Une seule chose est retournée par rapport à la recette : la LUMIÈRE. Le
   codepen éclaire du haut-droite (ombres portées vers le bas-gauche, vernis à
   224°) ; tout le hub éclaire du haut-gauche — `--raise` pose son blanc en
   -14px -14px et son ombre en +16px +18px. Copiée telle quelle, la bille aurait
   été la seule pièce éclairée à l'envers. Les offsets sont donc en miroir sur X,
   et l'angle du vernis passe à 360−224,38 = 135,62°.
   Elle est belle IMMOBILE : aucune animation, rien que `prefers-reduced-motion`
   ne puisse éteindre. */
.hero-ring::before{
  content:"";position:absolute;z-index:0;pointer-events:none;
  width:54px;height:54px;border-radius:50%;
  top:50%;left:50%;transform:translate(-50%,-50%);
  /* Corps COLORÉ, pas pâle : de la teinte vive à sa version profonde — même
     couleur, plus dense. Un voile noir aurait remonté le contraste du chiffre
     blanc en grisant la bille ; un dégradé de teinte le remonte en la gardant
     franche. Mesuré : blanc sur `--bille-deep` donne 4,3 à 6,4 pour 1, quand la
     teinte vive seule plafonnait à 2,25 — sous le seuil AA de 3. */
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,.7) 0 5%, rgba(255,255,255,.25) 15%, transparent 40%),
    radial-gradient(circle at 74% 80%, rgba(255,255,255,.26) 0 4%, transparent 24%),
    radial-gradient(circle at 34% 28%, var(--bille) 0 16%, var(--bille-deep) 84%);
  box-shadow:
    10px 10px 10px -5px rgba(124,134,158,.55),
    4px 4px 2px -5px rgba(74,84,108,.5),
    6px 12px 4px -10px rgba(92,102,126,.5),
    16px 12px 16px -10px rgba(140,150,174,.5),
    -8px -8px 8px rgba(255,255,255,.5),
    inset -2px -3px 8px rgba(0,0,0,.4);
}
/* Le vernis métallique, PAR-DESSUS le corps. */
.hero-ring::after{
  content:"";position:absolute;z-index:1;pointer-events:none;
  width:54px;height:54px;border-radius:50%;overflow:hidden;
  top:50%;left:50%;transform:translate(-50%,-50%);
  box-shadow:inset -2px -2px 4px rgba(255,255,255,.35);
  background:linear-gradient(135.62deg,#fff 15%,rgba(173,173,173,.3) 50%,
                             rgba(41,41,41,.4) 60%,rgba(109,109,109,.3) 90%);
  mix-blend-mode:overlay;
}
/* Jamais mesuré : la bille reste, en gris. La retirer laisserait le chiffre
   blanc illisible sur la matière claire — et le gris dit déjà « on ne sait
   pas », ce que le vert ne dirait pas. */
.hero-ring.m{--bille:var(--ink-3);--bille-deep:#6d7b93}
/* Le chiffre passe DEVANT la bille (z-index) et se lit en blanc dessus. Son
   ombre n'est plus la gravure inversée de `--grave` : sur une sphère colorée
   c'est une ombre portée sombre qui détache, pas un relief. */
.hero-ring b{position:absolute;inset:0;z-index:2;display:grid;place-items:center;
  font-family:'Clash Display';font-size:19px;font-weight:600;
  color:#fff;text-shadow:0 1px 3px rgba(0,0,0,.4)}

/* ── Alertes : gouttière discrète ── */
.gutter{
  display:flex;border-radius:20px;margin-bottom:34px;
  background:var(--surface);box-shadow:var(--carve);
  animation:var(--entree,fade) .9s .26s cubic-bezier(.22,1,.36,1) both;
}
.al{flex:1;display:flex;align-items:center;gap:14px;padding:15px 24px;position:relative;min-width:0}
.al + .al::before{content:"";position:absolute;left:0;top:26%;bottom:26%;width:1.5px;border-radius:2px;
  background:linear-gradient(90deg, rgba(28,39,64,.06), rgba(255,255,255,.85))}
.al .sig{width:8px;height:8px;flex:none;border-radius:50%}
.al.danger .sig{background:var(--danger);box-shadow:0 0 0 0 rgba(232,90,116,.4);animation:ping 2.4s infinite}
.al.warn .sig{background:var(--warn)}
.al.info .sig{background:#00c583}
@keyframes ping{60%{box-shadow:0 0 0 8px rgba(232,90,116,0)}100%{box-shadow:0 0 0 0 rgba(232,90,116,0)}}
.al .tx{min-width:0}
.al .tx b{font-size:13px;font-weight:600;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.al .tx span{font-size:12px;color:var(--ink-2)}
/* Une gouttière à une seule ligne n'a pas à rogner son titre : mesuré à 420 px
   le 14/09 (socle 42), « Le worker 0.11.0 attend d’être posé sur 1 site »
   perdait son compte, qui est le signal. Les trois alertes, elles, se partagent
   la largeur et gardent l'ellipse. */
.al.al-entier .tx b{white-space:normal}
/* Et quand la place manque, le geste passe sous le texte : sans ce retour, à
   420 px, le bouton gardait sa largeur et le titre tombait à un mot par ligne. */
.al.al-entier{flex-wrap:wrap}
.al.al-entier .tx{flex:1 1 10rem}
/* `.act` est le geste au bout d'une ligne : une alerte du dock, et une ligne de
   « Ce qui demande une action » sur la fiche d'un site. Le second n'était couvert
   par aucune règle — « Lancer la mise à jour » sortait donc en bouton nu du
   navigateur, bordé et en police système (constaté par Raphaël le 03/08).
   Un seul bloc pour les deux : les faire diverger, c'est un endroit de plus où
   ils se contrediront. */
.al .act,
.todo .act{
  margin-left:auto;flex:none;font-size:12.5px;font-weight:600;text-decoration:none;
  color:var(--accent-ink);display:flex;align-items:center;gap:6px;
  padding:6px 4px;transition:gap .25s;
  background:transparent;border:0;font-family:inherit;cursor:pointer;
}
.al .act::after,
.todo .act::after{content:"→";transition:transform .25s}
.al .act:hover,
.todo .act:hover{gap:9px}
.al .act:disabled,
.todo .act:disabled{opacity:.5;cursor:wait}

/* ── Table des sites ── */
.sites{animation:var(--entree,fade) .9s .34s cubic-bezier(.22,1,.36,1) both}
.sites-head{display:flex;align-items:baseline;gap:16px;margin-bottom:18px;padding:0 8px}
.sites-head h2{font-family:'Clash Display';font-size:16px;font-weight:600;letter-spacing:.06em;text-transform:uppercase}
.filters{display:flex;gap:4px;margin-left:8px}
.f{font-size:12.5px;font-weight:500;color:var(--ink-3);padding:7px 14px;border-radius:999px;
  cursor:pointer;transition:all .3s;
  background:transparent;border:0;font-family:inherit}
.f:hover{color:var(--ink-2)}
.f.on{color:var(--accent-ink);background:var(--surface);box-shadow:var(--carve)}
.sites-head .mono{margin-left:auto;font-size:10.5px;color:var(--ink-3)}
.cols,.row{
  display:grid;
  grid-template-columns:2.4fr .9fr .85fr .55fr .7fr .6fr 1.9fr 40px;
  align-items:center;gap:12px;
}
/* NEUVIÈME COLONNE : QUI EST RESPONSABLE DE CE SITE.
   Elle n'existe que sur un hub tenu par plus d'une personne : la classe
   `equipe` vient d'`Equipe::plusieurs()`, qui LIT la base. Sur l'instance de
   Raphaël, seul, ni la classe ni les cellules ne sont rendues : rien à masquer.

   ⚠️ **Les trois media queries plus bas n'ont pas à être touchées**, et il a
   fallu le vérifier. La cellule porte `hide-md`, donc à 1240 px elle passe en
   `display:none` et sort du flux de grille : il reste six enfants visibles,
   exactement ce que la règle des six colonnes décrit déjà. */
.sites.equipe .cols,.sites.equipe .row{
  grid-template-columns:2.4fr .9fr .85fr .55fr .7fr .6fr 1.9fr .95fr 40px;
}
.resp{
  font-size:11.5px;color:var(--ink-2);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* « sans responsable » est une information, pas un vide : elle se lit, mais
   elle ne crie pas : c'est un fait à régler, pas une anomalie. */
.resp.none{color:var(--ink-3);font-style:italic}
.cols{
  padding:0 24px 12px;
  font-size:10px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);
  position:relative;
}
.cols::after{content:"";position:absolute;left:16px;right:16px;bottom:0;height:1.5px;border-radius:2px;
  background:linear-gradient(180deg, rgba(28,39,64,.07), rgba(255,255,255,.9))}
.row{
  padding:13px 24px;border-radius:18px;position:relative;cursor:pointer;
  transition:box-shadow .35s, transform .3s cubic-bezier(.22,1,.36,1);
  animation:var(--entree,fade) .8s cubic-bezier(.22,1,.36,1) both;
}
.row + .row::before{content:"";position:absolute;top:-1px;left:28px;right:28px;height:1.5px;border-radius:2px;
  background:linear-gradient(180deg, rgba(28,39,64,.045), rgba(255,255,255,.75));
  transition:opacity .3s}
.row:hover{
  background:var(--posed);
  box-shadow:var(--raise-sm);
  transform:translateY(-1px);z-index:2;
}
.row:hover::before, .row:hover + .row::before{opacity:0}
.rows .row:nth-child(1){animation-delay:.4s}.rows .row:nth-child(2){animation-delay:.44s}
.rows .row:nth-child(3){animation-delay:.48s}.rows .row:nth-child(4){animation-delay:.52s}
.rows .row:nth-child(5){animation-delay:.56s}.rows .row:nth-child(6){animation-delay:.6s}
.rows .row:nth-child(7){animation-delay:.64s}.rows .row:nth-child(8){animation-delay:.68s}
.rows .row:nth-child(9){animation-delay:.72s}.rows .row:nth-child(10){animation-delay:.76s}
.s-id{display:flex;align-items:center;gap:14px;min-width:0}
/* Le bloc texte du site est un enfant flex : sans `min-width:0` il refuse de
   descendre sous sa largeur de contenu, et les ellipses de `b` et `span`
   ne se déclenchent jamais. C'est le défaut classique du flex, et c'est ce
   qui laissait `.s-id` réclamer 247 px en fenêtre étroite. */
.s-id > div{min-width:0}
/* monogramme céramique : embossé, monochrome */
.fav{width:36px;height:36px;flex:none;border-radius:13px;display:grid;place-items:center;
  color:var(--ink-2);font-weight:600;font-size:12px;letter-spacing:.02em;
  background:var(--posed);
  box-shadow:var(--raise-sm);
  transition:transform .35s cubic-bezier(.34,1.56,.64,1), color .3s}
.row:hover .fav{transform:scale(1.07);color:var(--accent-ink)}
/* L'icône du site se pose DANS la pastille, elle ne la remplit pas : le relief
   du monogramme reste visible tout autour (Raphaël, 03/08). `contain` plutôt
   que `cover` : un logo rectangulaire ne doit pas se faire rogner. */
.fav img,.fav-xl img{width:100%;height:100%;border-radius:inherit;
  object-fit:contain;display:block}
.fav img{padding:6px}
.fav-xl img{padding:9px}
.s-id b{font-size:13.5px;font-weight:600;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.s-id span{font-size:11px;color:var(--ink-3);
  /* Sans ellipse, l'adresse + le constructeur + l'état imposaient 247 px au
     bloc du site — mesuré le 03/08 : il débordait sur la colonne voisine dès
     1000 px de fenêtre. Le nom au-dessus, lui, tronquait déjà. */
  display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tag{font-size:9.5px;font-weight:500;letter-spacing:.06em;color:var(--ink-3);margin-left:8px;
  text-transform:uppercase;vertical-align:1px}
/* LA SOUS-LIGNE DU SITE — TROIS LIGNES EMPILÉES, arbitrage de Raphaël le
   03/09/2026 : l'adresse, puis les qualifications, puis l'état, chacune sur sa
   ligne et toutes au MÊME bord gauche. La version du matin les avait mises à
   deux (adresse + qualifications, puis état) pour économiser 13 px ; il a
   demandé la pile, il choisit la hauteur, et c'est son écran d'accueil.
   ⚠️ C'est `.s-id span` ci-dessus (0,1,1) qui empile : il attrape CHACUN des
   spans de la sous-ligne, plus spécifique que `.tag` (0,1,0) et que `.st`
   (0,1,0), et les passe tous en `display:block`. C'est lui aussi qui donne son
   ellipse à l'adresse. Ce qui suit ne fait que rendre leur forme aux deux
   enfants que cette sur-portée écrase.
   ⚠️ AUCUNE INDENTATION SUR LA LIGNE DES QUALIFICATIONS. `.tag` porte
   `margin-left:8px`, hérité du temps où elle suivait l'adresse sur la même
   ligne ; une fois passée en début de ligne, ces 8 px deviennent une
   indentation fantôme — le décalage exact dont Raphaël s'est plaint le matin
   du 03/09 (pastille à x=300 quand l'adresse était à x=292). `.tag` elle-même
   n'est pas touchée : l'écran Perf & SEO s'en sert aussi.
   ⚠️ `flex-wrap:wrap` ici, alors qu'il avait été essayé PUIS ÉCARTÉ le matin :
   ce qui a changé, c'est que l'adresse a quitté cette ligne. Il repliait dès
   1600 px tant qu'elle la partageait ; seule, la paire ELEMENTOR + WOO tient
   jusqu'à 1024 px et ne se replie qu'à 1000, où elle demande 102,7 px pour
   79,1. Sans lui, WOO déborderait de 11,6 px sur la colonne voisine. Le repli
   coûte 13 px sur UNE ligne, à UNE largeur ; une qualification coupée ne veut
   plus rien dire, et un débordement encore moins. `row-gap` à zéro : les 8 px
   du `gap` sont un espacement entre mots, pas entre lignes.
   `overflow:hidden` est le filet du cas où une seule pastille serait plus
   large que la colonne : ça clipe chez nous, ça ne mord pas chez le voisin. */
.s-id .s-quals{display:flex;align-items:center;flex-wrap:wrap;gap:0 8px;
  min-width:0;overflow:hidden}
.s-id .s-quals > .tag{flex:none;margin-left:0}
/* ⚠️ Et la même sur-portée rendait la pastille d'état INVISIBLE : `.st`
   forcée en `display:block`, son `<i>` redevenait un inline, où `width` et
   `height` ne s'appliquent pas — le point de couleur faisait 0 × 0. Rendre
   son `display:flex` à `.st` le fait réapparaître. */
.s-id .st{display:flex}
.s-id .st-txt{min-width:0}
.h{display:flex;align-items:center;gap:10px}
.h .c{width:26px;height:26px;border-radius:50%;flex:none;position:relative;
  background:conic-gradient(var(--hc,#00c583) calc(var(--hv,90)*1%), #dfe4ed 0)}
.h .c::before{content:"";position:absolute;inset:3.5px;border-radius:50%;
  background:var(--posed);
  box-shadow:inset 0 1px 1px rgba(28,39,64,.07)}
.h b{font-size:12.5px;font-weight:600;min-width:26px;font-variant-numeric:tabular-nums}
.up{font-size:11.5px;color:var(--ink-2)}
/* statuts minimalistes : point + valeur */
.st{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--ink-2);font-weight:500}
.st i{width:5px;height:5px;border-radius:50%;flex:none}
.st.ok i{background:#00c583}
.st.w i{background:var(--warn)}
.st.d{color:#c13a54;font-weight:600}
.st.d i{background:var(--danger)}
.st.m{color:var(--ink-3);font-weight:400}
.st.m i{display:none}
/* L'asymétrie de `.st` est VOULUE pour un ÉTAT : `.st.ok` ne colore que sa
   pastille, `.st.d` colore tout son texte — au milieu de vingt lignes « en
   ligne », la panne doit crier. Elle devient un défaut quand `.st` sert à une
   COMPARAISON : sur /performance/{site}/mots-cles, mesuré le 03/08 sur 126
   mots-clés réels, 42 baisses sortaient en rouge gras contre 22 hausses en
   gris — l'œil lisait un effondrement là où un tiers des mots-clés montait.
   `kw` rétablit l'équilibre, et NULLE PART ailleurs : sur l'onglet Maintenance,
   `.st.ok` (« à jour ») est le cas normal de dizaines de lignes. */
.inv-row.kw .st.ok{color:var(--accent-ink);font-weight:600}
.lastc{font-size:11.5px;color:var(--ink-3);line-height:1.35;min-width:0}
.lastc b{display:block;font-size:12.5px;color:var(--ink-2);font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.go{width:30px;height:30px;border-radius:50%;display:grid;place-items:center;color:var(--ink-3);
  transition:all .35s;opacity:0}
.row:hover .go{opacity:1;background:var(--surface);box-shadow:var(--carve);color:var(--accent-ink)}
.row-empty{padding:36px 24px;text-align:center;color:var(--ink-3);font-size:12.5px}
.foot{display:flex;align-items:center;margin-top:22px;padding:0 26px;
  font-size:11.5px;color:var(--ink-3)}
.foot .r{margin-left:auto;font-family:'Spline Sans Mono';font-size:10px}
.foot .r-dim{color:var(--ink-3);margin-left:6px}

/* ═══ États : toast, apparitions ═══ */
.toast{position:fixed;left:50%;bottom:28px;transform:translateX(-50%);z-index:80;
  padding:12px 24px;border-radius:999px;font-size:12.5px;font-weight:600;color:var(--accent-ink);
  background:var(--posed);box-shadow:var(--raise);
  animation:toastIn .5s cubic-bezier(.22,1,.36,1) both, toastOut .5s 3.6s ease forwards}
.toast::before{content:"";width:7px;height:7px;border-radius:50%;display:inline-block;
  margin-right:9px;background:var(--accent);box-shadow:0 0 10px rgba(0,255,167,.6);vertical-align:1px}
@keyframes toastIn{from{opacity:0;transform:translate(-50%,16px)}to{opacity:1;transform:translate(-50%,0)}}
@keyframes toastOut{to{opacity:0;transform:translate(-50%,10px);visibility:hidden}}
@keyframes fade{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}

/* ═══ Responsive ═══ */
/* Le dock ne DISPARAÎT plus sous 1500 px : il se replie en bande d'icônes,
   collée au bord droit, et se déploie au survol ou au focus clavier — même
   principe que le menu de gauche. */
.rail-mini{display:none}

@media (max-width:1500px){
  .page{padding-right:96px}

  .rail{
    width:72px;padding:22px 0;overflow:hidden;
    border-radius:30px 0 0 30px;
    transition:width .55s cubic-bezier(.3,1.15,.35,1), padding .55s cubic-bezier(.3,1.15,.35,1);
  }
  .rail:hover,.rail:focus-within{width:296px;padding:28px 26px 24px}

  /* Replié : seule la bande d'icônes est visible. */
  .rail-mini{
    display:flex;flex-direction:column;align-items:center;gap:14px;
    opacity:1;transition:opacity .25s;
  }
  .rail > section,.rail > div:not(.rail-mini){
    opacity:0;pointer-events:none;transition:opacity .3s;
  }
  .rail:hover .rail-mini,.rail:focus-within .rail-mini{opacity:0;pointer-events:none;height:0;overflow:hidden}
  .rail:hover > section,.rail:focus-within > section,
  .rail:hover > div:not(.rail-mini),.rail:focus-within > div:not(.rail-mini){
    opacity:1;pointer-events:auto;
  }

  .rm{position:relative;width:40px;height:40px;border-radius:50%;flex:none;
    display:grid;place-items:center;color:var(--ink-3);text-decoration:none;
    background:var(--posed);box-shadow:var(--raise-sm)}
  a.rm:hover{color:var(--ink-1)}
  .rm svg{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:1.7;
    stroke-linecap:round;stroke-linejoin:round}
  .rm b{position:absolute;top:-3px;right:-3px;min-width:17px;height:17px;border-radius:999px;
    display:grid;place-items:center;font-size:10px;font-weight:700;padding:0 4px;
    background:var(--ink);color:#fff}
  .rm-go{color:var(--accent-ink)}
  .rm-go b{background:var(--accent-deep)}
  .rm-warn b{background:var(--warn)}
  .rm-alarm{color:#fff;background:linear-gradient(150deg,#e0405c,#c22740);
    box-shadow:0 0 0 4px rgba(224,64,92,.16);animation:pulse 1.8s ease-in-out infinite}
  .rm-more{color:var(--ink-3);box-shadow:none;background:transparent;margin-top:4px}
}

/* Sous 1100 px, le dock ne disparaissait plus DU TOUT — c'était l'accès
   unique à l'approbation, à « TOUT ARRÊTER » et à la bascule Simple/Avancé
   (revue d'interface 29/07). On garde la bande d'icônes visible jusqu'en
   bas, en la restant repliable au survol comme entre 1100 et 1500 px. */
@media (max-width:1100px){
  .rail{width:56px;padding:16px 0}
  .rail:hover,.rail:focus-within{width:296px;padding:28px 26px 24px}
  .page{padding-right:76px}
  .rm{width:36px;height:36px}
}
@media (max-width:1240px){
  .kpi-bar{grid-template-columns:repeat(3,1fr)}
  /* 6 colonnes : .hide-md en masque 2 sur les 8 (Vuln., Tickets), il reste
     site / santé / uptime / MAJ / intervention / flèche.

     ⚠️ Vrai aussi avec la colonne « Responsable » : elle porte `hide-md`, donc
     à ce point de rupture c'est 3 masquées sur 9, et il reste les mêmes six. */
  .cols,.row{grid-template-columns:2.2fr .85fr .7fr .5fr 1.6fr 36px}
  .hide-md{display:none}
}

/* En dessous de 1100 px, six colonnes ne tiennent plus : mesuré le 03/08 au
   navigateur, `.s-id` réclame 247 px et n'en recevait que 205 à 1000 px, 118 à
   800, 64 à 700 — le nom du site passait par-dessus la colonne suivante, et la
   page débordait en largeur. Uptime et « Dernière intervention » sortent donc à
   leur tour : ce sont les deux qui ne disent pas « agis maintenant ».
   Reste site / santé / MAJ / flèche. */
@media (max-width:1100px){
  .cols,.row{grid-template-columns:minmax(0,2.6fr) .9fr .6fr 36px}
  .hide-sm{display:none}
}

/* Sous 860 px, même quatre colonnes ne tiennent pas : la ligne cesse d'être une
   grille et devient un bloc. Le nom prend toute la largeur, l'état passe
   dessous, la flèche reste à droite. Rien n'est masqué de plus — c'est la
   disposition qui change, pas l'information. */
@media (max-width:860px){
  .cols{display:none}
  .row{grid-template-columns:minmax(0,1fr) auto auto 36px;gap:8px 10px;padding:14px 18px}
  .row .s-id{grid-column:1/-1}
}


.st.state{font-size:13px}
.st.state.ok{color:var(--accent-ink)}
.st.state.m i{display:block;background:var(--ink-3);opacity:.55}
.st.state i{width:6px;height:6px}


/* ── Approbations en attente (parcours P1 : approuver en 1 clic) ── */
.approvals h3{color:var(--accent-ink)}
.appr{display:flex;flex-direction:column;gap:10px;padding:13px 15px;margin-bottom:10px;
  border-radius:16px;background:var(--posed);box-shadow:var(--raise-sm)}
.appr-tx{min-width:0}
.appr-tx b,.appr-tx a{display:block;font-size:12.5px;font-weight:600;line-height:1.35;
  color:var(--ink-1);text-decoration:none}
.appr-tx a:hover{color:var(--accent-ink)}
.appr-tx span{font-size:11px;color:var(--ink-3)}
/* Ce qui ne se répare pas se confirme — même standard que « TOUT ARRÊTER ». */
.appr-ask{font-size:11.5px;line-height:1.5;color:#a33049;margin:-2px 0 0}
.appr-act{display:flex;gap:6px}
.appr-act .ok{flex:1}
.appr-act .ghost{color:var(--ink-3);padding:8px 11px;box-shadow:none;background:transparent}
.appr-act .ghost:hover{color:var(--ink-2);box-shadow:var(--raise-sm);background:var(--surface)}
.appr-act .no.confirm{flex:1;color:#fff;background:linear-gradient(150deg,#e0405c,#c22740)}
.appr-act button{border:0;cursor:pointer;font-family:inherit;font-size:11.5px;font-weight:600;
  border-radius:999px;padding:8px 12px;background:var(--posed);
  box-shadow:var(--raise-sm);transition:transform .2s,box-shadow .3s,color .2s}
.appr-act .ok{color:var(--accent-ink)}
.appr-act .no{color:var(--ink-3);padding:8px 11px}
.appr-act button:hover{transform:translateY(-1px)}
.appr-act button:active{box-shadow:var(--carve);transform:none}
.appr-act button:disabled{opacity:.5;cursor:default}


/* ═══════════════════════════════════════════════════════════════════════
   Pipeline de mise à jour (écran /pipelines/{task}) — proto A2 « Relief »
   Tout est portée par .pipeline pour ne rien déborder sur les autres écrans.
   ═══════════════════════════════════════════════════════════════════════ */
.pipeline .back{width:38px;height:38px;flex:none;border-radius:50%;display:grid;place-items:center;
  text-decoration:none;color:var(--ink-2);font-size:15px;
  background:var(--posed);box-shadow:var(--raise-sm);
  transition:transform .25s, box-shadow .3s, color .25s}
.pipeline .back:hover{transform:translateX(-2px);color:var(--accent-ink);box-shadow:var(--raise)}
.pipeline .back:active{transform:none;box-shadow:var(--carve)}
.pipeline h1{font-size:26px}
.pipeline .live{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--ink-2);
  padding:10px 18px;border-radius:999px;background:var(--surface);box-shadow:var(--carve);white-space:nowrap}
.pipeline .live i{width:6px;height:6px;border-radius:50%;background:#00d68c;
  box-shadow:0 0 8px 1px rgba(0,230,150,.55);animation:pulse 3s infinite}

/* ── Panneaux sculptés ── */
.pipeline .panel{background:var(--posed);
  border-radius:28px;box-shadow:var(--raise);padding:24px 26px;margin-bottom:22px;
  animation:var(--entree,fade) .9s .18s cubic-bezier(.22,1,.36,1) both}
.pipeline .panel h2{font-family:'Clash Display';font-size:15px;font-weight:600;letter-spacing:.06em;
  text-transform:uppercase;white-space:nowrap;flex:none}
.pipeline .p-head{display:flex;align-items:center;gap:12px;margin-bottom:18px;flex-wrap:wrap}
.pipeline .p-head .mono{margin-left:auto;font-size:10.5px;color:var(--ink-3)}
.pipeline .chip{font-size:9.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  padding:5px 11px;border-radius:999px;background:var(--surface);box-shadow:var(--carve);
  color:var(--ink-2);display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.pipeline .chip.ok,.pipeline .chip.run{color:var(--accent-ink)}
.pipeline .chip.run i{width:5px;height:5px;border-radius:50%;background:#00d68c;
  box-shadow:0 0 7px rgba(0,230,150,.55);animation:pulse 2.2s infinite}
.pipeline .chip.sec{color:#b06a10;margin-left:8px}
.pipeline .chip.ko{color:#c13a54}
.pipeline .chip.mut{color:var(--ink-3)}

/* ── Où on en est : la phrase, puis le geste ── */
.pipeline .now-panel{animation-delay:.1s}
.pipeline .headline{font-size:17px;line-height:1.5;font-weight:700;max-width:74ch}
.pipeline .blocker{margin-top:10px;font-size:13px;line-height:1.55;color:var(--ink-2);max-width:74ch}
.pipeline .btns{display:flex;gap:12px;margin-top:18px;flex-wrap:wrap}
.pipeline .pl-appr .btns{flex-direction:column}
.pipeline .btn{display:inline-flex;align-items:center;justify-content:center;gap:9px;
  padding:13px 22px;border-radius:999px;border:0;font-family:inherit;cursor:pointer;
  font-size:13px;font-weight:700;color:var(--ink-2);
  background:var(--posed);box-shadow:var(--raise-sm);
  transition:transform .25s, box-shadow .3s, color .25s}
.pipeline .btn svg{width:15px;height:15px;flex:none;stroke:currentColor;fill:none;
  stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.pipeline .btn:hover{transform:translateY(-2px);color:var(--accent-ink);box-shadow:var(--raise)}
.pipeline .btn:active{transform:none;box-shadow:var(--carve)}
.pipeline .btn.deploy:not(:disabled){color:var(--accent-ink)}
.pipeline .btn.refuse{color:var(--ink-3)}
.pipeline .btn:disabled{background:var(--surface);box-shadow:var(--carve);color:var(--ink-3);
  cursor:not-allowed;font-weight:600;transform:none}
.pipeline .btn:disabled:hover{transform:none;color:var(--ink-3);box-shadow:var(--carve)}

/* ── Stepper : 9 étapes gravées dans une pièce ── */
.pipeline .pipe{animation-delay:.22s}
.pipeline .steps-wrap{overflow-x:auto;margin:0 -8px;padding:0 8px}
.pipeline .steps-wrap::-webkit-scrollbar{display:none}
.pipeline .steps{display:grid;grid-template-columns:repeat(9,1fr);min-width:900px}
.pipeline .step{position:relative;display:flex;flex-direction:column;align-items:center;gap:9px;
  padding:14px 6px 4px;text-align:center}
.pipeline .step:not(:first-child)::before{content:"";position:absolute;top:30px;height:3px;border-radius:3px;
  left:calc(-50% + 25px);right:calc(50% + 25px);
  background:#dfe4ed;box-shadow:inset 0 1px 2px rgba(28,39,64,.08)}
.pipeline .step.done:not(:first-child)::before,.pipeline .step.now::before{
  background:linear-gradient(90deg,#00d68c,var(--accent));box-shadow:0 0 8px rgba(0,255,167,.45)}
.pipeline .step.ko::before{background:linear-gradient(90deg,#e07f92,var(--danger))}
.pipeline .step .n{position:relative;width:34px;height:34px;border-radius:50%;display:grid;place-items:center;
  transition:transform .35s cubic-bezier(.34,1.56,.64,1)}
.pipeline .step:hover .n{transform:scale(1.1)}
.pipeline .step.done .n,.pipeline .step.now .n,.pipeline .step.ko .n,.pipeline .step.skip .n{
  background:var(--posed);box-shadow:var(--raise-sm)}
.pipeline .step .n svg{width:14px;height:14px;fill:none;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
.pipeline .step.done .n svg{stroke:var(--accent-ink)}
.pipeline .step.ko .n svg{stroke:var(--danger)}
.pipeline .step.now .n::after{content:"";position:absolute;inset:0;border-radius:50%;
  box-shadow:0 0 0 0 rgba(0,255,167,.45);animation:ping 2.4s infinite}
.pipeline .step.now .n i{width:10px;height:10px;border-radius:50%;background:var(--accent);
  box-shadow:0 0 12px 2px rgba(0,255,167,.55);animation:pulse 2.6s infinite}
.pipeline .step.todo .n{background:var(--surface);box-shadow:var(--carve);
  font-family:'Spline Sans Mono';font-size:11px;color:var(--ink-3)}
.pipeline .step b{font-size:11px;font-weight:600;line-height:1.25;color:var(--ink-2)}
.pipeline .step.now b{color:var(--ink);font-weight:700}
.pipeline .step.todo b{color:var(--ink-3);font-weight:500}
.pipeline .step.ko b{color:#c13a54}
.pipeline .step .tm{font-family:'Spline Sans Mono';font-size:9.5px;color:var(--ink-3)}
.pipeline .step.now .tm{color:var(--accent-ink)}

/* ── Corps : étape courante + colonne latérale ── */
.pipeline .pl-main{display:grid;grid-template-columns:1.5fr 1fr;gap:22px;align-items:start}
.pipeline .stage-panel{animation-delay:.3s}
.pipeline .stage-desc{font-size:13.5px;line-height:1.6;color:var(--ink-2);max-width:70ch}
.pipeline .stage-detail{margin-top:10px;font-size:12.5px;line-height:1.55;color:var(--ink-3);max-width:70ch}
.pipeline .stage-list{margin-top:2px}
.pipeline .stage-desc + .stage-list,.pipeline .stage-detail + .stage-list{margin-top:18px}
.pipeline .stage{display:flex;align-items:flex-start;gap:13px;padding:12px 8px;border-radius:14px;
  position:relative;transition:background .3s}
.pipeline .stage + .stage::before{content:"";position:absolute;top:0;left:16px;right:8px;height:1px;
  background:linear-gradient(180deg, rgba(28,39,64,.05), rgba(255,255,255,.7))}
.pipeline .stage:hover{background:rgba(255,255,255,.35)}
.pipeline .stage .sn{font-size:10px;color:var(--ink-3);padding-top:3px;flex:none}
.pipeline .stage.done .sn{color:var(--accent-ink)}
.pipeline .stage .sx{min-width:0;flex:1}
.pipeline .stage .sx b{font-size:12.5px;font-weight:700;display:flex;align-items:center;gap:8px}
.pipeline .stage.todo .sx b{font-weight:500;color:var(--ink-3)}
.pipeline .stage .sd{display:block;margin-top:3px;font-size:11.5px;line-height:1.5;color:var(--ink-3)}
.pipeline .arts{display:flex;flex-wrap:wrap;gap:6px;margin-top:7px}
.pipeline .art{font-size:9.5px;color:var(--ink-2);padding:4px 9px;border-radius:999px;
  background:var(--surface);box-shadow:var(--carve)}
/* Le geste d'une étape (entretenir 35) : ce que Raphaël fait. Il empruntait
   `.art`, la pastille de 9,5 px d'un lien d'artefact ; un renvoi ou une
   commande se lit à la taille de la phrase qui le porte, et la commande se
   sélectionne d'un clic pour être recopiée (socle 34). */
.pipeline .geste{font:inherit;color:inherit}
.pipeline a.geste{color:var(--accent-ink);font-weight:600;text-decoration:none}
.pipeline a.geste:hover{text-decoration:underline}
.pipeline .geste code{display:inline-block;margin-top:4px;font-size:11.5px;line-height:1.5;color:var(--ink);
  padding:3px 9px;border-radius:9px;background:var(--surface);box-shadow:var(--carve);
  user-select:all;overflow-wrap:anywhere}
/* Le retour arrière d'un passage qui a pu écrire en production : un bouton, et
   ce qu'il fait dit à côté (socle 34). */
.pipeline .retour{display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;margin-top:14px}
.pipeline .retour .btn{color:var(--accent-ink)}
.pipeline .retour .quoi{font-size:12px;line-height:1.5;color:var(--ink-3);max-width:62ch}
.pipeline .stage .stm{flex:none;font-size:9.5px;color:var(--ink-3);padding-top:3px;text-align:right}

/* ── Les écarts d'une comparaison visuelle ──────────────────────────────────
   Un écart ne se replie pas : c'est un signal, et le premier geste devant lui
   est d'aller voir la page. Les deux liens (copie et production) sont donc au
   même niveau que le chiffre, pas cachés derrière une poignée. */
.pipeline .ecarts{margin-top:18px;display:flex;flex-direction:column;gap:10px}
.pipeline .ecart{padding:13px 15px;border-radius:14px;background:var(--surface);box-shadow:var(--carve)}
/* La reprise d'un passage dont TOUS les écarts sont identiques à des décisions
   passées : il n'y a plus de bouton dans aucune carte, donc plus de porte de
   sortie sans celle-ci (08/09/2026). */
.pipeline .ecart-reprise{margin-top:14px;display:flex;flex-wrap:wrap;align-items:center;gap:10px}
.pipeline .ecart-reprise .mono{font-size:10px;color:var(--ink-3)}
.pipeline .ecart b{font-size:12.5px;font-weight:700;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.pipeline .ecart .ecart-pc{font-size:10.5px;color:#c13a54}
.pipeline .ecart .ecart-h{font-size:10px;color:var(--ink-3)}
.pipeline .ecart .ecart-go{display:flex;flex-wrap:wrap;gap:6px;margin-top:9px}
.pipeline .ecart .ecart-ia{display:flex;align-items:center;gap:11px;flex-wrap:wrap;margin-top:11px}
.pipeline .ecart .ecart-ia .btn{padding:8px 15px;font-size:11.5px}
.pipeline .ecart .ecart-prix{font-size:10px;color:var(--ink-3)}
.pipeline .ecart .ecart-avis{display:block;margin-top:11px;padding:11px 13px;border-radius:12px;
  background:var(--posed);box-shadow:var(--carve);font-size:12px;line-height:1.55;color:var(--ink-2)}
.pipeline .ecart .ecart-avis b{display:block;font-size:11.5px;margin-bottom:4px}
.pipeline .ecart .ecart-avis em{display:block;margin-top:6px;font-style:normal;font-size:11px;color:var(--ink-3)}
.pipeline .ecart .ecart-avis .ecart-src{font-size:10px;line-height:1.5}
.pipeline .ecart .ecart-avis.ko b{color:#c13a54}

/* ── Colonne : mises à jour + approbation ── */
.pipeline .pl-side{display:flex;flex-direction:column}
.pipeline .maj-panel{animation-delay:.36s}
.pipeline .maj{display:flex;align-items:center;gap:13px;padding:11px 6px;border-radius:14px;position:relative;
  transition:background .3s}
.pipeline .maj + .maj::before{content:"";position:absolute;top:0;left:16px;right:8px;height:1px;
  background:linear-gradient(180deg, rgba(28,39,64,.05), rgba(255,255,255,.7))}
.pipeline .maj:hover{background:rgba(255,255,255,.35)}
.pipeline .maj .fav{width:34px;height:34px;border-radius:12px;font-size:11px}
.pipeline .maj .maj-x{min-width:0;flex:1}
.pipeline .maj .maj-x b{font-size:12.5px;font-weight:700;display:flex;align-items:center;gap:4px}
.pipeline .maj .maj-x .maj-v{font-size:10.5px;color:var(--ink-3);display:block;margin-top:2px}
.pipeline .maj .maj-x .maj-v em{font-style:normal;color:var(--accent-ink)}
.pipeline .maj .st{flex:none;font-size:11.5px}
.pipeline .maj .st .mono{font-size:10px;color:var(--ink-3);margin-left:6px}

.pipeline .pl-appr{animation-delay:.44s}
.pipeline .pl-appr .hint{font-size:12.5px;color:var(--ink-2);line-height:1.55;margin:-6px 0 14px}
.pipeline .pre{display:flex;align-items:center;gap:11px;padding:8px 4px;font-size:12.5px;color:var(--ink-2)}
.pipeline .pre .pi{width:22px;height:22px;flex:none;border-radius:50%;display:grid;place-items:center;
  background:var(--surface);box-shadow:var(--carve)}
.pipeline .pre.done .pi{background:var(--posed);box-shadow:var(--raise-sm)}
.pipeline .pre.done .pi svg{width:11px;height:11px;stroke:var(--accent-ink);fill:none;stroke-width:2.4;
  stroke-linecap:round;stroke-linejoin:round}
.pipeline .pre.now .pi i{width:7px;height:7px;border-radius:50%;background:var(--accent);
  box-shadow:0 0 9px 1px rgba(0,255,167,.55);animation:pulse 2.4s infinite}
.pipeline .pre.now{color:var(--ink);font-weight:600}
.pipeline .pre.todo{color:var(--ink-3)}
.pipeline .pre.ko{color:#c13a54;font-weight:600}
.pipeline .pre .mono{margin-left:auto;font-size:10px;color:var(--ink-3)}
.pipeline .appr-foot{font-size:11px;color:var(--ink-3);line-height:1.6;margin-top:15px;
  display:flex;gap:8px;align-items:flex-start}
.pipeline .appr-foot svg{width:13px;height:13px;flex:none;margin-top:2px;stroke:var(--ink-3);fill:none;
  stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}

.pipeline .foot{animation:var(--entree,fade) .9s .55s cubic-bezier(.22,1,.36,1) both}

@media (max-width:1240px){
  .pipeline .pl-main{grid-template-columns:1fr}
}
@media (max-width:980px){
  .pipeline .live{display:none}
  .pipeline .top{flex-wrap:wrap}
}


/* ═══════════════════════════════════════════════════════════════════════
   Écran « Inbox tickets » (livewire.tickets.inbox)
   Source visuelle : design/propositions/screens/inbox-tickets.html
   ═══════════════════════════════════════════════════════════════════════ */

/* La page tient dans l'écran : ce sont la file et le fil qui défilent. */
.inbox-page{height:100vh;display:flex;flex-direction:column;padding-bottom:26px}
.inbox-page .top{margin-bottom:24px;flex:none}
.inbox-page .top .search{margin-left:14px;width:260px}
.inbox-page .inbox{flex:1;min-height:0;display:grid;grid-template-columns:356px minmax(0,1fr);gap:26px}

/* ── Colonne gauche : file de tickets ── */
.inbox-page .queue{display:flex;flex-direction:column;min-height:0;
  animation:var(--entree,fade) .9s .2s cubic-bezier(.22,1,.36,1) both}
.inbox-page .q-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:10px;margin-bottom:12px;padding:0 8px;flex:none}
.inbox-page .q-head h2{font-family:'Clash Display';font-size:16px;font-weight:600;letter-spacing:.06em;text-transform:uppercase}
.inbox-page .q-head .mono{margin-left:auto;font-size:10px;color:var(--ink-3)}
.inbox-page .q-head .filters{flex-basis:100%;margin-left:0;flex-wrap:wrap;gap:3px}
.inbox-page .q-head .f{font-size:11.5px;padding:5px 11px}
.inbox-page .tlist{flex:1;min-height:0;overflow-y:auto;padding:4px 8px 20px 4px;
  scrollbar-width:thin;scrollbar-color:rgba(28,39,64,.14) transparent}
.inbox-page .tlist::-webkit-scrollbar{width:6px}
.inbox-page .tlist::-webkit-scrollbar-thumb{background:rgba(28,39,64,.12);border-radius:99px}
.inbox-page .tk{display:block;padding:15px 18px 14px 24px;border-radius:18px;position:relative;cursor:pointer;
  transition:box-shadow .35s, transform .3s cubic-bezier(.22,1,.36,1);
  animation:var(--entree,fade) .8s cubic-bezier(.22,1,.36,1) both}
.inbox-page .tk + .tk::before{content:"";position:absolute;top:-1px;left:26px;right:26px;height:1.5px;border-radius:2px;
  background:linear-gradient(180deg, rgba(28,39,64,.045), rgba(255,255,255,.75));transition:opacity .3s}
.inbox-page .tk:hover{background:var(--posed);box-shadow:var(--raise-sm);
  transform:translateY(-1px);z-index:2}
.inbox-page .tk:hover::before, .inbox-page .tk:hover + .tk::before{opacity:0}
/* sélectionné : pressé dans la céramique, liseré accent */
.inbox-page .tk.sel{background:var(--surface);box-shadow:var(--carve);transform:none;z-index:1}
.inbox-page .tk.sel::before, .inbox-page .tk.sel + .tk::before{opacity:0}
.inbox-page .tk.sel::after{content:"";position:absolute;left:10px;top:20px;bottom:20px;width:3px;border-radius:4px;
  background:linear-gradient(180deg,#00d68c,var(--accent));box-shadow:0 0 9px rgba(0,255,167,.55)}
.inbox-page .tlist .tk:nth-child(1){animation-delay:.34s}.tlist .tk:nth-child(2){animation-delay:.39s}
.inbox-page .tlist .tk:nth-child(3){animation-delay:.44s}.tlist .tk:nth-child(4){animation-delay:.49s}
.inbox-page .tlist .tk:nth-child(5){animation-delay:.54s}.tlist .tk:nth-child(6){animation-delay:.59s}
.inbox-page .tk .l1{display:flex;align-items:center;gap:8px;margin-bottom:6px}
.inbox-page .tk .id{font-family:'Spline Sans Mono';font-size:10.5px;color:var(--ink-3)}
.inbox-page .tk .age{margin-left:auto;font-family:'Spline Sans Mono';font-size:10px;color:var(--ink-3);white-space:nowrap}
.inbox-page .tk .sub{display:block;font-size:13.5px;font-weight:600;line-height:1.3;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.inbox-page .tk .site{font-size:11px;color:var(--ink-2);margin-top:3px}
.inbox-page .tk .site span{color:var(--ink-3)}
.inbox-page .tk .site a{color:inherit;text-decoration:none;border-bottom:1px dotted transparent}
.inbox-page .tk .site a:hover{color:var(--accent-ink);border-bottom-color:currentColor}
.inbox-page .tk .ex{font-size:11.5px;color:var(--ink-3);line-height:1.45;margin-top:6px;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.inbox-page .tk .l4{display:flex;align-items:center;gap:8px;margin-top:9px}
/* tickets résolus : assourdis */
.inbox-page .tk.done{opacity:.68;transition:opacity .3s, box-shadow .35s, transform .3s cubic-bezier(.22,1,.36,1)}
.inbox-page .tk.done:hover{opacity:1}
.inbox-page .tk.done .sub{font-weight:500;color:var(--ink-2)}
.inbox-page .q-empty{padding:32px 18px;text-align:center;color:var(--ink-3);font-size:12.5px}
.inbox-page .q-foot{flex:none;padding:14px 10px 0;font-size:11px;color:var(--ink-3);line-height:1.6;
  animation:var(--entree,fade) .8s .6s cubic-bezier(.22,1,.36,1) both}
.inbox-page .q-foot .mono{font-size:10px}

/* classification IA : petit chip discret */
.inbox-page .chip{font-size:9.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  padding:3px 9px;border-radius:999px;line-height:1.4;white-space:nowrap}
.inbox-page .chip.bug{color:#c13a54;background:rgba(232,90,116,.11)}
.inbox-page .chip.evo{color:var(--accent-ink);background:rgba(0,214,140,.13)}
.inbox-page .chip.cnt{color:#a4691c;background:rgba(227,160,42,.14)}
.inbox-page .chip.qst{color:var(--ink-2);background:rgba(28,39,64,.06)}
/* urgence : point coloré */
.inbox-page .urg{width:7px;height:7px;border-radius:50%;flex:none;display:inline-block}
.inbox-page .urg.low{background:#c6cedd}
.inbox-page .urg.normal{background:#00c583}
.inbox-page .urg.high{background:var(--warn);box-shadow:0 0 0 0 rgba(227,160,42,.4);animation:ping 2.6s infinite}
.inbox-page .urg.critical{background:var(--danger);box-shadow:0 0 0 0 rgba(232,90,116,.4);animation:ping 2.4s infinite}
/* sur qui la balle est */
.inbox-page .mini{display:flex;align-items:center;gap:6px;font-size:10.5px;font-weight:500;color:var(--ink-2);min-width:0}
.inbox-page .mini i{width:5px;height:5px;border-radius:50%;flex:none}
.inbox-page .mini.wait i{background:var(--warn)}
.inbox-page .mini.client i{background:#7f8fb0}
.inbox-page .mini.new i{background:#00c583}
.inbox-page .mini.done{color:var(--ink-3)}
.inbox-page .mini.done i{background:#c6cedd}
/* badge « à propager sur la flotte » */
.inbox-page .pbk{margin-left:auto;display:flex;align-items:center;gap:5px;font-size:9.5px;font-weight:700;
  letter-spacing:.06em;text-transform:uppercase;color:var(--accent-ink);flex:none;
  padding:3px 9px;border-radius:999px;background:var(--surface);box-shadow:var(--carve)}
.inbox-page .pbk svg{width:10px;height:10px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

/* ── Colonne droite : fil de conversation ── */
.inbox-page .thread{display:flex;flex-direction:column;min-height:0;border-radius:28px;
  background:var(--posed);box-shadow:var(--raise);
  animation:var(--entree,fade) .9s .3s cubic-bezier(.22,1,.36,1) both}
.inbox-page .th-empty{margin:auto;padding:40px;text-align:center;color:var(--ink-3);font-size:13px}
.inbox-page .th-hint{margin:16px 28px 8px;padding:12px 16px;border-radius:14px;background:var(--surface);box-shadow:var(--carve);
  font-size:12px;color:var(--ink-3);line-height:1.55}
.inbox-page .th-hint b{color:var(--ink-2)}
.inbox-page .th-head{flex:none;padding:22px 28px 18px;position:relative}
.inbox-page .th-head::after{content:"";position:absolute;left:22px;right:22px;bottom:0;height:1.5px;border-radius:2px;
  background:linear-gradient(180deg, rgba(28,39,64,.07), rgba(255,255,255,.9))}
.inbox-page .th-row{display:flex;align-items:center;gap:12px}
.inbox-page .th-row h2{font-family:'Clash Display';font-size:17px;font-weight:600;letter-spacing:.04em;
  text-transform:uppercase;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.inbox-page .th-row h2 .id{font-family:'Spline Sans Mono';font-size:12px;font-weight:400;color:var(--ink-3);
  letter-spacing:0;margin-right:10px;vertical-align:2px}
.inbox-page .th-meta{display:flex;align-items:center;gap:10px;margin-top:10px;flex-wrap:wrap}
.inbox-page .th-meta .m{font-size:12px;color:var(--ink-2)}
.inbox-page .th-meta .m b{font-weight:600;color:var(--ink)}
.inbox-page .th-meta .urg-m{display:flex;align-items:center;gap:6px}
.inbox-page .th-meta .sep{width:3px;height:3px;border-radius:50%;background:var(--ink-3);opacity:.6}
/* Site à identifier : sélecteur juste à côté du blocage nommé, pour que le
   geste et sa raison partagent la même ligne. */
.inbox-page .tk-attach{display:inline-flex;align-items:center;gap:8px;font-size:12px;color:var(--ink-3)}
.inbox-page .tk-attach select{font-family:inherit;font-size:12px;font-weight:500;color:var(--ink-2);
  border:0;outline:none;cursor:pointer;padding:6px 12px;border-radius:999px;
  background:var(--surface);box-shadow:var(--carve)}
/* Le nom du site cité dans un ticket est un lien vers sa fiche — comme sur
   l'écran Perf. Sans cela, on voit le site mais on ne peut pas y aller. */
.inbox-page a.tk-site-link{color:inherit;text-decoration:none}
.inbox-page a.tk-site-link:hover b{color:var(--accent-ink)}

/* Bouton « + Nouveau » (saisie manuelle) — au niveau du filtre. */
.inbox-page .q-new{margin-left:6px}

/* Formulaire de saisie manuelle : dans le panneau de droite, à la place du
   fil. Reprend les tokens des autres formulaires du hub. */
.inbox-page .tk-new-form{padding:22px 28px;display:flex;flex-direction:column;gap:18px}
.inbox-page .tk-new-form .field{display:flex;flex-direction:column;gap:8px}
.inbox-page .tk-new-form .field-lbl{font-size:10.5px;font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3)}
.inbox-page .tk-new-form input,
.inbox-page .tk-new-form select,
.inbox-page .tk-new-form textarea{
  width:100%;padding:13px 16px;border:0;outline:none;border-radius:16px;
  font:inherit;font-size:13.5px;color:var(--ink);
  background:var(--surface);box-shadow:var(--carve);
  transition:box-shadow .3s;
}
.inbox-page .tk-new-form textarea{line-height:1.55;resize:vertical;min-height:120px}
.inbox-page .tk-new-form input:focus,
.inbox-page .tk-new-form select:focus,
.inbox-page .tk-new-form textarea:focus{box-shadow:var(--carve), 0 0 0 2px rgba(0,255,167,.35)}
.inbox-page .tk-new-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
@media (max-width:960px){.inbox-page .tk-new-grid{grid-template-columns:1fr}}
/* pastille d'état du ticket */
.inbox-page .thread .state{margin-left:auto;flex:none;display:flex;align-items:center;gap:7px;
  font-size:11px;font-weight:700;letter-spacing:.04em;color:#a4691c;
  padding:8px 15px;border-radius:999px;background:var(--surface);box-shadow:var(--carve);
  transition:color .4s}
.inbox-page .thread .state i{width:6px;height:6px;border-radius:50%;background:var(--warn);animation:pulse 3s infinite;transition:background .4s}
.inbox-page .thread .state.ok{color:var(--accent-ink)}
.inbox-page .thread .state.ok i{background:#00d68c;animation:none;box-shadow:0 0 8px rgba(0,230,150,.5)}
/* bascule « à propager sur la flotte » */
.inbox-page .pb-btn{flex:none;margin-left:auto;display:flex;align-items:center;gap:9px;padding:9px 15px;border:0;cursor:pointer;
  font-family:inherit;font-size:12px;font-weight:700;color:var(--ink-2);text-align:left;
  border-radius:999px;background:var(--posed);box-shadow:var(--raise-sm);
  transition:transform .25s, box-shadow .3s, color .25s}
.inbox-page .pb-btn svg{width:14px;height:14px;flex:none;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.inbox-page .pb-btn .n{font-family:'Spline Sans Mono';font-size:9.5px;font-weight:400;color:var(--ink-3);
  padding:2px 7px;border-radius:999px;background:var(--surface);box-shadow:var(--carve)}
.inbox-page .pb-btn:hover{transform:translateY(-1px);box-shadow:var(--raise)}
.inbox-page .pb-btn:active{transform:none;box-shadow:var(--carve)}
.inbox-page .pb-btn.tagged{color:var(--accent-ink);box-shadow:var(--carve)}
.inbox-page .pb-btn.tagged .n{color:var(--accent-ink)}

.inbox-page .th-scroll{flex:1;min-height:0;overflow-y:auto;padding:24px 28px 12px;
  scrollbar-width:thin;scrollbar-color:rgba(28,39,64,.14) transparent}
.inbox-page .th-scroll::-webkit-scrollbar{width:6px}
.inbox-page .th-scroll::-webkit-scrollbar-thumb{background:rgba(28,39,64,.12);border-radius:99px}
.inbox-page .th-scroll>*{animation:var(--entree,fade) .8s cubic-bezier(.22,1,.36,1) both}
.inbox-page .th-scroll>*:nth-child(1){animation-delay:.4s}
.inbox-page .th-scroll>*:nth-child(2){animation-delay:.48s}
.inbox-page .th-scroll>*:nth-child(3){animation-delay:.56s}
.inbox-page .th-scroll>*:nth-child(4){animation-delay:.64s}
.inbox-page .th-scroll>*:nth-child(5){animation-delay:.72s}

/* ── Mode simple : les trois questions qui comptent ── */
.inbox-page .recap{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;margin-bottom:22px}
.inbox-page .recap>div{padding:15px 17px;border-radius:18px;background:var(--surface);box-shadow:var(--carve)}
.inbox-page .recap span{display:block;font-size:9.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--ink-3);margin-bottom:9px}
.inbox-page .recap p{font-size:12.5px;line-height:1.55;color:var(--ink)}
.inbox-page .recap em{display:block;font-style:normal;font-size:10.5px;color:var(--ink-3);margin-top:7px}
.inbox-page .recap p.w-client{color:#7f8fb0;font-weight:600}
.inbox-page .recap p.w-wait, .inbox-page .recap p.w-new{color:#a4691c;font-weight:600}
.inbox-page .recap p.w-done{color:var(--accent-ink);font-weight:600}

/* ── Bloc triage IA : céramique sombre, distincte ── */
.inbox-page .triage{margin:0 0 22px;border-radius:20px;padding:20px 24px 18px;color:rgba(255,255,255,.82);
  background:linear-gradient(155deg,#155054,#0e393c);
  box-shadow:10px 16px 36px rgba(10,45,48,.28), inset 0 1px 0 rgba(255,255,255,.12)}
.inbox-page .triage header{display:flex;align-items:center;gap:10px;margin-bottom:16px}
.inbox-page .triage header svg{width:15px;height:15px;stroke:var(--accent);fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.inbox-page .triage header b{font-family:'Clash Display';font-size:11px;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;color:var(--accent)}
.inbox-page .tri-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
.inbox-page .tri-grid>div{padding:11px 14px;border-radius:13px;background:rgba(255,255,255,.05);
  box-shadow:inset 2px 3px 7px rgba(0,0,0,.28), inset -1px -1px 3px rgba(255,255,255,.07)}
.inbox-page .tri-grid span{display:block;font-family:'Spline Sans Mono';font-size:9px;letter-spacing:.12em;
  text-transform:uppercase;color:rgba(255,255,255,.42);margin-bottom:6px}
.inbox-page .tri-grid b{font-size:13px;font-weight:700;color:#fff}
.inbox-page .tri-grid b.hi{color:var(--warn)}
.inbox-page .tri-grid b.ac{color:var(--accent)}
.inbox-page .tri-cause{font-size:12.5px;line-height:1.55;color:rgba(255,255,255,.78);margin-top:16px}
.inbox-page .tri-cause b{color:#fff;font-weight:700}

/* ── Cadrage : verdict forfait/devis dans le fil du ticket ──
   Trois tons : compris (vert), devis à préparer (accent), à trancher (jaune).
   Pas un bloc criant : c'est une décision RENDUE, pas un appel à l'action. */
.inbox-page .scoping{margin:0 0 22px;padding:14px 18px;border-radius:18px;
  background:var(--surface);box-shadow:var(--carve);border-left:3px solid var(--ink-3)}
.inbox-page .scoping.s-included{border-color:#00c583}
.inbox-page .scoping.s-uncertain{border-color:var(--warn)}
.inbox-page .scoping header{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;margin-bottom:6px}
.inbox-page .scoping header b{font-size:12.5px;font-weight:700;color:var(--ink)}
.inbox-page .scoping p{font-size:12px;color:var(--ink-2);line-height:1.5;margin:0}
.inbox-page .scoping .mono{margin-top:8px;font-family:'Spline Sans Mono';font-size:10px;
  color:var(--ink-3);letter-spacing:.02em}

/* ── Double validation : lecture seule ── */
.inbox-page .valid{margin-bottom:22px;padding:14px 18px;border-radius:18px;background:var(--surface);box-shadow:var(--carve)}
.inbox-page .valid>span{display:block;font-size:9.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--ink-3);margin-bottom:10px}
.inbox-page .valid .v{display:flex;align-items:center;gap:9px;font-size:12.5px;color:var(--ink-2);padding:3px 0}
.inbox-page .valid .v i{width:6px;height:6px;border-radius:50%;flex:none;background:var(--warn)}
.inbox-page .valid .v.ok{color:var(--accent-ink)}
.inbox-page .valid .v.ok i{background:#00d68c;box-shadow:0 0 8px rgba(0,230,150,.5)}

/* ── Messages ── */
.inbox-page .msg{display:flex;gap:14px;margin-bottom:22px}
.inbox-page .mav{width:38px;height:38px;flex:none;border-radius:14px;display:grid;place-items:center;
  color:var(--ink-2);font-weight:700;font-size:12px;letter-spacing:.02em;
  background:var(--posed);box-shadow:var(--raise-sm)}
.inbox-page .mav.ia{background:linear-gradient(155deg,#155054,#0e393c);
  box-shadow:5px 8px 20px rgba(10,45,48,.25), inset 0 1px 0 rgba(255,255,255,.14)}
.inbox-page .mav.ia::before{content:"";width:9px;height:9px;border-radius:50%;background:var(--accent);
  box-shadow:0 0 12px 2px rgba(0,255,167,.5)}
.inbox-page .mbody{min-width:0;flex:1}
.inbox-page .mh{display:flex;align-items:baseline;gap:9px;margin-bottom:8px;flex-wrap:wrap}
.inbox-page .mh b{font-size:13px;font-weight:700}
.inbox-page .mh .who{font-size:11.5px;color:var(--ink-2)}
.inbox-page .mh .via{font-size:10.5px;color:var(--ink-3)}
.inbox-page .mh .mt{margin-left:auto;font-size:10px;color:var(--ink-3)}
.inbox-page .bubble{border-radius:18px;padding:16px 20px;font-size:13px;line-height:1.6;color:var(--ink);
  background:var(--posed);box-shadow:var(--raise-sm)}
.inbox-page .bubble p + p{margin-top:10px}
/* note interne : gravée, jamais envoyée au client */
.inbox-page .msg.note .mav{color:var(--ink-3);background:var(--surface);box-shadow:var(--carve)}
.inbox-page .bubble.noteb{background:var(--surface);box-shadow:var(--carve);color:var(--ink-2);
  border-left:3px solid rgba(227,160,42,.5)}
.inbox-page .pill{font-size:9.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  padding:3px 10px;border-radius:999px}
.inbox-page .pill.wait{color:#a4691c;background:rgba(227,160,42,.14)}
.inbox-page .pill.ok{color:var(--accent-ink);background:rgba(0,214,140,.14)}

/* ── Actions sur le ticket ── */
.inbox-page .th-actions{flex:none;display:flex;align-items:center;flex-wrap:wrap;gap:10px;padding:14px 28px 0}
.inbox-page .btn{display:flex;align-items:center;gap:8px;padding:10px 18px;border:0;cursor:pointer;
  font-family:inherit;font-size:12.5px;font-weight:700;color:var(--ink-2);
  border-radius:999px;background:var(--posed);box-shadow:var(--raise-sm);
  transition:transform .25s, box-shadow .3s, color .25s}
.inbox-page .btn:hover{transform:translateY(-1px);box-shadow:var(--raise);color:var(--accent-ink)}
.inbox-page .btn:active{transform:none;box-shadow:var(--carve)}
.inbox-page .st-select{display:flex;align-items:center;gap:10px;font-size:11px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3)}
.inbox-page .st-select select{font-family:inherit;font-size:12.5px;font-weight:600;color:var(--ink-2);
  border:0;outline:none;cursor:pointer;padding:9px 14px;border-radius:999px;
  background:var(--surface);box-shadow:var(--carve);letter-spacing:0;text-transform:none}

/* ── Composer : champ gravé ── */
.inbox-page .composer{flex:none;display:flex;align-items:flex-end;gap:12px;padding:16px 28px 26px;position:relative}
.inbox-page .composer::before{content:"";position:absolute;left:22px;right:22px;top:4px;height:1.5px;border-radius:2px;
  background:linear-gradient(180deg, rgba(28,39,64,.06), rgba(255,255,255,.9))}
.inbox-page .c-field{flex:1;display:flex;align-items:flex-end;gap:10px;min-width:0;
  background:var(--surface);border-radius:19px;padding:13px 16px;box-shadow:var(--carve);
  transition:box-shadow .3s}
.inbox-page .c-field:focus-within{box-shadow:var(--carve), 0 0 0 4px rgba(0,214,140,.08)}
.inbox-page .c-field textarea{flex:1;border:0;background:transparent;resize:none;outline:none;min-width:0;
  font-family:inherit;font-size:13px;line-height:1.5;color:var(--ink);height:44px;max-height:120px}
.inbox-page .c-field textarea::placeholder{color:var(--ink-3)}
.inbox-page .c-tool{flex:none;width:30px;height:30px;border:0;border-radius:50%;display:grid;place-items:center;
  cursor:pointer;color:var(--ink-3);background:transparent;transition:color .25s, box-shadow .3s}
.inbox-page .c-tool svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.inbox-page .c-tool:hover{color:var(--ink-2)}
.inbox-page .c-tool.on{color:#a4691c;box-shadow:var(--carve)}
/* Le bouton porte un LIBELLÉ (« Enregistrer sur le fil ») tant que l'envoi
   réel au client n'existe pas : un pictogramme d'avion sans envoi apprend à
   cliquer sans lire. Forme pilulaire, pas circulaire — pour dire du texte. */
.inbox-page .c-send{flex:none;height:44px;padding:0 18px;border:0;border-radius:999px;cursor:pointer;
  display:inline-flex;align-items:center;gap:9px;color:var(--accent);
  background:linear-gradient(155deg,#155054,#0e393c);
  box-shadow:6px 10px 24px rgba(10,45,48,.28), inset 0 1px 0 rgba(255,255,255,.12);
  transition:transform .25s, box-shadow .3s;
  font-family:inherit;font-size:12.5px;font-weight:600;letter-spacing:.01em}
.inbox-page .c-send svg{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;flex:none}
.inbox-page .c-send:hover{transform:translateY(-2px)}
.inbox-page .c-send:active{transform:none;box-shadow:inset 4px 4px 11px rgba(0,0,0,.4)}
.inbox-page .c-send:disabled{opacity:.6;cursor:wait;transform:none}
.inbox-page .c-note{position:absolute;right:34px;bottom:8px;font-family:'Spline Sans Mono';font-size:9px;color:var(--ink-3);opacity:.8}
.inbox-page .c-err{position:absolute;left:34px;bottom:8px;font-size:10.5px;font-weight:600;color:#c13a54}

/* ── Responsive ── */
@media (max-width:1240px){
  .inbox-page .inbox{grid-template-columns:300px minmax(0,1fr)}
  .inbox-page .tri-grid{grid-template-columns:repeat(2,1fr)}
  .inbox-page .recap{grid-template-columns:1fr}
  .inbox-page .th-meta .hide-md{display:none}
}
@media (max-width:1000px){
  .inbox-page{height:auto}
  .inbox-page .inbox{grid-template-columns:1fr}
  .inbox-page .queue{max-height:340px}
  .inbox-page .thread{min-height:70vh}
}


/* ═══════════════════════════════════════════════════════════════════════
   Fiche site (écran Sites\Show) — cible visuelle :
   design/propositions/screens/fiche-site.html
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Entête identité ── */
.site-top{align-items:center;gap:22px;margin-bottom:34px}
.back{width:40px;height:40px;flex:none;border-radius:50%;display:grid;place-items:center;
  text-decoration:none;color:var(--ink-2);font-size:15px;
  background:var(--posed);box-shadow:var(--raise-sm);
  transition:transform .25s, box-shadow .3s, color .25s}
.back:hover{transform:translateX(-2px);color:var(--accent-ink);box-shadow:var(--raise)}
.back:active{transform:none;box-shadow:var(--carve)}
.fav-xl{width:56px;height:56px;flex:none;border-radius:19px;display:grid;place-items:center;
  color:var(--ink-2);font-weight:600;font-size:17px;letter-spacing:.02em;
  background:var(--posed);box-shadow:var(--raise)}
.site-title{min-width:0}
.site-title h1{line-height:1}
.site-sub{margin-top:7px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.site-sub a{color:var(--ink-2);font-weight:600;text-decoration:none;transition:color .25s}
.site-sub a:hover{color:var(--accent-ink)}
.site-sub .sep{width:3px;height:3px;border-radius:50%;background:var(--ink-3);opacity:.6}
.badges{display:flex;flex-direction:column;align-items:flex-start;gap:9px;margin-left:6px}
.brow{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.brow:empty{display:none}
.bdg{display:inline-flex;align-items:center;gap:7px;padding:8px 14px;border-radius:999px;
  font-size:9.5px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-2);
  background:var(--posed);box-shadow:var(--raise-sm);
  transition:transform .25s, box-shadow .3s;cursor:default;white-space:nowrap}
.bdg:hover{transform:translateY(-1px);box-shadow:var(--raise)}
.bdg i{width:5px;height:5px;border-radius:50%;flex:none;background:var(--ink-3)}
.bdg.ssh i{background:#00c583;box-shadow:0 0 7px rgba(0,197,131,.55)}
/* forfaits : gravés, encre accent — l'état, pas l'objet */
.bdg.plan{background:var(--surface);box-shadow:var(--carve);color:var(--accent-ink)}
.bdg.plan i{background:#00c583}
.bdg.ro{background:var(--surface);box-shadow:var(--carve);color:#a9741e}
.bdg.ro i{background:var(--warn)}
.top-actions{margin-left:auto;display:flex;align-items:center;gap:12px;flex:none}
/* La fiche d'un site empile ses gestes sur DEUX lignes — quatre libellés en
   file mangeaient la largeur du titre (Raphaël, 03/08). Scopé à `.site-top` :
   les autres écrans qui portent `.top-actions` (ajout, gestion, accès) gardent
   leur rangée unique. */
.site-top .top-actions{flex-direction:column;align-items:flex-end;gap:8px}
.site-top .ta-row{display:flex;align-items:center;gap:8px}
/* Icône seule : carré, sans écart interne pour le libellé absent. Son nom vit
   dans `aria-label` + `title` — une icône muette n'est pas un bouton. */
.btn.ico{padding:0;width:38px;height:38px;justify-content:center;gap:0}
/* border/font-family/cursor ne sont PAS décoratifs ici : sans eux, un
   <button class="btn"> hérite du `2px outset ButtonBorder` du navigateur et de
   sa police système, pendant qu'un <a class="btn"> voisin reste propre. Mesuré
   le 03/08/2026 sur la fiche site : border-top 2px outset, font-family Arial,
   cursor default. Neuf boutons du hub étaient dans ce cas. */
.btn{display:inline-flex;align-items:center;gap:8px;padding:11px 19px;border-radius:999px;
  border:0;font-family:inherit;cursor:pointer;
  font-size:12.5px;font-weight:600;color:var(--ink-2);text-decoration:none;
  background:var(--posed);box-shadow:var(--raise-sm);
  transition:transform .25s, box-shadow .3s, color .25s;white-space:nowrap}
.btn svg{width:14px;height:14px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.btn:hover{transform:translateY(-2px);color:var(--accent-ink);box-shadow:var(--raise)}
.btn:active{transform:none;box-shadow:var(--carve)}

/* ── Bandeau santé : variantes de l'anneau + valeurs en alerte ── */
.site-kpis{grid-template-columns:1.5fr 1fr 1fr 1fr 1fr}
/* Ces variantes étaient scopées `.site-kpis`, donc inapplicables à `.kpi-bar` :
   l'anneau de la Flotte restait vert quel que soit l'état du parc, y compris
   jamais mesuré. Une classe d'état posée sur un anneau doit le colorer partout
   où il est — le conteneur n'a pas à en décider. */
/* L'état ne colore plus un trait — il colore la bille, corps et profondeur. */
.hero-ring.w{--bille:var(--warn);--bille-deep:#a86c10}
.hero-ring.d{--bille:var(--danger);--bille-deep:#b02a45}
.kpi .val.bad{color:#c13a54}
.dot.bad{background:var(--danger)}
.dot.ping{box-shadow:0 0 0 0 rgba(232,90,116,.4);animation:ping 2.4s infinite}

/* ── Grille de contenu : deux colonnes spacieuses ── */
.grid{display:grid;grid-template-columns:1.08fr .92fr;gap:26px;align-items:start}
.col{display:flex;flex-direction:column;gap:26px;min-width:0}
.card{background:var(--posed);
  border-radius:28px;box-shadow:var(--raise);padding:28px 30px 26px;
  animation:var(--entree,fade) .9s .34s cubic-bezier(.22,1,.36,1) both}
/* ── L'écart entre deux cartes : UNE règle, partout ──────────────────────────
   Deux cartes qui se suivent sont à 26 px l'une de l'autre. Point.

   Ça n'a pas toujours été le cas, et Raphaël a fini par poser la bonne
   question — « je ne comprends pas pourquoi ce n'est pas une règle globale ».
   `.card` n'avait aucune marge propre : chaque conteneur devait fournir
   l'écart, et la plupart ne le faisaient pas. On corrigeait donc conteneur par
   conteneur, au fil de ce qu'il voyait — l'onglet Maintenance, puis Perf & SEO,
   puis Tâches. Trois signalements pour un seul défaut.

   Le motif de l'ancienne prudence a disparu : une règle générale aurait
   cumulé avec le `margin-bottom:18px` de `.card.work-group`. Ce 18 px est
   maintenant 26 comme le reste, et cette exception est supprimée.

   26 px et non une autre valeur : c'est le `gap` de `.col` et de `.grid`, donc
   celui qu'on voit déjà entre les cartes d'une même page. */
.card + .card{margin-top:26px}
/* …sauf là où le conteneur pose DÉJÀ l'écart par un `gap` de flex : l'addition
   des deux donnerait 52 px. */
.col > .card + .card,
.stacked > .card + .card{margin-top:0}
.stacked{display:flex;flex-direction:column;gap:26px}
.col-b .card{animation-delay:.42s}
.ch{display:flex;align-items:center;gap:12px;margin-bottom:22px}
.ch h2{font-family:'Clash Display';font-size:13px;font-weight:600;letter-spacing:.1em;text-transform:uppercase}
.ch .mono{font-size:10px;color:var(--ink-3)}
.ch .spacer{margin-left:auto}
.card-empty{font-size:12.5px;color:var(--ink-3);line-height:1.5}
/* Un lien en pleine phrase — « voir Travail », « la vue d'ensemble ». Sans
   cette règle il sortait en bleu #0000EE souligné, le défaut du navigateur :
   hub.css n'a aucun reset sur `a`, et rien ne rattrapait un `<a>` sans classe.
   Mesuré au navigateur le 03/08 sur `mng-staging` (« Travail »).
   `.perf-why a` ajouté le 03/08 : le lot SEO enveloppait ses liens d'un
   `<span class="mng-hint">` pour emprunter cette règle — un contournement, pas
   une solution. Le sélecteur vise le `a` lui-même et non son parent : c'est ce
   qui le fait gagner sur `.perf-why{color:ink-3}` (l. 2053), déclarée plus bas
   mais qui ne l'atteint que par héritage. */
.card-empty a,.mng-hint a,.stg-meta a,.perf-why a,.perf-note a{color:var(--accent-ink);
  text-decoration:underline;text-underline-offset:2px;text-decoration-thickness:1px}
.card-empty a:hover,.mng-hint a:hover,.stg-meta a:hover,.perf-why a:hover,.perf-note a:hover{color:var(--tongue-deep)}
.mini{display:inline-flex;align-items:center;gap:7px;padding:8px 15px;border-radius:999px;
  font-size:11.5px;font-weight:600;color:var(--ink-2);text-decoration:none;cursor:pointer;
  background:var(--posed);box-shadow:var(--raise-sm);
  border:0;font-family:inherit;
  transition:transform .25s, box-shadow .3s, color .25s;white-space:nowrap}
.mini svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.mini:hover:not(:disabled){transform:translateY(-1px);color:var(--accent-ink);box-shadow:var(--raise)}
.mini:active:not(:disabled){transform:none;box-shadow:var(--carve)}
.mini:disabled{opacity:.45;cursor:not-allowed}
.sl{font-size:10px;font-weight:500;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-3);
  margin:22px 0 12px;display:flex;align-items:baseline;gap:8px}
.sl:first-of-type{margin-top:0}
.sl .mono{margin-left:auto;font-size:9.5px;letter-spacing:0;text-transform:none}
/* `.spacer` existait déjà sous `.ch`, `.mng-cred-foot` et `.mng-step-h` : un
   sous-titre `.sl` qui porte sa poignée de dépliant a le même besoin, et une
   quatrième déclaration valait mieux qu'une classe de plus. 04/08/2026. */
.sl .spacer{margin-left:auto}

/* ── Le planning éditorial : des mois côte à côte ──────────────────────────
   Trois classes, ajoutées le 05/08/2026 (perfseo), et le plafond du lot.
   Un tableau de lignes ne montre pas un calendrier : ce qu'on veut voir d'un
   coup d'œil, c'est quand, quoi, où ça en est, et si c'est la bonne saison. */
.pmois{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:14px;margin-top:6px}
.pcrn{padding:11px 13px;border-radius:12px;background:var(--posed);box-shadow:var(--carve);
  display:flex;flex-direction:column;gap:3px;min-width:0}
.pcrn b{font-size:12.5px;font-weight:600;line-height:1.35;overflow:hidden;text-overflow:ellipsis}
.pcrn .jour{font-family:'Spline Sans Mono';font-size:10px;color:var(--ink-3)}
.pcrn + .pcrn{margin-top:9px}
/* Un créneau LIBRE se voit d'un coup d'œil : c'est là qu'il reste de la place,
   et c'est la raison d'être du planning. Il s'estompe au lieu de disparaître —
   il est posé en creux, pas absent. Modificateur de `.pcrn`, pas classe neuve. */
.pcrn.libre{background:transparent;box-shadow:none;
  border:1px dashed rgba(28,39,64,.16);padding:10px 12px}
.pcrn.libre b{font-weight:500;color:var(--ink-3)}
/* Un créneau EN RETARD : son jour est passé et rien n'a été écrit. Modificateur
   de `.pcrn`, comme `.libre` — pas une classe de plus. Il ne sert que dans le
   calendrier, et la couleur n'est jamais seule : la colonne du mois passé porte
   le mot « en retard » à côté de son nom. 01/09/2026. */
.pcrn.retard{background:rgba(232,90,116,.09);box-shadow:inset 0 0 0 1px rgba(232,90,116,.28)}
.pcrn.retard .jour{color:var(--danger)}
.sl b.retard{color:var(--danger);font-weight:600}
/* La bande de saison : la seule chose qu'aucun tableau ne peut donner — voir
   que le contenu tombe DANS ou HORS de la fenêtre. Un site sans saison n'en
   affiche aucune, il ne s'en invente pas une. */
.psaison{height:5px;border-radius:999px;background:linear-gradient(90deg,rgba(0,214,140,.5),rgba(0,214,140,.16));
  margin-top:10px}
.psaison.hors{background:var(--surface);box-shadow:var(--carve)}

/* ── Écran Contenus : trois zones au lieu de dix cartes ────────────────────
   Mesuré au navigateur le 05/08/2026 : dix cartes empilées dans une seule
   colonne faisaient 2 759 px, et le planning — la question qu'on se pose
   chaque semaine — était à 1 800 px de défilement.
   Trois classes, et pas une de plus : les deux colonnes reposent sur `.grid`
   et `.col`, qui existaient déjà et servent ailleurs. */

/* La barre d'état : une ligne, pas une carte. Elle remplace « Où en est ce
   site », qui coûtait une carte entière pour dire trois chiffres. */
.etat-bar{display:flex;align-items:center;gap:0;margin:0 0 26px;padding:14px 26px;
  border-radius:999px;box-shadow:var(--carve);flex-wrap:wrap}
.etat-bar > *{display:flex;align-items:baseline;gap:8px;padding:0 22px;position:relative}
.etat-bar > * + *::before{content:"";position:absolute;left:0;top:-2px;bottom:-2px;width:1.5px;
  border-radius:2px;background:linear-gradient(90deg,rgba(28,39,64,.07),rgba(255,255,255,.9))}
.etat-bar b{font-family:'Clash Display';font-size:19px;font-weight:500;letter-spacing:-.01em;color:var(--ink)}
.etat-bar span{font-size:11.5px;color:var(--ink-2)}
.etat-bar .pousse{margin-left:auto;padding-right:4px}
.etat-bar .pousse::before{display:none}

/* Les tiroirs : cinq cartes qu'on ouvre une fois par mois deviennent cinq
   mots sur une ligne. Ce qu'on ouvre s'ouvre dessous, pleine largeur. */
.tiroirs{display:flex;flex-wrap:wrap;gap:10px;margin-top:26px}
.tiroirs > button{display:inline-flex;align-items:center;gap:9px;padding:11px 18px;
  border-radius:999px;border:0;cursor:pointer;background:var(--posed);box-shadow:var(--raise-sm);
  font-family:inherit;font-size:12.5px;font-weight:600;color:var(--ink-2);
  transition:transform .25s cubic-bezier(.22,1,.36,1),color .25s}
.tiroirs > button:hover{transform:translateY(-2px);color:var(--ink)}
.tiroirs > button i{font-style:normal;font-family:'Spline Sans Mono';font-size:10.5px;color:var(--ink-3)}
.tiroirs > button.on{box-shadow:var(--carve-net);color:var(--accent-ink)}

/* ⚠️ Sous 1 100 px les deux colonnes s'empilent, le fil d'abord : le hub n'est
   pas fait pour les très petits écrans, mais un portable à 1 280 existe. */
@media (max-width:1100px){
  .tab-contenus .grid{grid-template-columns:1fr}
  .etat-bar{border-radius:22px}
  .etat-bar .pousse{margin-left:0;width:100%;padding:10px 22px 0}
}

/* ── Mode Simple : ce qui demande une action ── */
.todo{display:flex;align-items:flex-start;gap:13px;padding:12px 0;position:relative}
.todo + .todo::before{content:"";position:absolute;top:0;left:16px;right:6px;height:1px;
  background:linear-gradient(180deg, rgba(28,39,64,.05), rgba(255,255,255,.7))}
.todo .st{margin-top:4px;flex:none}
/* la pastille reste visible même en tonalité neutre : l'alignement prime */
.todo .st i{width:7px;height:7px;display:block}
.todo .st.m i{background:var(--ink-3)}
/* ⚠️ **Sans `flex:1`, une action de fin de ligne SUIT LE TEXTE.** Mesuré au
   navigateur le 11/08 sur les neuf pages d'une piste : le bouton « titre »
   sortait à NEUF positions horizontales différentes (831 à 964 px) selon la
   longueur du titre de la page. `.todo .act` porte pourtant `margin-left:auto`
   mais avec DEUX actions, les deux marges automatiques se partagent l'espace
   libre, et la première se déplace avec le texte. Ce n'était pas une colonne,
   c'était une tabulation. Une ligne suffit, et elle vaut pour les sept écrans
   qui utilisent `.todo`. ⚠️ `hub.css` appartient à `socle` : signalé. */
.todo .tx{min-width:0;flex:1}
.todo .tx b{font-size:13px;font-weight:600;display:block;line-height:1.4}
.todo .tx span{font-size:12px;color:var(--ink-2)}
/* La ligne technique d'une ligne d'état (état côté file, ratio, essais) : elle
   passe SOUS le verdict au lieu de s'y coller. Mesuré au navigateur le 04/08 —
   les deux `span` étant en ligne, « 600 px de large, il en faut 1200. » et
   « 16:9 · file : pending » se lisaient comme une seule phrase. */
.todo .tx .meta{display:block;margin-top:3px;font-size:11px;color:var(--ink-3)}

/* ── Passeport ── */
.frag{list-style:none;display:flex;flex-direction:column;gap:9px}
.frag li{display:flex;gap:11px;font-size:13px;color:var(--ink-2);line-height:1.45}
.frag li::before{content:"";width:5px;height:5px;border-radius:50%;flex:none;margin-top:7px;background:var(--warn)}
.cp{display:flex;align-items:center;gap:12px;padding:9px 0;position:relative}
.cp + .cp::before{content:"";position:absolute;top:0;left:6px;right:6px;height:1px;
  background:linear-gradient(180deg, rgba(28,39,64,.05), rgba(255,255,255,.7))}
.cp .path{flex:none;font-family:'Spline Sans Mono';font-size:11px;color:var(--accent-ink);
  background:var(--surface);box-shadow:var(--carve);border-radius:9px;padding:5px 10px}
.cp .cpl{font-size:12.5px;color:var(--ink-2);min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ct{display:flex;align-items:center;gap:13px;padding:8px 0}
.ci{width:34px;height:34px;flex:none;border-radius:12px;display:grid;place-items:center;
  font-size:11px;font-weight:600;color:var(--ink-2);
  background:var(--posed);box-shadow:var(--raise-sm)}
.ct b{font-size:13px;font-weight:600;display:block}
.ct span{font-size:11.5px;color:var(--ink-3)}
.consigne{background:var(--surface);box-shadow:var(--carve);border-radius:18px;
  padding:16px 20px;font-size:13px;color:var(--ink-2);line-height:1.6;position:relative}
.consigne::before{content:"“";position:absolute;top:2px;left:12px;font-family:'Clash Display';
  font-size:34px;color:var(--ink-3);opacity:.35}
.consigne p{padding-left:16px}

/* ── Inventaire ── */
.inv-core{display:grid;grid-template-columns:1fr 1fr 1fr;gap:14px;margin-bottom:22px}
.core{background:var(--surface);box-shadow:var(--carve);border-radius:16px;padding:13px 16px;min-width:0}
.core .k{font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3);font-weight:500}
.core .v{font-family:'Spline Sans Mono';font-size:14px;margin-top:6px;display:flex;align-items:center;gap:8px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.core .v i{width:5px;height:5px;border-radius:50%;flex:none;background:#00c583}
.inv-row{display:grid;grid-template-columns:1.7fr .7fr .9fr .9fr;align-items:center;gap:12px;
  padding:11px 14px;border-radius:14px;position:relative;
  transition:box-shadow .3s, transform .3s cubic-bezier(.22,1,.36,1)}
.inv-row + .inv-row::before{content:"";position:absolute;top:0;left:16px;right:16px;height:1px;
  background:linear-gradient(180deg, rgba(28,39,64,.05), rgba(255,255,255,.7));transition:opacity .3s}
.inv-row:hover{background:var(--posed);box-shadow:var(--raise-sm);transform:translateY(-1px)}
.inv-row:hover::before, .inv-row:hover + .inv-row::before{opacity:0}
.inv-row .pn{min-width:0}
.inv-row .pn b{font-size:13px;font-weight:600;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.inv-row .pn span{font-size:10.5px;color:var(--ink-3);font-family:'Spline Sans Mono'}
.inv-row .cur{font-family:'Spline Sans Mono';font-size:12px;color:var(--ink-2)}
.inv-row .next{font-family:'Spline Sans Mono';font-size:12px;color:var(--accent-ink);font-weight:500}
.inv-row .next.none{color:var(--ink-3);font-weight:400}
.inv-row .st{justify-self:end}
.inv-row.vuln{background:linear-gradient(150deg, rgba(232,90,116,.07), rgba(232,90,116,.03));
  box-shadow:var(--carve)}
.inv-row.vuln:hover{transform:none}
.inv-row.vuln + .inv-row::before{opacity:0}
.vuln-note{display:flex;align-items:center;gap:13px;margin:10px 2px 12px;padding:14px 18px;
  border-radius:16px;background:var(--surface);box-shadow:var(--carve)}
.vuln-note .sig{width:8px;height:8px;flex:none;border-radius:50%;background:var(--danger);
  box-shadow:0 0 0 0 rgba(232,90,116,.4);animation:ping 2.4s infinite}
.vuln-note b{font-size:12.5px;font-weight:600;display:block;line-height:1.4}
.vuln-note span{font-size:11.5px;color:var(--ink-2)}
.inv-foot{display:flex;align-items:center;margin-top:18px;padding:0 4px;font-size:11.5px;color:var(--ink-3)}
.inv-foot .r{margin-left:auto;font-family:'Spline Sans Mono';font-size:10px}

/* ── Métriques : sparklines 30 j ── */
.mx-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
/* une seule série mesurée : elle prend toute la largeur plutôt qu'une demi-carte vide */
.mx-grid:has(.mx:only-child){grid-template-columns:1fr}
.mx{background:var(--surface);box-shadow:var(--carve);border-radius:18px;padding:16px 18px 12px;min-width:0}
.mx .k{font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3);font-weight:500}
.mx .v{font-family:'Clash Display';font-size:24px;font-weight:500;margin-top:7px;line-height:1;
  font-variant-numeric:tabular-nums}
.mx .v small{font-size:12px;color:var(--ink-3);font-weight:400}
.mx .d{font-size:11px;margin-top:5px;display:flex;align-items:center;gap:6px;color:var(--ink-2)}
.mx .d.w{color:#a9741e;font-weight:600}
.mx svg{display:block;width:100%;height:46px;margin-top:10px;overflow:visible}
.mx polyline{fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.mx polygon{opacity:.9}

/* ── Journal d'intervention : timeline ── */
.jl{position:relative;padding-left:30px}
.jl::before{content:"";position:absolute;left:9px;top:14px;bottom:14px;width:1.5px;border-radius:2px;
  background:linear-gradient(180deg, rgba(28,39,64,.05), rgba(28,39,64,.1), rgba(255,255,255,.8))}
.jli{position:relative;padding:10px 0 12px}
.jli::before{content:"";position:absolute;left:-25px;top:16px;width:9px;height:9px;border-radius:50%;
  background:var(--ink-3);box-shadow:0 0 0 3px var(--surface)}
.jli.ia::before{background:#00d68c;box-shadow:0 0 0 3px var(--surface), 0 0 10px rgba(0,214,140,.55)}
.jli.ra::before{background:var(--ink-2);box-shadow:0 0 0 3px var(--surface)}
.jli.sys::before{background:var(--danger);box-shadow:0 0 0 3px var(--surface)}
.jt{display:flex;align-items:baseline;gap:9px;min-width:0}
.jt b{font-size:13px;font-weight:600;line-height:1.4;min-width:0}
.jt .when{margin-left:auto;flex:none;font-family:'Spline Sans Mono';font-size:10px;color:var(--ink-3)}
.who{flex:none;font-family:'Spline Sans Mono';font-size:9px;letter-spacing:.08em;text-transform:uppercase;
  padding:3px 8px;border-radius:999px;font-weight:500;align-self:center}
.who.ia{color:var(--accent-ink);background:rgba(0,214,140,.13)}
.who.ra{color:var(--ink-2);background:rgba(28,39,64,.07)}
.who.sys{color:#c13a54;background:rgba(232,90,116,.11)}
.jli p{font-size:12px;color:var(--ink-2);margin-top:5px;line-height:1.5}
/* `.meta` n'existait que sous `.todo .tx` : c'est sa PORTÉE qui s'étend au fil,
   pas une classe de plus. Le fil des publications a besoin de deux niveaux de
   texte sous le titre — ce que dit la ligne, et ce qu'on en sait de moins
   important (les images, le tour) — sinon les deux se lisent d'un seul bloc. */
.jli .meta{font-size:11px;color:var(--ink-3)}
.jl-more{display:inline-flex;align-items:center;gap:6px;margin-top:14px;margin-left:30px;
  font-size:12.5px;font-weight:600;color:var(--accent-ink);text-decoration:none;cursor:pointer;
  background:transparent;border:0;font-family:inherit;padding:0;transition:gap .25s}
.jl-more::after{content:"→"}
.jl-more:hover{gap:9px}

/* ── Tickets liés / tâches récentes ── */
.tik{display:flex;align-items:center;gap:15px;padding:14px 16px;border-radius:18px;
  text-decoration:none;color:var(--ink);position:relative;
  transition:box-shadow .35s, transform .3s cubic-bezier(.22,1,.36,1)}
.tik + .tik::before{content:"";position:absolute;top:-1px;left:18px;right:18px;height:1px;
  background:linear-gradient(180deg, rgba(28,39,64,.05), rgba(255,255,255,.7));transition:opacity .3s}
.tik:hover{background:var(--posed);box-shadow:var(--raise-sm);transform:translateY(-1px);z-index:2}
.tik:hover::before, .tik:hover + .tik::before{opacity:0}
.tid{flex:none;font-family:'Spline Sans Mono';font-size:11px;color:var(--ink-2);
  background:var(--surface);box-shadow:var(--carve);border-radius:11px;padding:8px 10px}
.tik .tt{min-width:0}
.tik .tt b{font-size:13px;font-weight:600;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tik .tt span{font-size:11.5px;color:var(--ink-3);display:flex;align-items:center;gap:7px;margin-top:4px;flex-wrap:wrap}
.tik .st{margin-left:auto;flex:none}
.chip{font-style:normal;font-size:9.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  padding:3px 9px;border-radius:999px}
.chip.bug{color:#c13a54;background:rgba(232,90,116,.11)}
.chip.hot{color:#a9741e;background:rgba(227,160,42,.14)}
.chip.done{color:var(--ink-3);background:rgba(28,39,64,.06)}
.tik.closed{opacity:.66}
.tik.closed .tt b{color:var(--ink-2);font-weight:500}

/* ── Pied de fiche ── */
.pfoot{display:flex;align-items:center;margin-top:30px;padding:0 26px;
  font-size:11.5px;color:var(--ink-3);
  animation:var(--entree,fade) .9s .7s cubic-bezier(.22,1,.36,1) both}
.pfoot .r{margin-left:auto;font-family:'Spline Sans Mono';font-size:10px}

@media (max-width:1240px){
  .grid{grid-template-columns:1fr}
  .site-top{flex-wrap:wrap}
  .badges{margin-left:0;width:100%}
  .top-actions{margin-left:0}
  .inv-core{grid-template-columns:1fr 1fr}
  .inv-row{grid-template-columns:1.6fr .8fr 1fr}
  .inv-row .st{grid-column:1 / -1;justify-self:start}
}

/* ═══════════════════════════════════════════════════════════════════════
   Disjoncteur — PLAN.md §17 bis A
   Le seul endroit du système où l'on s'autorise à crier. Tout le reste du
   design system chuchote ; un disjoncteur armé doit être impossible à rater.
   Reliefs A2 uniquement (raise / carve), tokens existants, préfixe .brk-.
   ═══════════════════════════════════════════════════════════════════════ */

:root{
  --brk-red:#c8304c;
  --brk-red-deep:#8e1830;
  --brk-red-soft:rgba(232,90,116,.14);
}

/* ── Bandeau global : fixe, en haut, non ignorable ── */
.brk-banner{
  position:fixed;left:0;right:0;top:0;z-index:200;
  display:flex;align-items:center;gap:16px;
  padding:13px 26px;
  color:#fff;
  background:linear-gradient(150deg,var(--brk-red),var(--brk-red-deep));
  box-shadow:0 12px 34px rgba(142,24,48,.34), inset 0 1px 0 rgba(255,255,255,.16);
  animation:brkDrop .5s cubic-bezier(.22,1,.36,1) both;
}
@keyframes brkDrop{from{opacity:0;transform:translateY(-100%)}to{opacity:1;transform:none}}

/* Le contenu ne doit pas passer sous le bandeau. */
body:has(.brk-banner){padding-top:56px}
body:has(.brk-banner) .rail{top:56px}

.brk-pulse{
  width:11px;height:11px;flex:none;border-radius:50%;background:#fff;
  box-shadow:0 0 0 0 rgba(255,255,255,.6);
  animation:brkPulse 1.9s ease-out infinite;
}
@keyframes brkPulse{
  0%{box-shadow:0 0 0 0 rgba(255,255,255,.55)}
  70%{box-shadow:0 0 0 12px rgba(255,255,255,0)}
  100%{box-shadow:0 0 0 0 rgba(255,255,255,0)}
}
@media (prefers-reduced-motion:reduce){
  .brk-banner{animation:none}
  .brk-pulse{animation:none}
}

.brk-banner-tx{min-width:0;display:flex;align-items:baseline;gap:12px;flex-wrap:wrap}
.brk-banner-tx b{
  font-family:'Clash Display';font-size:12px;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;white-space:nowrap;
}
.brk-banner-tx span{
  font-size:12px;color:rgba(255,255,255,.82);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

.brk-banner .brk-resume,
.brk-banner .brk-yes,
.brk-banner .brk-no{
  margin-left:auto;flex:none;border:0;cursor:pointer;font-family:inherit;
  font-size:11.5px;font-weight:700;padding:8px 16px;border-radius:999px;
  color:#fff;background:rgba(255,255,255,.16);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22);
  transition:background .25s, transform .2s;
}
.brk-banner .brk-resume:hover,
.brk-banner .brk-no:hover{background:rgba(255,255,255,.26)}
.brk-confirm{margin-left:auto;display:flex;align-items:center;gap:10px;flex:none}
.brk-confirm>span{font-size:12px;font-weight:700;white-space:nowrap}
.brk-confirm .brk-yes,
.brk-confirm .brk-no{margin-left:0}
.brk-confirm .brk-yes{background:#fff;color:var(--brk-red-deep)}
.brk-confirm .brk-yes:hover{background:#fff;transform:translateY(-1px)}

/* ── Bloc du dock ── */
.brk-dock .brk-off{
  font-size:11px;font-weight:600;color:#a4691c;
  padding:8px 12px;border-radius:12px;background:rgba(227,160,42,.14);margin-bottom:12px;
}
.brk-dock .brk-hint{font-size:10.5px;line-height:1.5;color:var(--ink-3);margin-top:10px}
.brk-dock .brk-ask{font-size:12px;line-height:1.5;color:var(--ink-2);margin-bottom:12px}
.brk-dock .brk-actions{display:flex;gap:10px;flex-wrap:wrap}

/* Le bouton rouge. Posé (raise), pas creusé : il appelle la main. */
.brk-stop{
  width:100%;display:flex;align-items:center;justify-content:center;gap:10px;
  padding:14px 18px;border:0;cursor:pointer;font-family:'Clash Display',inherit;
  font-size:12.5px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:#fff;
  border-radius:18px;
  background:linear-gradient(150deg,var(--brk-red),var(--brk-red-deep));
  box-shadow:8px 12px 28px rgba(142,24,48,.28), inset 0 1px 0 rgba(255,255,255,.18);
  transition:transform .25s, box-shadow .3s;
}
.brk-stop svg{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.brk-stop:hover{transform:translateY(-2px);box-shadow:10px 16px 34px rgba(142,24,48,.34), inset 0 1px 0 rgba(255,255,255,.2)}
.brk-stop:active{transform:none;box-shadow:inset 4px 4px 12px rgba(0,0,0,.32)}
.brk-stop.confirm{flex:1;animation:brkWake .35s cubic-bezier(.22,1,.36,1) both}
@keyframes brkWake{from{transform:scale(.97);opacity:.6}to{transform:none;opacity:1}}

/* Réarmer : sobre par contraste — relancer la flotte ne se célèbre pas. */
.brk-go{
  width:100%;padding:12px 18px;border:0;cursor:pointer;font-family:inherit;
  font-size:12.5px;font-weight:700;color:var(--accent-ink);
  border-radius:999px;background:var(--posed);
  box-shadow:var(--raise-sm);transition:transform .25s, box-shadow .3s;
}
.brk-go:hover{transform:translateY(-1px);box-shadow:var(--raise)}
.brk-go:active{transform:none;box-shadow:var(--carve)}
.brk-go.confirm{flex:1}

.brk-cancel{
  padding:12px 18px;border:0;cursor:pointer;font-family:inherit;
  font-size:12.5px;font-weight:600;color:var(--ink-3);
  border-radius:999px;background:var(--surface);box-shadow:var(--carve);
}
.brk-cancel:hover{color:var(--ink-2)}

/* Liste des périmètres armés : gravée, rouge discret. */
.brk-list{list-style:none;margin:0 0 14px;padding:0;display:flex;flex-direction:column;gap:8px}
.brk-list li{
  padding:10px 13px;border-radius:14px;
  background:var(--brk-red-soft);box-shadow:var(--carve);
  border-left:3px solid var(--brk-red);
}
.brk-list b{display:block;font-size:12px;font-weight:700;color:var(--brk-red-deep)}
.brk-list span{display:block;font-size:10.5px;color:var(--ink-2);margin-top:3px}

/* Le dock disparaît sous 1500px : le bandeau, lui, reste. */
@media (max-width:1500px){
  body:has(.brk-banner) .rail{top:0}
  .brk-banner{padding:11px 18px}
  .brk-banner-tx span{display:none}
}


/* ── Ligne de flotte entièrement cliquable ── */
.row-link{position:absolute;inset:0;z-index:1;border-radius:inherit;
  text-decoration:none;-webkit-tap-highlight-color:transparent}
.row-link:focus-visible{outline:2px solid var(--accent-deep);outline-offset:-2px}
/* Le contenu passe au-dessus du lien pour rester sélectionnable, et les
   éléments réellement interactifs restent cliquables. */
.row > *:not(.row-link){position:relative;z-index:2;pointer-events:none}
.row .go{pointer-events:auto}
a.go{text-decoration:none}
.row:hover .s-id b{color:var(--accent-ink)}

.act-done{margin-left:auto;flex:none;font-size:11.5px;font-weight:600;color:var(--ink-3);
  background:var(--surface);box-shadow:var(--carve);border-radius:999px;padding:7px 14px}


/* ═══════════════════════════════════════════════════════════════════════
   Authentification — écran de connexion, vérification 2FA, « Mon accès »
   (SECURITY.md §4). Reliefs A2 uniquement (raise / carve), tokens existants.
   Préfixes .auth- et .sec- : rien ne déborde sur les autres écrans.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Coquille de connexion : une seule pièce posée sur la céramique ── */
.auth-body{display:grid;place-items:center;min-height:100vh;padding:32px 20px}
.auth-shell{width:100%;max-width:420px;display:flex;flex-direction:column;align-items:center;gap:22px;
  animation:var(--entree,fade) .9s cubic-bezier(.22,1,.36,1) both}
.auth-brand{display:flex;align-items:center;gap:10px;font-family:'Clash Display';
  font-size:11px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-2)}
.auth-dot{width:9px;height:9px;border-radius:50%;background:var(--accent);
  box-shadow:0 0 12px 2px rgba(0,255,167,.45)}
.auth-foot{font-size:11px;color:var(--ink-3);text-align:center}

.auth-card{width:100%;padding:36px 34px 32px;border-radius:30px;
  background:var(--posed);box-shadow:var(--raise)}
.auth-card h1{font-size:24px;margin-bottom:8px}
.auth-lead{font-size:13px;line-height:1.55;color:var(--ink-2);margin-bottom:24px;max-width:44ch}
.auth-notice{font-size:12.5px;line-height:1.5;color:var(--accent-ink);margin-bottom:18px;
  padding:11px 15px;border-radius:14px;background:var(--surface);box-shadow:var(--carve)}

.auth-form{display:flex;flex-direction:column;gap:16px}

/* ── Champs creusés ── */
.field{display:flex;flex-direction:column;gap:8px}
.field-lbl{font-size:10.5px;font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3)}
.field input{
  width:100%;padding:13px 18px;border:0;outline:none;border-radius:16px;
  font:inherit;font-size:14px;color:var(--ink);
  background:var(--surface);box-shadow:var(--carve);
  transition:box-shadow .3s, color .25s;
}
.field input::placeholder{color:var(--ink-3)}
.field input:focus{box-shadow:var(--carve), 0 0 0 2px rgba(0,255,167,.35)}
.code-input{font-family:'Spline Sans Mono';font-size:22px;letter-spacing:.34em;text-align:center}

.auth-error{font-size:12.5px;line-height:1.45;color:#c13a54;font-weight:600}

.auth-remember{display:flex;align-items:center;gap:10px;font-size:12.5px;color:var(--ink-2);cursor:pointer}
.auth-remember input{width:16px;height:16px;accent-color:#00c583;cursor:pointer}

.auth-btn{
  margin-top:4px;padding:14px 22px;border:0;border-radius:999px;cursor:pointer;
  font-family:inherit;font-size:13.5px;font-weight:700;color:var(--accent-ink);
  background:var(--posed);box-shadow:var(--raise-sm);
  transition:transform .25s, box-shadow .3s, color .25s;
}
.auth-btn:hover{transform:translateY(-2px);box-shadow:var(--raise)}
.auth-btn:active{transform:none;box-shadow:var(--carve)}
.auth-btn:disabled{color:var(--ink-3);box-shadow:var(--carve);cursor:wait;transform:none}

.auth-links{display:flex;flex-direction:column;gap:6px;margin-top:20px;align-items:flex-start}
.auth-links button{background:transparent;border:0;padding:4px 0;cursor:pointer;font-family:inherit;
  font-size:12.5px;font-weight:600;color:var(--accent-ink);transition:opacity .25s}
.auth-links button.mut{color:var(--ink-3);font-weight:500}
.auth-links button:hover{opacity:.7}

/* ── Écran « Mon accès » ── */
.sec-page{max-width:920px}
.sec-page .top form{margin-left:auto}
.sec-panel{background:var(--posed);border-radius:28px;box-shadow:var(--raise);
  padding:26px 28px;margin-bottom:22px;animation:var(--entree,fade) .9s .12s cubic-bezier(.22,1,.36,1) both}
.sec-head{display:flex;align-items:center;gap:12px;margin-bottom:14px}
.sec-head h2{font-family:'Clash Display';font-size:15px;font-weight:600;letter-spacing:.06em;text-transform:uppercase}
.sec-head .chip{font-size:9.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  padding:5px 12px;border-radius:999px;background:var(--surface);box-shadow:var(--carve)}
.sec-head .chip.on{color:var(--accent-ink)}
.sec-head .chip.off{color:#b06a10}
.sec-lead{font-size:13px;line-height:1.6;color:var(--ink-2);max-width:70ch}
.sec-acts{display:flex;flex-wrap:wrap;gap:10px;margin-top:18px}
.sec-page .btn{border:0;cursor:pointer;font-family:inherit;font-size:12.5px;font-weight:600;
  padding:11px 19px;border-radius:999px;color:var(--ink-2);
  background:var(--posed);box-shadow:var(--raise-sm);
  transition:transform .25s, box-shadow .3s, color .25s}
.sec-page .btn:hover{transform:translateY(-2px);box-shadow:var(--raise);color:var(--accent-ink)}
.sec-page .btn:active{transform:none;box-shadow:var(--carve)}
 /* « accent » et pas « go » : la classe .go de la vue flotte porte opacity:0 */
/* `.hub-page` est là parce que le bouton « Inspecter maintenant » a changé de
   coquille le 04/08 : la règle de base `.btn` est globale et l'a suivi, mais
   ces trois teintes-là étaient scopées `.sec-page`, et le geste principal de
   l'onglet Santé serait redevenu gris sans qu'aucun test ne tombe. */
.sec-page .btn.accent,.hub-page .btn.accent{color:var(--accent-ink)}
.sec-page .btn.mut,.hub-page .btn.mut{color:var(--ink-3)}
.sec-page .btn.danger,.hub-page .btn.danger{color:#c13a54}
.sec-page .btn.danger:hover,.hub-page .btn.danger:hover{color:#c13a54}

.sec-sub{margin-top:20px;padding-top:20px;position:relative}
.sec-sub::before{content:"";position:absolute;top:0;left:0;right:0;height:1.5px;border-radius:2px;
  background:linear-gradient(180deg, rgba(28,39,64,.07), rgba(255,255,255,.9))}
.sec-form{display:flex;flex-direction:column;gap:14px;max-width:400px}

/* Appairage : le carré à scanner, puis les trois gestes */
.sec-enrol{display:flex;gap:28px;margin-top:22px;padding-top:22px;position:relative;flex-wrap:wrap}
.sec-enrol::before{content:"";position:absolute;top:0;left:0;right:0;height:1.5px;border-radius:2px;
  background:linear-gradient(180deg, rgba(28,39,64,.07), rgba(255,255,255,.9))}
.sec-qr{flex:none;padding:14px;border-radius:22px;background:#fff;box-shadow:var(--raise-sm);
  line-height:0;align-self:flex-start}
.sec-qr svg{width:190px;height:190px;display:block}
.sec-enrol-tx{flex:1;min-width:260px}
.sec-steps{margin:0 0 20px 18px;padding:0;display:flex;flex-direction:column;gap:9px;
  font-size:13px;line-height:1.55;color:var(--ink-2)}
.sec-secret{display:inline-block;margin-top:7px;padding:8px 13px;border-radius:12px;
  background:var(--surface);box-shadow:var(--carve);font-size:12.5px;letter-spacing:.1em;
  color:var(--ink);word-break:break-all}

/* Codes de secours : gravés, monospace, à recopier */
.sec-codes{list-style:none;margin:16px 0 0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:10px}
.sec-codes li{padding:11px 14px;border-radius:14px;text-align:center;
  background:var(--surface);box-shadow:var(--carve);
  font-size:13px;letter-spacing:.06em;color:var(--ink)}

@media (max-width:760px){
  .sec-enrol{gap:20px}
  .sec-qr svg{width:160px;height:160px}
}

/* ── Écran « Le hub » : Santé et Coût de l'IA, deux onglets ─────────────────
   POURQUOI `.hub-page` ET PAS `.sec-page`. Le plafond `max-width:920px` de la
   famille `sec-*` est posé sur l'élément `.page`, celui qui porte le padding
   de page, et `box-sizing:border-box` est global, donc ces 474 à 554 px de
   padding se retirent DU PLAFOND, pas des marges.

   Mesuré au navigateur le 04/08, Chrome, `.page` de `/sante` et `/cout` :
     · 1 600 px, menu ouvert  → 218 + 336 de padding → 366 px de contenu
     · 1 600 px, menu replié  → 138 + 336 de padding → 446 px de contenu
   quand tous les autres écrans du hub reçoivent 1 046 et 1 126 px au même
   endroit. Les deux relevés qui semblaient se contredire disaient donc la même
   chose : l'écart est `--goo-w`, que le JS pose à 168 px menu ouvert et 88 px
   menu replié.

   `.sec-page` GARDE son plafond : son seul autre usage est « Mon accès », dont
   le contenu est intrinsèquement étroit (un formulaire de 400 px, un QR de
   190). Lui donner 1 046 px produirait le même vide que celui qu'on corrige
   ici, à l'envers. Le plafond appartient à un écran, pas à une famille.

   Ici, rien ne se plafonne sur la page : c'est la GRILLE qui borne les lignes
   de texte, et `.sec-lead{max-width:70ch}` finit le travail à l'intérieur. */
/* La barre d'onglets se serre autour de ses deux onglets. Celle d'une fiche de
   site en porte neuf et remplit la ligne ; ici, tirée sur 1 046 px pour deux
   mots, elle se lisait comme une gouttière vide. `max-width:100%` garde
   l'`overflow-x:auto` de `.tabs` utile si un troisième onglet arrivait. */
.hub-page .tabs{width:max-content;max-width:100%;margin-bottom:24px}

/* Deux colonnes égales. `align-items:start` n'est pas cosmétique : sans lui,
   une carte courte s'étire à la hauteur de sa voisine et son ombre se retrouve
   à trois cents pixels de son texte. */
.hub-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:22px;align-items:start}
/* Une colonne qui empile plusieurs cartes : c'est `gap` qui espace, comme dans
   la grille, sinon le `margin-bottom:22px` de `.sec-panel` s'y ajouterait. */
.hub-col{display:flex;flex-direction:column;gap:22px;min-width:0}
.hub-grid > .sec-panel,.hub-col > .sec-panel{margin-bottom:0}
/* Un bloc qui traverse les deux colonnes : les chiffres de tête. */
.sec-full{grid-column:1 / -1}

/* Le chiffre de tête. `.mx` est la tuile chiffrée du hub (creusée, Clash
   Display, chiffres tabulaires) ; elle est reprise telle quelle, seule la
   taille change : ces deux nombres-là sont la réponse de l'écran, pas une
   mesure parmi d'autres. Sélecteur en `.mx.hub-tete` (0,3,0) pour passer
   devant `.mx .v` (0,2,0) quel que soit l'ordre du fichier. */
.mx.hub-tete{padding:20px 22px 18px}
.mx.hub-tete .v{font-size:31px;margin-top:10px}
/* « Jamais mesuré » n'est pas un montant : il ne prend pas la taille d'un
   montant, il prend la couleur de ce qu'on ne sait pas. */
.mx.hub-tete .v.rien{font-size:17px;color:var(--ink-3);font-weight:400;
  font-family:'Atkinson Hyperlegible',sans-serif;letter-spacing:0}
/* Le chiffre reprend le signal que portait la pastille qu'il remplace, avec
   ses deux teintes exactes (vert d'accent au-dessus du seuil, ambre en
   dessous). Un chiffre de tête qui perdrait sa couleur perdrait le signal. */
.mx.hub-tete .v.on{color:var(--accent-ink)}
.mx.hub-tete .v.off{color:#b06a10}

/* Un chiffre de tête et la phrase qui l'explique, côte à côte : le nombre ne
   se lit pas au milieu d'un paragraphe. Le nom des deux enfants est explicite
   (jamais `:first-child` ni `+`) : un bloc déplacé emporterait sinon un style
   qui parlait de sa position d'avant. */
.hub-tete-row{display:flex;gap:24px;align-items:flex-start;flex-wrap:wrap}
.hub-tete-row .hub-tete{flex:none;width:210px}
.hub-tete-row .hub-tete-tx{flex:1;min-width:270px}

/* Deux explications sous deux chiffres. Le `gap` vaut celui de `.mx-grid`
   (16 px) : sans cette égalité, la phrase ne tombe pas sous son nombre. */
.hub-duo{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:18px}

/* Le pied de page de l'écran : ce qui explique un chiffre sans en être un.
   Même carte, moins d'encre. La hiérarchie se lit sans lire. */
.sec-panel.sec-pied{background:transparent;box-shadow:none;padding:4px 6px}
.sec-panel.sec-pied .sec-head h2{font-size:11px;color:var(--ink-3);letter-spacing:.12em}
.sec-panel.sec-pied .sec-lead{font-size:12.5px}

/* Une largeur retrouvée sans plafond de ligne, c'est un texte illisible.
   `.sec-lead` porte déjà `max-width:70ch` et rend 95 caractères par ligne
   mesurés ; `.mng-note`, elle, n'a aucun plafond dans tout le hub et montait à
   111 caractères à 1 600 px et 144 à 1 920 sur cet écran une fois la largeur
   rendue. Le même 70ch lui donne la même cadence de lecture (94 caractères),
   même si sa police est plus petite et son trait donc plus court : ce qui
   s'aligne d'un paragraphe à l'autre, c'est le nombre de mots par ligne.
   Scopé : `.mng-note` sert dans onze autres écrans que personne n'a demandé de
   déplacer. */
.hub-page .mng-note{max-width:70ch}

/* Sous 1100 px, deux colonnes ne valent plus rien : la gouttière a déjà pris
   sa place et chaque colonne tomberait sous 350 px. On repasse en pile. */
@media (max-width:1100px){
  .hub-grid,.hub-duo{grid-template-columns:minmax(0,1fr)}
}




/* ═══════════════════════════════════════════════════════════════════════
   Espace de gestion d'un site (écran Sites\Manage) — l'écran le plus
   sensible du hub : il manipule les accès de TOUS les sites clients.
   Reliefs A2 uniquement (raise / carve), tokens existants, préfixe .mng-.
   Règle de lecture : ce qui est COUPÉ ou VERROUILLÉ se voit de loin ;
   tout le reste chuchote.
   ═══════════════════════════════════════════════════════════════════════ */

.mng .fav-xl{font-size:22px;color:var(--ink-3)}
.mng .site-sub span{font-size:12.5px}

/* ── Bandeaux d'état : un choix assumé reste affiché tant qu'il dure ── */
.mng-banner{
  display:flex;align-items:center;gap:16px;margin:0 0 24px;padding:16px 24px;
  border-radius:22px;background:var(--surface);box-shadow:var(--carve);
  border-left:3px solid var(--warn);
  animation:var(--entree,fade) .9s .1s cubic-bezier(.22,1,.36,1) both;
}
.mng-banner .sig{width:8px;height:8px;flex:none;border-radius:50%;background:var(--warn)}
.mng-banner .tx{min-width:0}
.mng-banner .tx b{display:block;font-size:13px;font-weight:600;line-height:1.4}
.mng-banner .tx span{font-size:12px;color:var(--ink-2);line-height:1.5}
.mng-banner .act{
  margin-left:auto;flex:none;border:0;cursor:pointer;font-family:inherit;
  font-size:11.5px;font-weight:600;color:var(--accent-ink);padding:9px 16px;border-radius:999px;
  background:var(--posed);box-shadow:var(--raise-sm);
  transition:transform .25s, box-shadow .3s;
}
.mng-banner .act:hover{transform:translateY(-1px);box-shadow:var(--raise)}
/* Le geste d'un bandeau est parfois un LIEN (le pipeline arrêté mène à son
   écran) : sans ces deux lignes il arrive souligné, et sans réglure il ne
   centre pas son texte. Sélecteur sur `a.act` seul, pour ne pas décaler les
   sept bandeaux dont le geste est un `<button>`. */
.mng-banner a.act{display:inline-flex;align-items:center;text-decoration:none}
/* Deux gestes dans le même bandeau (le pipeline arrêté : restaurer, et voir ce
   qui s'est passé). Chaque `.act` pousse à droite par sa marge automatique :
   deux marges automatiques se partagent l'espace et le premier bouton finit au
   milieu. Le groupe pousse, ses gestes se suivent (socle 34). */
.mng-banner .acts{margin-left:auto;flex:none;display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px}
.mng-banner .acts .act{margin-left:0}
/* Quand la place manque, les gestes passent sous le texte au lieu de l'écraser :
   mesuré à 420 px, deux gestes côte à côte laissaient 0 px de large à la phrase. */
.mng-banner:has(> .acts){flex-wrap:wrap}
.mng-banner:has(> .acts) > .tx{flex:1 1 16rem}
.mng-banner:has(> .acts) > .acts{flex:0 1 auto;min-width:0;max-width:100%}
.mng-banner .tx .suite{display:block;margin-top:4px}
.mng-banner.lock{border-left-color:var(--danger)}
.mng-banner.lock .sig{background:var(--danger)}

/* ── Formulaires : champs creusés, mêmes reliefs que « Mon accès » ── */
.mng-form{display:flex;flex-direction:column;gap:18px}
.mng-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.mng .field select,
.mng .field textarea,
.mng .mng-check select{
  width:100%;padding:13px 16px;border:0;outline:none;border-radius:16px;
  font:inherit;font-size:13.5px;color:var(--ink);
  background:var(--surface);box-shadow:var(--carve);
  transition:box-shadow .3s;
}
.mng .field textarea{line-height:1.55;resize:vertical;min-height:84px}
.mng .field select:focus,
.mng .field textarea:focus,
.mng .field input:focus,
.mng .mng-check select:focus{box-shadow:var(--carve), 0 0 0 2px rgba(0,255,167,.35)}
.mng .field input::placeholder,
.mng .field textarea::placeholder{color:var(--ink-3)}
.mng .field input.mng-locked{color:var(--ink-3);cursor:not-allowed}
.mng-note{font-size:11px;line-height:1.5;color:var(--ink-3)}
.mng-note.warn{color:#a9741e}
/* « non enregistré » : le message doit se voir sans crier. */
.mng-note.dirty{color:#7a4d0a;background:rgba(228,177,73,.16);
  border-radius:6px;padding:6px 10px;margin:0 0 8px}
.mng-err{font-size:12px;line-height:1.45;color:#c13a54;font-weight:600}
.mng-lead{font-size:12.5px;line-height:1.65;color:var(--ink-2);margin-bottom:18px;max-width:62ch}
.mng-lead b{color:var(--ink);font-weight:600}
.mng-actions{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:4px}
.mng-sub{margin-top:6px;padding-top:20px;position:relative}
.mng-sub::before{content:"";position:absolute;top:0;left:0;right:0;height:1.5px;border-radius:2px;
  background:linear-gradient(180deg, rgba(28,39,64,.07), rgba(255,255,255,.9))}

/* Variantes du bouton .mini — le geste dit sa couleur */
.mini.accent{color:var(--accent-ink)}
.mini.mut{color:var(--ink-3)}
.mini.danger{color:#c13a54}
.mini.danger:hover:not(:disabled){color:#c13a54}

/* ── Lignes répétables : pages critiques, contacts ── */
.mng-rep{display:grid;grid-template-columns:1fr 1fr 34px;gap:10px;align-items:center;margin-bottom:10px}
/* Un contact tient sur deux lignes plutôt qu'en quatre champs illisibles :
   nom + rôle, puis e-mail + téléphone, la croix couvrant les deux. */
.mng-rep.contact{row-gap:8px;margin-bottom:14px}
.mng-rep.contact .mng-x{grid-column:3;grid-row:1 / 3;align-self:center}
.mng-rep input{
  width:100%;padding:11px 14px;border:0;outline:none;border-radius:14px;
  font:inherit;font-size:12.5px;color:var(--ink);
  background:var(--surface);box-shadow:var(--carve);transition:box-shadow .3s;
}
.mng-rep input::placeholder{color:var(--ink-3)}
.mng-rep input:focus{box-shadow:var(--carve), 0 0 0 2px rgba(0,255,167,.35)}
.mng-rep .mng-err{grid-column:1 / -1}
.mng-x{
  width:34px;height:34px;border:0;cursor:pointer;border-radius:50%;font-family:inherit;
  font-size:16px;line-height:1;color:var(--ink-3);
  background:var(--posed);box-shadow:var(--raise-sm);
  transition:color .25s, box-shadow .3s;
}
.mng-x:hover{color:#c13a54;box-shadow:var(--raise)}

/* ── Pages critiques proposées : Claude propose, le hub vérifie, Raphaël signe ──
   Le verdict de CHAQUE page se lit sans cliquer nulle part. Une page écartée
   n'est pas repliée : c'est ce qu'on croyait tenir et qu'on ne tient pas. */
.pgc-sl{margin-top:16px}
.pgc-list{list-style:none;margin:10px 0 0;padding:0;display:flex;flex-direction:column;gap:2px}
.pgc-list li{
  display:grid;grid-template-columns:auto 1fr;column-gap:10px;row-gap:2px;
  align-items:baseline;padding:8px 12px 8px 26px;border-radius:12px;position:relative;
}
.pgc-list li:nth-child(odd){background:rgba(28,39,64,.025)}
/* La pastille porte le verdict : verte = chargée et répondue, ocre = pas retenue.
   Jamais un rouge d'alarme — une page écartée n'est pas une panne du site. */
.pgc-list li::before{
  content:"";position:absolute;left:11px;top:13px;width:6px;height:6px;border-radius:50%;
}
.pgc-list li.ok::before{background:#00d68c}
.pgc-list li.ko::before{background:#e3a02a}
.pgc-list b{font-size:12.5px;font-weight:600;color:var(--ink);word-break:break-all}
.pgc-list li.ko b{color:var(--ink-2);text-decoration:line-through;text-decoration-color:rgba(102,116,141,.4)}
.pgc-list .lbl{font-size:12.5px;color:var(--ink-2)}
.pgc-list .why{grid-column:1 / -1;font-size:11px;line-height:1.45;color:var(--ink-3)}
.pgc .mng-actions{margin-top:14px}
/* Sur l'écran d'arrivée, le bloc n'hérite pas de la boîte du formulaire de
   gestion : il lui faut sa propre respiration au-dessus des boutons de fin. */
.acc-pgc{margin:18px 0 4px}
.mng-x:active{box-shadow:var(--carve)}

/* ── Forfaits : une pièce gravée par prestation ── */
.mng-plan{padding:18px 20px 16px;border-radius:20px;margin-bottom:14px;
  background:var(--surface);box-shadow:var(--carve)}
.mng-plan:last-of-type{margin-bottom:0}
.mng-plan-h{display:flex;align-items:center;gap:12px;margin-bottom:8px}
.mng-plan-h b{font-size:13.5px;font-weight:600}
.mng-plan p{font-size:12.5px;line-height:1.6;color:var(--ink-2);margin-bottom:14px;max-width:60ch}
.mng-plan.on{background:var(--posed);box-shadow:var(--raise-sm)}
.mng-state{margin-left:auto;flex:none;font-size:9.5px;font-weight:600;letter-spacing:.09em;
  text-transform:uppercase;color:var(--ink-3);padding:5px 12px;border-radius:999px;
  background:var(--surface);box-shadow:var(--carve)}
.mng-state.on{color:var(--accent-ink)}

/* L'icône du site, et la phrase qui dit d'où elle vient — ou pourquoi il n'y
   en a pas. La pastille ne s'affiche que s'il y a une image : un monogramme de
   plus n'apprendrait rien, la fiche en porte déjà un. */
.icone-etat{display:flex;align-items:center;gap:14px;margin-bottom:14px}
.icone-etat .mng-note{margin:0;max-width:52ch}

/* Confirmation en ligne : une résiliation ne part jamais d'un seul clic */
.mng-confirm{padding:14px 16px;border-radius:16px;margin-top:4px;
  background:rgba(232,90,116,.07);box-shadow:var(--carve);border-left:3px solid var(--danger)}
.mng-confirm b{display:block;font-size:12.5px;font-weight:700;color:#a3253f}
.mng-confirm span{display:block;font-size:12px;line-height:1.55;color:var(--ink-2);margin-top:5px}
.mng-confirm-act{display:flex;gap:10px;margin-top:12px;flex-wrap:wrap}

/* ── Interrupteurs : l'état d'abord, la conséquence juste dessous ── */
.mng-switch{
  width:100%;display:flex;align-items:flex-start;gap:14px;text-align:left;
  padding:16px 18px;border:0;cursor:pointer;border-radius:20px;font-family:inherit;
  background:var(--surface);box-shadow:var(--carve);color:var(--ink);
  transition:box-shadow .3s;
}
/* Creux NET, sans les lueurs extérieures de `--carve` : sur les 38 px de la
   rainure, son halo blanc de 15 px débordait tout autour et, une fois la
   rainure verte, donnait une auréole laiteuse au lieu d'un sillon. */
.mng-switch i{
  width:38px;height:22px;flex:none;margin-top:2px;border-radius:999px;position:relative;
  background:var(--surface);box-shadow:var(--carve-net);transition:background .3s;
}
.mng-switch i::after{
  content:"";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;
  background:var(--posed);box-shadow:var(--raise-sm);
  transition:transform .3s cubic-bezier(.22,1,.36,1);
}
.mng-switch.on i{background:linear-gradient(150deg,#00e39a,#00b482)}
.mng-switch.on i::after{transform:translateX(16px)}
.mng-switch.warn.on i{background:linear-gradient(150deg,#e8a13a,#c9791a)}
.mng-switch span{min-width:0;display:block}
.mng-switch b{display:block;font-size:13px;font-weight:600;line-height:1.4}
.mng-switch em{display:block;font-style:normal;font-size:12px;line-height:1.55;color:var(--ink-2);margin-top:4px}
.mng-switch:hover{box-shadow:var(--carve), 0 0 0 2px rgba(0,255,167,.18)}
.mng-switch:disabled{opacity:.6;cursor:wait}
@media (prefers-reduced-motion:reduce){
  .mng-switch i::after{transition:none}
}

/* ── Contrôles : intitulé humain à gauche, rythme à droite ── */
.mng-check{display:flex;align-items:center;gap:14px;padding:12px 2px;position:relative}
.mng-check + .mng-check::before{content:"";position:absolute;top:0;left:6px;right:6px;height:1px;
  background:linear-gradient(180deg, rgba(28,39,64,.05), rgba(255,255,255,.7))}
/* Même spécificité que la règle générale des champs, mais plus bas dans le
   fichier : le rythme reste à sa largeur propre et n'écrase pas l'intitulé. */
.mng .mng-check select{flex:none;width:auto;min-width:168px;font-size:12.5px;padding:10px 14px}
.mng-check-lbl{display:flex;align-items:flex-start;gap:11px;cursor:pointer;min-width:0;flex:1 1 auto}
.mng-check-lbl input[type=checkbox]{width:17px;height:17px;flex:none;margin-top:2px;
  accent-color:#00c583;cursor:pointer}
.mng-check-lbl span{min-width:0;font-size:12.5px;color:var(--ink-2)}
.mng-check-lbl b{display:block;font-size:13px;font-weight:600;color:var(--ink);line-height:1.4}
.mng-check-lbl em{display:block;font-style:normal;font-size:11.5px;color:var(--ink-3);margin-top:3px}

/* ── Accès : l'existence, jamais la valeur ── */
.mng-cred{padding:16px 18px;border-radius:20px;margin-bottom:14px;
  background:var(--surface);box-shadow:var(--carve)}
.mng-cred-h{display:flex;align-items:baseline;gap:12px}
.mng-cred-h b{font-size:13px;font-weight:600}
.mng-cred-h .mono{margin-left:auto;font-size:10px;color:var(--ink-3)}
.mng-cred-meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:11px}
.mng-cred-meta span{display:inline-flex;align-items:center;gap:7px;padding:6px 11px;border-radius:11px;
  font-family:'Spline Sans Mono';font-size:10.5px;color:var(--ink-2);
  background:var(--posed);box-shadow:var(--raise-sm)}
.mng-cred-meta i{font-style:normal;font-size:9px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3)}
.mng-cred-foot{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:14px}
.mng-cred-foot .spacer{margin-left:auto}
.mng-sealed{display:inline-flex;align-items:center;gap:7px;font-size:11px;font-weight:600;
  color:var(--accent-ink);padding:6px 12px;border-radius:999px;
  background:rgba(0,214,140,.12)}
.mng-sealed::before{content:"";width:5px;height:5px;border-radius:50%;background:#00c583}
@media (max-width:1240px){
  .mng-row{grid-template-columns:1fr}
  .mng-rep{grid-template-columns:1fr 34px}
  .mng-rep.contact .mng-x{grid-row:1 / 5}
  .mng-check{flex-wrap:wrap}
  .mng .mng-check select{width:100%}
}


/* ═══════════════════════════════════════════════════════════════════════
   Gestion des accès (écran Sites\Access) — l'écran le plus sensible.
   Aucune valeur de secret n'est affichable : les pièces ci-dessous ne
   montrent que des métadonnées, sauf .acc-once (clé générée, vue une fois).
   ═══════════════════════════════════════════════════════════════════════ */

.acc-page .site-sub b{color:var(--ink-2);font-weight:600}
.acc-grid{grid-template-columns:1.15fr .85fr}

/* ── Une entrée d'accès : état, résumé humain, gestes ── */
.acc{padding:18px 0;position:relative}
.acc + .acc::before{content:"";position:absolute;top:0;left:2px;right:2px;height:1px;
  background:linear-gradient(180deg, rgba(28,39,64,.06), rgba(255,255,255,.8))}
.acc-head{display:flex;align-items:center;gap:11px;flex-wrap:wrap}
.acc-head b{font-size:13.5px;font-weight:600}
.acc-head .st{font-size:11.5px}
.acc-sum{font-size:12.5px;color:var(--ink-2);line-height:1.55;margin-top:7px;max-width:56ch}
.acc.missing .acc-sum{color:#c13a54}
.acc-meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:10px;
  font-size:11px;color:var(--ink-3)}
.acc-meta .sep{width:3px;height:3px;border-radius:50%;background:var(--ink-3);opacity:.6;flex:none}
.acc-set{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px;margin-top:14px}
.acc-set .core .v{font-size:12px}
.acc-hidden{font-size:11px;color:var(--ink-3);line-height:1.5;margin-top:9px}
/* La promesse « valeur scellée · non consultable », rendue à cet écran le
   10/09/2026 avec la référence `vault:{id}` : les deux phrases sont parties
   avec la carte « Accès » de `/gerer`, dissous le matin même, et n'existaient
   plus nulle part. La pastille est `.mng-sealed` (plus haut), telle qu'elle
   était : une seconde déclaration de la même chose aurait divergé au premier
   correctif. Ici, seul son décalage. */
.acc-seal{margin-top:13px}
.acc-acts{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-top:15px}

/* Gestes : les pastilles de la fiche site (`.mini.danger`, `.mini.mut`, plus
   haut) valent ici telles quelles — les redéclarer à l'identique n'ajoutait
   qu'un endroit de plus où les faire diverger. Une seule tonalité en propre. */
.mini.acc-go{color:var(--accent-ink)}

/* ── Panneau de droite : le geste en cours ── */
.acc-panel .ch{margin-bottom:16px}
.acc-lead{font-size:12.5px;color:var(--ink-2);line-height:1.6;max-width:58ch}
.acc-lead + .acc-form{margin-top:20px}
.acc-warn{font-size:13px;color:#c13a54;line-height:1.55;margin-bottom:12px}
.acc-panel.danger{background:linear-gradient(150deg, rgba(232,90,116,.09), rgba(241,244,249,.9))}

.acc-form{display:flex;flex-direction:column;gap:15px}
.acc-row{display:grid;grid-template-columns:.4fr 1fr;gap:14px}
.acc-form .field-lbl{display:flex;align-items:baseline;gap:7px}
.acc-opt{font-size:9.5px;letter-spacing:.06em;text-transform:none;color:var(--ink-3);font-weight:400}
.acc-form textarea{
  width:100%;padding:13px 18px;border:0;outline:none;border-radius:16px;resize:vertical;
  font-family:'Spline Sans Mono',monospace;font-size:12px;line-height:1.5;color:var(--ink);
  background:var(--surface);box-shadow:var(--carve);transition:box-shadow .3s;
}
.acc-form textarea::placeholder{color:var(--ink-3)}
.acc-form textarea:focus{box-shadow:var(--carve), 0 0 0 2px rgba(0,255,167,.35)}
.acc-form select{width:100%;padding:13px 18px;border:0;outline:none;border-radius:16px;
  font:inherit;font-size:14px;color:var(--ink);background:var(--surface);box-shadow:var(--carve);
  appearance:none;cursor:pointer;transition:box-shadow .3s}
.acc-form select:focus{box-shadow:var(--carve), 0 0 0 2px rgba(0,255,167,.35)}
.acc-form-acts{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:4px}
/* Le sélecteur « clé ou mot de passe » d'un panneau d'accès.
   ⚠️ Il portait `class="mode"` — le conteneur de la bascule Simple/Avancé,
   dont la RÈGLE a disparu avec elle le 03/08/2026 pendant que le `<div>`
   restait dans la vue. Deux boutons `.f` sans gouttière ni alignement, HTML
   valide, aucune assertion pour le dire : c'est exactement le piège n° 8 de
   `docs/roles/socle.md`. Réparé le 31/08 en même temps que le panneau SFTP,
   qui allait le recopier. `.filters` aurait fait l'affaire à un `margin-left`
   près, qui décalait le groupe de 8 px dans un formulaire. */
.acc-modes{display:flex;gap:4px;flex-wrap:wrap}
.acc-note{font-size:11.5px;color:var(--ink-3);line-height:1.5;margin-top:18px}
/* `.acc-link` n'appartient plus à la famille « accès » depuis longtemps : il
   sert déjà sur `sites/add` et `mng-depots`. C'est LE bouton nu du hub — et
   c'est aussi, depuis le 03/08/2026, la poignée d'un dépliant : `.on` = ouvert,
   seule la flèche tourne. Rien n'anime la hauteur, ça demanderait du JS de
   mesure sur du contenu rendu serveur pour zéro gain — et ça obligerait à
   toucher les trois blocs `prefers-reduced-motion`. */
/* ⚠️ `text-decoration:none` n'est pas décoratif : cette classe n'avait jamais
   servi que sur des <button>, qui ne se soulignent pas. Posée sur un <a> — le
   lien « Voir le brouillon ↗ » du fil, 05/08/2026 — le soulignement du
   navigateur revenait, et le lien détonnait au milieu de gestes qui n'en ont
   pas. Même famille que le titre du dock rendu en bleu navigateur le 03/08. */
.acc-link{background:transparent;border:0;padding:0;cursor:pointer;font-family:inherit;
  font-size:11.5px;font-weight:600;color:var(--accent-ink);text-decoration:none;
  transition:opacity .25s}
.acc-link:hover{opacity:.7}
.acc-link svg{width:12px;height:12px;vertical-align:-1px;margin-right:5px;transition:transform .25s}
.acc-link.on svg{transform:rotate(90deg)}
/* Une poignée qui annonce un manque ne se peint pas de la couleur d'un geste.
   Le vert accent du hub dit « clique, c'est la suite normale » ; ici la poignée
   porte le seul signal visible sans ouvrir (« 1 page à vérifier »), et un
   signal peint en vert n'en est plus un. Même ocre que `.mng-note.warn`. */
.acc-link.warn{color:#a9741e}

/* ── Choix du type d'accès à ajouter ── */
.acc-choices{display:flex;flex-direction:column;gap:11px}
.acc-choice{display:flex;flex-direction:column;align-items:flex-start;gap:5px;text-align:left;
  padding:14px 17px;border:0;border-radius:18px;cursor:pointer;font-family:inherit;
  background:var(--posed);box-shadow:var(--raise-sm);
  transition:transform .25s, box-shadow .3s, color .25s}
.acc-choice b{font-size:12.5px;font-weight:600;color:var(--ink)}
.acc-choice span{font-size:11.5px;color:var(--ink-2);line-height:1.45}
.acc-choice:hover{transform:translateY(-2px);box-shadow:var(--raise)}
.acc-choice:hover b{color:var(--accent-ink)}
.acc-choice:active{transform:none;box-shadow:var(--carve)}
/* Choix retenu (écran d'ajout : niveau d'accès sélectionné) */
.acc-choice.on{box-shadow:var(--carve), 0 0 0 2px rgba(0,255,167,.35)}
.acc-choice.on b{color:var(--accent-ink)}

/* ── Guide hébergeur (écran d'ajout) : contenu markdown, ton discret ── */
.host-guide{padding:16px 20px;border-radius:16px;background:var(--surface);box-shadow:var(--carve);
  font-size:12.5px;line-height:1.6;color:var(--ink-2)}
.host-guide h1{font-size:13px;font-weight:600;color:var(--ink);margin:0 0 8px}
.host-guide h2{font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  color:var(--ink-3);margin:14px 0 6px}
/* Un `###` du markdown tombait sur le style par défaut du navigateur, donc
   PLUS gros que le `##` qui le contient : hiérarchie inversée (01/09/2026). */
.host-guide h3{font-size:12px;font-weight:600;color:var(--ink);margin:12px 0 5px}
.host-guide p{margin:6px 0}
.host-guide ol,.host-guide ul{margin:6px 0;padding-left:20px}
.host-guide li{margin:3px 0}
.host-guide blockquote{margin:8px 0;padding:8px 14px;border-left:3px solid var(--warn);
  border-radius:0 10px 10px 0;color:var(--ink-2)}
.host-guide code{font-family:'Spline Sans Mono';font-size:11px;color:var(--ink)}

/* La clé publique générée : fond clair de l'écran d'ajout — .acc-code est
   taillé pour le panneau sombre de la clé worker, illisible ici. */
.pubkey{margin:0;padding:14px 18px;border-radius:14px;background:var(--surface);box-shadow:var(--carve);
  font-family:'Spline Sans Mono',monospace;font-size:11.5px;line-height:1.6;color:var(--ink);
  white-space:pre-wrap;word-break:break-all;user-select:all}

/* ── Verdict de test : réutilise la gouttière d'alertes ── */
.acc-verdict{margin-bottom:26px}
.acc-verdict .al .tx span{line-height:1.5}

/* ── Clé générée : la SEULE valeur en clair du hub, montrée une fois ── */
.acc-once{margin-bottom:26px;padding:26px 30px 24px;border-radius:28px;
  background:linear-gradient(150deg,#12474a,#0d3538);
  box-shadow:16px 18px 44px rgba(10,45,48,.24), inset 0 1px 0 rgba(255,255,255,.12);
  animation:var(--entree,fade) .9s cubic-bezier(.22,1,.36,1) both}
.acc-once .ch{margin-bottom:14px}
.acc-once .ch h2{color:#fff}
.acc-once .ch .mono{color:var(--accent);margin-left:auto}
.acc-once-lead{font-size:12.5px;line-height:1.6;color:rgba(255,255,255,.72);max-width:64ch}
.acc-once code{font-family:'Spline Sans Mono',monospace;font-size:11.5px;color:var(--accent)}
/* ⚠️ Le blanc appartient au PANNEAU SOMBRE de la clé générée, pas à la classe.
   La même liste sert l'écran d'ajout, sur fond clair, où elle était illisible
   (trouvée à l'image le 01/09/2026, invisible en test : le HTML était juste).
   Même leçon que .pubkey plus haut, et même piège que .acc-code. */
.acc-steps{margin:16px 0 16px 18px;padding:0;display:flex;flex-direction:column;gap:7px;
  font-size:12.5px;line-height:1.5;color:var(--ink-2)}
.acc-steps code{font-family:'Spline Sans Mono',monospace;font-size:11px;color:var(--ink)}
/* Une étape ÉCHOUÉE ne se distingue pas par un caractère.
   ⚠️ Le compte rendu d'arrivée rendait « ✗ » et « ✓ » dans la même teinte, la
   même graisse et la même taille : une étape en échec se lisait comme une
   réussie, ce qui est exactement le défaut que le lot du 01/09/2026 corrige
   (un transport annoncé en place alors que sa racine ne contenait aucun
   WordPress). Le mot compte plus que le signe. */
.acc-steps li.ko{color:var(--danger);font-weight:500}
.acc-steps li.ko code{color:var(--danger)}
.acc-once .acc-steps{color:rgba(255,255,255,.72)}
.acc-once .acc-steps code{color:var(--accent)}
.acc-code{margin:0 0 18px;padding:16px 20px;border-radius:16px;overflow-x:auto;
  background:rgba(0,0,0,.28);box-shadow:inset 0 1px 0 rgba(255,255,255,.06);
  font-family:'Spline Sans Mono',monospace;font-size:12px;line-height:1.7;color:var(--accent);
  white-space:pre;user-select:all}
.acc-once .mini{background:rgba(255,255,255,.1);box-shadow:none;color:#fff}
.acc-once .mini:hover:not(:disabled){background:rgba(255,255,255,.16);color:#fff;transform:none;box-shadow:none}

@media (max-width:1180px){
  .acc-grid{grid-template-columns:1fr}
  .acc-row{grid-template-columns:1fr}
}


/* ── Écran du travail ─────────────────────────────────────────────────────
   Aucun écran ne listait les tâches : trois étaient en échec en base, dont le
   triage d'un bug client urgent, sans que rien ne le remonte. */
.work-page .work-filters{display:flex;gap:8px;padding:0 26px;margin:-6px 0 20px}
.work-group .ch .mono{margin-left:auto;color:var(--ink-3);font-size:11px}

.wk{display:flex;align-items:flex-start;gap:16px;padding:13px 0;
    border-top:1px solid var(--hair)}
.wk:first-of-type{border-top:0}
.wk-main{min-width:0;flex:1}
.wk-title{display:flex;align-items:baseline;gap:9px;min-width:0}
.wk-title b,.wk-title a{font-size:13.5px;font-weight:600;color:var(--ink-1);
    text-decoration:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wk-title a:hover{color:var(--accent-ink)}
.wk-title .chip{flex:none}
.wk-title .id{flex:none;font-size:10px;color:var(--ink-3)}
.wk-sub{display:flex;align-items:center;gap:7px;margin-top:4px;
    font-size:11.5px;color:var(--ink-3)}
.wk-sub a{color:var(--ink-2);text-decoration:none}
.wk-sub a:hover{color:var(--accent-ink)}
.wk-sub .sep{width:3px;height:3px;border-radius:50%;background:var(--ink-3);
    opacity:.5;flex:none}
.wk-why{margin-top:7px;padding:8px 11px;border-radius:9px;
    background:rgba(232,90,116,.06);
    font-size:11.5px;line-height:1.5;color:#a33049}
/* ⚠️ UNE SESSION QUI A LIVRÉ N'EST PAS UNE ANOMALIE. `.wk-why` est le bloc
   ROUGE de cet écran : un échec, un point non vérifié, un report subi.
   Réutilisé tel quel pour « cette session a rendu son travail », il fait lire
   un problème là où il n'y a qu'un fait — mesuré à l'image le 02/09/2026, le
   HTML était juste et rien ne tombait. Même boîte, même place, même poids :
   seule la teinte change. */
.wk-why.calme{background:var(--surface);box-shadow:var(--carve);color:var(--ink-2)}
.wk-why.calme b{color:var(--ink-1)}
.wk-act{flex:none;display:flex;align-items:center;gap:8px;padding-top:2px}
.wk-act .mini{white-space:nowrap}
.wk-act .mini.go{color:var(--accent-ink);font-weight:600}
.wk-act .mini.no{color:var(--ink-3)}
.wk-act .mini.no:hover{color:#c13a54}
.wk-act .mini.no.confirm{color:#c13a54;font-weight:700;background:rgba(224,64,92,.08)}

/* Une tâche en échec doit se voir : la classe existait dans la vue depuis
   toujours (work/index.blade.php:114) mais n'existait pas ici — les tâches
   cassées avaient la même typographie que le reste, sur le seul écran
   censé les faire remonter. */
.wk-fail{position:relative;padding-left:14px}
.wk-fail::before{content:"";position:absolute;left:0;top:13px;bottom:13px;width:3px;
  border-radius:2px;background:linear-gradient(180deg,#e07f92,var(--danger))}
.wk-fail .wk-title b,.wk-fail .wk-title a{color:#a33049}

.brief{margin:6px 0 0;font-size:13px;line-height:1.6;color:var(--ink-2);max-width:74ch}
.progress-bar{margin-top:10px;height:6px;border-radius:99px;background:rgba(143,157,182,.15);overflow:hidden}
.progress-bar > i{display:block;height:100%;background:linear-gradient(90deg,#00d68c,var(--accent))}
.task-body{margin-top:12px;padding:12px 14px;border-radius:10px;background:rgba(143,157,182,.07);
  font-family:'Spline Sans Mono';font-size:11.5px;line-height:1.6;color:var(--ink-2);
  overflow:auto;max-height:360px;white-space:pre-wrap;word-break:break-word}
.task-artifacts{margin-top:12px;padding:11px 14px;border-radius:10px;background:rgba(143,157,182,.07)}
.task-artifacts > b{display:block;font-size:11.5px;font-weight:600;color:var(--ink-1);margin-bottom:6px}
.task-artifacts ul{list-style:none;margin:0;padding:0}
.task-artifacts li{font-size:11.5px;line-height:1.7;color:var(--ink-2);display:flex;gap:8px;align-items:baseline;flex-wrap:wrap}
.task-artifacts a{color:var(--accent-ink);text-decoration:none}
.task-artifacts a:hover{text-decoration:underline}
.run{padding:12px 0;border-top:1px solid var(--hair)}
.run:first-of-type{border-top:0}
.run-h{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.run-h .chip{flex:none;font-size:9.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;
  padding:4px 9px;border-radius:999px;background:var(--surface);box-shadow:var(--carve);
  color:var(--ink-2);display:inline-flex;align-items:center;gap:5px}
.run-h .chip.run i{width:5px;height:5px;border-radius:50%;background:#00d68c;
  box-shadow:0 0 6px rgba(0,230,150,.6);animation:pulse 2.2s infinite}
.run-h .chip.ok{color:var(--accent-ink)}
.run-h .chip.ko{color:#c13a54}
.run-h b{font-size:12.5px;font-weight:600;color:var(--ink-1)}
.run-h .mono{font-size:10.5px;color:var(--ink-3);margin-left:auto}

/* ── Les écrans du travail à 420 px ──
   Mesuré au navigateur le 13/09/2026 : `/travail` défilait de 512 px en
   largeur, `/travail/278` de 71 px. Le dock n'y était pour rien (masqué, le
   défilement ne bougeait pas d'un pixel). C'étaient l'entête (la recherche à
   290 px et deux boutons insécables), les filtres, la colonne d'actions d'une
   ligne (`flex:none`, jusqu'à 444 px) et les chemins d'artefacts, sans point
   de coupure. Au-dessus de 560 px, rien ne change.

   ── Et tout le hub à 420 px (13/09/2026, socle 38) ──
   La colonne de contenu faisait 125 px menu déplié, 206 replié : `.page`
   réservait `--goo-w + 50px` à gauche et 76 px à droite. Sous 560 px elle ne
   réserve plus que le menu REPLIÉ (88 px) et la bande du dock (56 px), plus
   une gouttière : 250 px dans les deux états. Le menu s'y ouvre toujours replié
   (`hub.js`), et déplié il passe par-dessus la page au lieu de la pousser.
   Seuls `padding-left` et `padding-right` : `.inbox-page` règle son bas. */
@media (max-width:560px){
  .page{padding-left:102px;padding-right:68px}
  /* Avant que `hub.js` ait replié le menu, ses libellés ne clignotent pas. */
  .goo:not([data-goo-init]) .lb{opacity:0}
  /* Le bandeau de chiffres (Flotte, fiche d'un site, `/monitoring`) gardait
     trois à cinq colonnes : 245 px de défilement sur la Flotte, 436 sur la
     fiche. Deux colonnes, l'anneau de santé sur toute la ligne. */
  .kpi-bar{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .kpi-bar .kpi.hero{grid-column:1/-1}
  .kpi{padding:18px 16px}
  .kpi + .kpi::before{display:none}
  .kpi .lbl{overflow-wrap:anywhere}
  /* `/playbooks` : l'intitulé passe au-dessus de son texte. */
  .pb-detail{grid-template-columns:minmax(0,1fr)}
  .pb-detail dd{overflow-wrap:anywhere}
  /* L'entête de tous les écrans : recherche (290 px) et boutons insécables
     faisaient défiler la Flotte de 169 px, la fiche d'un site de 61. */
  .top{flex-wrap:wrap;gap:12px}
  .top .search{margin-left:0;width:100%}
  .top .btn{white-space:normal}
  .site-top .top-actions{flex:1 1 100%;min-width:0;align-items:flex-start}
  .site-top .ta-row{flex-wrap:wrap}
  /* La Flotte : les filtres de la liste passent à la ligne. */
  .sites-head{flex-wrap:wrap;gap:8px 16px}
  .filters{flex-wrap:wrap;margin-left:0}
  /* Le journal de la fiche : le titre d'un geste prend sa ligne, sinon il
     tenait entre l'acteur et la date, un mot par ligne. */
  .jt{flex-wrap:wrap}
  .jt b{flex-basis:100%}
  /* « Ce qui demande une action » (Flotte et fiche) : le geste passe sous le
     texte, qui tenait sinon un mot par ligne à côté de lui. 20 px = la pastille
     et son écart. */
  .todo{flex-wrap:wrap}
  .todo .tx{flex-basis:calc(100% - 20px)}
  .todo .act{margin-left:20px}
  .work-page .top{flex-wrap:wrap;gap:12px}
  .work-page .top .search{margin-left:0;width:100%}
  .work-page .top .btn{white-space:normal}
  .work-page .work-filters{flex-wrap:wrap;padding:0;gap:4px}
  .work-page .wk{flex-wrap:wrap}
  .work-page .wk-title{flex-wrap:wrap}
  .work-page .wk-why{overflow-wrap:anywhere}
  .work-page .wk-act{flex:1 1 100%;flex-wrap:wrap}
  .work-page .wk-act .mini,.work-page .mng-actions .mini{white-space:normal}
  .work-page .task-artifacts li .mono{min-width:0;overflow-wrap:anywhere}
  /* `/monitoring` et l'onglet Surveillance (13/09/2026, surveiller 04). Mesuré
     à 420 px : `.wk-sub` ne passait jamais à la ligne, ses phrases tenaient sur
     25 à 77 px de large et jusqu'à 196 px de haut, et le titre était coupé à
     190 px par son ellipse ; dans l'onglet, qui ne porte pas `.work-page`, les
     gestes (351 px) ramenaient `.wk-main` à 0 px. La ligne s'empile dans l'ordre
     de lecture : ce qui ne va pas, depuis quand, le détail, le geste. Rien n'est
     masqué, le titre s'écrit en entier. */
  .mon-alerte{flex-wrap:wrap}
  .mon-alerte .wk-main{flex:1 1 100%}
  .mon-alerte .wk-title{flex-wrap:wrap;row-gap:2px}
  .mon-alerte .wk-title b{flex-basis:100%;white-space:normal;overflow-wrap:anywhere}
  .mon-alerte .wk-sub{flex-wrap:wrap;row-gap:3px}
  .mon-alerte .wk-sub > span:not(.sep),.mon-alerte .wk-why{overflow-wrap:anywhere}
  .mon-alerte > .wk-act{flex:1 1 100%;flex-wrap:wrap}
  .mon-alerte > .wk-act .mini{white-space:normal}
  /* Les contrôles : le nom et l'état sur une ligne quand ils y tiennent, puis
     la date ou le geste, puis le motif. La grille (170 et 150 px, `1fr auto`
     sous 900) serrait le nom sur 46 px à côté d'un état long et rangeait le
     geste dans la seule première colonne, 98 px de large. Sélecteurs doublés :
     la grille est déclarée plus bas dans ce fichier et gagnerait sinon. */
  .mon-rows > .mon-row{display:flex;flex-wrap:wrap;align-items:center;gap:3px 10px}
  .mon-rows > .mon-row > .mon-when,.mon-rows > .mon-row > .wk-act,
  .mon-rows > .mon-row > .mon-msg,.mon-rows > .mon-row > .wk-why{flex:1 1 100%;min-width:0}
  .mon-rows > .mon-row > .wk-act{flex-wrap:wrap}
  .mon-rows > .mon-row .mini{white-space:normal}
  .mon-rows > .mon-row .mon-when,.mon-rows > .mon-row .mon-msg{overflow-wrap:anywhere}
  /* Le nom du site, son responsable et « Contrôler » ; dans l'onglet, le titre
     de la carte et « Contrôler maintenant » (146 px qui débordaient). */
  .mon-head{flex-wrap:wrap}
  .tab-embed .work-group .ch{flex-wrap:wrap}
}

/* Un staging en erreur : la ligne d'explication se colle sous la ligne
   principale, pour ne pas passer inaperçue. */
.stg-err-row{border-top:0;padding-top:0;padding-left:16px}
.stg-err-row .wk-sub{color:#a33049}

/* La pastille « en direct » du pipeline ne doit pulser QUE quand la page
   respire. `.live.mut` la sort de son animation. */
.pipeline .live.mut i{animation:none;background:var(--ink-3);box-shadow:none}
.pipeline .live-tick{margin-left:6px;font-size:10.5px;color:var(--ink-3);font-family:'Spline Sans Mono'}

/* Bloc « Déployer » sur la fiche de gestion : la classe existait dans
   manage.blade.php:564, absente d'ici — les boutons Recharger/Démonter,
   qui touchent la copie, et Comparer/Préparer, qui préparent la prod,
   se lisaient comme une seule rangée. */
.stg-deploy{margin-top:18px;padding-top:16px;border-top:1px dashed rgba(143,157,182,.35)}


/* ── Respecter « moins d'animations » ──────────────────────────────────────
   Une quinzaine de pulsations tournent en boucle infinie sur un tableau de
   bord qui reste ouvert toute la journée. Deux blocs ciblés les couvraient ;
   celui-ci couvre le reste, d'un coup. Découvert en constatant que Playwright
   ne parvenait jamais à considérer la page comme « stable ». */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
}


/* ── Monitoring : les contrôles, groupés par site ────────────────────────── */
.mon-site{padding:13px 0;border-top:1px solid var(--hair)}
.mon-site:first-of-type{border-top:0}
.mon-head{display:flex;align-items:baseline;gap:10px;margin-bottom:8px}
.mon-head a{font-size:13px;font-weight:600;color:var(--ink-1);text-decoration:none}
.mon-head a:hover{color:var(--accent-ink)}
.mon-rows{display:flex;flex-direction:column;gap:5px}
.mon-row{display:grid;grid-template-columns:170px 150px 1fr;align-items:center;gap:12px}
.mon-kind{font-size:12px;color:var(--ink-2)}
.mon-when{font-family:'Spline Sans Mono';font-size:10.5px;color:var(--ink-3)}
.mon-msg{grid-column:1 / -1;font-size:11.5px;color:#a33049;padding:5px 10px;border-radius:8px;
  background:rgba(232,90,116,.06)}
@media (max-width:900px){
  .mon-row{grid-template-columns:1fr auto}
  .mon-when{grid-column:1 / -1}
}


/* Commandes à recopier : monospace, lisibles, sélectionnables. */
.cmd-list{display:flex;flex-direction:column;gap:7px;margin-top:12px}
.cmd-list code{font-family:'Spline Sans Mono';font-size:11.5px;color:var(--ink-2);
  padding:8px 12px;border-radius:9px;background:rgba(143,157,182,.09);
  user-select:all;overflow-x:auto;white-space:nowrap}


/* ── Pages d'erreur ───────────────────────────────────────────────────────
   Une page introuvable renvoyait la page blanche de Laravel, sans même un
   chemin de retour : au milieu d'un hub, c'est une impasse de plus. */
.err-body{min-height:100vh;display:grid;place-items:center;
  background:linear-gradient(200deg,#f6f8fc,#eef1f7);margin:0}
.err{text-align:center;padding:40px;max-width:520px}
.err-code{font-family:'Spline Sans Mono';font-size:11px;letter-spacing:.22em;
  color:var(--ink-3);margin-bottom:18px}
.err h1{font-family:'Clash Display';font-size:26px;font-weight:600;letter-spacing:.02em;
  text-transform:uppercase;color:var(--ink-1);margin:0 0 12px}
.err p{font-size:13.5px;line-height:1.6;color:var(--ink-2);margin:0 0 28px}
.err-back{display:inline-flex;align-items:center;gap:8px;padding:11px 20px;border-radius:999px;
  font-size:12.5px;font-weight:600;color:var(--accent-ink);text-decoration:none;
  background:var(--surface);box-shadow:var(--raise-sm);transition:transform .25s}
.err-back:hover{transform:translateY(-1px)}


/* ── Copie de recette, sur la fiche de gestion ────────────────────────────
   Le staging n'est pas qu'une étape du pipeline : c'est l'endroit où l'on
   essaie avant de toucher à la production. */
.stg-live{display:flex;flex-direction:column;gap:4px;margin-bottom:14px}
.stg-url{font-size:13px;font-weight:600;color:var(--accent-ink);text-decoration:none;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.stg-url:hover{text-decoration:underline}
.stg-meta{font-size:11.5px;color:var(--ink-3)}
.mng-actions{display:flex;flex-wrap:wrap;gap:9px;margin-top:12px}
.mng-actions .mini.go{color:var(--accent-ink);font-weight:600}
.mng-actions .mini.no{color:var(--ink-3)}
.mng-actions .mini.no:hover{color:#c13a54}
.mng-actions .mini:disabled{opacity:.45;cursor:default;box-shadow:none}
.stg-busy{margin-top:12px;font-size:11.5px;line-height:1.5;color:var(--ink-3)}
.stg-busy a{color:var(--accent-ink);text-decoration:none}


/* ── « Ce que j'ai changé » sur la copie de recette ───────────────────────
   Revenir sur un staging vieux de trois jours et se rappeler ce qu'on y a
   touché n'a rien d'évident. */
.stg-diff{margin-top:14px;padding:12px 14px;border-radius:11px;
  background:rgba(143,157,182,.07)}
.stg-diff > b{display:block;font-size:12.5px;font-weight:600;color:var(--ink-1);margin-bottom:10px}
.stg-diff-groupe{margin-top:10px}
.stg-diff-groupe .st{font-size:11.5px;font-weight:600}
.stg-diff-groupe ul{list-style:none;margin:5px 0 0;padding:0 0 0 13px}
.stg-diff-groupe li{font-family:'Spline Sans Mono';font-size:10.5px;color:var(--ink-2);
  line-height:1.7;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.stg-why{margin-top:10px;font-size:11.5px;line-height:1.5;color:var(--ink-3)}
.stg-why code{font-family:'Spline Sans Mono';font-size:10.5px;color:var(--ink-2)}

/* ── Playbooks ──────────────────────────────────────────────────────────────
   « Ce problème que j'ai déjà résolu, où se pose-t-il encore ? » L'écran vit
   de deux gestes seulement — comparer, puis lancer — donc rien ici ne cherche
   à impressionner : la liste des sites concernés EST le contenu. */
.pb-scope{display:inline-flex;align-items:center;gap:9px;cursor:pointer;
  font-size:12px;color:var(--ink-2)}
.pb-scope input{accent-color:var(--acc);width:15px;height:15px;cursor:pointer}

.pb-symptom{margin:4px 0 0;font-size:12.5px;line-height:1.6;color:var(--ink-2)}

/* Le détail est réservé au mode Avancé : en simple, le symptôme suffit à
   reconnaître un playbook, et cinq paragraphes de procédure noieraient les
   deux boutons qui comptent. */
.pb-detail{display:grid;grid-template-columns:auto 1fr;gap:6px 14px;
  margin:12px 0 0;padding:11px 13px;border-radius:10px;
  background:rgba(143,157,182,.06)}
.pb-detail dt{font-size:10.5px;font-weight:600;text-transform:uppercase;
  letter-spacing:.04em;color:var(--ink-3);white-space:nowrap}
.pb-detail dd{margin:0;font-size:11.5px;line-height:1.55;color:var(--ink-2)}

/* Les lignes des groupes portent ici un nom de site en gras suivi d'une
   raison en clair : elles doivent pouvoir revenir à la ligne, contrairement
   aux chemins de fichiers du staging qu'on tronque volontairement. */
.stg-diff-groupe li b{color:var(--ink-1);font-weight:600}
.pb-wrap li{white-space:normal;overflow:visible;text-overflow:clip}

/* ── Perf & SEO ─────────────────────────────────────────────────────────────
   Deux questions, et l'écran refuse de confondre leurs réponses : quels sites
   sont lents, et lesquels n'ont pas été mesurés. Un site injoignable n'est pas
   un site rapide.

   Grille unique pour toutes les lignes mesurées : le TTFB et le score démarrent
   au même endroit quel que soit le mot du verdict. Une grille par ligne, comme
   avant, faisait bouger les colonnes selon la largeur du mot — les chiffres
   qu'on veut balayer verticalement ne s'alignaient pas. */
/* SIX colonnes depuis le 04/08/2026, sept auparavant : la colonne « Tendance »
   est descendue dans la cellule du temps de réponse, sous le chiffre qu'elle
   qualifie. Isolée entre « Poids » et « PageSpeed », elle se lisait comme la
   tendance du score alors qu'elle ne compare que deux TTFB. */
.perf-rows{margin-top:12px;display:grid;grid-template-columns:1fr 90px 76px 68px 96px 96px;
  align-items:center;gap:6px 12px}
/* L'en-tête de colonnes : mêmes six cellules que la ligne, donc `display:
   contents` lui aussi, la grille de `.perf-rows` les place. Les colonnes
   de chiffres sont à droite, comme leurs valeurs. */
.perf-cols{display:contents}
.perf-cols > span{
  font-size:10px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3);padding:0 0 8px;text-align:right;white-space:nowrap}
.perf-cols > span[title]{cursor:help}
.perf-cols > span:first-child{padding-left:11px;text-align:left}
.perf-cols > span:last-child{padding-right:11px}
.perf-row{display:contents}
.perf-row>*{padding:9px 0;transition:background .12s}
.perf-row>*:first-child{padding-left:11px;border-top-left-radius:9px;border-bottom-left-radius:9px}
.perf-row>*:last-child{padding-right:11px;border-top-right-radius:9px;border-bottom-right-radius:9px}
.perf-row:hover>*{background:rgba(143,157,182,.06)}
.perf-row.muet{grid-column:1/-1;display:grid;grid-template-columns:1fr auto 1fr auto;
  align-items:center;gap:12px;padding:9px 11px;border-radius:9px}
.perf-row.muet:hover{background:rgba(143,157,182,.06)}
.perf-row.muet>*{padding:0;background:transparent}
.perf-site{font-size:12.5px;font-weight:600;color:var(--ink-1);text-decoration:none;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.perf-site:hover{color:var(--acc)}
.perf-val{font-family:'Spline Sans Mono';font-size:11px;color:var(--ink-2);
  text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Score PageSpeed : coloré selon les seuils Google (vert ≥ 90, orange 50-89,
   rouge < 50) et accompagné du mot. Un chiffre sans seuil est du bruit — 31/100
   avec la même classe qu'un poids en Ko a le poids visuel d'une unité. */
.perf-score{display:flex;flex-direction:column;align-items:flex-end;line-height:1.05;text-align:right}
.perf-score b{font-family:'Spline Sans Mono';font-size:13px;font-weight:600;letter-spacing:-.01em}
.perf-score small{font-size:9.5px;color:var(--ink-3);font-weight:400;margin-left:1px}
.perf-score-mot{font-size:9.5px;letter-spacing:.04em;text-transform:uppercase;color:var(--ink-3);margin-top:1px}
.perf-score.bon b{color:#00c583}
.perf-score.moyen b{color:var(--warn)}
.perf-score.moyen .perf-score-mot{color:var(--warn)}
.perf-score.mauvais b{color:#c13a54}
.perf-score.mauvais .perf-score-mot{color:#c13a54}

/* La tendance est le seul chiffre qui réponde à « ça va mieux ou moins bien ».
   Sous 10 % d'écart entre deux mesures : « stable ». Sans point de comparaison
   elle se tait — « muet » n'est pas « stable » : c'est le défaut identitaire
   du hub, et l'ancien @else de la vue l'écrivait sans savoir.

   `.perf-stack` l'empile SOUS le temps de réponse, dans la même cellule de
   grille. Elle avait sa colonne à elle, voisine de « PageSpeed », et se lisait
   comme la tendance du score : elle ne compare que deux TTFB. Collée à son
   chiffre, elle n'a plus besoin d'en-tête pour dire ce qu'elle mesure. */
.perf-stack{display:flex;flex-direction:column;align-items:flex-end;line-height:1.2}
.perf-trend{font-family:'Spline Sans Mono';font-size:10.5px;text-align:right;
  color:#3ddc97;cursor:help}
.perf-trend.pire{color:#ff6b6b}
.perf-trend.stable{color:var(--ink-3)}
.perf-trend.muet{color:var(--ink-3);opacity:.5;cursor:help}

/* Bouton d'action par ligne : « Remesurer ce site » est le geste évident
   qu'un client vient chercher — l'écran renvoyait au terminal jusque-là. */
.perf-actions{display:flex;justify-content:flex-end}
.perf-btn{font:inherit;font-size:10.5px;font-weight:600;padding:5px 10px;border:0;
  border-radius:8px;color:var(--ink-2);background:var(--surface);box-shadow:var(--carve);
  cursor:pointer;transition:box-shadow .18s,color .18s;letter-spacing:.02em}
.perf-btn:hover{color:var(--accent-ink);box-shadow:var(--raise)}
.perf-btn[disabled]{opacity:.55;cursor:wait}

/* Le bloc « forfait perf/SEO sans livrable » : un client qui paie sans qu'on
   mesure ce qu'il achète. Chaque ligne dit lequel des deux livrables manque. */
.perf-forfait-liste{margin:8px 0 0 0;padding-left:18px;font-size:12px;line-height:1.7;color:var(--ink-2)}
.perf-forfait-liste a{color:var(--ink-1);text-decoration:none;font-weight:600}
.perf-forfait-liste a:hover{color:var(--acc)}

.perf-note{margin:0;font-size:12px;line-height:1.6;color:var(--ink-2)}
.perf-note code{font-family:'Spline Sans Mono';font-size:10.5px;color:var(--ink-1)}
.perf-why{margin:2px 0 8px 11px;font-size:11px;line-height:1.5;color:var(--ink-3)}
.perf-why code{font-family:'Spline Sans Mono';font-size:10px}
/* La grille de .perf-rows fait de chaque cellule un enfant direct : les
   paragraphes .perf-why qui suivent une .perf-row (elle-même display:contents)
   sont aussi des enfants de la grille et s'y logeraient dans une seule
   colonne, cassant la lecture. On les fait déborder sur toute la largeur. */
.perf-rows > .perf-why{grid-column:1/-1}
/* Un LCP labo mauvais sans terrain — le labo peut exagérer, mais on ne peut
   pas non plus laisser passer 16 s en silence. Coloré comme un avertissement. */
.perf-lab-warn{color:var(--warn);border-left:2px solid var(--warn);padding-left:8px;margin-left:9px}

@media (max-width:900px){
  .perf-rows{grid-template-columns:1fr}
  /* Une seule colonne : l'en-tête n'a plus rien à coiffer, il tomberait en
     six étiquettes empilées au-dessus des valeurs. */
  .perf-cols{display:none}
  .perf-row>*{padding:2px 0;background:transparent!important}
  .perf-row>*:first-child{padding-left:0}
  .perf-row.muet{grid-template-columns:1fr auto;row-gap:4px}
  .perf-val,.perf-trend,.perf-stack,.perf-score,.perf-actions{text-align:left;justify-content:flex-start;align-items:flex-start}
}

/* ── Dépôts des composants sur mesure ───────────────────────────────────────
   Le code que Raphaël écrit lui-même n'est suivi par aucune base et ne se met
   à jour nulle part. La liste vient de l'inventaire réel, pas d'une saisie
   libre : un slug tapé de travers ne se verrait qu'au moment de la mise à
   jour, c'est-à-dire trop tard. */
/* `container-type` porte la bascule étroite du bloc, écrite plus bas avec sa
   mesure : ce qui décide ici, c'est la largeur de la CARTE, pas celle de la
   fenêtre. */
.mng-repos{display:flex;flex-direction:column;gap:2px;margin-top:12px;container-type:inline-size}
.mng-repo{display:grid;grid-template-columns:1fr auto minmax(140px,.8fr) minmax(220px,1.3fr);
  align-items:center;gap:12px;padding:9px 11px;border-radius:9px;
  transition:background .12s}
/* L'adresse de dépôt sortait en champ nu du navigateur, à côté d'un `select`
   proprement creusé — constaté par Raphaël le 03/08. Les deux partagent la
   même boîte : les séparer, c'est un endroit de plus où ils divergeront. */
.mng-repo select,
.mng-repo input{width:100%;padding:9px 12px;border:0;outline:none;border-radius:10px;
  font:inherit;font-size:11.5px;color:var(--ink);
  background:var(--surface);box-shadow:var(--carve);cursor:pointer;
  transition:box-shadow .3s}
/* Le `cursor:pointer` du bloc partagé vaut pour le `select` ; sur un champ de
   saisie il ment — on n'y clique pas, on y écrit. */
.mng-repo input{cursor:text}
.mng-repo select:focus,
.mng-repo input:focus{box-shadow:var(--carve), 0 0 0 2px rgba(0,255,167,.35)}
.mng-repo input::placeholder{color:var(--ink-3)}
.mng-repo .mng-note{margin:0;font-size:10.5px}

/* ── Parcours de fumée (fiche du site) ── */
.mng-journeys{margin-top:26px;padding-top:18px;position:relative}
.mng-journeys::before{content:"";position:absolute;top:0;left:6px;right:6px;height:1px;
  background:linear-gradient(90deg,transparent,rgba(143,157,182,.35),transparent)}
.mng-journey{display:flex;align-items:center;gap:12px;padding:10px 11px;border-radius:9px}
.mng-journey:hover{background:rgba(143,157,182,.06)}
.mng-journey .mng-repo-id{flex:1;min-width:0}
.mng-journey-proposal,
.mng-journey-editor{display:flex;flex-direction:column;gap:10px;padding:14px 16px;margin-top:10px;
  border-radius:14px;background:var(--surface);box-shadow:var(--carve)}
.mng-journey-proposal>b,
.mng-journey-editor>b{font-size:12.5px;font-weight:600;color:var(--ink-1)}
/* Une étape de parcours : creusée dans le bloc, elle se relève. */
.mng-steps{display:flex;flex-direction:column;gap:10px}
.mng-step{display:flex;flex-direction:column;gap:12px;padding:14px 16px;
  border-radius:14px;background:var(--surface);box-shadow:var(--raise-sm)}
.mng-step-h{display:flex;align-items:center;gap:6px}
.mng-step-h .spacer{margin-left:auto}
.mng-step-no{font-size:10px;font-weight:500;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-3)}
.mng-step .mng-x{width:28px;height:28px;font-size:13px}
.mng-step .mng-x:disabled{opacity:.35;cursor:not-allowed}
.mng-step .mng-x:disabled:hover{color:var(--ink-3);box-shadow:var(--raise-sm)}
/* Monter / descendre n'est pas une suppression : pas de rouge au survol. */
.mng-x.mv:hover{color:var(--accent-ink)}
.mng-repo:hover{background:rgba(143,157,182,.06)}
.mng-repo-id{display:flex;flex-direction:column;gap:1px;min-width:0}
.mng-repo-id b{font-size:12.5px;font-weight:600;color:var(--ink-1);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* La ligne technique porte le nom de dossier depuis le 03/09 (deux composants
   du même nom sur un site réel) : elle peut être longue, elle se tronque donc
   comme le titre juste au-dessus plutôt que de pousser la colonne. */
.mng-repo-id span{font-family:'Spline Sans Mono';font-size:10px;color:var(--ink-3);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mng-repo input{font-family:'Spline Sans Mono';font-size:11px}
.mng-repo .mng-err{grid-column:1/-1}
.mng-hint{margin:0;font-size:11.5px;line-height:1.55;color:var(--ink-3)}
.mng-hint code{font-family:'Spline Sans Mono';font-size:10.5px;color:var(--ink-2)}

@media (max-width:900px){
  .mng-repo{grid-template-columns:1fr 1fr;row-gap:6px}
}

/* ⚠️ Et la même bascule sur la largeur de la CARTE, parce que la fenêtre ne
   dit rien de la colonne : mesuré le 03/09 dans le Chrome de Raphaël, à
   1440 px d'écran la carte de l'écran de gestion fait 506 px et la ligne 446.
   Les trois dernières colonnes plus les gouttières réclament exactement les
   424 px de contenu disponibles, si bien que `grid-template-columns` rendait
   « 0px 28px 140px 220px » : la colonne d'identité tombait à ZÉRO et AUCUN
   composant n'était nommé à l'écran. C'est ce qui rendait deux extensions
   « The7 Elements » indiscernables : elles n'affichaient ni l'une ni l'autre
   quoi que ce soit. Une requête de média ne peut pas voir ça, puisqu'à 1440 px
   elle croit la place large.
   ⚠️ Ce bloc vient APRÈS `.mng-repo`, et ce n'est pas cosmétique : à
   spécificité égale c'est l'ordre qui tranche, et placé avant il était
   silencieusement écrasé par la règle de base (mesuré, `grid-template-columns`
   restait à quatre pistes alors que la requête matchait). */
@container (max-width:600px){
  .mng-repo{grid-template-columns:1fr 1fr;row-gap:6px}
  /* Sur deux colonnes, l'identité prend la ligne entière : c'est elle qu'on lit
     pour savoir de quel composant on parle, et « dossier · type · version » ne
     tient pas dans une demi-largeur. */
  .mng-repo-id{grid-column:1/-1}
}

/* ── Fiche à onglets (site) ─────────────────────────────────────────── */
/* La coquille `.mng` posée sur `.page.mng` porte les styles form (select,
   textarea, mng-check) sur tous les onglets sans dupliquer un `.acc-form`. */
/* padding 10 et non 5 : l'onglet actif porte `--raise-sm`, dont la lueur blanche
   déborde de 11 px autour de lui. À 5 px de marge, elle mordait sur l'ombre
   interne de la barre — deux lueurs qui se recouvrent, et le creux comme le
   relief perdaient leur bord. Le rayon suit (18 de l'onglet + 10 de marge). */
.tabs{position:relative;display:flex;gap:4px;background:var(--surface);box-shadow:var(--carve);
  padding:10px;border-radius:28px;margin:0 0 26px;overflow-x:auto}
.tabs a{position:relative;z-index:1;
  display:inline-flex;align-items:center;gap:8px;padding:11px 18px;
  font-size:12.5px;font-weight:500;color:var(--ink-2);text-decoration:none;
  border-radius:18px;white-space:nowrap;
  transition:transform .18s, box-shadow .28s, color .2s}
.tabs a:hover{color:var(--accent-ink);transform:translateY(-1px)}
/* L'onglet actif ne porte plus que sa couleur : le fond est dans `.tab-slide`,
   qui glisse sous les libellés. */
.tabs a.on{color:var(--accent-ink)}

/* ── Le bloc qui glisse ────────────────────────────────────────────────────
   Deux tentatives par transition de vue ont échoué, et la photo au ralenti a
   dit pourquoi : porté par le lien, le bloc emmenait son texte — à mi-course
   c'était un rectangle blanc affichant DEUX libellés en fondu, qui masquait
   les onglets sous lui ; porté par un `::before` en `z-index:-1`, il repassait
   devant son propre label, l'ordre d'empilement de la page ne s'appliquant plus
   dans la couche de transition. Aucune des deux ne pouvait le faire passer
   SOUS les libellés : une couche nommée est toujours peinte au-dessus.
   D'où cet élément à part, dans le flux normal, en `z-index:0` sous des liens
   en `z-index:1`. Il glisse par une simple transition CSS — aucune transition
   de vue n'est en jeu ici, donc rien à synchroniser avec la navigation. */
.tab-slide{
  position:absolute;z-index:0;top:10px;left:0;height:calc(100% - 20px);width:0;
  border-radius:18px;pointer-events:none;opacity:0;
  background:var(--posed);box-shadow:var(--raise-sm);
  /* AUCUNE transition sur `transform` ni `width` : le trajet est joué image par
     image en JavaScript (`hub.js`). Une transition CSS ici ne doublait pas le
     mouvement, elle le FAUSSAIT — le span est recréé à chaque navigation avec
     la largeur nulle ci-dessus, et la première valeur écrite par le script
     partait alors de zéro en glissant. C'est le rétrécissement qu'on voyait au
     début du trajet, et il venait d'ici, pas du script.
     Seule l'opacité reste transitionnée : elle ne dépend d'aucune mesure. */
  transition:opacity .2s;
}
/* Tant qu'il n'a pas été positionné, il ne s'affiche pas : un span fraîchement
   rendu par le serveur est à la largeur zéro, et cette classe l'empêche de se
   montrer dans cet état. */
.tab-slide.pose{opacity:1}

/* ── Le mouvement des transitions de vue ──────────────────────────────────
   Le chaînon JS est dans `hub.js` : Livewire 4.3 n'ouvre de transition que sur
   ses morphs (`wire:transition`), jamais sur `wire:navigate`, qui délègue à
   Alpine. Ici on ne règle que le MOUVEMENT.
   L'onglet actif, lui, n'est plus de la partie : son bloc glisse par une
   transition CSS ordinaire (`.tab-slide`), seule façon de le faire passer SOUS
   les libellés. */

/* PERSISTANCE RÉELLE du shell — menu et gouttière.
   Un élément nommé est capturé deux fois, et ses deux calques se croisent en
   fondu par défaut. Sur un objet qui ne change pas d'un écran à l'autre, ce
   fondu est précisément le clignotement qu'on veut supprimer : il se dissout
   dans sa propre copie. On masque donc le calque sortant et on fige l'entrant.
   Le groupe, lui, continue d'interpoler la position — si le menu ou la
   gouttière se déplaçaient, ils glisseraient. */
::view-transition-old(menu),
::view-transition-old(rail){display:none}
::view-transition-new(menu),
::view-transition-new(rail){animation:none}

/* L'entête, lui, garde un fondu court : d'un onglet à l'autre il est identique
   et le fondu ne se voit pas, mais d'un ÉCRAN à l'autre il change vraiment —
   « Sites » puis le nom d'un site. Le couper ferait un saut sec. */
::view-transition-group(entete){animation-duration:.3s}
::view-transition-old(entete),
::view-transition-new(entete){animation-duration:.22s}

/* Le balai global plus bas ne touche que `animation-duration` sur les éléments
   de la page — les pseudo-éléments de transition lui échappent. Le JS refuse
   déjà d'ouvrir une transition sous ce réglage ; cette règle couvre le cas où
   le navigateur en déclencherait une lui-même. */
@media (prefers-reduced-motion: reduce){
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*){animation:none !important}
}
/* Le compte n'est plus une bulle : c'est un chiffre GRAVÉ dans la barre. La
   pastille creusée marchait tant que `--carve` était doux ; à son nouveau
   contraste elle devenait un gros bouton sombre à côté d'un mot. Le principe du
   codepen — l'ombre inversée qui enfonce le chiffre — dit la même chose sans
   fabriquer d'objet. La COULEUR reste : c'est elle qui porte le signal, et un
   signal ne se replie pas. */
/* Le chiffre prend la couleur du FOND : plus aucune encre propre, ce sont ses
   deux ombres qui le dessinent — exactement le procédé du codepen, où le
   chiffre est de la teinte de la surface et n'existe que par son relief.
   L'ombre est un cran plus marquée que `--grave` parce que Clash Display
   plafonne à 600 ici (les seuls woff2 chargés sont 400/500/600), là où la
   recette d'origine s'appuie sur un 900 : ce que la graisse ne donne pas, le
   contraste de l'ombre le rend. */
/* L'encre du chiffre est un gris-bleu clair — pas tout à fait la teinte du fond,
   un cran en dessous. Assez proche pour que ce soit l'ombre qui le dessine et
   qu'il reste gravé dans la matière, assez distinct pour se lire. Aucun fond
   propre : une plage colorée en ferait de nouveau une pastille posée dessus. */
/* Le centrage est OPTIQUE, pas géométrique : mesuré, la boîte du chiffre est
   déjà centrée au pixel près dans le lien. C'est Clash Display qui pose ses
   chiffres haut dans la ligne — sa hauteur d'ascendante est généreuse. On fixe
   donc la ligne à 1 pour supprimer la marge du haut, et on redescend de 1 px
   pour aligner le chiffre sur le libellé à l'œil. */
.tabs a i{display:inline-block;padding:0 0 0 3px;
  font-family:'Clash Display';font-size:15px;font-weight:600;font-style:normal;
  line-height:1;position:relative;top:1px;
  text-align:center;color:#d7dfeb;
  text-shadow:0 -1px 1px rgba(18,30,58,.4), 0 1px 1px rgba(255,255,255,.95)}
/* Aucune surcharge de couleur — ni accent, ni rouge, ni orange. Un chiffre
   gravé tient à l'écart entre son encre et l'ombre qui l'enfonce : coloré, il
   redevient un chiffre posé DESSUS. Il compense en taille et en graisse, ce qui
   le rend plus lisible que la pastille qu'il remplace, pas moins. */

/* Panneau — pas de `display:none` global : la coquille rend UN panneau à la
   fois côté serveur ; la classe .on garde l'animation d'entrée cohérente. */
.tab-panel{animation:var(--entree,tabin) .32s ease-out}
@keyframes tabin{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}

/* Un onglet en chantier DIT où vit encore son contenu — respecte règle n°2
   du cadrage : « un onglet vide dit pourquoi ». */
.empty-tab{background:var(--posed);
  box-shadow:var(--raise);border-radius:24px;
  padding:38px 40px;text-align:left;max-width:620px}
.empty-tab .lbl{font-family:'Clash Display';font-size:11px;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
.empty-tab h2{font-family:'Clash Display';font-size:19px;font-weight:600;
  letter-spacing:.02em;margin:12px 0 14px;line-height:1.35}
.empty-tab p{font-size:13px;line-height:1.65;color:var(--ink-2);margin-bottom:10px}
.empty-tab p b{color:var(--ink);font-weight:600}
.empty-tab .mng-actions{margin-top:20px}

/* ── Encastrement dans un onglet (Tickets, plus tard Client) ─────────────
   L'écran de départ tient dans 100vh ; à l'intérieur d'un onglet, la
   fiche fournit déjà entête et bascule Simple/Avancé et prend la hauteur
   qu'il lui faut. On désarme `height:100vh` pour laisser respirer, et on
   borne la file+fil à une hauteur lisible (le défilement reste interne). */
.inbox-page.inbox-embed{height:auto;padding-bottom:0}
.inbox-page.inbox-embed .inbox{min-height:520px;height:calc(100vh - 320px)}

/* ── Onglet Rapports ─────────────────────────────────────────────────────
   Une liste sobre : un rapport = une ligne cliquable (mois, état, résumé
   d'une phrase). Le détail dépile les cinq volets figés du builder ; le
   « mot du responsable » est un textarea sur brouillon, un paragraphe
   figé sur envoyé. Pas de tableau, pas de graphique : c'est un livrable
   qui se relit vite avant l'envoi. */
.rp-list{list-style:none;padding:0;margin:16px 0 8px;display:flex;
  flex-direction:column;gap:8px}
.rp-item{position:relative}
.rp-open{display:block;width:100%;text-align:left;padding:14px 18px;
  background:var(--posed);
  box-shadow:var(--carve);border-radius:16px;border:none;cursor:pointer;
  transition:box-shadow .3s, transform .2s}
.rp-open:hover{box-shadow:var(--raise-sm);transform:translateY(-1px)}
.rp-line1{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:4px}
.rp-per{font-family:'Clash Display';font-size:14px;font-weight:600;
  letter-spacing:.02em;color:var(--ink)}
.rp-status{font-size:11px;font-weight:600;padding:3px 10px;border-radius:99px;
  letter-spacing:.02em;background:var(--surface);box-shadow:var(--carve)}
.rp-status.done{color:#2c6a3f}
.rp-status.wait{color:#a9741e}
.rp-status.new{color:var(--accent-ink)}
.rp-when,.rp-fw{margin-left:auto;font-size:11px;color:var(--ink-3)}
.rp-sum{font-size:13px;line-height:1.55;color:var(--ink-2);margin:4px 0 0}
.rp-meta{font-size:10.5px;color:var(--ink-3);margin-top:6px;font-family:'Spline Sans Mono'}
.rp-detail .ch{gap:12px}
.rp-hero{background:var(--posed);
  border-radius:18px;padding:18px 22px;margin:14px 0 18px}
.rp-hero p{font-size:14px;line-height:1.65;color:var(--ink);margin:0}
.rp-fw-form textarea{width:100%;min-height:64px;padding:11px 14px;
  border-radius:14px;background:var(--surface);box-shadow:var(--carve);
  border:none;font:inherit;font-size:13px;line-height:1.55;color:var(--ink);
  resize:vertical}
.rp-fw-shown{margin:12px 0 18px;padding:12px 16px;
  background:var(--surface);box-shadow:var(--carve);border-radius:14px}
.rp-fw-shown p{font-size:13px;line-height:1.55;color:var(--ink);margin:6px 0 0}
.rp-sections{display:flex;flex-direction:column;gap:22px;margin-top:22px}
.rp-sec h3{font-family:'Clash Display';font-size:13px;font-weight:600;
  letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3);
  margin-bottom:8px}
.rp-sec p{font-size:13px;line-height:1.6;color:var(--ink-2);margin:0}
.rp-sec .rp-nm{color:var(--ink-3);font-style:italic}
.rp-crit{color:#c13a54}
.rp-items{list-style:none;padding:0;margin:8px 0 0;display:flex;
  flex-direction:column;gap:4px}
.rp-items li{font-size:12.5px;color:var(--ink-2);line-height:1.5}
.rp-items li .mono{color:var(--ink-3);margin-right:8px}

/* ⚠️ `.go` porte `opacity:0` et n'apparaît qu'au survol d'une ligne (`.row:hover .go`)
   — c'est voulu pour la pastille discrète de la Flotte, et RUINEUX ailleurs.
   Six boutons du hub portaient `class="mini go"` hors d'une `.row` : ils étaient
   purement invisibles, dont « C'est bon » sur /travail, qui approuve un
   déploiement en production. Mesuré au navigateur le 02/08/2026.
   Un téléphone n'a pas de survol : un geste qui dépend de `:hover` n'existe pas
   pour qui approuve depuis son lit.
   Pour colorer un `.mini`, utiliser `.accent`, `.mut` ou `.danger` (l. 1543). */


/* ── Le fil éditorial (onglet Contenus) ───────────────────────────────────
   Quatre classes, et pas une de plus : c'est le seul bloc de l'onglet que
   l'existant ne savait pas rendre. La quatrième (`.plan-part`) est arrivée le
   04/08 avec le plan lui-même — 12 pièces à puces, qu'un `<p>` ordinaire
   aplatit en un pavé. Tout le reste (cartes, `.todo`, `.mini`,
   `.mng-form`, `.acc-link`) est réemployé tel quel.
   `pre-wrap` n'est pas cosmétique : un article de 1 200 mots collé dans un
   `<p>` ordinaire perd tous ses paragraphes, et devient illisible au moment
   précis où on doit le relire. C'est aussi ce qui rend les réponses du modèle
   lisibles, elles arrivent avec leurs sauts de ligne. */
.conv{display:flex;flex-direction:column;gap:10px;margin:0 0 18px}
.conv-m{padding:12px 15px;border-radius:14px;background:rgba(143,157,182,.07);
  font-size:12.5px;line-height:1.65;color:var(--ink-2);white-space:pre-wrap}
.plan-part{font-size:12.5px;line-height:1.7;color:var(--ink-2);
  white-space:pre-wrap;margin:0 0 16px}
.conv-who{display:block;font-size:10px;font-weight:600;letter-spacing:.13em;
  text-transform:uppercase;color:var(--ink-3);margin-bottom:6px;white-space:normal}

/* ── Onglet Contenus ──────────────────────────────────────────────────────
   Ses cartes sont pleine largeur (986 px à 1 600 px de fenêtre, 1 334 à
   1 920) et trois de ses classes de texte n'ont aucun plafond. Mesuré au
   navigateur le 04/08 : `.mng-note` sort à 138 caractères par ligne à
   1 600 px et 178 à 1 920 ; `.card-empty` à 119 et 158 ; `.conv-m` à 122.
   Les classes voisines ont déjà tranché la question : `.mng-lead` 62ch,
   `.acc-lead` 58ch, `.mng-plan p` 60ch. Scopé à l'onglet : les onze autres
   écrans ne bougent pas. Et la cadence est un nombre entre 0 et 31 : son
   champ n'a pas besoin de 986 px.
   Le plafond est posé sur `.conv` et non sur `.conv-m` : le conteneur est une
   colonne flex, et brider chaque bulle laisserait la colonne large, donc les
   bulles alignées sur un bord qui n'existe plus. */
.tab-contenus .card-empty,
.tab-contenus .mng-note,
.tab-contenus .conv{max-width:72ch}
.tab-contenus .field.court input{max-width:150px}

/* Le geste « Décaler » vit DANS un créneau du planning, une carte de 190 px de
   large au plus étroit. `.mini` y arrive à 8 px / 15 px de rembourrage et
   11,5 px de texte, taillé pour une barre d'actions, pas pour une vignette.
   Aucune classe neuve : un rembourrage scopé sur le seul endroit où `.mini`
   est à l'étroit, et `.mng-actions` réemployée pour le poser SUR la ligne de
   l'état plutôt que sous elle.
   Mesuré au navigateur le 01/09/2026 sur reunionplongee, à 1 440 px : les
   quatre boutons retirés du DOM font passer `.pmois` de 641 à 546 px (−95),
   et la page reste à 1 669 px — c'est la colonne de gauche (1 133 px contre
   993) qui la fixe. Le geste ne coûte donc rien en hauteur d'écran. */
.pcrn .mini{padding:5px 11px;font-size:10.5px}
.pcrn .field.court input{max-width:100%}
.pcrn .mng-actions{margin-top:3px;gap:8px;align-items:center;justify-content:space-between}

/* ── Onglet Perf & SEO ────────────────────────────────────────────────────
   Même question que Contenus, même réponse, deux règles. Cet onglet porte
   depuis le 07/08 le texte du rapport d'audit : le constat et la proposition
   de chaque piste, écrits par la session, longs de plusieurs phrases. Ils
   vivent dans `.jli p`, qui n'a aucun plafond de longueur de ligne.

   Mesuré au navigateur le 07/08 sur le rapport v1 de reunionplongee :
   **164 caractères par ligne à 1 920 px**, dans une carte de 1 366 px. Les
   classes voisines ont déjà tranché — `.mng-lead` 62ch, `.acc-lead` 58ch,
   `.tab-contenus` 72ch — et l'avant-propos du même écran, qui est en
   `.mng-lead`, se lit correctement juste au-dessus. Le contraste entre les
   deux blocs se voyait à l'œil.

   Et le champ « le jour où tu l'as appliquée » est une date de dix
   caractères : mesuré à **1 276 px de large**. `.field.court` existait déjà
   pour exactement ça, mais son unique règle était scopée à `.tab-contenus` ;
   la classe était donc posée sur le champ sans rien faire.

   Scopé à l'onglet : aucun des onze autres écrans ne bouge. */
.tab-perf .jli p,
.tab-perf .card-empty,
.tab-perf .mng-note{max-width:72ch}
.tab-perf .field.court input{max-width:170px}

/* Le responsable sous le nom d'un site, sur l'écran /performance. Il vit dans
   la cellule du nom et non dans une septième colonne : la grille de `.perf-row`
   est partagée avec l'onglet Perf d'une fiche, où la question ne se pose pas. */
.perf-resp{display:block;margin-top:2px;font-size:10.5px;font-weight:400;color:var(--ink-3)}
