/* workflow-canvas.css — Système de volets du canevas
 *
 * Structure et mecanique, direction visuelle verrouillee sur maquette :
 * superposition (canevas fixe), onglet solidaire du volet, forme « filet
 * d'accent » (sobre, gris, accent reserve a l'actif). La FORME des onglets est
 * isolee dans sa propre section, pour qu'on puisse y revenir sans toucher au
 * reste — c'est ce qui rend la base « solide » : les retouches cosmetiques sont
 * confinees.
 *
 * Toutes les valeurs viennent de builder-tokens.css. Zero couleur/dimension en
 * dur, zero style inline, zero style.display en JS (l'ouverture passe par un
 * attribut data-open sur la racine, lu en CSS).
 */

/* ── Scrollbars : CENTRALISEES sur la charte sombre ───────────────────────────
   Une seule regle pour toutes les zones scrollables du Builder (panneaux,
   palette, docks, config…). Eviter le piege WFD : styler chaque scrollbar une
   par une. Ici, une source unique — modifier la charte se fait a un endroit.
   Deux moteurs couverts : standard (Firefox) et WebKit (Chrome/Electron). */
.bd-canvas-root,
.bd-canvas-root * {
  scrollbar-width: thin;
  scrollbar-color: var(--bd-panel-border) transparent;
}
.bd-canvas-root ::-webkit-scrollbar { width: 10px; height: 10px; }
.bd-canvas-root ::-webkit-scrollbar-track { background: transparent; }
.bd-canvas-root ::-webkit-scrollbar-thumb {
  background: var(--bd-panel-border);
  border-radius: 6px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
.bd-canvas-root ::-webkit-scrollbar-thumb:hover {
  background: var(--bd-text-dim);
  background-clip: padding-box;
}

/* ── Cadre general : bandeau d'etat + scene ──────────────────────────────── */
/* Body en colonne : header en haut (hauteur naturelle), canvas dessous (reste).
   Ainsi le header partagé ne décale pas le canvas — il prend juste sa place. */
body { margin: 0; display: flex; flex-direction: column; height: 100vh; overflow: hidden; }
.aps-header { flex: none; }

.bd-canvas-root {
  display: grid;
  grid-template-rows: var(--bd-statusbar-height) minmax(0, 1fr);
  flex: 1;
  min-height: 0;
  width: 100%;
  background: var(--bd-canvas-bg);
  overflow: hidden;
}

/* Bandeau d'etat : informe, ne commande pas. */
/* ── Bandeau d'état : trois zones, retenue de couleur ─────────────────────── */
.bd-statusbar {
  display: flex;
  align-items: center;
  padding: 0 14px;
  border-bottom: 1px solid var(--bd-panel-border);
  background: var(--bd-panel-bg);
  color: var(--bd-text);
  font-weight: var(--bd-font-weight);
  font-size: 12.5px;
}

/* Segments séparés par un filet ; la couleur ne sert qu'aux pastilles. */
.bd-seg { display: flex; align-items: center; gap: 8px; padding: 0 14px; height: 100%; }
.bd-seg + .bd-seg { border-left: 1px solid var(--bd-panel-border); }
.bd-spacer { flex: 1; }

.bd-wf-name { font-weight: 600; color: var(--bd-text); }

.bd-badge {
  font-size: 10.5px; letter-spacing: .04em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 4px;
  border: 1px solid var(--bd-panel-border);
  color: var(--bd-text-dim); background: var(--bd-canvas-surface);
}
.bd-badge[data-state="draft"]     { color: var(--warn); }
.bd-badge[data-state="published"] { color: var(--ok); }

/* Pastille d'état : gris par défaut, coloré selon data-state. */
.bd-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--bd-text-dim); flex: none; }
.bd-dot[data-state="ok"]   { background: var(--ok); }
.bd-dot[data-state="warn"] { background: var(--warn); }
.bd-dot[data-state="err"]  { background: var(--err); }
.bd-dot-warn { background: var(--warn); }

/* Indicateur non-enregistré : masqué sauf si la racine le signale. */
.bd-dirty { display: none; align-items: center; gap: 5px; color: var(--warn); font-size: 11.5px; }
.bd-canvas-root[data-dirty="1"] .bd-dirty { display: flex; }

/* Badge « INACTIVE » : indépendant de draft/published (bd-badge), masqué
   sauf si la racine le signale — ne répond plus au webhook Iconik. */
.bd-inactive-badge {
  display: none; font-size: 10.5px; letter-spacing: .04em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 4px; font-weight: 700;
  background: var(--err); color: #fff;
}
.bd-canvas-root[data-active="0"] .bd-inactive-badge { display: inline-block; }

.bd-env-select {
  appearance: none; cursor: pointer;
  background: #151718; color: var(--bd-text, #eef0f1);
  border: 1px solid var(--bd-panel-border, #2a3033);
  border-radius: 6px; padding: 3px 8px; font: inherit; font-size: 12px;
}
.bd-env-select:hover { border-color: #3a4147; }
.bd-env-org  { color: var(--bd-text-dim); font-size: 11.5px; }
.bd-engine-name { color: var(--bd-text); }

.bd-icon-btn {
  background: none; border: 1px solid var(--bd-panel-border); color: var(--bd-text-dim);
  width: 24px; height: 24px; border-radius: 5px; cursor: pointer; font-size: 13px;
  display: flex; align-items: center; justify-content: center; font-family: inherit;
}
.bd-icon-btn:hover { color: var(--bd-text); border-color: var(--bd-text-dim); }

/* Retour visuel pendant un rafraîchissement (env + données Iconik) — la
   classe est posée/retirée par JS, jamais un style inline. */
.bd-icon-btn.bd-spinning { animation: bd-spin 0.7s linear infinite; color: var(--bd-text); }
@keyframes bd-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

.bd-tech { color: var(--bd-text-dim); font-size: 11.5px; gap: 12px; }
.bd-tech b { color: var(--bd-text); font-weight: 600; }


/* ── Palette (dock droit) ─────────────────────────────────────────────────── */
.bd-panel-hd { display: flex; align-items: center; justify-content: space-between; }
.bd-filter {
  background: var(--bd-canvas-surface); border: 1px solid var(--bd-panel-border);
  color: var(--bd-text-dim); border-radius: 5px; padding: 3px 8px; font-size: 11px;
  width: 110px; font-family: inherit;
}
.bd-filter:focus { outline: none; border-color: var(--bd-text-dim); color: var(--bd-text); }

/* Sous-onglets horizontaux, distincts des onglets de bord (verticaux). */
.bd-subtabs { display: flex; gap: 4px; padding: 8px 10px; border-bottom: 1px solid var(--bd-panel-border); }
.bd-subtab {
  flex: 1; text-align: center; padding: 6px 8px; font-size: 11.5px; font-family: inherit;
  background: var(--bd-panel-bg); border: 1px solid var(--bd-panel-border);
  border-radius: 6px; color: var(--bd-text-dim); cursor: pointer;
}
.bd-subtab:hover { color: var(--bd-text); }
.bd-subtab.bd-subtab-active {
  color: var(--bd-text);
  box-shadow: inset 0 -2px 0 var(--accent);
}

.bd-pane { display: none; }
.bd-pane.bd-pane-active { display: block; }

.bd-node-list { display: flex; flex-direction: column; gap: 6px; }
.bd-node {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px;
  background: var(--bd-panel-bg); border: 1px solid var(--bd-panel-border);
  border-radius: 6px; cursor: grab; user-select: none;
}
.bd-node:hover { border-color: var(--bd-text-dim); }
.bd-node .bd-glyph {
  width: 22px; height: 22px; border-radius: 5px; flex: none;
  display: flex; align-items: center; justify-content: center; font-size: 12px;
  background: var(--bd-canvas-surface); color: var(--bd-text-dim);
  border: 1px solid var(--bd-panel-border);
}
.bd-node .bd-nm { color: var(--bd-text); }
.bd-node .bd-sub { color: var(--bd-text-dim); font-size: 11px; margin-left: auto; }
/* Badge de plateforme dans la liste : petit tag coloré pour repérer d'un coup
   d'œil à quelle plateforme un nœud est lié, sans le glisser sur le canevas. */
.bd-node[data-platform] .bd-sub {
  padding: 1px 7px; border-radius: 10px; font-size: 10px; text-transform: uppercase;
  letter-spacing: .04em; border: 1px solid var(--bd-panel-border);
}
.bd-node[data-platform="iconik"]     .bd-sub { color: #6ea8ff; border-color: color-mix(in srgb, #6ea8ff 40%, transparent); }
.bd-node[data-platform="aws_s3"]     .bd-sub { color: #e0a04c; border-color: color-mix(in srgb, #e0a04c 40%, transparent); }
.bd-node[data-platform="vodfactory"] .bd-sub { color: #c07ce0; border-color: color-mix(in srgb, #c07ce0 40%, transparent); }
.bd-node[data-platform="aps"]        .bd-sub { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }

/* Portée d'un nœud Custom : badge + promotion (mécanique câblée plus tard). */
.bd-scope {
  font-size: 10px; text-transform: uppercase; letter-spacing: .04em;
  padding: 1px 6px; border-radius: 3px; border: 1px solid var(--bd-panel-border);
  color: var(--bd-text-dim); margin-left: auto;
}
.bd-scope[data-scope="platform"] { color: var(--accent); }
.bd-promote {
  font-size: 10.5px; color: var(--accent); background: none; border: none;
  cursor: pointer; padding: 0; margin-left: 10px; font-family: inherit;
}
.bd-empty { color: var(--bd-text-dim); font-size: 12px; line-height: 1.6; margin-top: 16px; }

/* ── Nœud du canevas (rendu par node-renderer.js) ─────────────────────────── */
/* Positionné dans la surface via --nx/--ny (variables posées par le renderer,
   pas du style d'apparence en dur). La couleur du badge et des pastilles vient
   aussi de variables par-élément : c'est de la donnée passée à CSS, pas de
   l'inline cosmétique. */
.bd-node-canvas {
  position: absolute;
  left: 0; top: 0;
  transform: translate(var(--nx, 0px), var(--ny, 0px));
  will-change: transform;
  width: 230px;
  background: var(--bd-canvas-surface);
  border: 1px solid var(--bd-panel-border);
  border-radius: 12px;
  overflow: hidden;
  font-size: 13px;
  cursor: grab;
}
/* Nœud sélectionné : contour accent (seul marquage, sobre). */
.bd-node-canvas[data-selected="1"] {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}

/* Post-it — port de WFD (.wfd-postit, workflow-designer.css:563). Mêmes
   proportions et même construction en `color-mix` : le fond et la bordure
   dérivent de la teinte choisie, pour que sept couleurs ne demandent pas
   quatorze règles. Volontairement PAS de `overflow:hidden` (hérité de
   .bd-node-canvas) : un post-it doit pouvoir grandir avec son texte, alors
   qu'un nœud garde une hauteur tenue par ses ports. */
.bd-node-canvas.bd-postit {
  width: 200px;
  min-height: 60px;
  overflow: visible;
  border-width: 1.5px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--postit-color, #f1c40f) 9%, transparent);
  border-color: color-mix(in srgb, var(--postit-color, #f1c40f) 40%, transparent);
}
.bd-postit-body {
  padding: 10px 12px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--postit-color, #f1c40f);
  white-space: pre-wrap;
  word-break: break-word;
}
/* La sélection reprend la main sur la bordure teintée (spécificité double). */
.bd-node-canvas.bd-postit[data-selected="1"] { border-color: var(--accent); }

/* Statut de run live (wf-run-overlay.js) — indépendant de data-selected,
   les deux peuvent coexister. `running` réutilise cfg-pulse tel quel (déjà
   le langage visuel "quelque chose se passe en direct" de cette app, cf.
   .cfg-bille[data-etat="test"] plus bas) ; `blocked` prend un tempo plus
   lent (2s vs 1s) — c'est la correction directe du bug WFD : un état
   VRAIMENT figé (run arrêté ici) ne doit jamais se confondre visuellement
   avec une erreur qui a simplement continué ailleurs (`error`, statique). */
.bd-node-canvas[data-run-status="running"] { border-color: var(--info); box-shadow: 0 0 0 1px var(--info); animation: cfg-pulse 1s ease-in-out infinite; }
.bd-node-canvas[data-run-status="success"] { border-color: var(--ok);   box-shadow: 0 0 0 1px var(--ok); }
.bd-node-canvas[data-run-status="error"]   { border-color: var(--err);  box-shadow: 0 0 0 1px var(--err); }
.bd-node-canvas[data-run-status="blocked"] { border-color: var(--warn); box-shadow: 0 0 0 1px var(--warn); animation: cfg-pulse 2s ease-in-out infinite; }
/* La sélection doit rester visible même sur un nœud coloré par son statut
   de run — sinon un nœud "success"/"error"/etc. devient impossible à
   distinguer "sélectionné" de "pas sélectionné" (même spécificité qu'un
   seul attribut ci-dessus, donc l'ordre du fichier tranchait à tort en
   faveur du statut). Double attribut = spécificité plus élevée, gagne
   toujours, quel que soit l'ordre des règles. */
.bd-node-canvas[data-run-status][data-selected="1"] { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }

/* Badge de job animé (wf-run-badges.js) — port fidèle de WFD
   (.wfd-job-badge, script-workflow-designer.js / workflow-designer.css) :
   même taille, mêmes classes de cycle de vie (entering/transit/exiting),
   mêmes durées d'animation, mêmes états. Couleurs alignées sur les jetons
   de cette app plutôt que les couleurs WFD en dur, seule adaptation. */
.bd-job-badge {
  position: absolute;
  width: 24px; height: 24px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 600;
  pointer-events: none;
  z-index: 50;
  transition: transform .15s, opacity .15s;
  box-shadow: 0 2px 8px rgba(0,0,0,.5);
  border: 2px solid rgba(255,255,255,.1);
  color: #fff;
}
.bd-job-badge.running { background: var(--info); animation: bd-badge-pulse-blue 1s ease-in-out infinite; }
.bd-job-badge.success { background: var(--ok); }
.bd-job-badge.error    { background: var(--err); }
.bd-job-badge.warn    { background: var(--warn); }
.bd-job-badge.entering { animation: bd-badge-enter .2s ease-out; }
.bd-job-badge.exiting   { animation: bd-badge-exit  .2s ease-in forwards; }
.bd-job-badge.transit  { animation: bd-badge-transit .35s ease-in-out; }

@keyframes bd-badge-pulse-blue {
  0%, 100% { box-shadow: 0 2px 8px rgba(0,0,0,.5); }
  50%      { box-shadow: 0 0 12px color-mix(in srgb, var(--info) 55%, transparent); }
}
@keyframes bd-badge-enter {
  from { transform: scale(0); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}
@keyframes bd-badge-exit {
  from { transform: scale(1); opacity: 1; }
  to   { transform: scale(0); opacity: 0; }
}
@keyframes bd-badge-transit {
  0%   { transform: scale(.8) translateY(-4px); opacity: .6; }
  50%  { transform: scale(1.1); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

/* Arête réellement empruntée par le run affiché (wf-run-overlay.js). */
.cnv-edge-run-taken .cnv-edge-line { filter: drop-shadow(0 0 3px var(--info)); stroke-width: 3; }

.nc-head { display: flex; gap: 10px; padding: 12px 14px 10px; }
.nc-badge {
  width: 30px; height: 30px; border-radius: 8px; flex: none;
  display: flex; align-items: center; justify-content: center; font-size: 15px;
  color: #fff; background: var(--badge-color, #5a6570);
}
.nc-id { min-width: 0; flex: 1; }
.nc-title {
  font-weight: 600; font-size: 13.5px; color: var(--bd-text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.nc-type {
  color: var(--bd-text-dim); font-size: 11.5px; margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.nc-plat {
  display: inline-block; font-size: 9.5px; text-transform: uppercase; letter-spacing: .04em;
  padding: 1px 5px; border-radius: 3px; border: 1px solid var(--bd-panel-border);
  color: var(--bd-text-dim); margin-left: 6px;
}

/* Boucle avec un corps déjà posé : "N steps", visible sans double-cliquer.
   Cliquable (workflow-canvas.js, pointerdown) : ouvre directement le corps
   de la boucle — curseur pointer pour le signaler, hover pour confirmer. */
.nc-loop-badge {
  flex: none; align-self: flex-start;
  font-size: 10px; padding: 2px 7px; border-radius: 5px;
  border: 1px solid var(--bd-panel-border); color: var(--bd-text-dim);
  background: var(--bd-canvas-surface);
  cursor: pointer;
}
.nc-loop-badge:hover { border-color: var(--accent); color: var(--bd-text); }

/* Bouton "Edit body →" dans le panneau Config d'un nœud Loop. */
.bd-btn-loop-body {
  display: block; width: 100%; margin-top: 14px;
  background: var(--bd-canvas-surface); color: var(--bd-text);
  border: 1px solid var(--bd-panel-border); border-radius: 7px;
  padding: 8px 12px; font: inherit; font-size: 12.5px; cursor: pointer;
}
.bd-btn-loop-body:hover { border-color: var(--accent); color: var(--accent); }

.nc-body { padding: 2px 14px 10px; font-family: ui-monospace, Menlo, monospace; font-size: 11.5px; }
.nc-var { color: var(--bd-text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nc-arrow { color: var(--accent); }

.nc-ports { border-top: 1px solid var(--bd-panel-border); padding: 8px 0; margin-top: 4px;
  display: flex; flex-direction: column; gap: 6px; }
.nc-prow { display: flex; align-items: center; padding: 0 12px; }
.nc-pin, .nc-pout { display: flex; align-items: center; gap: 7px; font-size: 11.5px; }
.nc-pout { margin-left: auto; flex-direction: row-reverse; }
.nc-dot {
  width: 9px; height: 9px; border-radius: 50%; flex: none;
  border: 2px solid var(--port-color, var(--bd-text-dim));
  background: var(--bd-canvas-surface);
}
.nc-pin .nc-plbl  { color: var(--bd-text-dim); }
.nc-pout .nc-plbl { color: var(--bd-text); }

/* ── Scene : le canevas remplit tout, les volets se superposent ──────────── */
.bd-stage {
  position: relative;
  overflow: hidden;
}

/* ── Fil d'Ariane : navigation de portée, en superposition sur le canevas,
   même principe que les volets (le canevas fixe ne bouge jamais). ────────── */
.bd-breadcrumb {
  position: absolute;
  top: 10px; left: 50%;
  transform: translateX(-50%);
  z-index: 5;
  display: flex; align-items: center; gap: 10px;
  padding: 5px 8px 5px 14px;
  border-radius: 8px;
  border: 1px solid var(--bd-panel-border);
  background: var(--bd-panel-bg);
  color: var(--bd-text-dim);
  font-size: 12px;
  box-shadow: 0 2px 10px rgba(0,0,0,.25);
}
/* `display: flex` ci-dessus est une règle AUTEUR — elle gagne sur la règle
   `[hidden] { display: none }` de l'agent utilisateur quelle que soit sa
   spécificité (l'origine prime avant la spécificité dans la cascade). Sans
   cette ligne, l'attribut `hidden` ne cachait plus rien : constaté en testant
   dans un vrai navigateur, le fil d'Ariane restait visible à la racine. */
.bd-breadcrumb[hidden] { display: none; }
.bd-breadcrumb-seg {
  background: none; border: none; color: inherit; font: inherit; cursor: pointer;
  padding: 0; color: var(--bd-text-dim);
}
.bd-breadcrumb-seg:hover:not(:disabled) { color: var(--bd-text); text-decoration: underline; }
.bd-breadcrumb-seg:disabled { color: var(--bd-text); cursor: default; font-weight: 600; }

/* ── Canevas : cadre fixe + surface transformable ────────────────────────── */
.cnv-frame {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* Un éditeur graphique ne veut jamais que le glissé sélectionne le texte des
     nœuds (surlignage bleu facon Ctrl+A). On neutralise la sélection native. */
  user-select: none;
  -webkit-user-select: none;
  background:
    radial-gradient(var(--bd-grid-line) 1px, transparent 1px)
    0 0 / var(--bd-grid-step) var(--bd-grid-step);
  background-color: var(--bd-canvas-surface);
}
/* Arêtes : la zone de clic élargie porte le curseur ; le trait visible réagit
   à la sélection. La ligne provisoire (tirage) est en pointillés accent. */
.cnv-edge-hit { cursor: pointer; }
.cnv-edge-selected .cnv-edge-line { filter: drop-shadow(0 0 3px var(--accent)); }
.cnv-edge-draft {
  stroke: var(--accent);
  stroke-dasharray: 5 4;
  pointer-events: none;
}
/* Pastille d'entrée illuminée quand elle est une cible valide de connexion. */
.nc-pin.nc-pin-cible .nc-dot {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 30%, transparent);
}
/* Pastille de sortie : curseur indiquant qu'on peut y démarrer une liaison. */
.nc-pout .nc-dot { cursor: crosshair; }

/* Vues du dock droit : Palette vs Config, basculées par data-panel du dock.
   La vue active occupe la hauteur restante en flex, pour que son corps
   (bd-panel-bd) puisse scroller quand le contenu déborde. */
.bd-view { display: none; flex: 1; min-height: 0; flex-direction: column; }
.bd-dock-right[data-panel="palette"]   .bd-view-palette   { display: flex; }
.bd-dock-right[data-panel="config"]    .bd-view-config    { display: flex; }
.bd-dock-right[data-panel="variables"] .bd-view-variables { display: flex; }
.bd-dock-right[data-panel="run"]       .bd-view-run       { display: flex; }
/* Même bascule pour le dock gauche (Jobs / Logs). */
.bd-dock-left[data-panel="jobs"] .bd-view-jobs { display: flex; }
.bd-dock-left[data-panel="logs"] .bd-view-logs { display: flex; }
/* Dans une vue flex, le corps prend l'espace et scrolle (overflow:auto déjà
   posé par .bd-panel-bd de base). */
.bd-view .bd-panel-bd { flex: 1; min-height: 0; }

/* Champs de configuration (rendus par le moteur déclaratif). */
.cfg-field { display: flex; flex-direction: column; gap: 4px; padding: 8px 12px; }
.cfg-label {
  font-size: 11px; letter-spacing: .03em; text-transform: uppercase;
  color: var(--bd-text-dim);
}
.cfg-aide {
  margin: 0; font-size: 12px; line-height: 1.4; color: var(--bd-text-dim);
}
/* Note de portabilité, sous un choix — reflète l'option sélectionnée, jamais
   stockée (le générateur la déclare, cf. builder-etat.md). */
.cfg-portabilite { margin-top: 2px; }
.cfg-input {
  background: var(--bd-canvas-surface); border: 1px solid var(--bd-panel-border);
  color: var(--bd-text); border-radius: 6px; padding: 7px 9px; font: inherit; font-size: 13px;
}
.cfg-input:focus { outline: none; border-color: var(--bd-text-dim); }
.cfg-variable { font-family: ui-monospace, Menlo, monospace; color: var(--accent); }
.cfg-select { appearance: none; cursor: pointer; }

/* Texte long (nature `texteLong`) : mêmes bordure, fond et rythme que
   .cfg-input, seule la hauteur change. `resize: vertical` seulement — un
   redimensionnement horizontal casserait la colonne du panneau. */
.cfg-textarea {
  background: var(--bd-canvas-surface); border: 1px solid var(--bd-panel-border);
  color: var(--bd-text); border-radius: 6px; padding: 7px 9px; font: inherit; font-size: 13px;
  min-height: 80px; resize: vertical; line-height: 1.5;
}
.cfg-textarea:focus { outline: none; border-color: var(--bd-text-dim); }

/* Pastilles de couleur (nature `couleur`). La pastille choisie se marque par
   un anneau, pas par une bordure épaisse : la teinte doit rester lisible. */
.cfg-teintes { display: flex; gap: 8px; flex-wrap: wrap; }
.cfg-teinte {
  width: 22px; height: 22px; border-radius: 50%; cursor: pointer;
  background: var(--teinte); border: 1px solid var(--bd-panel-border); padding: 0;
}
.cfg-teinte:hover { transform: scale(1.12); }
.cfg-teinte[data-choisie="1"] { box-shadow: 0 0 0 2px var(--bd-canvas-surface), 0 0 0 4px var(--teinte); }

/* Booléen : case à cocher alignée avec son libellé. */
.cfg-check { display: flex; align-items: center; gap: 8px; cursor: pointer; color: var(--bd-text); font-size: 13px; }
.cfg-checkbox { width: 15px; height: 15px; accent-color: var(--accent); cursor: pointer; }
.cfg-field-inline { padding-top: 10px; padding-bottom: 10px; }

/* Aperçu calculé (endpoint webhook, ligne d'historique...) + bouton Copy. */
.cfg-apercu-ligne { display: flex; align-items: center; gap: 8px; }
.cfg-apercu { font-family: ui-monospace, Menlo, monospace; font-size: 12px; color: var(--bd-text); word-break: break-all; }
.cfg-apercu-copie {
  flex: none; background: none; border: 1px solid var(--bd-panel-border); color: var(--bd-text-dim);
  border-radius: 5px; padding: 2px 8px; font: inherit; font-size: 11px; cursor: pointer;
}
.cfg-apercu-copie:hover { color: var(--bd-text); border-color: var(--bd-text-dim); }

/* Masque le champ texte libre d'un `choixOuTexte` quand un préréglage est
   choisi (jamais style.display, cf. discipline du dépôt). */
.cfg-hidden { display: none; }

/* Panneau Variables — groupé par étape d'origine, ligne cliquable (copie). */
.bd-vars-filter { flex: none; width: 120px; }
.bd-var-groupe-titre {
  font-size: 10.5px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--bd-text-dim); padding: 9px 12px 3px;
}
.bd-var-ligne {
  display: flex; align-items: baseline; gap: 8px; padding: 3px 12px;
  cursor: pointer; font-size: 12px; border-radius: 3px;
}
.bd-var-ligne:hover { background: var(--bd-canvas-surface); }
.bd-var-nom { font-family: ui-monospace, Menlo, monospace; color: var(--accent); flex: none; }
.bd-var-aide {
  color: var(--bd-text-dim); font-size: 11px; flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bd-var-incertain { color: var(--warn); font-size: 10px; flex: none; }
.bd-var-toggle {
  padding: 3px 12px; font-size: 11px; color: var(--accent); cursor: pointer;
}
.bd-var-toggle:hover { text-decoration: underline; }
.bd-var-ligne-copie { background: color-mix(in srgb, var(--ok) 18%, transparent); }

/* Endpoint : méthode (étroite) + URL (extensible) sur une ligne. */
.cfg-endpoint { display: flex; gap: 8px; }
.cfg-method { flex: none; width: 92px; }
.cfg-url { flex: 1; min-width: 0; font-family: ui-monospace, Menlo, monospace; font-size: 12px; }

/* Connexion : bille d'état + sélecteur. Code couleur, zéro texte à lire.
   vert = testé & répond · bleu = connectée non testée · rouge = échec ·
   gris = inactive / non testable · pulsation pendant le test. */
.cfg-connexion { display: flex; align-items: center; gap: 8px; }
.cfg-connexion .cfg-select { flex: 1; min-width: 0; }

/* Champ variable + sélecteur d'insertion accolé — le texte reste éditable à
   la main, le menu n'est qu'un raccourci pour éviter de deviner un nom. */
.cfg-variable-ligne { display: flex; align-items: center; gap: 8px; }
.cfg-variable-ligne .cfg-variable { flex: 2; min-width: 0; }
.cfg-variable-picker { flex: 1; min-width: 0; font-size: 11px; }
.cfg-bille { flex: none; width: 10px; height: 10px; border-radius: 50%;
  background: var(--bd-panel-border); }
.cfg-bille[data-etat="vide"]     { background: var(--bd-panel-border); }
.cfg-bille[data-etat="connecte"] { background: var(--info, #4c8dff); }
.cfg-bille[data-etat="vert"]     { background: var(--ok, #35c46a); }
.cfg-bille[data-etat="orange"]   { background: var(--warn, #e08a2b); }
.cfg-bille[data-etat="rouge"]    { background: var(--err, #e5484d); }
.cfg-bille[data-etat="gris"]     { background: var(--bd-text-dim); }
.cfg-bille[data-etat="test"]     { background: var(--info, #4c8dff); animation: cfg-pulse 1s ease-in-out infinite; }
@keyframes cfg-pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }

/* Texte toujours visible à côté de la pastille — distingue "inactive" de
   "non testable par nature" (ex. S3), qui partagent la même couleur grise. */
.cfg-connexion-etat { font-size: 10.5px; color: var(--bd-text-dim); flex: none; white-space: nowrap; }

/* Nature liste : lignes avec sous-champs + boutons add/remove. */
.cfg-liste-ligne { display: flex; gap: 8px; align-items: flex-start;
  padding: 8px; margin: 4px 0; background: var(--bd-canvas-surface);
  border: 1px solid var(--bd-panel-border); border-radius: 8px; }
.cfg-liste-corps { flex: 1; min-width: 0; }
.cfg-liste-corps .cfg-field { padding: 4px 0; }
.cfg-liste-suppr { flex: none; background: none; border: none; color: var(--bd-text-dim);
  cursor: pointer; font-size: 13px; padding: 2px 6px; border-radius: 4px; }
.cfg-liste-suppr:hover { color: var(--err); }
.cfg-liste-ajout { margin: 6px 12px; background: none; border: 1px dashed var(--bd-panel-border);
  color: var(--bd-text-dim); border-radius: 6px; padding: 6px 12px; cursor: pointer;
  font: inherit; font-size: 12px; }
.cfg-liste-ajout:hover { color: var(--bd-text); border-color: var(--bd-text-dim); }

.bd-empty[data-hidden="1"] { display: none; }

/* Menu contextuel (clic droit sur un nœud). Position fixe au curseur. */
.bd-ctx-menu {
  position: fixed;
  left: 0; top: 0;
  transform: translate(var(--cx, 0px), var(--cy, 0px));
  z-index: 2000;
  min-width: 160px;
  padding: 5px;
  background: var(--bd-panel-bg);
  border: 1px solid var(--bd-panel-border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .5);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.bd-ctx-item {
  text-align: left;
  padding: 7px 10px;
  background: none;
  border: none;
  border-radius: 5px;
  color: var(--bd-text);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}
.bd-ctx-item:hover { background: var(--bd-canvas-surface); }
.bd-ctx-danger { color: var(--err); }

/* Historique des versions (bouton 🕘) — même conteneur que le menu
   contextuel (.bd-ctx-menu), ancré sous le bouton plutôt qu'au curseur. */
.bd-history-menu { min-width: 260px; max-height: 320px; overflow-y: auto; }
.bd-history-title { padding: 4px 8px 6px; font-size: 11px; text-transform: uppercase;
  letter-spacing: .04em; color: var(--bd-text-dim); }
.bd-history-empty { padding: 8px; font-size: 12.5px; color: var(--bd-text-dim); }
.bd-history-row { display: flex; align-items: center; gap: 4px; padding: 4px 4px 4px 8px;
  border-radius: 5px; }
.bd-history-row:hover { background: var(--bd-canvas-surface); }
.bd-history-label { flex: 1; font-size: 12.5px; color: var(--bd-text); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.bd-history-action { background: none; border: none; color: var(--bd-text-dim);
  cursor: pointer; padding: 4px 6px; border-radius: 4px; font-size: 13px; }
.bd-history-action:hover { background: var(--bd-panel-border); color: var(--bd-text); }
.bd-history-action.bd-ctx-danger:hover { color: var(--err); }

/* Fantôme suivant le curseur pendant le glisser depuis la palette. */
.bd-drag-ghost {
  position: fixed;
  left: 0; top: 0;
  transform: translate(var(--gx, 0px), var(--gy, 0px));
  pointer-events: none;
  z-index: 1000;
  padding: 6px 10px;
  background: var(--bd-canvas-surface);
  border: 1px solid var(--accent);
  border-radius: 6px;
  color: var(--bd-text);
  font-size: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, .4);
}
/* Repère discret quand on survole le canevas avec un nœud en cours de dépôt. */
.cnv-frame.bd-drop-target { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent) 45%, transparent); }

/* Rectangle de lasso (sélection par encadrement). Positionné par variables. */
.cnv-lasso {
  position: absolute;
  left: 0; top: 0;
  transform: translate(var(--lx, 0px), var(--ly, 0px));
  width: var(--lw, 0px);
  height: var(--lh, 0px);
  border: 1px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  pointer-events: none;
  display: none;
}
.cnv-frame.cnv-lassoing .cnv-lasso { display: block; }

.cnv-frame:focus { outline: none; }
.cnv-surface {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  transform:
    translate(var(--bd-pan-x, 0px), var(--bd-pan-y, 0px))
    scale(var(--bd-zoom, 1));
}
.cnv-edges {
  position: absolute;
  top: 0;
  left: 0;
  overflow: visible;
  pointer-events: none;
}
/* Les arêtes elles-mêmes redeviennent cliquables (la couche reste inerte
   partout ailleurs, pour ne pas voler les clics au canevas). */
.cnv-edges .cnv-edge { pointer-events: auto; }
.cnv-edges .cnv-edge-draft { pointer-events: none; }
.cnv-nodes {
  position: absolute;
  top: 0;
  left: 0;
}

/* ── Docks : volet + onglets SOLIDAIRES, superposes au canevas ───────────── */
/* Un dock est la piece entiere (volet + onglets + poignee). On translate le
   dock : ferme, seuls les onglets depassent dans le canevas ; ouvert, le volet
   entre et les onglets restent accroches a son bord exterieur. Le canevas ne
   bouge pas — superposition, jamais poussee. */
.bd-dock {
  position: absolute;
  z-index: 20;
  display: flex;
  transition: transform .28s cubic-bezier(.4, 0, .2, 1);
}

.bd-dock-left {
  top: 64px; left: 0;
  flex-direction: row;
  transform: translateX(calc(-1 * var(--bd-left-width)));
}
.bd-dock-right {
  top: 64px; right: 0;
  flex-direction: row-reverse;
  transform: translateX(var(--bd-right-width));
}
.bd-dock-bottom {
  left: 64px; bottom: 0;
  flex-direction: column-reverse;
  transform: translateY(var(--bd-bottom-height));
}

/* Ouverture : pilotee par data-open sur la racine, lu en CSS (pas de style.* JS) */
.bd-canvas-root[data-open~="left"]   .bd-dock-left   { transform: translateX(0); }
.bd-canvas-root[data-open~="right"]  .bd-dock-right  { transform: translateX(0); }
.bd-canvas-root[data-open~="bottom"] .bd-dock-bottom { transform: translateY(0); }

/* Le volet lui-meme */
.bd-panel {
  background: var(--bd-panel-bg);
  border: 1px solid var(--bd-panel-border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.bd-dock-left   .bd-panel { width: var(--bd-left-width);   height: calc(100vh - var(--bd-header-height) - var(--bd-statusbar-height) - 128px); border-left: none; }
.bd-dock-right  .bd-panel { width: var(--bd-right-width);  height: calc(100vh - var(--bd-header-height) - var(--bd-statusbar-height) - 128px); border-right: none; }
.bd-dock-bottom .bd-panel { height: var(--bd-bottom-height); width: calc(100vw - 128px); border-bottom: none; }

.bd-panel-hd {
  padding: 12px 14px;
  border-bottom: 1px solid var(--bd-panel-border);
  color: var(--bd-text);
  font-weight: 600;
}
.bd-panel-bd {
  padding: 12px 14px;
  color: var(--bd-text-dim);
  overflow: auto;
}

/* Poignee d'elargissement (superposition n'empeche pas l'elargissement) */
.bd-grip { background: transparent; }
.bd-dock-left   .bd-grip,
.bd-dock-right  .bd-grip { width: var(--bd-gutter); cursor: col-resize; align-self: stretch; }
.bd-dock-bottom .bd-grip { height: var(--bd-gutter); cursor: row-resize; align-self: stretch; }
.bd-grip:hover,
.bd-grip:focus-visible { background: var(--bd-gutter-hover); outline: none; opacity: .5; }

/* ── Onglets ─────────────────────────────────────────────────────────────── */
/* Barre d'onglets accolee au volet. */
.bd-tabs { display: flex; }
.bd-dock-left   .bd-tabs,
.bd-dock-right  .bd-tabs { flex-direction: column; gap: 8px; padding-top: 6px; }
.bd-dock-bottom .bd-tabs { flex-direction: row; gap: 8px; padding-left: 6px; }

.bd-tab {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bd-panel-bg);
  color: var(--bd-text-dim);
  border: 1px solid var(--bd-panel-border);
  cursor: pointer;
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  font-family: inherit;
  transition: color .15s, box-shadow .15s;
}
.bd-tab:hover { color: var(--bd-text); }

/* Texte vertical coherent des deux cotes (bas -> haut). */
.bd-dock-left  .bd-tab,
.bd-dock-right .bd-tab { writing-mode: vertical-rl; transform: rotate(180deg); padding: 14px 8px; }
.bd-dock-bottom .bd-tab { padding: 8px 14px; }

/* ── FORME « filet d'accent » (verrouillee, isolee pour retouche facile) ──── */
/* Rectangle sobre ; l'onglet actif recoit un mince filet d'accent sur son bord.
   Pour changer de forme un jour, on ne touche QUE ce bloc. */
.bd-tab.bd-tab-active { color: var(--bd-text); }
.bd-dock-left   .bd-tab.bd-tab-active { box-shadow: inset  3px 0 0 var(--accent); }
.bd-dock-right  .bd-tab.bd-tab-active { box-shadow: inset -3px 0 0 var(--accent); }
.bd-dock-bottom .bd-tab.bd-tab-active { box-shadow: inset 0 -3px 0 var(--accent); }

/* ── États d'interaction ─────────────────────────────────────────────────── */
.bd-canvas-root.bd-resizing { cursor: col-resize; user-select: none; }
.cnv-frame.bd-panning { cursor: grabbing; }

@media (prefers-reduced-motion: reduce) {
  .bd-dock { transition: none; }
}

/* ── Header : breadcrumb calé sur la charte sombre du Builder ─────────────────
   navbar.css ne style pas .breadcrumb (pensé pour un thème clair) ; ici on le
   met aux couleurs du Builder pour qu'il ne jure pas avec la page. */
.aps-header .breadcrumb {
  color: var(--bd-text-dim);
  font-size: 12.5px;
}
.aps-header .breadcrumb a {
  color: var(--bd-text-dim);
  text-decoration: none;
}
.aps-header .breadcrumb a:hover {
  color: var(--bd-text);
}

/* ── Header : centrage du sélecteur désormais dans navbar.css partagé ───────── */

/* Nœud de palette hors périmètre de l'organisation courante (filtre par
   contexte). Masqué par classe, jamais par style inline — réversible si le
   contexte change. */
.bd-node.bd-hors-contexte { display: none; }

/* Erreur de sauvegarde : texte SÉLECTIONNABLE et COPIABLE (contrairement à un
   alert() natif, illisible/non copiable). Reste affiché jusqu'au prochain essai
   ou une fermeture manuelle, pour laisser le temps de copier. */
.bd-save-error {
  display: inline-flex; align-items: center; gap: 8px;
  max-width: 420px; padding: 4px 10px;
  background: rgba(231,76,60,.12); border: 1px solid rgba(231,76,60,.35);
  border-radius: 6px; color: #e88; font-size: 11.5px;
  user-select: text; cursor: text;
}
.bd-save-error[hidden] { display: none; }
.bd-save-error-fermer {
  background: transparent; border: none; color: inherit; cursor: pointer;
  font-size: 13px; line-height: 1; padding: 0;
}

/* Organisation : INFORMATION en lecture seule dans le canvas (pas un
   sélecteur — voir commentaire HTML). Sobre, non interactive. */
.bd-org-info {
  font-size: 11.5px; color: var(--bd-text-dim, #a6b0b8);
  padding: 3px 8px; border: 1px solid var(--bd-panel-border, #262a2e);
  border-radius: 10px;
}
.bd-org-info:empty { display: none; }

/* ── Vue Run (dock droit) ─────────────────────────────────────────────────── */
.rn-payload { font-family: ui-monospace, Menlo, monospace; font-size: 12px; resize: vertical; }
.rn-error { color: var(--err); }
.rn-error[hidden] { display: none; }
.rn-result { margin-top: 14px; }
.rn-result[hidden] { display: none; }
.rn-result-texte {
  margin: 0; padding: 10px 12px; border-radius: 8px;
  background: var(--bd-canvas-surface); border: 1px solid var(--bd-panel-border);
  color: var(--bd-text); font-family: ui-monospace, Menlo, monospace; font-size: 11.5px;
  white-space: pre-wrap; word-break: break-word; user-select: text;
  max-height: 320px; overflow: auto;
}
.rn-result[data-etat="success"] .rn-result-texte { border-color: color-mix(in srgb, var(--ok) 45%, var(--bd-panel-border)); }
.rn-result[data-etat="partial"] .rn-result-texte { border-color: color-mix(in srgb, var(--warn) 45%, var(--bd-panel-border)); }
.rn-result[data-etat="failed"]  .rn-result-texte { border-color: color-mix(in srgb, var(--err) 45%, var(--bd-panel-border)); }

/* ── Déclencheur de test (vue Jobs, dock gauche) ──────────────────────────── */
.rn-trigger {
  margin: 10px 10px 4px; padding: 0 2px 8px; border-bottom: 1px solid var(--bd-panel-border);
}
.rn-trigger summary {
  cursor: pointer; font-size: 12px; color: var(--bd-text-dim); padding: 6px 0; list-style: none;
}
.rn-trigger summary::-webkit-details-marker { display: none; }
.rn-trigger summary:hover { color: var(--bd-text); }
.rn-trigger[open] summary { color: var(--bd-text); }
.rn-trigger-body { padding-top: 4px; }

/* ── Vue Jobs (dock gauche) ───────────────────────────────────────────────── */
.jb-row {
  display: flex; align-items: center; gap: 9px; padding: 8px 10px; margin: 0 0 6px;
  background: var(--bd-canvas-surface); border: 1px solid var(--bd-panel-border);
  border-radius: 8px; cursor: pointer; font-size: 12px;
}
.jb-row:hover { border-color: var(--bd-text-dim); }
.jb-row[data-selected="1"] { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.jb-status { flex: none; }
.jb-body { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
.jb-titre { color: var(--bd-text); display: flex; align-items: center; gap: 6px; }
.jb-trigger {
  font-size: 9.5px; text-transform: uppercase; letter-spacing: .04em;
  padding: 1px 5px; border-radius: 3px; border: 1px solid var(--bd-panel-border);
  color: var(--bd-text-dim);
}
.jb-meta { color: var(--bd-text-dim); font-size: 11px; }
.jb-err { color: var(--err); font-size: 11px; }

/* ── Vue Logs (dock gauche) ───────────────────────────────────────────────── */
.lg-run-hd { padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px solid var(--bd-panel-border); }
.lg-event {
  display: flex; align-items: flex-start; gap: 8px; padding: 7px 0;
  border-bottom: 1px solid var(--bd-panel-border); font-size: 12px;
}
.lg-event:last-child { border-bottom: none; }
.lg-dot { flex: none; margin-top: 4px; }
.lg-body { min-width: 0; flex: 1; }
.lg-ligne { color: var(--bd-text); display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; }
.lg-type { font-family: ui-monospace, Menlo, monospace; color: var(--accent); font-size: 11px; }
.lg-step { color: var(--bd-text-dim); font-size: 11px; }
.lg-msg { color: var(--bd-text); font-size: 12px; margin-top: 2px; white-space: pre-wrap; user-select: text; }
.lg-msg[data-severity="warn"]  { color: var(--warn); }
.lg-msg[data-severity="fatal"] { color: var(--err); }
.lg-at { color: var(--bd-text-dim); font-size: 10.5px; margin-left: auto; flex: none; }
.lg-snapshot { margin-top: 4px; }
.lg-snapshot summary { color: var(--bd-text-dim); font-size: 11px; cursor: pointer; }
.lg-snapshot summary:hover { color: var(--bd-text); }
.lg-snapshot pre {
  margin: 6px 0 0; padding: 8px 10px; border-radius: 6px;
  background: var(--bd-canvas-surface); border: 1px solid var(--bd-panel-border);
  color: var(--bd-text); font-family: ui-monospace, Menlo, monospace; font-size: 11px;
  white-space: pre-wrap; word-break: break-word; user-select: text;
  max-height: 260px; overflow: auto;
}

/* ── Vue Run — onglets Assets/Action (dock droit) ─────────────────────────── */
.rp-section { margin-bottom: 14px; }
.rp-section:last-child { margin-bottom: 0; }
.rp-section-title {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--bd-text-dim); margin-bottom: 6px;
}
.rp-asset-row {
  display: flex; align-items: baseline; gap: 8px; padding: 6px 0;
  border-bottom: 1px solid var(--bd-panel-border); font-size: 12px;
}
.rp-asset-row:last-child { border-bottom: none; }
.rp-asset-name { color: var(--bd-text); user-select: text; }
.rp-asset-id { color: var(--bd-text-dim); font-size: 10.5px; font-family: ui-monospace, Menlo, monospace; user-select: text; }
.rp-kv {
  display: flex; justify-content: space-between; gap: 10px; padding: 4px 0;
  border-bottom: 1px solid var(--bd-panel-border); font-size: 12px;
}
.rp-kv:last-child { border-bottom: none; }
.rp-kv-key { color: var(--bd-text-dim); flex: none; }
.rp-kv-val { color: var(--bd-text); text-align: right; word-break: break-word; user-select: text; }
.rp-kv-val[data-changed="1"] { color: var(--accent); }
.rp-occurrence { margin-bottom: 12px; }
.rp-occurrence:last-child { margin-bottom: 0; }
.rp-occurrence-hd {
  display: flex; align-items: center; gap: 6px; font-size: 11px;
  color: var(--bd-text-dim); margin-bottom: 4px;
}
.rp-port { font-weight: 600; }
.rp-port[data-ok="1"] { color: var(--ok); }
.rp-port[data-ok="0"] { color: var(--err); }
/* Avertissement non fatal remonté par le moteur (ctx.errors) — lisible tel
   quel dans l'onglet Action, plus seulement enfoui dans le JSON du snapshot. */
.rp-warn {
  margin-top: 8px; padding: 8px 10px; border-radius: 4px;
  font-size: 12px; line-height: 1.45; white-space: pre-wrap; word-break: break-word;
  border-left: 3px solid var(--warn); background: rgba(255, 176, 32, .08); color: var(--bd-text);
}
.rp-warn[data-severity="fatal"] { border-left-color: var(--err); background: rgba(255, 90, 90, .08); }
/* 'info' : constat de diagnostic, jamais un échec (cf. computeStatus) —
   neutre visuellement pour ne pas se lire comme un problème. */
.rp-warn[data-severity="info"] {
  border-left-color: var(--bd-text-dim); background: rgba(255, 255, 255, .04); color: var(--bd-text-dim);
}
/* Résumé lisible : une ligne = un fait établi. Le vert/rouge porte le
   verdict (fait / pas fait), jamais la simple présence d'une valeur. */
.rp-ligne {
  display: flex; gap: 10px; align-items: baseline; justify-content: space-between;
  padding: 4px 0; border-bottom: 1px solid var(--bd-panel-border);
  font-size: 12px; line-height: 1.45;
}
.rp-ligne:last-child { border-bottom: none; }
.rp-ligne-g { color: var(--bd-text-dim); flex: 1 1 auto; min-width: 0; word-break: break-word; user-select: text; }
.rp-ligne-d { color: var(--bd-text); flex: 0 1 auto; text-align: right; word-break: break-word; user-select: text; }
.rp-ligne[data-etat="ok"] .rp-ligne-d { color: var(--ok); }
.rp-ligne[data-etat="ko"] .rp-ligne-d { color: var(--err); }
.rp-ligne-note {
  display: block; font-size: 10.5px; opacity: .7; margin-top: 1px;
}
/* Brut : disponible, jamais imposé. */
.rp-verbose { margin-top: 10px; }
.rp-verbose > summary {
  cursor: pointer; font-size: 11px; color: var(--bd-text-dim);
  text-transform: uppercase; letter-spacing: .04em; padding: 4px 0; user-select: none;
}
.rp-verbose > summary:hover { color: var(--bd-text); }
.rp-empty { color: var(--bd-text-dim); font-size: 12px; padding: 16px 0; text-align: center; }
.bd-subtab-count { opacity: .65; font-size: 10.5px; margin-left: 2px; }

/* ══ Volet API ops ══════════════════════════════════════════════════════════
   Port du tiroir API Ops de WFD (wfd-api-ops.js + workflow-designer.css).
   Même lecture — timeline, flux de données, détail — mais en classes CSS et
   tokens partagés plutôt qu'en styles en ligne (règle dure du dépôt). */
.ao-hd {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 2px 0 8px; border-bottom: 1px solid var(--bd-panel-border);
  margin-bottom: 8px; flex-wrap: wrap;
}
.ao-hd-g { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
.ao-hd-d { display: flex; align-items: center; gap: 6px; }
.ao-titre { font-size: 12px; font-weight: 600; color: var(--bd-text); }
.ao-flow  { font-size: 11.5px; color: var(--bd-text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ao-count { font-size: 10.5px; color: var(--accent); }
.ao-export {
  font-size: 11px; padding: 3px 8px; border-radius: 4px; cursor: pointer;
  background: transparent; color: var(--bd-text-dim);
  border: 1px solid var(--bd-panel-border);
}
.ao-export:hover { color: var(--bd-text); border-color: var(--accent); }

/* 1. Timeline — défile horizontalement, jamais le volet lui-même. */
.ao-timeline {
  display: flex; align-items: stretch; gap: 0;
  overflow-x: auto; padding-bottom: 8px; margin-bottom: 10px;
}
.ao-carte {
  flex: 0 0 auto; min-width: 132px; max-width: 200px; cursor: pointer;
  background: var(--bd-panel-bg); border: 1px solid var(--bd-panel-border);
  border-radius: 5px; padding: 6px 8px;
  transition: border-color .15s, background .15s, box-shadow .15s;
}
.ao-carte:hover {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: color-mix(in srgb, var(--accent) 7%, var(--bd-panel-bg));
}
/* Sélection : fond teinté + liseré, comme .api-op-card.active de WFD, plus
   une pulsation brève — l'animation attire l'oeil sur la carte retenue quand
   la timeline est longue et défile horizontalement. */
.ao-carte[data-actif="1"] {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, var(--bd-panel-bg));
  box-shadow: 0 0 0 1px var(--accent);
  animation: ao-pulse .9s ease-out;
}
.ao-carte[data-actif="1"] .ao-carte-nom,
.ao-carte[data-actif="1"] .ao-ep { color: var(--bd-text); }
@keyframes ao-pulse {
  0%   { box-shadow: 0 0 0 1px var(--accent), 0 0 0 0 color-mix(in srgb, var(--accent) 60%, transparent); }
  70%  { box-shadow: 0 0 0 1px var(--accent), 0 0 0 9px transparent; }
  100% { box-shadow: 0 0 0 1px var(--accent), 0 0 0 0 transparent; }
}
/* La carte correspondante du flux de données se surligne en même temps :
   c'est la MÊME étape vue sous deux angles, la lier évite de la chercher. */
.ao-vcarte[data-actif="1"] {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, var(--bd-panel-bg));
  animation: ao-pulse .9s ease-out;
}
@media (prefers-reduced-motion: reduce) {
  .ao-carte[data-actif="1"], .ao-vcarte[data-actif="1"] { animation: none; }
}
.ao-carte[data-imbrique="1"] { border-left-width: 3px; border-left-color: var(--accent); }
.ao-carte-nom {
  font-size: 10.5px; color: var(--bd-text); margin-bottom: 4px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ao-carte-nom[data-suite="1"] { color: var(--bd-text-dim); font-size: 9.5px; }
.ao-ep {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 9.5px;
  color: var(--bd-text-dim); margin-top: 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ao-fleche {
  flex: 0 0 auto; display: flex; align-items: center; padding: 0 4px;
  color: var(--bd-text-dim); opacity: .5; font-size: 11px;
}
.ao-methode {
  display: inline-block; min-width: 44px; text-align: center;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 9.5px; font-weight: 600; padding: 1px 5px; border-radius: 3px;
  background: rgba(255,255,255,.06); color: var(--bd-text-dim);
}
.ao-methode[data-m="GET"]    { background: rgba(90,170,255,.15); color: #6fb4ff; }
.ao-methode[data-m="POST"]   { background: rgba(93,187,107,.15); color: #6fcf7f; }
.ao-methode[data-m="PUT"]    { background: rgba(240,160,48,.15); color: #f0a030; }
.ao-methode[data-m="PATCH"]  { background: rgba(240,160,48,.15); color: #f0a030; }
.ao-methode[data-m="DELETE"] { background: rgba(255,90,90,.15);  color: #ff6b6b; }
.ao-methode[data-m="HEAD"]   { background: rgba(150,150,255,.15); color: #9a9aff; }
.ao-methode[data-m="local"]  { background: rgba(255,255,255,.04); color: var(--bd-text-dim); }

/* 2. Flux de données */
.ao-section-titre {
  font-size: 10px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--bd-text-dim); margin-bottom: 5px;
}
.ao-vars { margin-bottom: 10px; }
.ao-vars-piste { display: flex; align-items: flex-start; gap: 0; overflow-x: auto; padding-bottom: 6px; }
.ao-vcarte {
  flex: 0 0 auto; min-width: 152px; max-width: 176px;
  background: var(--bd-panel-bg); border: 1px solid var(--bd-panel-border);
  border-radius: 5px; padding: 7px 9px;
}
.ao-vcarte-hd { display: flex; align-items: center; gap: 5px; margin-bottom: 5px; }
.ao-vcarte-nom {
  font-size: 10px; font-weight: 500; color: var(--bd-text); flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ao-src { font-size: 9px; padding: 1px 4px; border-radius: 3px; border: 1px solid; flex: none; }
.ao-src[data-src="iconik"]     { background: #0d1f30; color: #7ec8e3; border-color: #1a3a50; }
.ao-src[data-src="s3"]         { background: #0d2010; color: #7dce82; border-color: #1a4020; }
.ao-src[data-src="vodfactory"] { background: #2a1a00; color: #f0a030; border-color: #4a3000; }
.ao-src[data-src="api"]        { background: #2a1a00; color: #f0a030; border-color: #4a3000; }
.ao-src[data-src="aps"]        { background: #1a1a2e; color: #9090c0; border-color: #2a2a4a; }
.ao-vlabel {
  font-size: 9px; color: var(--bd-text-dim); text-transform: uppercase;
  letter-spacing: .04em; margin-top: 4px; opacity: .75;
}
.ao-vconn { font-size: 9.5px; color: var(--bd-text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ao-pills { display: flex; flex-wrap: wrap; gap: 2px; margin-top: 2px; }
.ao-pill {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 9px;
  padding: 1px 4px; border-radius: 3px; max-width: 140px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  background: #1a1a2e; color: #9090c0; border: 1px solid #2a2a4a;
}
.ao-pill[data-src="iconik"] { background: #0d1f30; color: #7ec8e3; border-color: #1a3a50; }
.ao-pill[data-src="s3"]     { background: #0d2010; color: #7dce82; border-color: #1a4020; }
.ao-pill[data-src="api"], .ao-pill[data-src="vodfactory"] { background: #2a1a00; color: #f0a030; border-color: #4a3000; }
.ao-vsteps { margin-top: 5px; border-top: 1px solid var(--bd-panel-border); padding-top: 4px; }
.ao-vsteps > summary { font-size: 9px; color: var(--bd-text-dim); cursor: pointer; user-select: none; }
.ao-vstep { font-size: 9px; color: var(--bd-text-dim); padding: 1px 0; }
.ao-vstep-n { color: #f0a030; }
.ao-vstep-out { color: #7dce82; }
.ao-vvide { font-size: 9px; color: var(--bd-text-dim); font-style: italic; margin-top: 4px; opacity: .6; }
.ao-vfleche { flex: 0 0 auto; padding: 18px 3px 0; color: var(--bd-text-dim); opacity: .4; font-size: 12px; }

/* 3. Détail */
.ao-detail { border-top: 1px solid var(--bd-panel-border); padding-top: 8px; }
.ao-detail-vide { font-size: 11.5px; color: var(--bd-text-dim); padding: 10px 0; text-align: center; }
.ao-detail-titre { font-size: 11.5px; font-weight: 600; color: var(--bd-text); margin-bottom: 6px; }
.ao-detail-fam { font-size: 9.5px; color: var(--bd-text-dim); font-weight: 400; margin-left: 6px; }
.ao-detail-op { margin-bottom: 10px; }
.ao-detail-l { display: flex; align-items: baseline; gap: 7px; }
.ao-detail-desc { font-size: 11px; color: var(--bd-text-dim); user-select: text; }
.ao-detail-ep {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10px;
  color: #6fcf7f; margin-top: 2px; word-break: break-all; user-select: text;
}
.ao-detail-body-lbl {
  font-size: 9px; color: var(--bd-text-dim); text-transform: uppercase;
  letter-spacing: .05em; margin-top: 5px;
}
.ao-detail-body {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10px;
  background: rgba(255,255,255,.03); border-radius: 4px; padding: 6px 8px;
  margin-top: 2px; max-height: 220px; overflow: auto; user-select: text;
  color: var(--bd-text-dim); white-space: pre;
}
