/* creep-ds — tokens + styles composants. Base palette studio (light/dark).
 *
 * Charte alignee sur le kit UI Maquettes v2 (#1996). Le cockpit etait en full-flat :
 * aucune elevation, bordures translucides a 8%, deux rayons, accent bleu generique.
 * Tout etait au meme niveau z et la hierarchie ne tenait qu'a la typo.
 *
 * Ce que la charte apporte :
 *   - une echelle d'ELEVATION (sm/md/lg) — ce qui flotte se detache du fond ;
 *   - quatre RAYONS hierarchises, du badge au panneau ;
 *   - un ACCENT de marque (violet #635bff) au lieu du bleu Tailwind par defaut ;
 *   - des BORDURES opaques, avec un cran "strong" pour separer faible et fort ;
 *   - les ETATS manquants (surface-hover, accent-hover) ;
 *   - des tokens de TYPO, au lieu de system-ui reecrit dans chaque composant.
 */
:root, [data-theme="light"] {
  /* Fonds et surfaces */
  --cs-bg: #f4f4f6;
  --cs-surface: #ffffff;
  --cs-surface-2: #fafafa;
  --cs-surface-hover: #f7f7f8;
  --cs-sunken: #f4f4f5;

  /* Bordures — opaques : une separation doit se voir sans dependre du fond */
  --cs-border: #ececee;
  --cs-border-strong: #dcdce0;

  /* Texte */
  --cs-text: #18181b;
  --cs-text-2: #52525b;
  /* AA (#CS-90) : #8a8a94 donnait 3.42:1 sur --cs-surface (le pire des 3 fonds
     clairs), sous le seuil 4.5:1 texte normal — et c'est le token de texte
     secondaire, donc le plus repandu. #666e82 passe les trois fonds clairs
     (5.10 / 4.89 / 4.64). Les usages non-textuels (dot de statut, bordure de
     champ au survol) restent lisibles a ce niveau, seul le texte l'exigeait. */
  --cs-muted: #666e82;
  --cs-text-inverse: #ffffff;

  /* Accent de marque */
  /* AA (#CS-90) : #635bff donnait 4.28:1 sur --cs-bg (le pire des 3 fonds
     clairs), sous 4.5:1. #5f57fb passe les trois (4.95 / 4.74 / 4.51) sans
     changer perceptiblement la teinte de marque. */
  --cs-accent: #5f57fb;
  --cs-accent-hover: #524bec;
  --cs-accent-soft: #eeecff;
  --cs-accent-text: #524bec;

  /* Fond d'accent PORTANT DU TEXTE BLANC (#2141), meme patron que
     `--cs-danger-solid` : le blanc sur `--cs-accent` brut donne 4.95:1 ici
     (#CS-90 : 4.70:1 avant #5f57fb), conforme — mais 3.62:1 en sombre, et
     2.94:1 au survol, sous AA a 13px.
     L'accent sombre est volontairement eclairci pour se detacher du fond, ce
     qui le rend trop clair pour porter du blanc.
     En clair les deux valent l'accent : rien a corriger de ce cote. */
  --cs-accent-solid: var(--cs-accent);
  --cs-accent-solid-hover: var(--cs-accent-hover);

  /* Premium SaaS (#2021) — paire de gradient, gradient et halos d'accent.
     Reserves aux elements de marque : action primaire, avatars, indicateurs. */
  --cs-accent-2: #a68bff;
  --cs-accent-grad: linear-gradient(135deg, var(--cs-accent), var(--cs-accent-2));
  --cs-glow: color-mix(in srgb, var(--cs-accent) 22%, transparent);
  --cs-glow-strong: color-mix(in srgb, var(--cs-accent) 40%, transparent);

  /* Semantique */
  --cs-success: #1ea672;
  --cs-warning: #e0a13a;
  --cs-danger: #e5484d;
  --cs-info: #3a7bd5;

  /* Variante TEXTE du danger (#2105), meme patron que --cs-accent-text : le
     rouge de surface est fait pour des fonds et des bordures, pas pour du texte.
     --cs-danger sur fond clair donne 3.75:1, sous AA. La variante assombrie
     donne 5.70:1 sur --cs-surface-2 et 4.90:1 sur --cs-danger-bg. En sombre le
     token de surface est deja lisible (5.97:1), la variante s'y confond. */
  --cs-danger-text: #c0242a;

  /* Variantes TEXTE de success/warning/info (#CS-90), meme patron que
     --cs-accent-text et --cs-danger-text ci-dessus : les couleurs de surface
     restent conformes en fond/pastille/bordure (seuil 3:1) mais echouent AA
     texte (4.5:1) sur les trois fonds clairs — success 3.11 / warning 2.25 /
     info 4.22 sur --cs-surface, le pire cas descendant a 2.05 (warning) sur
     --cs-bg. success-text/warning-text sont plus sombres que la premiere
     proposition (#00804c/#a06100, 5.01/4.99 sur --cs-surface) : .cs-badge
     les pose aussi sur son propre fond tinte (color-mix ~16% sur surface),
     ou la premiere proposition tombait a 4.24/4.35, sous AA — #00753f et
     #8f5900 y remontent a 4.91/5.09 tout en restant a 5.81/5.84 sur
     --cs-surface, 5.29/5.32 sur --cs-bg. Pour info-text, cf. le bloc
     suivant : ce kit en cree desormais un usage sur fond tinte. */
  --cs-success-text: #00753f;
  --cs-warning-text: #8f5900;
  /* Assombri (#CS-90 avait retenu #2e6fc9) : ce lot cree le PREMIER usage
     d'`info-text` sur fond TINTE — `.cs-timeline__glyph--info` pose ce texte
     sur `--cs-info-bg`, ou #2e6fc9 tombait a 3.92:1. #2865ba passe les trois
     fonds nus (5.74 / 5.22 / 5.50) ET le fond tinte (4.95 / 4.53 / 4.78). */
  --cs-info-text: #2865ba;

  /* Fonds doux associes (#2001, alignes sur le kit en #2105) — motif
     « pilule / alerte » : fond teinte + texte de la couleur semantique. Ils
     existaient dans packages/ui-kit sans jamais avoir ete repercutes ici : une
     maquette qui les consommait obtenait un fond TRANSPARENT (custom property
     indefinie => declaration invalid at computed-value time). */
  --cs-success-bg: color-mix(in srgb, var(--cs-success) 12%, transparent);
  --cs-warning-bg: color-mix(in srgb, var(--cs-warning) 14%, transparent);
  --cs-danger-bg:  color-mix(in srgb, var(--cs-danger) 12%, transparent);
  --cs-info-bg:    color-mix(in srgb, var(--cs-info) 12%, transparent);
  --cs-muted-bg:   color-mix(in srgb, var(--cs-muted) 14%, transparent);

  /* Roles cockpit (#2103) — palette CATEGORIELLE, volontairement distincte des
     couleurs semantiques : --cs-danger reste reserve aux erreurs (role non
     reconnu) et aux actions destructives. Un privilege eleve appelle la
     vigilance (ambre), pas l'erreur.
     Alias var() declares une seule fois : ils suivent la redefinition de leur
     token source par theme, ne pas les dupliquer dans le bloc dark. */
  --cs-role-admin: var(--cs-warning);
  --cs-role-operator: var(--cs-accent);
  --cs-role-viewer: var(--cs-success);

  /* Elevation — c'est ce qui manquait au full-flat */
  --cs-shadow-sm: 0 1px 2px rgba(24,24,27,.06);
  --cs-shadow-md: 0 4px 12px rgba(24,24,27,.08);
  --cs-shadow-lg: 0 12px 32px rgba(24,24,27,.12);

  /* Rayons — du plus petit (badge, puce) au plus large (panneau, modale) */
  /* ECHELLE DE HAUTEURS DES CONTROLES. Sans elle, un bouton `md` mesurait
     32px et un champ 35px : poses cote a cote dans une barre de filtres ou un
     formulaire en ligne, ils ne s'alignaient pas — 3px de decalage, a chaque
     fois. La hauteur d'un controle ne peut pas dependre de son padding et de
     sa police, sinon deux controles voisins ne s'accordent que par hasard.
     Valeurs calees sur le champ, le controle le plus contraint (il porte une
     bordure et doit rester cliquable). */
  --cs-control-h-xs: 24px;
  --cs-control-h-sm: 28px;
  --cs-control-h:    34px;   /* md — la taille par defaut */
  --cs-control-h-lg: 42px;
  --cs-control-h-xl: 48px;

  /* Palette categorielle des avatars — distinctive, sans valeur semantique.
     Meme ROLE que les `--cs-role-*` (identifier, pas signifier) mais PAS le
     meme mecanisme : ceux-la sont des alias `var()` qui suivent leur token
     source d'un theme a l'autre, ceux-ci sont des litteraux, donc figes.
     C'est voulu — ces six teintes portent du texte blanc et sont calibrees
     pour lui (4.59 a 5.44), pas pour le fond qui les entoure ; elles tiennent
     3.29 a 3.89 face a `--cs-surface` sombre, au-dessus du seuil 3:1 non
     textuel. Un token qui suivrait le theme casserait le premier rapport pour
     ameliorer le second, qui n'en a pas besoin.
     `gris` fait exception et a une valeur par theme (plus bas) : il derivait de
     `--cs-muted`, un token de TEXTE calibre pour etre lu SUR un fond —
     l'employer comme aplat portant du blanc donnait 3.42:1 en sombre. C'est
     l'inversion de fonction que `--cs-accent-solid` a ete cree pour eviter
     (#2141). */
  --cs-avatar-violet: #6d5ce0;
  --cs-avatar-bleu:   #3572c6;
  --cs-avatar-cyan:   #1c7f8f;
  --cs-avatar-vert:   #2b7a52;
  --cs-avatar-ambre:  #a2691a;
  --cs-avatar-rose:   #b0407a;
  --cs-avatar-gris:   #666e82;   /* 5.10:1 */

  --cs-radius-xs: 6px;
  --cs-radius-sm: 6px;   /* conserve : deja consomme partout */
  --cs-radius: 9px;      /* conserve : controles */
  --cs-radius-lg: 14px;  /* cartes */
  --cs-radius-xl: 20px;  /* panneaux, modales */

  /* Typo */
  --cs-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --cs-mono: "SF Mono", ui-monospace, "JetBrains Mono", Menlo, monospace;

  /* Chips a teinte variable (labels) — la teinte vient du contenu, la clarte du
     theme. Sans ca, un hsl() ecrit en dur reste sombre en theme clair. */
  --cs-chip-bg-s: 70%; --cs-chip-bg-l: 92%;
  --cs-chip-fg-s: 55%; --cs-chip-fg-l: 28%;
  --cs-chip-bd-s: 60%; --cs-chip-bd-l: 85%;
}
[data-theme="dark"] {
  /* Neutre plutot que bleute — moins fatigant sur de longues sessions */
  --cs-bg: #0c0c0e;
  --cs-surface: #17171a;
  --cs-surface-2: #141417;
  --cs-surface-hover: #1f1f23;
  --cs-sunken: #0a0a0c;

  --cs-border: #26262b;
  --cs-border-strong: #34343b;

  --cs-text: #f4f4f5;
  --cs-text-2: #a1a1aa;
  /* AA (#CS-90) : #6f6f78 donnait 3.60:1 sur --cs-surface, sous 4.5:1 — le
     defaut n'etait pas propre au theme clair. #8a8a94 (l'ancienne valeur
     LIGHT de ce meme token) passe les trois fonds sombres une fois inversee
     (5.23 / 5.72 / 5.38, surface / bg / surface-2). */
  --cs-muted: #8a8a94;
  --cs-text-inverse: #17171a;

  --cs-accent: #7c74ff;
  --cs-accent-hover: #8f88ff;
  /* 86% / 78% : blanc a 4.70:1 et 5.53:1, tout en gardant 3.81:1 et 3.23:1
     face a `--cs-surface` — en dessous de 78%, l'aplat commence a se fondre
     dans le fond sombre. Le survol doit ASSOMBRIR : `--cs-accent-hover` est
     plus CLAIR que l'accent (patron du theme clair inverse), l'appliquer tel
     quel ferait remonter le contraste a 2.94:1. */
  --cs-accent-solid: color-mix(in srgb, var(--cs-accent) 86%, #000);
  --cs-accent-solid-hover: color-mix(in srgb, var(--cs-accent) 78%, #000);
  --cs-accent-soft: #211f3a;
  --cs-accent-text: #a9a3ff;

  /* Premium SaaS (#2021) — cf. bloc light */
  --cs-accent-2: #a68bff;
  --cs-accent-grad: linear-gradient(135deg, var(--cs-accent), var(--cs-accent-2));
  --cs-glow: color-mix(in srgb, var(--cs-accent) 22%, transparent);
  --cs-glow-strong: color-mix(in srgb, var(--cs-accent) 40%, transparent);

  --cs-success: #3ecf95;
  --cs-warning: #f0b752;
  --cs-danger: #f0666b;
  --cs-info: #5c9ce8;
  --cs-danger-text: var(--cs-danger);
  /* AA (#CS-90) : contrairement au theme clair, les tokens de surface sont
     DEJA lisibles en texte ici (memes chiffres que le commentaire
     --cs-danger-text ci-dessus) — success 9.00:1, warning 9.88:1,
     info 6.28:1 sur --cs-surface, tous largement au-dessus de 4.5:1. Les
     variantes -text s'alignent donc sur le token de base, meme patron. */
  --cs-success-text: var(--cs-success);
  --cs-warning-text: var(--cs-warning);
  --cs-info-text: var(--cs-info);

  /* Sur fond sombre il faut un peu plus de matiere pour que la pilule se lise. */
  --cs-success-bg: color-mix(in srgb, var(--cs-success) 18%, transparent);
  --cs-warning-bg: color-mix(in srgb, var(--cs-warning) 20%, transparent);
  --cs-danger-bg:  color-mix(in srgb, var(--cs-danger) 18%, transparent);
  --cs-info-bg:    color-mix(in srgb, var(--cs-info) 18%, transparent);
  --cs-muted-bg:   color-mix(in srgb, var(--cs-muted) 20%, transparent);

  /* Ombres plus profondes : sur fond sombre, une ombre faible ne se lit pas */
  --cs-shadow-sm: 0 1px 2px rgba(0,0,0,.4);
  --cs-shadow-md: 0 4px 14px rgba(0,0,0,.5);
  --cs-shadow-lg: 0 16px 40px rgba(0,0,0,.6);

  /* Le gris d'avatar s'eclaircit juste assez pour rester visible sur un fond
     sombre (3.87:1 face a `--cs-surface`) tout en portant du blanc a 4.62:1.
     Les six teintes nommees, elles, ne bougent pas : calibrees pour porter du
     texte blanc, elles ne dependent pas du fond qui les entoure. */
  --cs-avatar-gris: #74747f;   /* 4.62:1 */

  /* Chips : fond sombre desature, texte clair sature — l'inverse du light */
  --cs-chip-bg-s: 45%; --cs-chip-bg-l: 16%;
  --cs-chip-fg-s: 80%; --cs-chip-fg-l: 72%;
  --cs-chip-bd-s: 45%; --cs-chip-bd-l: 26%;
}

/* Les controles du kit se mesurent BORDURE COMPRISE. Sans ca, `min-height:
   34px` sur un champ borde rend 35px, et le bouton voisin — sans bordure
   visible — en rend 34 : un pixel d'ecart, systematique, entre deux controles
   censes s'aligner. La portee reste aux classes du kit ; un `*` global
   s'imposerait aux pages consommatrices, ce qu'un design system n'a pas a
   faire. */
.cs-btn, .cs-input, .cs-select, .cs-textarea, .cs-icon-btn,
.cs-theme-toggle, .cs-header__btn, .cs-sidebar__link, .cs-tab {
  box-sizing: border-box;
}

/* ---- Sidebar ---- */
.cs-sidebar {
  width: 230px; flex-shrink: 0; box-sizing: border-box;
  height: 100%; display: flex; flex-direction: column;
  background: var(--cs-surface); border-right: 1px solid var(--cs-border);
  padding: 14px 10px; overflow-y: auto;
  font-family: var(--cs-font);
}
.cs-sidebar__brand { display: flex; align-items: center; gap: 10px; padding: 4px 8px 14px; }
.cs-sidebar__logo {
  width: 30px; height: 30px; border-radius: 8px; flex-shrink: 0;
  background: var(--cs-accent-grad);
  color: #fff; font-weight: 700; font-size: 14px;
  display: flex; align-items: center; justify-content: center;
}
.cs-sidebar__brand-text { font-weight: 700; font-size: 16px; color: var(--cs-text); }
.cs-sidebar__nav { display: flex; flex-direction: column; gap: 1px; }
.cs-sidebar__group { display: flex; flex-direction: column; gap: 1px; }
/* Separateur entre sections. Sur `+` et non sur `:not(:first-child)` : il
   separe deux GROUPES VOISINS, ce qui reste vrai quoi qu'on pose avant la nav
   (une marque, un selecteur d'espace). Un selecteur qui compte les positions
   se casse au premier element ajoute en tete. */
.cs-sidebar__group + .cs-sidebar__group {
  margin-top: 7px; padding-top: 12px;
  border-top: 1px solid var(--cs-border);
}

/* Item porteur d'actions (epingle, poignee) ou reordonnable : le lien occupe
   la ligne, les actions se posent a sa droite. */
.cs-sidebar__item { position: relative; display: flex; align-items: center; }
.cs-sidebar__item > .cs-sidebar__link { flex: 1; min-width: 0; }
.cs-sidebar__item.is-dragging { opacity: .45; }
/* Trait de depot : il marque le POINT d'insertion, d'ou un filet en bord de
   ligne plutot qu'un fond — un fond designerait l'item, pas l'entre-deux. */
.cs-sidebar__item.is-drop-before::before,
.cs-sidebar__item.is-drop-after::after {
  content: ""; position: absolute; left: 4px; right: 4px; height: 2px;
  background: var(--cs-accent); border-radius: 2px;
}
.cs-sidebar__item.is-drop-before::before { top: -1px; }
.cs-sidebar__item.is-drop-after::after { bottom: -1px; }
.cs-sidebar__group-title {
  font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--cs-muted); padding: 14px 8px 5px;
}
.cs-sidebar__link {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 8px; border-radius: var(--cs-radius-sm);
  color: var(--cs-text-2); font-size: 13.5px; text-decoration: none; cursor: pointer;
  transition: background .12s, color .12s;
}
.cs-sidebar__link:hover { background: var(--cs-surface-hover); color: var(--cs-text); }
/* AA (#CS-90) : couleur de TEXTE (13.5px) -> --cs-accent-text, pas --cs-accent. */
.cs-sidebar__link.is-active { background: var(--cs-accent-soft); color: var(--cs-accent-text); font-weight: 600; }
.cs-sidebar__link.is-disabled { color: var(--cs-muted); cursor: default; opacity: .55; }
.cs-sidebar__link.is-disabled:hover { background: transparent; color: var(--cs-muted); }
.cs-sidebar__icon { display: inline-flex; width: 18px; height: 18px; flex-shrink: 0; }
.cs-sidebar__icon svg { width: 18px; height: 18px; }
.cs-sidebar__label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; }

/* Sections repliables — le titre devient un bouton, sans changer d'allure : un
   titre de groupe qui ressemblerait a un bouton attirerait le clic au detriment
   des items eux-memes. */
.cs-sidebar__group-toggle {
  display: flex; align-items: center; gap: 6px; width: 100%;
  background: none; border: 0; cursor: pointer; text-align: left;
  font: inherit; font-size: 11px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--cs-muted);
  border-radius: var(--cs-radius-sm);
}
.cs-sidebar__group-toggle:hover { color: var(--cs-text-2); }
.cs-sidebar__caret {
  display: inline-flex; width: 12px; height: 12px; flex-shrink: 0;
  transform: rotate(90deg); transition: transform .15s ease;
}
.cs-sidebar__caret.is-shut { transform: rotate(0deg); }
.cs-sidebar__caret svg { width: 12px; height: 12px; }

/* Pastille de compteur sur un item (issues ouvertes, agents actifs...). */
.cs-sidebar__badge {
  flex-shrink: 0; min-width: 20px; padding: 1px 6px; border-radius: 999px;
  background: var(--cs-sunken); color: var(--cs-text-2);
  font-size: 10.5px; font-weight: 600; text-align: center;
}
.cs-sidebar__link.is-active .cs-sidebar__badge {
  background: var(--cs-accent-solid); color: #fff;
}
/* Compteur d'ALERTE : le meme emplacement, une autre urgence. Un compteur
   ordinaire informe (« 12 issues ») ; celui-ci appelle une action (« 3 tickets
   en attente »). `support-hub-admin` le rendait deja sous le nom `is-alert`,
   sans que le kit le connaisse. */
.cs-sidebar__badge.is-alert {
  background: var(--cs-danger-bg); color: var(--cs-danger-text);
}
.cs-sidebar__link.is-active .cs-sidebar__badge.is-alert {
  /* Blanc sur `--cs-danger` BRUT : 3.91:1 en clair, 3.08:1 en sombre — c'est du
     texte a 10.5px, seuil 4.5:1. Meme correctif que #2140 (6.16 / 5.00). */
  background: color-mix(in srgb, var(--cs-danger) 76%, #000); color: #fff;
}

/* Item DESACTIVE en variante « hors perimetre » : le kit Preact le rendait en
   `<span>` avec un `title`, mais rien ne le distinguait a l'oeil d'un lien
   simplement grise. Le curseur et l'opacite le disent maintenant. */
.cs-sidebar__link.is-disabled { cursor: default; }

.cs-sidebar__footer {
  margin-top: auto; padding-top: 10px;
  border-top: 1px solid var(--cs-border);
}

/* Rail : la barre repliee a la largeur d'une icone. Les titres de groupe
   disparaissent — un intitule tronque a 48 px ne renseigne rien — et le
   libelle passe en `title` natif. */
.cs-sidebar--rail { width: 60px; padding: 14px 8px; }
.cs-sidebar--rail .cs-sidebar__brand { justify-content: center; padding: 4px 0 14px; }
.cs-sidebar--rail .cs-sidebar__link { justify-content: center; padding: 9px 0; }
.cs-sidebar--rail .cs-sidebar__group + .cs-sidebar__group { margin-top: 10px; }

/* ---- Badge ---- */
.cs-badge {
  display: inline-flex; align-items: center; padding: 2px 9px;
  border-radius: 999px; font-size: 11.5px; font-weight: 500; line-height: 1.5;
}
/* AA (#CS-90) : le libelle du badge (11.5px) est du texte, pas une pastille
   pleine — les variantes -text s'appliquent, le fond garde le token vif en
   tinte (color-mix), lu au seuil 3:1 des elements non-textuels. */
.cs-badge--info { background: var(--cs-accent-soft); color: var(--cs-accent-text); }
.cs-badge--success { background: color-mix(in srgb, var(--cs-success) 16%, transparent); color: var(--cs-success-text); }
.cs-badge--warning { background: color-mix(in srgb, var(--cs-warning) 18%, transparent); color: var(--cs-warning-text); }
.cs-badge--danger { background: color-mix(in srgb, var(--cs-danger) 16%, transparent); color: var(--cs-danger-text); }
.cs-badge--neutral { background: var(--cs-surface-2); color: var(--cs-text-2); }

/* ---- DataTable ---- */
.cs-table {
  display: block;
  overflow: hidden;
  font-family: var(--cs-font);
}
.cs-table__head {
  display: grid;
  grid-template-columns: var(--cs-table-cols, 1fr);
  border-bottom: 1px solid var(--cs-border);
}
.cs-table__th {
  padding: 9px 12px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--cs-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cs-table__th--right { text-align: right; }
.cs-table__th--center { text-align: center; }
.cs-table__body { display: block; }
.cs-table__row {
  display: grid;
  grid-template-columns: var(--cs-table-cols, 1fr);
  border-bottom: 1px solid var(--cs-border);
  text-decoration: none;
  color: inherit;
  transition: background .12s;
}
.cs-table__row:last-child { border-bottom: none; }
/* Survol doux sur TOUTE ligne (aide au balayage), pointeur seulement si cliquable. */
.cs-table__row:hover { background: color-mix(in srgb, var(--cs-text) 3%, transparent); }
.cs-table__row--click { cursor: pointer; }
.cs-table__row--click:hover { background: var(--cs-surface-hover); }
/* Teinte de survol sans cursor:pointer — ligne inerte portant un lien dans une cellule (#2106). */
.cs-table__row--hoverable:hover { background: var(--cs-surface-hover); }
.cs-table__td {
  display: flex;
  align-items: center;
  padding: 11px 12px;
  min-width: 0;
  overflow: hidden;
  font-size: 13px;
  color: var(--cs-text);
}
.cs-table__td--right { justify-content: flex-end; }
.cs-table__td--center { justify-content: center; }
/* Modifier "flush" : le tableau s'aligne au bord du contenu de page (full-flat) —
   la 1re/derniere colonne perdent leur gouttiere laterale. */
.cs-table--flush .cs-table__th:first-child,
.cs-table--flush .cs-table__td:first-child { padding-left: 0; }
.cs-table--flush .cs-table__th:last-child,
.cs-table--flush .cs-table__td:last-child { padding-right: 0; }

/* ---- AgentRow ---- */
.cs-agent-row {
  display: flex; align-items: center; gap: 10px; padding: 8px 6px;
  border-radius: var(--cs-radius-sm); font-family: var(--cs-font);
}
.cs-agent-row--click { cursor: pointer; }
.cs-agent-row--click:hover { background: var(--cs-surface-2); }
.cs-agent-row__avatar {
  width: 28px; height: 28px; border-radius: 7px; flex-shrink: 0;
  background: var(--cs-accent-solid); color: #fff; font-size: 10px; font-weight: 600;
  display: flex; align-items: center; justify-content: center;
}
.cs-agent-row__body { flex: 1; min-width: 0; }
.cs-agent-row__name { font-size: 12.5px; font-weight: 600; color: var(--cs-text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cs-agent-row__meta { font-size: 11px; color: var(--cs-muted); }
.cs-agent-row__dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }

/* ---- AgentsPanel ---- */
.cs-agents-panel {
  display: flex; flex-direction: column;
  font-family: var(--cs-font);
}
.cs-agents-panel__header {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px 6px;
}
.cs-agents-panel__title {
  flex: 1; font-size: 12px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--cs-text);
}
.cs-agents-panel__controls { display: flex; gap: 4px; }
.cs-agents-panel__ctrl-btn {
  background: none; border: 1px solid var(--cs-border); border-radius: 5px;
  color: var(--cs-text-2); font-size: 11px; padding: 3px 8px;
  cursor: pointer; transition: background .12s, color .12s;
}
.cs-agents-panel__ctrl-btn:hover { background: var(--cs-border); color: var(--cs-text); }
.cs-agents-panel__section { margin-top: 8px; }
.cs-agents-panel__section:first-child { margin-top: 0; }
.cs-agents-panel__section-hd {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 12px 2px;
}
.cs-agents-panel__section-title {
  flex: 1; font-size: 10px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--cs-muted);
}
.cs-agents-panel__section-count {
  font-size: 10px; font-weight: 600; color: var(--cs-muted);
}
.cs-agents-panel__section-x {
  background: none; border: none; cursor: pointer; color: var(--cs-muted);
  font-size: 13px; line-height: 1; padding: 1px 4px; border-radius: 3px;
  opacity: .5; transition: opacity .12s;
}
.cs-agents-panel__section-x:hover { opacity: 1; }
/* Groupe survole pendant un glisser : la cible du depot doit etre evidente
   AVANT de lacher, sinon on depose au juge. */
.cs-agents-panel__section--over {
  background: color-mix(in srgb, var(--cs-accent) 7%, transparent);
  outline: 1px dashed var(--cs-accent);
  outline-offset: -2px; border-radius: 8px;
}
.cs-agents-panel__section-empty {
  margin: 0; padding: 6px 12px 8px; font-size: 11.5px;
  font-style: italic; color: var(--cs-muted);
}
/* ---- Creation de groupe (pied du panneau) ---- */
.cs-agents-panel__addsec { padding: 10px 12px 4px; }
.cs-agents-panel__addsec-form { display: flex; align-items: center; gap: 5px; }
.cs-agents-panel__addsec-input {
  flex: 1; min-width: 0; padding: 4px 7px;
  background: var(--cs-surface); color: var(--cs-text);
  border: 1px solid var(--cs-border-strong); border-radius: 5px;
  font-family: inherit; font-size: 11.5px; outline: none;
}
.cs-agents-panel__addsec-input:focus { border-color: var(--cs-accent); }
.cs-agents-panel__addsec-err {
  margin: 5px 0 0; font-size: 11px; color: var(--cs-danger-text);
}
/* ---- Menu ⋯ d'une ligne — chemin sans souris vers le deplacement ---- */
.cs-agents-panel__menu-anchor { position: relative; flex-shrink: 0; }
.cs-agents-panel__menu-scrim { position: fixed; inset: 0; z-index: 40; }
.cs-agents-panel__menu {
  position: absolute; top: calc(100% + 4px); right: 0; z-index: 50; min-width: 170px;
  padding: 5px; display: flex; flex-direction: column;
  background: var(--cs-surface); border: 1px solid var(--cs-border);
  border-radius: 10px; box-shadow: var(--cs-shadow-lg);
}
.cs-agents-panel__menu-label {
  padding: 5px 9px 4px; font-size: 10px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--cs-muted);
}
.cs-agents-panel__menu-item {
  appearance: none; background: none; border: 0; text-align: left; cursor: pointer;
  padding: 7px 9px; border-radius: 7px; font-family: inherit; font-size: 12.5px;
  color: var(--cs-text);
}
.cs-agents-panel__menu-item:hover { background: var(--cs-surface-hover); }
.cs-agents-panel__menu-empty {
  padding: 6px 9px; font-size: 11.5px; font-style: italic; color: var(--cs-muted);
}
.cs-agents-panel__row {
  display: flex; flex-direction: column; gap: 5px;
  padding: 7px 12px; cursor: pointer; transition: background .12s;
  border-radius: 6px;
}
.cs-agents-panel__row:hover { background: color-mix(in srgb, var(--cs-muted) 6%, transparent); }
.cs-agents-panel__row--active { background: var(--cs-accent-soft); }
.cs-agents-panel__row--active:hover { background: var(--cs-accent-soft); }
.cs-agents-panel__row-1 { display: flex; align-items: center; gap: 8px; min-width: 0; }
.cs-agents-panel__avatar {
  width: 26px; height: 26px; border-radius: 7px; flex-shrink: 0;
  color: #fff; font-size: 9px; font-weight: 700; letter-spacing: .02em;
  display: flex; align-items: center; justify-content: center;
  background: var(--cs-accent-solid);
}
.cs-agents-panel__avatar--c0 { background: linear-gradient(135deg,#3b82f6,#1d4ed8); }
.cs-agents-panel__avatar--c1 { background: linear-gradient(135deg,#8b5cf6,#6d28d9); }
.cs-agents-panel__avatar--c2 { background: linear-gradient(135deg,#10b981,#047857); }
.cs-agents-panel__avatar--c3 { background: linear-gradient(135deg,#f59e0b,#b45309); }
.cs-agents-panel__avatar--c4 { background: linear-gradient(135deg,#ef4444,#b91c1c); }
.cs-agents-panel__avatar--c5 { background: linear-gradient(135deg,#ec4899,#be185d); }
.cs-agents-panel__avatar--c6 { background: linear-gradient(135deg,#14b8a6,#0f766e); }
.cs-agents-panel__avatar--c7 { background: linear-gradient(135deg,#6366f1,#4338ca); }
.cs-agents-panel__name {
  flex: 1; min-width: 0; font-size: 12.5px; font-weight: 600; color: var(--cs-text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cs-agents-panel__drag {
  flex-shrink: 0; color: var(--cs-muted); opacity: .4; font-size: 10px;
  letter-spacing: -2px; cursor: grab; user-select: none;
}
/* La poignee est un INDICE visuel, pas le point de prehension : la ligne
   entiere se tire (cible plus large sur une liste dense). Le champ de note
   reste selectionnable — le composant annule le drag parti de lui, decision
   prise au mousedown. */
.cs-agents-panel__drag:hover { opacity: 1; color: var(--cs-text-2); }
.cs-agents-panel__drag:active { cursor: grabbing; }
/* La ligne tiree reste a sa place, estompee — le vide se creerait a l'arrivee,
   pas au depart, et ferait sauter la liste sous le curseur. */
.cs-agents-panel__row--dragging { opacity: .45; }
.cs-agents-panel__more {
  flex-shrink: 0; background: none; border: none; cursor: pointer;
  color: var(--cs-muted); font-size: 16px; padding: 1px 4px;
  border-radius: 4px; line-height: 1; opacity: .65;
  transition: background .12s, opacity .12s;
}
.cs-agents-panel__more:hover { opacity: 1; background: color-mix(in srgb, var(--cs-muted) 14%, transparent); }
.cs-agents-panel__dot {
  width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0;
}
.cs-agents-panel__dot--running { background: var(--cs-success); }
.cs-agents-panel__dot--idle { background: var(--cs-muted); opacity: .5; }
.cs-agents-panel__dot--starting { background: var(--cs-accent); }
/* Pas de `max-width` ici : le libelle doit rester lisible en entier, tronque
   il ne dirait plus quoi faire. */
/* AA (#CS-90) : le libelle ("A reconfigurer"...) est du texte -> --cs-warning-text.
   La bordure reste --cs-warning (seuil 3:1, deja conforme). */
.cs-agents-panel__reconf {
  flex-shrink: 0; padding: 2px 5px;
  border: 1px solid var(--cs-warning); border-radius: var(--cs-radius-xs, 4px);
  background: var(--cs-warning-bg); color: var(--cs-warning-text); font-size: 10px;
  font-weight: 700; line-height: 1.2; white-space: nowrap;
}
/* Ligne de travail d'un agent permanent — cle d'issue, bouton workspace,
   branche. Meme composition que `.dc-ephgrp__head`. */
.cs-agents-panel__work {
  display: flex; align-items: center; gap: 6px; min-width: 0; margin-bottom: 2px;
}
/* AA (#CS-90) : la cle d'issue affichee (ex. "CS-90") est du texte -> --cs-accent-text. */
.cs-agents-panel__work-key {
  font-size: 11px; font-weight: 600; color: var(--cs-accent-text);
  min-width: 0; flex-shrink: 1;
  text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  background: none; border: 0; padding: 0; font-family: inherit; cursor: pointer; text-align: left;
}
.cs-agents-panel__work-key:hover { text-decoration: underline; }
.cs-agents-panel__work-ws {
  flex-shrink: 0; background: none; border: 0;
  width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;
  font-size: 13px; line-height: 1; color: var(--cs-muted);
  cursor: pointer; font-family: inherit;
}
.cs-agents-panel__work-ws:hover { color: var(--cs-accent); }
.cs-agents-panel__work-ws:focus-visible, .cs-agents-panel__work-key:focus-visible {
  outline: 2px solid var(--cs-accent); outline-offset: 2px;
  border-radius: var(--cs-radius-xs);
}
.cs-agents-panel__work-branch {
  flex-shrink: 1; min-width: 0; font-size: 11px; color: var(--cs-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cs-agents-panel__row-2 {
  display: flex; flex-direction: column; gap: 2px; min-width: 0;
}
.cs-agents-panel__note-row {
  display: flex; align-items: center; gap: 5px; min-width: 0; overflow: hidden;
}
.cs-agents-panel__note-pencil {
  flex-shrink: 0; color: var(--cs-muted); opacity: 0; transition: opacity .12s;
}
.cs-agents-panel__row:hover .cs-agents-panel__note-pencil { opacity: .6; }
.cs-agents-panel__note-row:has(.cs-agents-panel__note:focus) .cs-agents-panel__note-pencil { opacity: 0; }
.cs-agents-panel__note {
  flex: 1; min-width: 0; background: none; border: none;
  border-bottom: 1px solid transparent; outline: none; padding: 0; margin: 0;
  font-size: 11.5px; color: var(--cs-text-2); font-family: inherit;
  cursor: pointer; transition: border-color .15s;
}
.cs-agents-panel__note:focus { border-bottom-color: var(--cs-accent); cursor: text; }
.cs-agents-panel__note::placeholder { color: var(--cs-muted); font-style: italic; }
.cs-agents-panel__meta {
  font-size: 10px; color: var(--cs-muted);
  font-family: var(--cs-mono);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  padding-left: 15px; /* aligne sous le crayon + note */
}

/* ---- Button — systeme hybride "plein + contour" ----
   Combine les deux langages retenus :
     - PLEIN (solide) pour les actions a forte emphase : primary (accent) et
       danger-solid (confirmation destructive).
     - CONTOUR (outline, bordure 1px) pour les actions secondaires : secondary,
       neutral, danger.  ghost = texte seul.
   Modificateur `--solid` : passe secondary/neutral/danger en PLEIN a la demande
   (ex. une barre d'action a forte densite) -> le DS porte les 2 styles.
   Taille md par defaut sur .cs-btn -> un bare `cs-btn` est deja utilisable. */
.cs-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  font-family: var(--cs-font); font-weight: 500;
  border: 1px solid transparent; border-radius: var(--cs-radius-sm);
  cursor: pointer; transition: background .12s, color .12s, border-color .12s, box-shadow .12s;
  white-space: nowrap; line-height: 1;
  font-size: 13.5px; padding: 0 15px;
  /* Hauteur prise sur l'ECHELLE, pas deduite du padding : c'est ce qui fait
     qu'un bouton et un champ voisins s'alignent. `min-height` et non
     `height` — un bouton a contenu haut doit pouvoir grandir. */
  min-height: var(--cs-control-h);
}
/* Echelle de tailles — la hauteur vient des tokens, le padding ne regle plus
   que la respiration HORIZONTALE. */
.cs-btn--xs  { font-size: 12px;   padding: 0 10px; gap: 4px; min-height: var(--cs-control-h-xs); }
.cs-btn--sm  { font-size: 12.5px; padding: 0 12px; min-height: var(--cs-control-h-sm); }
.cs-btn--md  { font-size: 13.5px; padding: 0 15px; min-height: var(--cs-control-h); }
.cs-btn--lg  { font-size: 14.5px; padding: 0 20px; min-height: var(--cs-control-h-lg); }
.cs-btn--xl  { font-size: 15.5px; padding: 0 26px; min-height: var(--cs-control-h-xl); }
/* -- Plein -- */
.cs-btn--primary { background: var(--cs-accent-solid); color: #fff; border-color: var(--cs-accent-solid); box-shadow: var(--cs-shadow-sm); }
.cs-btn--primary:hover { background: var(--cs-accent-solid-hover); border-color: var(--cs-accent-solid-hover); box-shadow: var(--cs-shadow-md); }
/* Le blanc sur `--cs-danger` brut donne 3.91:1 en clair et 3.08:1 en sombre :
   c'est le theme SOMBRE le plus en faute. Assombrir le fond a 76% corrige les
   deux (6.16:1 / 5.00:1) sans descendre sous 3:1 face a la surface — en dessous
   de 70%, le bouton commence a se fondre dans le fond sombre. */
.cs-btn--danger-solid { background: color-mix(in srgb, var(--cs-danger) 76%, #000); color: #fff; border-color: color-mix(in srgb, var(--cs-danger) 76%, #000); box-shadow: var(--cs-shadow-sm); }
/* Le survol doit ASSOMBRIR : a 88% il eclaircissait le repos a 76%. */
.cs-btn--danger-solid:hover { background: color-mix(in srgb, var(--cs-danger) 70%, #000); border-color: color-mix(in srgb, var(--cs-danger) 70%, #000); }
/* -- Contour -- */
.cs-btn--secondary { background: transparent; color: var(--cs-text); border-color: var(--cs-border); }
.cs-btn--secondary:hover { background: var(--cs-surface-2); border-color: var(--cs-text-2); }
.cs-btn--neutral { background: transparent; color: var(--cs-text-2); border-color: var(--cs-border); }
.cs-btn--neutral:hover { background: var(--cs-surface-2); color: var(--cs-text); }
/* AA (#2140) — `--cs-danger` en texte donne 3.91:1 sur surface claire, sous le
   seuil 4.5:1. `--cs-danger-text` (#2105) existe pour ce cas : 5.95:1 en clair,
   5.81:1 en sombre. La bordure a 55% tombait a 2.13:1, sous le seuil 3:1 des
   indicateurs non textuels ; a 70% de --cs-danger-text elle atteint 3.57:1. */
.cs-btn--danger  { background: transparent; color: var(--cs-danger-text); border-color: color-mix(in srgb, var(--cs-danger-text) 70%, transparent); }
/* Le survol teinte le fond : le libelle doit rester lisible DESSUS (5.24:1 en
   clair, 5.12:1 en sombre) — c'etait 3.44:1 avec l'ancienne couleur de texte. */
.cs-btn--danger:hover { background: color-mix(in srgb, var(--cs-danger) 10%, transparent); border-color: var(--cs-danger-text); }
/* -- Texte seul -- */
.cs-btn--ghost   { background: transparent; color: var(--cs-text-2); border-color: transparent; }
.cs-btn--ghost:hover { background: var(--cs-surface-hover); color: var(--cs-text); }
/* -- Modificateur PLEIN (style solide) sur les variantes contour -- */
.cs-btn--solid.cs-btn--secondary { background: var(--cs-surface-2); color: var(--cs-text); border-color: transparent; }
.cs-btn--solid.cs-btn--secondary:hover { background: color-mix(in srgb, var(--cs-text) 12%, var(--cs-surface-2)); }
.cs-btn--solid.cs-btn--neutral { background: var(--cs-surface-2); color: var(--cs-text-2); border-color: transparent; }
.cs-btn--solid.cs-btn--neutral:hover { background: color-mix(in srgb, var(--cs-text) 12%, var(--cs-surface-2)); color: var(--cs-text); }
/* Meme fond que --danger-solid, et pour la meme raison (#2140) : le blanc sur
   `--cs-danger` brut echoue AA. Sa specificite (0,2,0) l'emporte sur
   `.cs-btn--danger` (0,1,0) — le laisser tel quel rendait le correctif
   contournable par un simple `cs-btn--danger cs-btn--solid`. */
.cs-btn--solid.cs-btn--danger { background: color-mix(in srgb, var(--cs-danger) 76%, #000); color: #fff; border-color: transparent; }
.cs-btn--solid.cs-btn--danger:hover { background: color-mix(in srgb, var(--cs-danger) 70%, #000); }
.cs-btn--disabled, .cs-btn:disabled { opacity: .45; cursor: default; pointer-events: none; }
.cs-btn__icon { display: inline-flex; width: 14px; height: 14px; }
.cs-btn__icon svg { width: 14px; height: 14px; }

/* ---- Icon button — action carree sans libelle (kebab, refresh, close) ---- */
.cs-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--cs-control-h); height: var(--cs-control-h);
  border: 0; border-radius: var(--cs-radius-sm);
  background: transparent; color: var(--cs-text-2); cursor: pointer;
  transition: background .12s, color .12s;
}
.cs-icon-btn:hover { background: var(--cs-surface-hover); color: var(--cs-text); }
.cs-icon-btn--sm { width: var(--cs-control-h-sm); height: var(--cs-control-h-sm); }
.cs-icon-btn svg { width: 17px; height: 17px; }

/* ---- Card — vraie boite (#1996) ----
   Etait un simple border-bottom sans surface ni ombre : les cartes ne se
   distinguaient pas du fond. Elles redeviennent des objets poses sur la page. */
.cs-card {
  background: var(--cs-surface);
  border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius-lg);
  box-shadow: var(--cs-shadow-sm);
  overflow: hidden;
  font-family: var(--cs-font);
}
.cs-card--hover { cursor: pointer; transition: box-shadow .16s, border-color .16s, transform .16s; }
/* Au survol la carte monte d'un cran : le retour est spatial, pas juste colore. */
.cs-card--hover:hover {
  box-shadow: var(--cs-shadow-md);
  border-color: var(--cs-border-strong);
  transform: translateY(-1px);
}
/* Modificateur "flat" : rendu d'origine, pour les listes denses ou l'empilement
   de boites nuirait a la lecture (suites de lignes, tableaux imbriques). */
.cs-card--flat {
  background: transparent; border: 0; border-bottom: 1px solid var(--cs-border);
  border-radius: 0; box-shadow: none;
}
/* Le header n'a pas de padding bas : il compte sur le body ou le footer qui
   suit. Une carte reduite a son header — titre + sous-titre, sans corps ni
   pied, ce qui est le cas d'une carte de liste — collait donc au bord.
   `:last-child` le rattrape sans toucher au cas nominal. */
.cs-card__header {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px 16px 0;
}
.cs-card__header:last-child { padding-bottom: 14px; }
/* Header suivi DIRECTEMENT d'un footer, sans corps entre les deux : le trait
   du footer viendrait se coller au sous-titre. */
.cs-card__header + .cs-card__footer { margin-top: 12px; }
.cs-card__header-left { flex: 1; min-width: 0; }
.cs-card__title { font-size: 14px; font-weight: 600; color: var(--cs-text); }
.cs-card__subtitle { font-size: 12px; color: var(--cs-text-2); margin-top: 2px; }
.cs-card__actions { flex-shrink: 0; }
.cs-card__body { padding: 12px 16px; }
.cs-card__footer {
  padding: 8px 16px; border-top: 1px solid var(--cs-border);
  font-size: 12px; color: var(--cs-text-2);
}

/* ---- PageHeader ---- */
.cs-page-header {
  padding: 20px 0 16px;
  font-family: var(--cs-font);
}
.cs-page-header__breadcrumb {
  display: flex; align-items: center; gap: 4px;
  font-size: 12px; color: var(--cs-muted); margin-bottom: 8px;
}
/* Le separateur prenait `--cs-border` : un token de TRAIT, quasi invisible en
   texte (#ececee sur blanc). Il structure la lecture du fil, il doit se voir —
   `--cs-muted` le pose au meme niveau que le fil lui-meme, sans concurrencer
   les segments qui, eux, sont cliquables. */
.cs-page-header__bc-sep { color: var(--cs-muted); }
.cs-page-header__bc-link {
  color: var(--cs-text-2); text-decoration: none; transition: color .12s;
}
/* AA (#CS-90) : couleur de TEXTE (12px) -> --cs-accent-text. */
.cs-page-header__bc-link:hover { color: var(--cs-accent-text); }
.cs-page-header__bc-cur { color: var(--cs-text-2); }
.cs-page-header__row {
  display: flex; align-items: flex-start; gap: 12px;
}
.cs-page-header__left { flex: 1; min-width: 0; }
.cs-page-header__title-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cs-page-header__title { margin: 0; font-size: 22px; font-weight: 700; color: var(--cs-text); }
.cs-page-header__subtitle { margin: 4px 0 0; font-size: 13px; color: var(--cs-text-2); }
.cs-page-header__actions { flex-shrink: 0; display: flex; gap: 8px; align-items: center; }

/* ---- Tabs ---- */
.cs-tabs {
  display: flex; gap: 0; border-bottom: 1px solid var(--cs-border);
  font-family: var(--cs-font);
  /* Une barre a huit onglets doit defiler plutot que passer a la ligne : des
     onglets sur deux rangs ne se lisent plus comme une barre. */
  overflow-x: auto; scrollbar-width: none;
}
.cs-tabs::-webkit-scrollbar { display: none; }
.cs-tabs--sm .cs-tab { padding: 6px 11px; font-size: 12.5px; }
.cs-tabs__panel { padding: 16px 0; }
.cs-tabs__panel:focus-visible { outline: 2px solid var(--cs-accent); outline-offset: 2px; }
.cs-tab__icon { display: inline-flex; width: 15px; height: 15px; }
.cs-tab__icon svg { width: 15px; height: 15px; }
.cs-tab--disabled { color: var(--cs-muted); cursor: not-allowed; }
.cs-tab--disabled:hover { color: var(--cs-muted); border-bottom-color: transparent; }
.cs-tab:focus-visible {
  outline: none; color: var(--cs-text);
  box-shadow: inset 0 0 0 2px var(--cs-accent-soft); border-radius: var(--cs-radius-xs);
}
.cs-tab {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 14px; font-size: 13.5px; font-weight: 500; color: var(--cs-text-2);
  background: none; border: none; border-bottom: 2px solid transparent;
  cursor: pointer; transition: color .12s, border-color .12s;
  margin-bottom: -1px; white-space: nowrap;
}
.cs-tab:hover { color: var(--cs-text); background: var(--cs-surface-2); border-radius: 6px 6px 0 0; }
/* AA (#CS-90) : `color` est du texte -> --cs-accent-text ; border-bottom-color
   reste --cs-accent, c'est une bordure (seuil 3:1, deja conforme). */
.cs-tab--active { color: var(--cs-accent-text); border-bottom-color: var(--cs-accent); font-weight: 600; }
.cs-tab__badge {
  background: var(--cs-accent-soft); color: var(--cs-accent-text);
  font-size: 11px; font-weight: 600; padding: 1px 6px; border-radius: 999px;
}

/* ---- StatCard ---- */
.cs-stat-card {
  padding: 16px 16px 14px;
  display: flex; gap: 12px; align-items: flex-start;
  font-family: var(--cs-font);
  background: var(--cs-surface);
  border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius-lg);
  box-shadow: var(--cs-shadow-sm);
}
/* Variante d'origine : bandeau segmente par un filet, sans boite (#1996). */
.cs-stat-card--flat {
  background: transparent; border: 0; border-radius: 0; box-shadow: none;
  border-right: 1px solid var(--cs-border);
}
.cs-stat-card--flat:last-child { border-right: none; }
.cs-stat-card__icon {
  width: 36px; height: 36px; border-radius: var(--cs-radius); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
}
.cs-stat-card__icon svg { width: 18px; height: 18px; }
.cs-stat-card__body { flex: 1; min-width: 0; }
.cs-stat-card__value { font-size: 26px; font-weight: 700; line-height: 1; }
.cs-stat-card__label { font-size: 12px; color: var(--cs-text-2); margin-top: 4px; }
.cs-stat-card__delta { font-size: 11.5px; color: var(--cs-muted); margin-top: 3px; }

/* ---- StatLine — bandeau de stats plat (full-flat, sans boite) ----
   Items alignes sur une ligne, separes par un filet vertical. Chaque item =
   valeur (grosse, coloree par tone) + label. Alternative flat aux StatCards. */
.cs-statline {
  display: flex; align-items: center; flex-wrap: wrap;
  font-family: var(--cs-font);
}
.cs-statline__item {
  display: inline-flex; align-items: baseline; gap: 7px;
  padding: 2px 20px; border-left: 1px solid var(--cs-border);
}
.cs-statline__item:first-child { padding-left: 0; border-left: 0; }
.cs-statline__value { font-size: 21px; font-weight: 700; line-height: 1; color: var(--cs-text); }
/* AA (#CS-90) : la valeur est du texte lu, pas une pastille — les variantes
   -text s'imposent memes ici ou --cs-success/-danger/accent passeraient de
   justesse le seuil 3:1 des gros textes : --cs-warning brut echoue meme ce
   seuil relache (2.25:1 sur --cs-surface). */
.cs-statline__value--success { color: var(--cs-success-text); }
.cs-statline__value--warning { color: var(--cs-warning-text); }
.cs-statline__value--danger  { color: var(--cs-danger-text); }
.cs-statline__value--accent  { color: var(--cs-accent-text); }
.cs-statline__label { font-size: 12.5px; color: var(--cs-text-2); }

/* ---- EmptyState ---- */
.cs-empty {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 40px 24px; text-align: center;
  font-family: var(--cs-font);
}
.cs-empty__icon { font-size: 32px; color: var(--cs-muted); opacity: .6; }
/* L'etat vide remplace une donnee ATTENDUE (la source a echoue) et non une
   absence legitime : seule l'icone vire au danger, le texte reste neutre —
   un bloc entierement rouge se lit comme une erreur de l'utilisateur. */
.cs-empty__icon.is-error { color: var(--cs-danger); opacity: 1; }
.cs-empty__title { font-size: 14px; font-weight: 600; color: var(--cs-text); }
.cs-empty__text { font-size: 13px; color: var(--cs-text-2); max-width: 340px; }

/* ---- ProfileMenu ---- */
/* Implementation : <details>/<summary> natif — zero hook Preact, compatible cross-slug. */
.cs-profile-menu {
  position: relative;
  font-family: var(--cs-font);
}
/* Supprime le marqueur natif du <summary> */
.cs-profile-menu__btn { list-style: none; }
.cs-profile-menu__btn::-webkit-details-marker { display: none; }
.cs-profile-menu__btn::marker { display: none; }
.cs-profile-menu__btn {
  display: flex; align-items: center; gap: 7px;
  background: none; border: none; cursor: pointer;
  padding: 3px 6px 3px 3px; border-radius: var(--cs-radius-sm);
  transition: background .12s; color: var(--cs-text);
}
.cs-profile-menu__btn:hover { background: var(--cs-surface-hover); }
.cs-profile-menu__avatar {
  width: 28px; height: 28px; border-radius: var(--cs-radius-sm);
  /* Avatar d'identite : suit l'accent. A distinguer de la palette categorielle
     .cs-agents-panel__avatar--cN, qui doit rester multi-teintes (#1996). */
  background: var(--cs-accent-grad);
  color: #fff; font-size: 10px; font-weight: 700; letter-spacing: .03em;
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.cs-profile-menu__name {
  font-size: 13px; font-weight: 600; color: var(--cs-text);
  white-space: nowrap; max-width: 130px; overflow: hidden; text-overflow: ellipsis;
}
.cs-profile-menu__chevron {
  display: flex; align-items: center; color: var(--cs-muted); flex-shrink: 0;
  transition: transform .15s;
}
/* Variante COMPACTE : l'avatar seul, sans nom ni chevron. Le cockpit
   l'obtenait en masquant `__name` et `__chevron` depuis sa media query — donc
   en atteignant les classes INTERNES du composant, ce qui se casse au premier
   renommage. La variante rend l'intention explicite et le repli automatique
   sous un shell etroit, ou le nom mange la largeur des actions. */
.cs-profile-menu--compact .cs-profile-menu__name,
.cs-profile-menu--compact .cs-profile-menu__chevron { display: none; }
.cs-profile-menu--compact .cs-profile-menu__btn { padding: 3px; }
@container cs-shell (max-width: 860px) {
  .cs-shell .cs-profile-menu__name,
  .cs-shell .cs-profile-menu__chevron { display: none; }
  .cs-shell .cs-profile-menu__btn { padding: 3px; }
}
details.cs-profile-menu[open] .cs-profile-menu__chevron { transform: rotate(180deg); }
.cs-profile-menu__panel {
  display: none;
  position: absolute; right: 0; top: calc(100% + 6px);
  min-width: 200px;
  background: var(--cs-surface); border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius-lg);
  box-shadow: var(--cs-shadow-lg);
  z-index: 120; overflow: hidden;
}
details.cs-profile-menu[open] .cs-profile-menu__panel { display: block; }
.cs-profile-menu__hd {
  padding: 10px 14px 9px; border-bottom: 1px solid var(--cs-border);
}
.cs-profile-menu__hd-name { font-size: 13px; font-weight: 600; color: var(--cs-text); }
.cs-profile-menu__hd-email { font-size: 11.5px; color: var(--cs-muted); margin-top: 2px; }
.cs-profile-menu__list { padding: 4px; }
.cs-profile-menu__item {
  display: flex; align-items: center; gap: 8px;
  width: 100%; padding: 7px 10px; border-radius: var(--cs-radius-sm);
  font-size: 13px; font-family: var(--cs-font);
  color: var(--cs-text); background: none; border: none; cursor: pointer;
  text-align: left; text-decoration: none; transition: background .1s;
}
.cs-profile-menu__item:hover { background: var(--cs-surface-hover); }
/* AA (#CS-90) : le libelle est du texte -> --cs-danger-text. L'icone SVG
   qui suit reste --cs-danger (element graphique, seuil 3:1, 3.91:1 conforme). */
.cs-profile-menu__item--danger { color: var(--cs-danger-text); }
.cs-profile-menu__item--danger:hover {
  background: color-mix(in srgb, var(--cs-danger) 10%, transparent);
}
.cs-profile-menu__item-icon {
  display: inline-flex; width: 15px; height: 15px; flex-shrink: 0; color: var(--cs-muted);
}
.cs-profile-menu__item--danger .cs-profile-menu__item-icon { color: var(--cs-danger); }
.cs-profile-menu__item-icon svg { width: 15px; height: 15px; }
.cs-profile-menu__divider { height: 1px; background: var(--cs-border); margin: 3px 4px; }

/* ---- Select (single + multiple) ---- */
.cs-ms {
  position: relative;
  font-family: var(--cs-font);
}
.cs-ms-trigger {
  display: flex; align-items: center; gap: 6px;
  background: var(--cs-surface); border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius-sm); padding: 5px 8px; min-height: 34px;
  cursor: pointer; user-select: none; min-width: 160px; max-width: 460px;
  transition: border-color .12s;
}
.cs-ms-trigger:hover { border-color: var(--cs-accent); }
.cs-ms-trigger--open { border-color: var(--cs-accent); }

.cs-ms-chips { flex: 1; display: flex; flex-wrap: wrap; gap: 5px; align-items: center; min-width: 0; }
.cs-ms-placeholder { font-size: 13px; color: var(--cs-muted); white-space: nowrap; }

/* Mode multiple — chips */
.cs-ms-chip {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--cs-surface-2); border: 1px solid var(--cs-border);
  border-radius: 999px; padding: 1px 5px 1px 6px; font-size: 12px; color: var(--cs-text); line-height: 1.5;
  white-space: nowrap; max-width: 180px;
}
.cs-ms-chip__dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.cs-ms-chip__remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; border-radius: 50%; cursor: pointer;
  color: var(--cs-muted); font-size: 13px; line-height: 1; flex-shrink: 0;
}
.cs-ms-chip__remove:hover { background: var(--cs-border); color: var(--cs-text); }

/* Mode single — valeur selectionnee */
.cs-ms-single-val {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 13px; color: var(--cs-text); white-space: nowrap;
}

.cs-ms-actions { display: flex; align-items: center; gap: 5px; flex-shrink: 0; }
.cs-ms-clear {
  font-size: 11.5px; color: var(--cs-muted); cursor: pointer; white-space: nowrap;
  padding: 1px 5px; border-radius: 3px; transition: color .1s, background .1s;
}
.cs-ms-clear:hover { color: var(--cs-text); background: var(--cs-surface-2); }
.cs-ms-chevron { color: var(--cs-muted); flex-shrink: 0; display: flex; transition: transform .15s; }
.cs-ms-trigger--open .cs-ms-chevron { transform: rotate(180deg); }

/* Overlay click-dehors — transparent, z-index sous le popover */
.cs-ms-overlay { position: fixed; inset: 0; z-index: 99; background: transparent; }

/* Popover */
.cs-ms-popover {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 100;
  background: var(--cs-surface); border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius); min-width: 220px;
  box-shadow: var(--cs-shadow-md); overflow: hidden;
}

/* Champ de recherche */
.cs-ms-search {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-bottom: 1px solid var(--cs-border);
}
.cs-ms-search__icon { display: flex; color: var(--cs-muted); flex-shrink: 0; }
.cs-ms-search__input {
  background: none; border: none; outline: none;
  font-size: 13px; color: var(--cs-text); flex: 1; min-width: 0;
  font-family: var(--cs-font);
}
.cs-ms-search__input::placeholder { color: var(--cs-muted); }

/* Options */
.cs-ms-options { max-height: 300px; overflow-y: auto; padding: 4px 0; }
.cs-ms-option {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 12px; cursor: pointer; font-size: 13px; color: var(--cs-text);
  transition: background .1s;
}
.cs-ms-option:hover { background: var(--cs-accent-soft); }
/* Option atteinte au CLAVIER. Meme fond que le survol : la fleche du bas et la
   souris designent la meme chose, les distinguer visuellement suggererait deux
   etats differents. Sans cette regle, naviguer au clavier ne montre RIEN. */
.cs-ms-option--focused { background: var(--cs-accent-soft); }
.cs-ms-option__check {
  width: 15px; height: 15px; border: 1.5px solid var(--cs-border);
  border-radius: 3px; flex-shrink: 0; display: flex; align-items: center; justify-content: center;
  transition: background .1s, border-color .1s;
}
.cs-ms-option--checked .cs-ms-option__check { background: var(--cs-accent); border-color: var(--cs-accent); }
.cs-ms-option__dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.cs-ms-option__label { flex: 1; }
.cs-ms-option__count { font-size: 11px; color: var(--cs-muted); min-width: 18px; text-align: right; }
.cs-ms-empty { padding: 10px 12px; font-size: 12px; color: var(--cs-muted); text-align: center; }

/* ---- DaemonPicker ---- */
.cs-daemon-picker { font-family: var(--cs-font); }
.cs-daemon-picker__label {
  display: block; font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .04em; color: var(--cs-muted); margin-bottom: 6px;
}
.cs-daemon-picker__list { display: flex; flex-direction: column; gap: 3px; }
.cs-daemon-picker__item {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-radius: var(--cs-radius-sm);
  background: transparent; border: 1px solid transparent;
  cursor: pointer; text-align: left; transition: background .12s, border-color .12s;
}
.cs-daemon-picker__item:hover { background: var(--cs-surface-2); border-color: var(--cs-border); }
.cs-daemon-picker__item--active {
  background: var(--cs-accent-soft); border-color: color-mix(in srgb, var(--cs-accent) 35%, transparent);
}
.cs-daemon-picker__dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.cs-daemon-picker__name { flex: 1; font-size: 12.5px; font-weight: 500; color: var(--cs-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cs-daemon-picker__meta { font-size: 11px; color: var(--cs-muted); }
.cs-daemon-picker__teams { font-size: 11px; color: var(--cs-text-2); }

/* ── Champs (cs-field / cs-input / cs-select / cs-textarea) ────────────────
   Le DS n'avait AUCUN style de champ generique : chaque composant qui en
   voulait un le redecrivait (`cs-agents-panel__addsec-input`,
   `cs-ms-search__input`).

   Le `<select>` natif est le point sensible : sans `appearance: none`, il
   garde le chrome du systeme — fleche grise, hauteur imposee, coins carres —
   et detonne a cote d'un `<input>` stylise. On le neutralise donc et on
   redessine la fleche en `background-image`, seule facon d'en poser une sur un
   `<select>` (il n'accepte pas de pseudo-element).

   La fleche est un SVG inline en data:, avec `--cs-text-2` FIGE : une couleur
   de fond ne suit pas `currentColor`, donc chaque theme redefinit l'image. */

.cs-field { display: block; margin-bottom: 14px; }
.cs-field__label {
  display: block; margin-bottom: 6px;
  font-size: 12px; font-weight: 500; color: var(--cs-text-2);
}
.cs-field__hint { display: block; margin-top: 6px; font-size: 11.5px; color: var(--cs-muted); }
/* AA (#CS-90) : message d'erreur = texte -> --cs-danger-text (deja le patron
   suivi par .cs-agents-panel__addsec-err, juste au-dessus dans ce fichier). */
.cs-field__error {
  display: block; margin-top: 6px; font-size: 11.5px; color: var(--cs-danger-text);
}
/* Une ligne de champs cote a cote — chacun garde sa largeur propre. */
.cs-field-row { display: flex; gap: 12px; }
.cs-field-row > .cs-field { flex: 1; min-width: 0; }

.cs-input,
.cs-select,
.cs-textarea {
  display: block; width: 100%;
  min-height: var(--cs-control-h); padding: 7px 11px;
  /* `line-height` cale pour que le contenu TIENNE dans la hauteur d'echelle :
     a 1.45 le texte mesurait 18.85px et poussait le champ a 34.85px, un
     pixel au-dessus du bouton voisin. Le `min-height` est un plancher, il ne
     rattrape pas un contenu trop haut — c'est l'interligne qui doit ceder. */
  font: inherit; font-size: 13px; line-height: 1.38;
  color: var(--cs-text);
  background: var(--cs-surface);
  border: 1px solid var(--cs-border-strong);
  border-radius: var(--cs-radius-sm);
  box-shadow: var(--cs-shadow-sm);
  transition: border-color .13s ease, box-shadow .13s ease, background .13s ease;
}
.cs-textarea { min-height: 72px; resize: vertical; }

.cs-input::placeholder,
.cs-textarea::placeholder { color: var(--cs-muted); }

.cs-input:hover:not([disabled]):not(:focus),
.cs-select:hover:not([disabled]):not(:focus),
.cs-textarea:hover:not([disabled]):not(:focus) {
  border-color: var(--cs-muted);
}

/* Le halo remplace l'outline : il epouse le rayon du champ, ce que l'outline
   ne fait pas sur tous les moteurs. La bordure change AUSSI de couleur — un
   halo seul disparait pour qui ne distingue pas l'accent du fond. */
.cs-input:focus,
.cs-select:focus,
.cs-textarea:focus {
  outline: none;
  border-color: var(--cs-accent);
  box-shadow: 0 0 0 3px var(--cs-accent-soft);
}

.cs-input[disabled],
.cs-select[disabled],
.cs-textarea[disabled] {
  background: var(--cs-sunken);
  color: var(--cs-muted);
  border-color: var(--cs-border);
  box-shadow: none;
  cursor: not-allowed;
}

/* Etat invalide : porte par `aria-invalid`, pas par une classe — l'attribut
   est ce que lit la technologie d'assistance, la classe ne dit rien a
   personne. */
.cs-input[aria-invalid="true"],
.cs-select[aria-invalid="true"],
.cs-textarea[aria-invalid="true"] {
  border-color: var(--cs-danger);
}
.cs-input[aria-invalid="true"]:focus,
.cs-select[aria-invalid="true"]:focus,
.cs-textarea[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 3px var(--cs-danger-bg);
}

/* Tailles — memes crans que les boutons, pour qu'un champ et un bouton
   alignes sur la meme ligne aient la meme hauteur. */
/* Les variantes prenaient leurs hauteurs en dur (28 / 40) : un bouton `lg`
   mesurait 42px, un champ `lg` 41. Elles suivent l'echelle desormais. */
.cs-input--sm, .cs-select--sm { min-height: var(--cs-control-h-sm); padding: 4px 9px; font-size: 12.5px; }
.cs-input--lg, .cs-select--lg { min-height: var(--cs-control-h-lg); padding: 10px 13px; font-size: 14px; }

/* Champ avec icone ou unite collee (`cs-input-group`). */
.cs-input-group { position: relative; display: flex; align-items: center; }
.cs-input-group .cs-input { padding-left: 32px; }
.cs-input-group__icon {
  position: absolute; left: 10px;
  display: inline-flex; width: 14px; height: 14px;
  color: var(--cs-muted); pointer-events: none;
}
.cs-input-group__icon svg { width: 14px; height: 14px; }
.cs-input-group__suffix {
  position: absolute; right: 11px;
  font-size: 12px; color: var(--cs-muted); pointer-events: none;
}
.cs-input-group:has(.cs-input-group__suffix) .cs-input { padding-right: 46px; }

/* ── Case a cocher et radio ────────────────────────────────────────────────
   Le carre (ou le rond) visible est un pseudo-element : `appearance: none`
   neutralise le controle natif, qui ne se stylise pas de facon fiable entre
   moteurs. L'input reste un vrai `<input type=checkbox|radio>` — le clavier et
   les technologies d'assistance le connaissent, un `<div role=checkbox>`
   non. */
.cs-check {
  display: flex; align-items: flex-start; gap: 9px;
  cursor: pointer; font-size: 13px; color: var(--cs-text);
}
.cs-check--disabled { cursor: not-allowed; color: var(--cs-muted); }
.cs-check__box {
  appearance: none; -webkit-appearance: none;
  position: relative; flex-shrink: 0;
  width: 16px; height: 16px; margin: 1px 0 0;
  background: var(--cs-surface);
  border: 1px solid var(--cs-border-strong); border-radius: 4px;
  cursor: inherit;
  transition: background .12s, border-color .12s;
}
.cs-check--radio .cs-check__box { border-radius: 50%; }
.cs-check__box:hover:not(:disabled) { border-color: var(--cs-muted); }
.cs-check__box:focus-visible {
  outline: none; border-color: var(--cs-accent);
  box-shadow: 0 0 0 3px var(--cs-accent-soft);
}
.cs-check__box:checked { background: var(--cs-accent); border-color: var(--cs-accent); }
/* La coche est dessinee en bordures pivotees : un SVG en background ne suit
   pas `currentColor` et imposerait une regle par theme. */
.cs-check__box:checked::after {
  content: ''; position: absolute; left: 5px; top: 1.5px;
  width: 4px; height: 8px;
  border: solid #fff; border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.cs-check--radio .cs-check__box:checked::after {
  left: 4px; top: 4px; width: 6px; height: 6px;
  border: 0; border-radius: 50%; background: #fff; transform: none;
}
.cs-check__box:disabled { background: var(--cs-sunken); border-color: var(--cs-border); }
.cs-check__box:disabled:checked { background: var(--cs-muted); border-color: var(--cs-muted); }
.cs-check__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cs-check__label { line-height: 1.35; }
.cs-check__hint { font-size: 11.5px; color: var(--cs-muted); }
.cs-check-group { display: flex; flex-direction: column; gap: 10px; }

/* ── Interrupteur ──────────────────────────────────────────────────────────
   Un checkbox deguise, pas un bouton : c'est l'etat coche/decoche que la
   technologie d'assistance doit annoncer. */
.cs-switch {
  display: inline-flex; align-items: flex-start; gap: 10px;
  cursor: pointer; font-size: 13px; color: var(--cs-text);
}
.cs-switch--disabled { cursor: not-allowed; color: var(--cs-muted); }
.cs-switch__input { position: absolute; opacity: 0; width: 0; height: 0; }
.cs-switch__track {
  position: relative; flex-shrink: 0;
  width: 34px; height: 20px; margin-top: 1px;
  background: var(--cs-border-strong); border-radius: 999px;
  transition: background .15s ease;
}
.cs-switch__thumb {
  position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px;
  background: #fff; border-radius: 50%;
  box-shadow: var(--cs-shadow-sm);
  transition: transform .15s ease;
}
.cs-switch__input:checked + .cs-switch__track { background: var(--cs-accent); }
.cs-switch__input:checked + .cs-switch__track .cs-switch__thumb { transform: translateX(14px); }
.cs-switch__input:focus-visible + .cs-switch__track {
  box-shadow: 0 0 0 3px var(--cs-accent-soft);
}
.cs-switch__input:disabled + .cs-switch__track { background: var(--cs-border); }

/* ── Action dans un champ (mot de passe) ───────────────────────────────── */
.cs-input--with-action { padding-right: 84px; }
.cs-input-group__action {
  position: absolute; right: 5px;
  padding: 3px 9px;
  font: inherit; font-size: 11.5px; font-weight: 500;
  color: var(--cs-text-2); background: var(--cs-sunken);
  border: 1px solid var(--cs-border); border-radius: var(--cs-radius-xs);
  cursor: pointer;
}
.cs-input-group__action:hover { color: var(--cs-text); border-color: var(--cs-border-strong); }

/* ── Depot de fichier ──────────────────────────────────────────────────────
   Le `<input type=file>` natif n'est pas stylisable : il est masque mais
   reste DANS le label, donc cliquable et focalisable au clavier. */
.cs-file { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; }
.cs-file--disabled { cursor: not-allowed; opacity: .6; }
.cs-file__input { position: absolute; opacity: 0; width: 0; height: 0; }
.cs-file__button {
  padding: 7px 13px; font-size: 12.5px; font-weight: 500;
  color: var(--cs-text); background: var(--cs-surface);
  border: 1px solid var(--cs-border-strong); border-radius: var(--cs-radius-sm);
  box-shadow: var(--cs-shadow-sm);
}
.cs-file__input:focus-visible + .cs-file__button {
  border-color: var(--cs-accent); box-shadow: 0 0 0 3px var(--cs-accent-soft);
}
.cs-file__name { font-size: 12.5px; color: var(--cs-muted); }

/* Le champ numerique garde ses fleches natives : les retirer priverait la
   souris d'un increment que rien ne remplace ici. */
.cs-input[type="number"] { padding-right: 6px; }

/* ── Select natif ──────────────────────────────────────────────────────────
   `appearance: none` retire le chrome systeme ; la fleche est redessinee en
   background-image. Sans ca, le select detonne a cote d'un input : hauteur
   imposee par l'OS, coins carres, fleche grise. */
.cs-select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  padding-right: 32px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2352525b' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  background-size: 12px;
  cursor: pointer;
}
.cs-select::-ms-expand { display: none; }
/* Le menu deroulant natif est peint par l'OS : sans cette regle, un theme
   sombre rend du texte clair sur fond clair sous Windows et Linux. */
.cs-select option { background: var(--cs-surface); color: var(--cs-text); }
/* Une `background-image` ne suit pas `currentColor` : le theme sombre doit
   redessiner la fleche, sinon elle reste dans le gris du theme clair. */
[data-theme="dark"] .cs-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23a1a1aa' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

/* ── Modal ────────────────────────────────────────────────────────────────── */
.cs-modal__overlay {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: rgb(0 0 0 / 55%);
}
/* Ancre le voile sur le parent positionne : voir `contained` dans modal.js —
   un voile fixed intercepte les clics de toute la page, storybook comprise. */
.cs-modal__overlay--contained { position: absolute; }
.cs-modal {
  display: flex; flex-direction: column;
  width: min(560px, 100%); max-height: calc(100vh - 96px);
  background: var(--cs-surface);
  border: 1px solid var(--cs-border-strong);
  border-radius: var(--cs-radius-lg);
  box-shadow: var(--cs-shadow-lg);
  overflow: hidden;
}
.cs-modal--sm { width: min(400px, 100%); }
.cs-modal--md { width: min(560px, 100%); }
.cs-modal--lg { width: min(820px, 100%); }
/* `xl` : le cockpit inventait `cs-modal--wide` faute d'un cran au-dessus de
   `lg` — une modale de detail qui affiche un tableau ou un bloc de logs a
   besoin de cette largeur. Nommee dans l'echelle du kit plutot que par un
   qualificatif, pour que la serie reste lisible. */
.cs-modal--xl { width: min(1040px, 100%); }
.cs-modal__header {
  display: flex; align-items: flex-start;
  padding: 18px 22px 0;
}
.cs-modal__header-text { flex: 1; min-width: 0; }
.cs-modal__title { font-size: 15px; font-weight: 600; color: var(--cs-text); }
/* Bouton de fermeture — les dix-neuf modales maison en ont une, le kit n'en
   rendait aucune. Un vrai <button> : le cockpit posait un `<div role=button>`,
   qui n'est ni focalisable ni actionnable au clavier sans travail
   supplementaire. */
.cs-modal__close {
  flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; margin: -3px -4px 0 8px; padding: 0;
  background: none; border: 0; border-radius: var(--cs-radius-sm);
  color: var(--cs-muted); cursor: pointer;
  transition: background .12s, color .12s;
}
.cs-modal__close:hover { background: var(--cs-surface-hover); color: var(--cs-text); }
.cs-modal__close:focus-visible { outline: 2px solid var(--cs-accent); outline-offset: 1px; }
.cs-modal__close svg { width: 16px; height: 16px; }
.cs-modal__subtitle { margin-top: 4px; font-size: 12.5px; color: var(--cs-text-2); }
.cs-modal__body { padding: 18px 22px; overflow-y: auto; }
.cs-modal__footer {
  display: flex; gap: 8px; justify-content: flex-end;
  padding: 14px 22px; border-top: 1px solid var(--cs-border);
  background: var(--cs-surface-2);
}

/* ── Topbar ───────────────────────────────────────────────────────────────── */
.cs-topbar {
  display: flex; align-items: center; gap: 16px;
  height: 52px; padding: 0 20px;
  background: var(--cs-surface);
  border-bottom: 1px solid var(--cs-border);
}
.cs-topbar__search { flex: 1; max-width: 380px; }
.cs-topbar__right { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.cs-topbar__icon-btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0;
  color: var(--cs-text-2);
  background: transparent;
  border: 1px solid transparent; border-radius: var(--cs-radius-sm);
  cursor: pointer; transition: background .12s, color .12s;
}
.cs-topbar__icon-btn:hover { background: var(--cs-surface-hover); color: var(--cs-text); }
.cs-topbar__badge {
  position: absolute; top: 1px; right: 1px;
  min-width: 15px; height: 15px; padding: 0 4px;
  font-size: 10px; line-height: 15px; text-align: center;
  color: var(--cs-text-inverse); background: var(--cs-danger);
  border-radius: 8px;
}

/* ── Alert ──────────────────────────────────────────────────────────────── */
.cs-alert {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--cs-border-strong);
  border-radius: var(--cs-radius);
  background: var(--cs-surface-2);
  font-size: 13px;
}
/* L'icone de ton : `sh-callout` et `gw-banner` en portaient une, `cs-alert`
   non — c'est une des raisons pour lesquelles les deux surfaces l'ont refait.
   Elle prend la couleur du ton par heritage, comme le reste du bandeau. */
.cs-alert__icon { display: flex; flex-shrink: 0; width: 16px; height: 16px; margin-top: 1px; }
.cs-alert__icon svg { width: 16px; height: 16px; }
.cs-alert__body { flex: 1; min-width: 0; }
.cs-alert__title { font-weight: 600; color: var(--cs-text); }
.cs-alert__text { margin-top: 3px; color: var(--cs-text-2); }
.cs-alert__action { flex-shrink: 0; }
.cs-alert__close {
  flex-shrink: 0; width: 22px; height: 22px; padding: 0;
  background: none; border: 0; border-radius: var(--cs-radius-xs);
  color: var(--cs-muted); font-size: 17px; line-height: 1; cursor: pointer;
}
.cs-alert__close:hover { background: var(--cs-surface-hover); color: var(--cs-text); }
/* Le ton colore le BORD et le fond, jamais le texte du corps : un paragraphe
   entier en rouge se lit moins bien, et l'accent perd son sens quand il porte
   sur plusieurs lignes. */
.cs-alert--info    { border-color: var(--cs-info);    background: var(--cs-info-bg); }
.cs-alert--success { border-color: var(--cs-success); background: var(--cs-success-bg); }
.cs-alert--warning { border-color: var(--cs-warning); background: var(--cs-warning-bg); }
.cs-alert--danger  { border-color: var(--cs-danger);  background: var(--cs-danger-bg); }

/* ── Pill ───────────────────────────────────────────────────────────────── */
.cs-pill {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; padding: 1px 8px;
  border-radius: 999px;
  font-size: 11.5px; font-weight: 600; line-height: 1.6;
}
.cs-pill--neutral { background: var(--cs-sunken); color: var(--cs-text-2); }
/* AA (#CS-90) : libelle de la pilule = texte -> --cs-accent-text. */
.cs-pill--accent  { background: var(--cs-accent-soft); color: var(--cs-accent-text); }

/* ── Menu ───────────────────────────────────────────────────────────────── */
.cs-menu-wrap { position: relative; display: inline-flex; }
/* Le voile ferme le menu au clic ailleurs. Sans lui, deux menus peuvent
   rester ouverts en meme temps. */
.cs-menu__scrim { position: fixed; inset: 0; z-index: 40; }
/* Voile ancre sur le parent positionne — voir `defaultOpen` dans menu.js. */
.cs-menu__scrim--contained { position: absolute; }
.cs-menu {
  position: absolute; z-index: 41; top: calc(100% + 4px);
  min-width: 190px; padding: 4px;
  background: var(--cs-surface);
  border: 1px solid var(--cs-border-strong); border-radius: var(--cs-radius);
  box-shadow: var(--cs-shadow-md);
}
.cs-menu--right { right: 0; }
.cs-menu--left { left: 0; }
.cs-menu__item {
  display: block; width: 100%; padding: 7px 10px;
  background: none; border: 0; border-radius: var(--cs-radius-sm);
  color: var(--cs-text); font: inherit; font-size: 13px; text-align: left;
  text-decoration: none; cursor: pointer;
}
.cs-menu__item:hover { background: var(--cs-surface-hover); }
.cs-menu__item[disabled] { color: var(--cs-muted); cursor: not-allowed; }
.cs-menu__item[disabled]:hover { background: none; }
/* AA (#CS-90) : libelle de l'item = texte -> --cs-danger-text. */
.cs-menu__item--danger { color: var(--cs-danger-text); }
.cs-menu__item--danger:hover { background: var(--cs-danger-bg); }
.cs-menu__sep { height: 1px; margin: 4px 0; background: var(--cs-border); }

/* ── AppSwitcher — grille des applications studio ──
   Reutilise `.cs-menu__scrim` : meme contrat de fermeture, un seul voile a
   maintenir. Ce qui differe est la GRILLE — quatre destinations qu'on vise du
   regard, la ou un menu se lit ligne a ligne. */
.cs-appsw { position: relative; display: inline-flex; }
.cs-appsw__grip { display: inline-flex; width: 16px; height: 16px; }
.cs-appsw__grip svg { width: 100%; height: 100%; }
.cs-appsw__grid {
  position: absolute; z-index: 41; top: calc(100% + 4px); right: 0;
  display: grid; grid-template-columns: repeat(2, minmax(178px, 1fr));
  gap: 4px; padding: 6px; width: max-content; max-width: min(420px, calc(100vw - 24px));
  grid-auto-rows: 1fr;
  background: var(--cs-surface);
  border: 1px solid var(--cs-border-strong); border-radius: var(--cs-radius);
  box-shadow: var(--cs-shadow-md);
}
/* La tuile est un LIEN : Ctrl+clic, molette et nouvel onglet doivent marcher —
   c'est une navigation, pas une action. */
.cs-appsw__item {
  display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto auto;
  column-gap: 9px; align-items: center;
  padding: 9px 11px;
  border-radius: var(--cs-radius-sm);
  color: var(--cs-text); text-decoration: none;
}
.cs-appsw__item:hover { background: var(--cs-surface-hover); }
.cs-appsw__item:focus-visible { outline: 2px solid var(--cs-accent); outline-offset: -2px; }
.cs-appsw__icon {
  grid-row: 1 / 3; display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: var(--cs-radius-sm);
  background: var(--cs-surface-2); color: var(--cs-text-2);
}
.cs-appsw__icon svg { width: 17px; height: 17px; }
.cs-appsw__label { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* UNE ligne, toujours : une description plus longue que les autres ferait
   grandir sa rangee et desalignerait la grille. */
.cs-appsw__desc {
  font-size: 11.5px; color: var(--cs-text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* L'application courante reste un lien (retour a son accueil) : elle se
   distingue par sa teinte, pas en cessant d'etre cliquable. */
.cs-appsw__item.is-current { background: var(--cs-surface-2); }
.cs-appsw__item.is-current .cs-appsw__icon { background: var(--cs-accent-soft); color: var(--cs-accent-text); }
/* Sous 480px la grille passe en colonne : deux tuiles cote a cote y tiennent,
   mais leur libelle se coupe. */
@media (max-width: 480px) {
  .cs-appsw__grid { grid-template-columns: minmax(0, 1fr); }
}

/* ── IconButton ─────────────────────────────────────────────────────────── */
.cs-icon-btn--danger { color: var(--cs-danger); }
.cs-icon-btn--danger:hover { background: var(--cs-danger-bg); }

/* ── Toast ─────────────────────────────────────────────────────────────────
   Distinct d'`Alert` : celui-ci vit DANS le flux de la page et y reste ; le
   toast se superpose et disparait. */
.cs-toast-stack {
  position: fixed; z-index: 200;
  display: flex; flex-direction: column; gap: 8px;
  width: min(380px, calc(100vw - 32px));
  pointer-events: none;
}
/* Ancre la pile sur le parent positionne — pour une demonstration en place :
   une pile `fixed` couvrirait la page entiere, storybook comprise. */
.cs-toast-stack--contained { position: absolute; }
.cs-toast-stack--bottom-right { right: 16px; bottom: 16px; }
.cs-toast-stack--bottom-left  { left: 16px;  bottom: 16px; }
.cs-toast-stack--top-right    { right: 16px; top: 16px; }
.cs-toast-stack--top-left     { left: 16px;  top: 16px; }
/* La pile ne capte pas les clics (elle couvre une zone vide la plupart du
   temps), mais chaque toast si — sinon ses boutons seraient inertes. */
.cs-toast-stack > * { pointer-events: auto; }

.cs-toast {
  position: relative;
  display: flex; align-items: flex-start; gap: 11px;
  padding: 12px 14px 12px 15px;
  background: var(--cs-surface);
  border: 1px solid var(--cs-border-strong);
  border-radius: var(--cs-radius);
  box-shadow: var(--cs-shadow-lg);
  font-size: 13px;
  overflow: hidden;
}
/* Le ton se porte sur un liseré lateral, pas sur le fond : un toast se
   superpose au contenu, un fond colore plein le rendrait illisible par-dessus
   n'importe quelle page. */
.cs-toast__mark { position: absolute; left: 0; top: 0; bottom: 0; width: 3px; }
.cs-toast--info    .cs-toast__mark { background: var(--cs-info); }
.cs-toast--success .cs-toast__mark { background: var(--cs-success); }
.cs-toast--warning .cs-toast__mark { background: var(--cs-warning); }
.cs-toast--danger  .cs-toast__mark { background: var(--cs-danger); }

.cs-toast__body { flex: 1; min-width: 0; }
.cs-toast__title { font-weight: 600; color: var(--cs-text); }
.cs-toast__text { margin-top: 2px; color: var(--cs-text-2); }
.cs-toast__action { flex-shrink: 0; }
.cs-toast__close {
  flex-shrink: 0; width: 22px; height: 22px; padding: 0;
  background: none; border: 0; border-radius: var(--cs-radius-xs);
  color: var(--cs-muted); font-size: 17px; line-height: 1; cursor: pointer;
}
.cs-toast__close:hover { background: var(--cs-surface-hover); color: var(--cs-text); }

/* ══════════════════════════════════════════════════════════════════════════
   AppShell — le chassis : header, nav, contenu.

   Ce bloc absorbe ce que chaque application reecrivait : la grille, le drawer
   mobile, le scrim, le rail. Cote `creep-studio` c'est ~300 lignes de CSS
   `dc-*` qui disparaissent, dont la neutralisation de la `.cs-sidebar` — celle
   qui produisait « une colonne de 230px dans une de 208, avec une double
   bordure et un padding double ».

   LE BREAKPOINT EST UNE CONTAINER QUERY, ET C'EST DELIBERE. Le cockpit
   dupliquait `860px` en QUATRE endroits (cockpit.css, use-media-query.ts, et
   deux fichiers de la maquette) avec un commentaire demandant de les aligner a
   la main — parce qu'une media query n'accepte pas de custom property. Une
   container query resout les deux problemes d'un coup : la valeur ne vit qu'ici,
   et le shell reagit a SA largeur plutot qu'a celle de la fenetre. Un cockpit
   embarque dans un panneau etroit se replie enfin correctement, ce qu'aucune
   media query ne pouvait faire.
   ══════════════════════════════════════════════════════════════════════════ */

:root {
  /* Largeurs de nav — surchargeables par application, sans forker le CSS. */
  --cs-nav-w: 230px;
  --cs-nav-rail-w: 60px;
  --cs-header-h: 54px;
  /* Drawer : `min()` pour qu'un tres petit ecran garde du contenu visible. */
  --cs-nav-drawer-w: min(282px, 84vw);
}

/* `min-height: 0` sur les regions : sans lui, un enfant long fait grandir la
   rangee de grille au lieu de defiler dans sa region. */
/* DEUX elements, et c'est la seule facon de faire marcher la container query :
   un element ne peut PAS interroger son propre conteneur. `.cs-shell` declare
   le conteneur, `.cs-shell__grid` porte la grille et se replie — il est un
   DESCENDANT, donc il peut lire la largeur mesuree au-dessus de lui. Poser les
   deux sur le meme element donne une grille qui ne se replie jamais (la regle
   `@container` y est simplement ignoree, sans avertissement). */
.cs-shell {
  container-type: inline-size;
  container-name: cs-shell;
  height: 100%;
  overflow: hidden;
  position: relative;
  background: var(--cs-bg);
  font-family: var(--cs-font);
}
.cs-shell__grid {
  display: grid;
  grid-template-columns: var(--cs-nav-w) 1fr;
  grid-template-rows: var(--cs-header-h) 1fr;
  height: 100%;
  position: relative;
}
.cs-shell--rail .cs-shell__grid { grid-template-columns: var(--cs-nav-rail-w) 1fr; }
.cs-shell--no-nav .cs-shell__grid { grid-template-columns: 1fr; }
.cs-shell--no-header .cs-shell__grid { grid-template-rows: 1fr; }

/* La nav COIFFE le header : elle occupe les deux rangees, le header ne
   commence qu'apres elle. C'est la mise en page du cockpit, obtenue la-bas au
   prix d'un `display: contents` sur un conteneur intermediaire. Ici les trois
   regions sont soeurs, il n'y a rien a effacer. */
.cs-shell__nav {
  grid-column: 1; grid-row: 1 / -1;
  min-height: 0; display: flex; flex-direction: column;
  background: var(--cs-surface);
  border-right: 1px solid var(--cs-border);
  overflow-y: auto;
  /* `overflow-x` explicite : `overflow-y: auto` seul laisse l'axe horizontal
     en `auto`, et le moindre enfant trop large y pose une barre. */
  overflow-x: hidden;
  overscroll-behavior: contain;
}
.cs-shell--no-header .cs-shell__nav { grid-row: 1 / -1; }

.cs-shell__header {
  grid-column: 2; grid-row: 1;
  display: flex; align-items: center; gap: 12px;
  min-width: 0; padding: 0 16px;
  background: var(--cs-surface);
  border-bottom: 1px solid var(--cs-border-strong);
  /* La barre se detache du contenu par l'elevation, pas par un trait seul. */
  position: relative; z-index: 5;
  box-shadow: var(--cs-shadow-sm);
}
.cs-shell--no-nav .cs-shell__header { grid-column: 1; }

.cs-shell__content {
  grid-column: 2; grid-row: 2;
  min-width: 0; min-height: 0; overflow: auto;
}
.cs-shell--no-nav .cs-shell__content { grid-column: 1; }
.cs-shell--no-header .cs-shell__content { grid-row: 1; }

/* La `.cs-sidebar` posee DANS le shell s'efface : le shell porte deja la
   largeur, la bordure et le defilement. C'est exactement la neutralisation que
   chaque consommateur ecrivait — elle est ici, ecrite une fois. */
.cs-shell__nav > .cs-sidebar {
  width: 100%; height: auto; flex: 1; min-height: 0;
  border-right: 0; background: none;
  /* `hidden` et non `visible` : c'est la nav INTERNE qui defile (cf. plus
     bas), pas l'aside — sinon la marque defile avec elle. */
  overflow: hidden;
  padding: 10px 0;
}
.cs-shell__nav > .cs-sidebar > .cs-sidebar__nav { padding: 0 8px; }
/* Les separateurs de section vont d'un bord a l'autre : le padding lateral vit
   sur la nav interne, les separateurs le rattrapent en negatif. Sans ca ils
   s'arretent avant les bords et la section flotte. */
.cs-shell__nav > .cs-sidebar .cs-sidebar__group + .cs-sidebar__group {
  margin-left: -8px; margin-right: -8px;
  padding-left: 8px; padding-right: 8px;
}
/* La marque coiffe la nav a la HAUTEUR EXACTE du header : les deux identites
   se posent sur la meme ligne optique, et leurs separations se repondent d'un
   bord a l'autre de la colonne. Le `margin` negatif remonte sur le padding
   vertical de l'aside — sinon la marque flotte 10px plus bas que le header et
   le decalage se voit immediatement. */
.cs-shell__nav > .cs-sidebar > .cs-sidebar__brand,
.cs-shell__nav > .cs-sidebar > :first-child:not(.cs-sidebar__nav) {
  height: var(--cs-header-h); box-sizing: border-box; flex-shrink: 0;
  /* Le padding de l'aside vaut 10px en haut : on le neutralise exactement. */
  margin: -10px 0 6px; padding: 0 12px;
  border-bottom: 1px solid var(--cs-border);
  /* La `Sidebar` rend son brand en `display:flex` avec un padding propre —
     il faut le reprendre pour que la hauteur imposee soit tenue. */
  display: flex; align-items: center; gap: 10px;
}
/* En rail la marque est centree : le nom disparait, le glyphe reste seul. */
.cs-shell--rail .cs-shell__nav > .cs-sidebar > .cs-sidebar__brand,
.cs-shell--rail .cs-shell__nav > .cs-sidebar > :first-child:not(.cs-sidebar__nav) {
  justify-content: center; padding: 0;
}
/* Le separateur traverse la colonne ENTIERE. Le padding lateral de la marque
   l'arreterait avant les bords, et le trait flotterait au lieu de repondre a
   celui du header. */
.cs-shell__nav > .cs-sidebar > .cs-sidebar__brand,
.cs-shell__nav > .cs-sidebar > :first-child:not(.cs-sidebar__nav) {
  margin-left: 0; margin-right: 0;
}

/* La nav DEFILE, la marque reste. Sans cette separation, une nav plus haute
   que la colonne emporte sa marque au defilement — et le seul repere d'ou
   l'on se trouve disparait. */
.cs-shell__nav > .cs-sidebar { display: flex; flex-direction: column; }
.cs-shell__nav > .cs-sidebar > .cs-sidebar__nav {
  flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden;
  /* La derniere section ne colle pas au bord bas de la colonne. */
  padding-bottom: 10px;
}

/* Hamburger — n'existe qu'en drawer, masque partout ailleurs. */
.cs-shell__burger {
  display: none;
  align-items: center; justify-content: center; flex-shrink: 0;
  width: 40px; height: 40px; padding: 0; margin-left: -6px;
  background: none; border: 0; border-radius: var(--cs-radius-sm);
  color: var(--cs-text-2); cursor: pointer;
}
.cs-shell__burger:hover { background: var(--cs-surface-hover); color: var(--cs-text); }
.cs-shell__burger.is-open { color: var(--cs-accent-text); background: var(--cs-accent-soft); }

.cs-shell__scrim { display: none; }

/* ---- Repli : la nav devient un drawer ------------------------------------
   Sur la largeur du SHELL, pas de la fenetre (cf. en-tete de bloc). */
@container cs-shell (max-width: 860px) {
  .cs-shell__grid {
    grid-template-columns: 1fr;
    grid-template-rows: var(--cs-header-h) 1fr;
  }
  .cs-shell__header, .cs-shell__content { grid-column: 1; }
  .cs-shell__content { grid-row: 2; }

  .cs-shell__burger { display: flex; }

  /* Le drawer part SOUS le header : le hamburger reste visible et sert aussi
     de fermeture — pas de seconde croix a viser dans le panneau.
     `visibility` en plus du `transform` : un panneau hors ecran mais visible
     garde ses liens dans l'ordre de tabulation. */
  .cs-shell__nav {
    position: absolute; top: var(--cs-header-h); left: 0; bottom: 0; z-index: 40;
    width: var(--cs-nav-drawer-w);
    transform: translateX(-100%); visibility: hidden;
    transition: transform .22s cubic-bezier(.4, 0, .2, 1), visibility .22s;
    box-shadow: var(--cs-shadow-lg);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .cs-shell__nav.is-open { transform: translateX(0); visibility: visible; }

  .cs-shell__scrim {
    display: block; position: absolute; inset: var(--cs-header-h) 0 0 0; z-index: 39;
    background: rgba(0, 0, 0, .45);
  }

  /* Cible tactile : 44px de haut sur les liens de nav. Cette regle vivait dans
     le cockpit HORS de sa media query — le padding tactile s'appliquait donc
     aussi en desktop, sans que personne le voie. */
  .cs-shell__nav .cs-sidebar__link { padding: 11px 10px; font-size: 14px; }
  /* La marque ne se REPETE pas dans le drawer : le header la porte deja, et
     le panneau s'ouvre juste en dessous. Uniquement quand il Y A un header —
     sans lui (cockpit embarque), la tete de nav est le seul repere de l'ecran
     ou l'on se trouve, et l'effacer laisserait une liste de liens anonyme. */
  .cs-shell:not(.cs-shell--no-header) .cs-shell__nav > .cs-sidebar > .cs-sidebar__brand,
  .cs-shell:not(.cs-shell--no-header) .cs-shell__nav > .cs-sidebar > :first-child:not(.cs-sidebar__nav) {
    display: none;
  }
  /* Les actions d'item (epingle, poignee) ne se revelent pas au survol sur
     tactile : il n'y a pas de survol. */
  .cs-shell__nav .cs-sidebar__item [data-hover-only] { opacity: 1; }
}

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

/* ---- Etat actif : la « signature » qui n'en etait pas une ----------------
   Le cockpit surchargeait l'actif du kit (fond uni) par un gradient + filet
   lateral, en commentant que c'etait « une signature du cockpit, pas du DS ».
   Le meme motif est recopie a l'identique dans `support-hub/web/app.css` et
   dans la maquette `daemon-cockpit` : recopie trois fois, ce n'est plus une
   signature, c'est le langage commun. Il rejoint donc le kit. */
.cs-sidebar__link.is-active {
  position: relative;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--cs-accent) 14%, transparent),
    color-mix(in srgb, var(--cs-accent) 5%, transparent));
  color: var(--cs-accent-text); font-weight: 600;
}
.cs-sidebar__link.is-active::before {
  content: ""; position: absolute; left: 0; top: 6px; bottom: 6px;
  width: 3px; border-radius: 2px;
  background: var(--cs-accent-grad);
  box-shadow: 0 0 8px var(--cs-glow);
}
/* En rail, le DEGRADE cede la place a un aplat uni : l'icone centree ne lui
   laisse pas la largeur qu'il lui faut, il s'y lirait comme une bavure. Le
   filet lateral, lui, reste — l'actif y porte donc les deux marqueurs. */
.cs-sidebar--rail .cs-sidebar__link.is-active { background: var(--cs-accent-soft); }
/* Le filet se recentre sur la hauteur de l'icone : en rail, un filet aux
   memes marges qu'en pleine largeur depasse visiblement de l'aplat. */
.cs-sidebar--rail .cs-sidebar__link.is-active::before { top: 8px; bottom: 8px; }

/* ══════════════════════════════════════════════════════════════════════════
   AppHeader — barre haute en zones.
   ══════════════════════════════════════════════════════════════════════════ */

.cs-header {
  display: flex; align-items: center; gap: 12px;
  flex: 1; min-width: 0; height: 100%;
}
.cs-header__brand { flex-shrink: 0; min-width: 0; }
/* LA MARQUE NE SE REPETE PAS — l'autre moitie de la regle du drawer.
   Le kit masquait deja celle de la NAV quand un header existe, mais seulement
   sous 860px, ou la nav est un drawer ferme. Au-dessus les deux sont montees
   en meme temps : une application qui passe la meme identite aux deux prises
   — ce que fait le cockpit avec le nom du daemon — l'affiche DEUX FOIS, a
   quelques pixels d'ecart.
   Le header cede, pas la nav : la nav prend toute la hauteur, c'est elle qui
   porte l'identite, et sa tete est deja alignee au pixel sur celle du header.
   Sous 860px la regle s'inverse (le drawer se ferme, le header reprend la
   marque) — c'est le bloc `@container` plus bas.
   Un header SANS nav garde evidemment la sienne. */
/* La garde vise une MARQUE reellement rendue EN TETE de nav — ni la presence
   du noeud nav, ni un premier enfant quelconque. `nav` est un ReactNode libre
   et la tete de `Sidebar` accepte n'importe quoi (un champ de recherche, par
   exemple) : tester le noeud masquait le header alors que rien ne reprenait
   l'identite, et l'ecran se retrouvait sans AUCUNE marque.
   DEUX selecteurs parce que `Sidebar` a DEUX formes de tete, et qu'une seule
   passe par `Brand` : `brand=`/`logo=` rend `.cs-sidebar__brand` (la forme par
   DEFAUT, celle de quatre stories sur six), un `header` custom rend ce qu'on
   lui donne — `.cs-brand` quand c'est un `Brand`. N'en couvrir qu'une laisse
   l'autre afficher deux marques.
   Le `>` borne a la TETE : une marque posee dans un item ou un pied de nav
   n'est pas l'identite de l'ecran. */
.cs-shell__grid:has(.cs-shell__nav > .cs-sidebar > .cs-sidebar__brand) .cs-header__brand,
.cs-shell__grid:has(.cs-shell__nav > .cs-sidebar > .cs-brand) .cs-header__brand {
  display: none;
}
.cs-header__start { display: flex; align-items: center; gap: 10px; min-width: 0; }
/* `margin-left: auto` : la zone de droite est poussee sans qu'on ait besoin
   d'un element vide entre les deux — c'est le `dc-spacer` du cockpit, qui y
   servait 7 fois faute d'equivalent au kit. `HeaderSpacer` reste expose pour
   les separations INTERNES a une zone. */
.cs-header__end {
  display: flex; align-items: center; gap: 8px;
  margin-left: auto; flex-shrink: 0;
}

.cs-header__divider { width: 1px; height: 24px; background: var(--cs-border); flex-shrink: 0; }
.cs-header__spacer { flex: 1; }

.cs-header__tag {
  flex-shrink: 0;
  font-size: 11px; color: var(--cs-muted);
  padding: 2px 7px; border: 1px solid var(--cs-border); border-radius: 999px;
  white-space: nowrap;
}
.cs-header__tag.is-accent { color: var(--cs-accent-text); border-color: var(--cs-accent-soft); background: var(--cs-accent-soft); }
.cs-header__tag.is-success { color: var(--cs-success-text); border-color: var(--cs-success-bg); background: var(--cs-success-bg); }
.cs-header__tag.is-warning { color: var(--cs-warning-text); border-color: var(--cs-warning-bg); background: var(--cs-warning-bg); }

/* Bouton d'icone. Fusionne `cs-topbar__icon-btn` (pastille danger) et le
   `dc-needyou-btn` du cockpit (pastille d'accent + etat `is-active`). */
.cs-header__btn {
  position: relative; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--cs-control-h); height: var(--cs-control-h); padding: 0;
  color: var(--cs-text-2); background: transparent;
  border: 1px solid transparent; border-radius: var(--cs-radius-sm);
  cursor: pointer; text-decoration: none;
  transition: background .12s, color .12s;
}
.cs-header__btn:hover { background: var(--cs-surface-hover); color: var(--cs-text); }
/* L'icone est fournie par l'appelant : le bouton la BORNE plutot que de lui
   faire confiance. Sans cette regle, un SVG sans `width` deborde du bouton et
   passe sous la pastille de compteur. */
.cs-header__btn > svg { width: 16px; height: 16px; flex-shrink: 0; }
.cs-header__btn:focus-visible {
  outline: 2px solid var(--cs-accent); outline-offset: 1px;
}
/* Le bouton reste allume tant que le panneau qu'il ouvre est ouvert. */
.cs-header__btn.is-active { background: var(--cs-accent-soft); color: var(--cs-accent-text); }
.cs-header__btn-badge {
  position: absolute; top: -2px; right: -2px;
  min-width: 16px; height: 16px; padding: 0 4px;
  font-size: 10px; font-weight: 600; line-height: 16px; text-align: center;
  color: #fff;
  /* Meme correctif que #2140 : le blanc sur `--cs-danger` brut echoue AA a
     cette taille (3.91 clair / 3.08 sombre -> 6.16 / 5.00). */
  background: color-mix(in srgb, var(--cs-danger) 76%, #000);
  border-radius: 999px;
  /* Detouree sur le fond du header : sans ca la pastille bave sur l'icone. */
  box-shadow: 0 0 0 2px var(--cs-surface);
}

/* ---- Brand : glyphe + nom, du header comme de la tete de nav ------------- */
.cs-brand {
  display: flex; align-items: center; gap: 9px;
  min-width: 0; text-decoration: none; color: inherit;
}
.cs-brand__glyph {
  display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 8px; flex-shrink: 0;
  background: var(--cs-accent-grad); color: #fff;
  font-weight: 700; font-size: 13px;
  box-shadow: 0 2px 10px var(--cs-glow), inset 0 1px 0 rgba(255,255,255,.25);
}
.cs-brand__text { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.cs-brand__name {
  font-size: 14.5px; font-weight: 700; color: var(--cs-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Un identifiant machine (hote, tenant) se lit en chasse fixe. */
.cs-brand__name.is-mono { font-family: var(--cs-mono); font-size: 13.5px; font-weight: 600; }
.cs-brand__sub {
  font-size: 11px; color: var(--cs-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
a.cs-brand:hover .cs-brand__name { color: var(--cs-accent-text); }

/* En drawer, le header perd ce qui n'est pas identitaire : la place manque et
   un jeton tronque ne renseigne rien. L'application n'a plus a le prevoir. */
@container cs-shell (max-width: 860px) {
  /* Le header perd ce qui n'est pas identitaire : la place manque et un jeton
     tronque ne renseigne rien. L'application n'a plus a le prevoir — le
     cockpit le faisait a la main, en masquant six elements un a un. */
  .cs-header { gap: 10px; }
  .cs-header__start { display: none; }
  .cs-brand__sub { display: none; }
  /* Le glyphe RESTE : quand la nav est un drawer ferme, le header est le seul
     porteur d'identite, et l'en vider le rend anonyme. Il retrecit plutot. */
  .cs-brand__glyph { width: 24px; height: 24px; border-radius: 7px; }
  .cs-brand__name { font-size: 13px; }
  /* La marque prend la largeur restante et s'ellipse plutot que de pousser
     les actions hors du header — mais elle ne se retrecit qu'en DERNIER
     recours : `min-width: 0` seul la laissait s'ellipser alors que la place
     etait libre, parce qu'un conteneur flex accorde le retrait au premier
     enfant qui l'autorise. `flex-shrink` sur les actions inverse l'ordre. */
  /* La marque REVIENT : le drawer est ferme, le header redevient le seul
     porteur d'identite. Meme specificite que la regle desktop qui la masque,
     posee APRES — c'est l'ordre qui tranche, pas un `!important`. */
  .cs-shell__grid:has(.cs-shell__nav > .cs-sidebar > .cs-sidebar__brand) .cs-header__brand,
  .cs-shell__grid:has(.cs-shell__nav > .cs-sidebar > .cs-brand) .cs-header__brand {
    display: flex;
  }
  .cs-header__brand { flex: 1 1 auto; min-width: 0; }
  .cs-header__end { flex-shrink: 0; }
}

/* ══════════════════════════════════════════════════════════════════════════
   ThemeToggle — bascule de theme.
   ══════════════════════════════════════════════════════════════════════════ */

.cs-theme-toggle {
  display: inline-flex; align-items: center; gap: 8px;
  height: var(--cs-control-h); padding: 0 11px 0 9px;
  background: var(--cs-surface); color: var(--cs-text-2);
  border: 1px solid var(--cs-border-strong); border-radius: var(--cs-radius-sm);
  font-family: var(--cs-font); font-size: 12.5px; font-weight: 500;
  cursor: pointer; transition: background .12s, color .12s, border-color .12s;
}
.cs-theme-toggle:hover { background: var(--cs-surface-hover); color: var(--cs-text); border-color: var(--cs-muted); }
.cs-theme-toggle:focus-visible { outline: 2px solid var(--cs-accent); outline-offset: 1px; }
.cs-theme-toggle__icon { display: inline-flex; width: 16px; height: 16px; flex-shrink: 0; }
.cs-theme-toggle__icon svg { width: 16px; height: 16px; }
.cs-theme-toggle__label { white-space: nowrap; }
.cs-theme-toggle--sm { height: var(--cs-control-h-sm); padding: 0 9px 0 7px; font-size: 11.5px; gap: 6px; }
.cs-theme-toggle--sm .cs-theme-toggle__icon,
.cs-theme-toggle--sm .cs-theme-toggle__icon svg { width: 14px; height: 14px; }
/* Icone seule : le bouton devient carre, comme les autres boutons d'icone du
   header — il s'aligne sur `cs-header__btn` plutot que d'inventer sa taille. */
.cs-theme-toggle--icon {
  width: var(--cs-control-h); padding: 0; justify-content: center;
  background: transparent; border-color: transparent;
}
.cs-theme-toggle--icon:hover { background: var(--cs-surface-hover); border-color: transparent; }


/* Le basculement ne s'anime pas : repeindre toute la page en fondu produit un
   entre-deux ou ni l'un ni l'autre theme n'est lisible. Seul l'element qu'on
   manipule garde sa transition. */
@media (prefers-reduced-motion: reduce) {
  .cs-theme-toggle, .cs-segmented__opt { transition: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Note / Hint — le texte explicatif discret.

   `dc-note` est la classe la plus utilisee du cockpit (30 fichiers), et ses
   equivalents s'appellent `gw-hint`, `gw-error`, `sh-hint` selon la surface.
   Aucun composant du kit ne la servait : `Alert` INTERROMPT (fond, bordure,
   role ARIA), une note ACCOMPAGNE. Un fond colore sous chaque libelle d'aide
   signalerait une anomalie a chaque champ.
   ══════════════════════════════════════════════════════════════════════════ */

.cs-note {
  margin: 6px 0 0;
  font-family: var(--cs-font); font-size: 12px; line-height: 1.5;
  color: var(--cs-muted);
}
.cs-note--error { color: var(--cs-danger-text); }
.cs-note--success { color: var(--cs-success-text); }
.cs-note--warning { color: var(--cs-warning-text); }
.cs-note.is-mono {
  font-family: var(--cs-mono);
  font-size: 11.5px; word-break: break-all;
}
/* Le code inline dans une note : le cockpit le posait a la main, dans une
   regle `.dc-note code` — c'est le meme besoin partout. */
.cs-note code, .cs-hint code {
  font-family: var(--cs-mono);
  font-size: .92em;
  background: var(--cs-sunken); color: var(--cs-text-2);
  padding: 1px 5px; border-radius: var(--cs-radius-xs);
}

/* Hint — la note qui doit se remarquer, sans devenir une alerte. Le filet
   lateral suffit a la detacher : un encart plein ferait concurrence aux
   vraies alertes de la page. */
.cs-hint {
  font-family: var(--cs-font); font-size: 12px; line-height: 1.55;
  color: var(--cs-text-2);
  background: var(--cs-surface-2);
  border: 1px solid var(--cs-border);
  border-left: 3px solid var(--cs-accent);
  border-radius: var(--cs-radius-sm);
  padding: 9px 12px;
}
.cs-hint b, .cs-hint strong { color: var(--cs-text); font-weight: 600; }
.cs-hint--warning { border-left-color: var(--cs-warning); }
.cs-hint--danger { border-left-color: var(--cs-danger); }
.cs-hint--success { border-left-color: var(--cs-success); }

/* ══════════════════════════════════════════════════════════════════════════
   Utilitaire d'accessibilite — le texte reserve aux lecteurs d'ecran.

   Le kit n'en avait AUCUN, ce qui obligeait chaque composant a choisir entre
   une info visible ou pas d'info du tout. Recette standard : hors du flux
   visuel, present dans l'arbre d'accessibilite. Surtout pas `display: none`
   ni `visibility: hidden`, qui le retirent des deux.
   ══════════════════════════════════════════════════════════════════════════ */
.cs-sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* ══════════════════════════════════════════════════════════════════════════
   KeyValue — la liste descriptive.

   Quatre variantes internes au cockpit (`dc-kv` flex, `dc-kv-row` grille
   180px, `dc-gwkv`, `dc-ws-repo__kv`), plus `gw-kv` et `sh-meta-grid`. Elles
   divergeaient deja pour un besoin identique.
   ══════════════════════════════════════════════════════════════════════════ */

.cs-kv { margin: 0; font-family: var(--cs-font); font-size: 13px; }
.cs-kv__k { color: var(--cs-muted); font-size: 12px; }
.cs-kv__v { margin: 0; color: var(--cs-text); min-width: 0; overflow-wrap: anywhere; }
.cs-kv__v.is-mono {
  font-family: var(--cs-mono);
  font-size: 12px;
}
/* Une valeur absente se DIT. Un blanc laisse penser que la ligne n'a pas
   fini de charger. */
.cs-kv__empty { color: var(--cs-muted); }

/* Rows — cle a gauche, valeur a droite. La fiche dense. */
.cs-kv--rows .cs-kv__row {
  display: flex; align-items: baseline; gap: 16px;
  padding: 7px 0; border-bottom: 1px solid var(--cs-border);
}
.cs-kv--rows .cs-kv__row:last-child { border-bottom: 0; }
.cs-kv--rows .cs-kv__k { flex-shrink: 0; }
.cs-kv--rows .cs-kv__v { margin-left: auto; text-align: right; }

/* Grid — cle au-dessus, en colonnes. La fiche aeree : une URL ou un chemin n'a
   pas a se battre pour la moitie d'une ligne. */
.cs-kv--grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 14px 22px;
}
.cs-kv--grid .cs-kv__row { display: flex; flex-direction: column; gap: 3px; min-width: 0; }

.cs-kv.is-dense { font-size: 12.5px; }
.cs-kv.is-dense .cs-kv__row { padding: 4px 0; }
.cs-kv.is-dense.cs-kv--grid { gap: 9px 16px; }

/* ══════════════════════════════════════════════════════════════════════════
   StatusDot — la pastille d'etat.

   Quatre copies dans le parc pour cinq lignes de CSS. Le composant expose des
   TONS, jamais un vocabulaire metier : c'est l'application qui sait qu'un
   agent `running` est un point `success`.
   ══════════════════════════════════════════════════════════════════════════ */

.cs-dot-wrap { display: inline-flex; align-items: center; gap: 7px; font-family: var(--cs-font); }
.cs-dot__label { font-size: 12.5px; color: var(--cs-text-2); }
.cs-dot {
  display: inline-block; flex-shrink: 0;
  width: 8px; height: 8px; border-radius: 999px;
  background: var(--cs-muted);
}
.cs-dot--sm { width: 6px; height: 6px; }
.cs-dot--success { background: var(--cs-success); }
.cs-dot--warning { background: var(--cs-warning); }
.cs-dot--danger  { background: var(--cs-danger); }
.cs-dot--info    { background: var(--cs-info); }
.cs-dot--neutral { background: var(--cs-muted); }

/* Le halo : ce que les quatre copies portaient toutes. Il distingue l'etat
   VIVANT du simple « vert » — un daemon en ligne respire, un daemon arrete est
   un point plat. */
.cs-dot.is-pulse { box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 0%, transparent); animation: cs-dot-pulse 2s ease-out infinite; }
.cs-dot--success.is-pulse { animation-name: cs-dot-pulse-success; }
.cs-dot--info.is-pulse { animation-name: cs-dot-pulse-info; }
.cs-dot--warning.is-pulse { animation-name: cs-dot-pulse-warning; }
.cs-dot--danger.is-pulse { animation-name: cs-dot-pulse-danger; }

@keyframes cs-dot-pulse-success {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--cs-success) 45%, transparent); }
  70%  { box-shadow: 0 0 0 5px color-mix(in srgb, var(--cs-success) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--cs-success) 0%, transparent); }
}
@keyframes cs-dot-pulse-info {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--cs-info) 45%, transparent); }
  70%  { box-shadow: 0 0 0 5px color-mix(in srgb, var(--cs-info) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--cs-info) 0%, transparent); }
}
@keyframes cs-dot-pulse-warning {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--cs-warning) 45%, transparent); }
  70%  { box-shadow: 0 0 0 5px color-mix(in srgb, var(--cs-warning) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--cs-warning) 0%, transparent); }
}
@keyframes cs-dot-pulse-danger {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--cs-danger) 45%, transparent); }
  70%  { box-shadow: 0 0 0 5px color-mix(in srgb, var(--cs-danger) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--cs-danger) 0%, transparent); }
}
/* Le halo est un ORNEMENT : il ne porte aucune information que la couleur et
   le libelle ne portent deja. Il s'arrete donc sans rien couter. */
@media (prefers-reduced-motion: reduce) {
  .cs-dot.is-pulse { animation: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Timeline — le fil d'evenements. Cinq implementations dans le parc.
   ══════════════════════════════════════════════════════════════════════════ */

.cs-timeline { margin: 0; padding: 0; list-style: none; font-family: var(--cs-font); }
.cs-timeline__item { position: relative; }
.cs-timeline__body { min-width: 0; }
.cs-timeline__head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.cs-timeline__title { font-size: 13px; font-weight: 600; color: var(--cs-text); }
.cs-timeline__meta {
  font-family: var(--cs-mono);
  font-size: 10.5px; color: var(--cs-muted);
}
.cs-timeline__meta code { background: none; padding: 0; }
/* L'horodatage part a droite : c'est une donnee de reperage, pas de lecture —
   la ranger en fin de ligne laisse le titre commencer au meme endroit partout. */
.cs-timeline__when { margin-left: auto; font-size: 11.5px; color: var(--cs-muted); }
.cs-timeline__text { margin-top: 3px; font-size: 12.5px; line-height: 1.55; color: var(--cs-text-2); }
.cs-timeline__quote {
  margin-top: 7px; padding: 9px 12px;
  background: var(--cs-surface-2); border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius-sm);
  font-size: 12.5px; line-height: 1.55; color: var(--cs-text);
  white-space: pre-wrap;
}
/* Une entree systeme s'efface : elle documente, elle ne se lit pas. */
.cs-timeline__item.is-muted .cs-timeline__title { font-weight: 500; color: var(--cs-text-2); }
.cs-timeline__item.is-muted .cs-timeline__text { color: var(--cs-muted); }

/* -- Rail : le journal. Le glyphe porte la nature, le trait porte la duree. -- */
.cs-timeline--rail .cs-timeline__item { display: flex; gap: 12px; padding-bottom: 16px; }
.cs-timeline--rail .cs-timeline__item:last-child { padding-bottom: 0; }
/* Le trait relie les glyphes SANS depasser du dernier : un rail qui continue
   sous la derniere entree promet une suite qui n'existe pas. */
.cs-timeline--rail .cs-timeline__item::before {
  content: ""; position: absolute; left: 13px; top: 28px; bottom: 0;
  width: 2px; background: var(--cs-border);
}
.cs-timeline--rail .cs-timeline__item:last-child::before { display: none; }
.cs-timeline__glyph {
  position: relative; z-index: 1; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 999px;
  background: var(--cs-surface-2); color: var(--cs-text-2);
  border: 1px solid var(--cs-border);
}
.cs-timeline__glyph svg { width: 14px; height: 14px; }
/* Variante TEXTE comme les quatre autres glyphes : le token de surface donnait
   3.35:1 sur le fond tinte, sous AA. */
.cs-timeline__glyph--info { color: var(--cs-info-text); background: var(--cs-info-bg); border-color: transparent; }
.cs-timeline__glyph--success { color: var(--cs-success-text); background: var(--cs-success-bg); border-color: transparent; }
.cs-timeline__glyph--warning { color: var(--cs-warning-text); background: var(--cs-warning-bg); border-color: transparent; }
.cs-timeline__glyph--danger { color: var(--cs-danger-text); background: var(--cs-danger-bg); border-color: color-mix(in srgb, var(--cs-danger) 35%, transparent); }
.cs-timeline__glyph--accent { color: var(--cs-accent-text); background: var(--cs-accent-soft); border-color: transparent; }
.cs-timeline--rail .cs-timeline__body { padding-top: 4px; }

/* -- Flat : la conversation. Pas de rail — tous les glyphes seraient egaux. -- */
.cs-timeline--flat .cs-timeline__item {
  padding: 9px 0; border-bottom: 1px solid var(--cs-border);
}
.cs-timeline--flat .cs-timeline__item:last-child { border-bottom: 0; }

/* ══════════════════════════════════════════════════════════════════════════
   CodeBlock — bloc de code ou de logs, avec sa copie.
   ══════════════════════════════════════════════════════════════════════════ */

.cs-code {
  border: 1px solid var(--cs-border); border-radius: var(--cs-radius);
  background: var(--cs-sunken); overflow: hidden;
  font-family: var(--cs-font);
}
.cs-code__bar {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 8px 6px 12px;
  border-bottom: 1px solid var(--cs-border);
  background: var(--cs-surface-2);
}
.cs-code__title { font-size: 11.5px; font-weight: 600; color: var(--cs-text-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cs-code__lang {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--cs-muted);
}
.cs-code__copy {
  display: inline-flex; align-items: center; gap: 5px;
  margin-left: auto; flex-shrink: 0;
  height: var(--cs-control-h-sm); padding: 0 9px;
  background: var(--cs-surface); color: var(--cs-text-2);
  border: 1px solid var(--cs-border-strong); border-radius: var(--cs-radius-sm);
  font: inherit; font-size: 11.5px; font-weight: 500;
  cursor: pointer; transition: background .12s, color .12s, border-color .12s;
}
.cs-code__copy:hover { background: var(--cs-surface-hover); color: var(--cs-text); }
.cs-code__copy:focus-visible { outline: 2px solid var(--cs-accent); outline-offset: 1px; }
/* Le retour visuel EST le signal que la copie a eu lieu : sans lui, rien ne
   distingue un succes d'un echec, et l'utilisateur reclique. */
.cs-code__copy.is-done { color: var(--cs-success-text); border-color: color-mix(in srgb, var(--cs-success) 40%, transparent); }
.cs-code__copy svg { width: 13px; height: 13px; }
.cs-code__pre {
  margin: 0; padding: 12px 14px; overflow: auto;
  font-family: var(--cs-mono);
  font-size: 11.5px; line-height: 1.6; color: var(--cs-text-2);
  tab-size: 2;
}
.cs-code__pre code { font: inherit; background: none; padding: 0; }
.cs-code.is-wrap .cs-code__pre { white-space: pre-wrap; overflow-wrap: anywhere; }

/* ══════════════════════════════════════════════════════════════════════════
   Progress — la barre d'avancement. Quatre variantes dans le seul cockpit.
   ══════════════════════════════════════════════════════════════════════════ */

.cs-progress { font-family: var(--cs-font); }
.cs-progress__head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 6px; }
.cs-progress__label { font-size: 12.5px; color: var(--cs-text-2); }
.cs-progress__value {
  margin-left: auto; font-size: 11.5px; font-weight: 600; color: var(--cs-text);
  font-variant-numeric: tabular-nums;
}
.cs-progress__track {
  position: relative; overflow: hidden;
  height: 6px; border-radius: 999px; background: var(--cs-sunken);
}
.cs-progress--sm .cs-progress__track { height: 4px; }
.cs-progress--lg .cs-progress__track { height: 9px; }
.cs-progress__fill {
  display: block; height: 100%; border-radius: 999px;
  background: var(--cs-accent);
  transition: width .3s cubic-bezier(.4, 0, .2, 1);
}
.cs-progress__fill--success { background: var(--cs-success); }
.cs-progress__fill--warning { background: var(--cs-warning); }
.cs-progress__fill--danger  { background: var(--cs-danger); }
.cs-progress__fill--info    { background: var(--cs-info); }

/* Indeterminee : une bande qui traverse en boucle. Elle ne dit pas COMBIEN,
   seulement que quelque chose avance — ce qu'aucune des quatre variantes du
   cockpit ne savait exprimer. */
.cs-progress__track.is-indeterminate .cs-progress__fill {
  width: 35%; transition: none;
  animation: cs-progress-slide 1.3s ease-in-out infinite;
}
@keyframes cs-progress-slide {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(320%); }
}
/* Le mouvement PORTE l'information ici (il dit que ca avance) : on ne le
   supprime pas, on le ralentit et on l'adoucit. */
@media (prefers-reduced-motion: reduce) {
  .cs-progress__fill { transition: none; }
  .cs-progress__track.is-indeterminate .cs-progress__fill { animation-duration: 2.6s; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Avatar — trois implementations dans le parc, dont deux internes au cockpit.
   La couleur est DERIVEE du nom : elle n'aide a reconnaitre quelqu'un que si
   elle est stable d'un ecran a l'autre.
   ══════════════════════════════════════════════════════════════════════════ */

.cs-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0; overflow: hidden;
  width: 30px; height: 30px; border-radius: var(--cs-radius);
  font-family: var(--cs-font); font-size: 11.5px; font-weight: 700;
  letter-spacing: .02em; color: #fff;
  /* Le fond est TOUJOURS pose. Son absence avait rendu le texte blanc
     invisible sur fond clair (#1997) parce que l'appelant etait cense le
     fournir en inline — un correctif qui doit vivre une seule fois. */
  background: var(--cs-accent-solid);
  user-select: none;
}
.cs-avatar__img { width: 100%; height: 100%; object-fit: cover; }
.cs-avatar--xs { width: 22px; height: 22px; font-size: 9px; border-radius: var(--cs-radius-xs); }
.cs-avatar--sm { width: 26px; height: 26px; font-size: 10.5px; }
.cs-avatar--lg { width: 40px; height: 40px; font-size: 14px; border-radius: var(--cs-radius-lg); }

/* Palette categorielle, en TOKENS — meme patron que les `--cs-role-*` de
   #2103/#2105, qui repondaient exactement au meme besoin : des teintes
   distinctives, sans valeur semantique, et thémables comme le reste du kit.
   Les valeurs sont declarees plus haut avec les autres tokens. */
.cs-avatar--violet { background: var(--cs-avatar-violet); }
.cs-avatar--bleu   { background: var(--cs-avatar-bleu); }
.cs-avatar--cyan   { background: var(--cs-avatar-cyan); }
.cs-avatar--vert   { background: var(--cs-avatar-vert); }
.cs-avatar--ambre  { background: var(--cs-avatar-ambre); }
.cs-avatar--rose   { background: var(--cs-avatar-rose); }
.cs-avatar--gris   { background: var(--cs-avatar-gris); }
.cs-avatar--reste  { background: var(--cs-sunken); color: var(--cs-text-2); font-weight: 600; }

/* Groupe : les avatars se chevauchent, chacun detoure sur le fond pour que la
   pile reste lisible. */
.cs-avatar-group { display: inline-flex; align-items: center; }
/* Le recouvrement mange le bord GAUCHE de chaque avatar : son initiale, qui
   est centree, s'y retrouverait a cheval. Deux mesures ensemble — une seule
   lettre dans un groupe (cf. `short` dans le composant) et un decalage de son
   centre vers la partie visible, par un padding compensatoire. */
.cs-avatar-group > .cs-avatar { box-sizing: border-box; }
.cs-avatar-group > .cs-avatar + .cs-avatar { margin-left: -8px; padding-left: 8px; }
.cs-avatar-group > .cs-avatar--xs + .cs-avatar { margin-left: -6px; padding-left: 6px; }
.cs-avatar-group > .cs-avatar--lg + .cs-avatar { margin-left: -12px; padding-left: 12px; }
.cs-avatar-group > .cs-avatar { box-shadow: 0 0 0 2px var(--cs-surface); }

/* ══════════════════════════════════════════════════════════════════════════
   Spinner / Skeleton — l'attente.

   UNE implementation dans tout le parc, sur UNE page, et aucun squelette.
   Quand un kit n'offre pas d'etat de chargement, les pages n'en ont pas.
   ══════════════════════════════════════════════════════════════════════════ */

.cs-spinner-wrap { display: inline-flex; align-items: center; gap: 8px; font-family: var(--cs-font); }
.cs-spinner__label { font-size: 12.5px; color: var(--cs-text-2); }
.cs-spinner {
  display: inline-block; flex-shrink: 0;
  width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid var(--cs-border-strong);
  border-top-color: var(--cs-accent);
  animation: cs-spin .7s linear infinite;
}
.cs-spinner--sm { width: 12px; height: 12px; border-width: 1.5px; }
.cs-spinner--lg { width: 22px; height: 22px; border-width: 2.5px; }
@keyframes cs-spin { to { transform: rotate(360deg); } }
/* Le mouvement EST l'information : il dit qu'on attend. On le ralentit plutot
   que de le supprimer — un spinner fige ressemble a une panne. */
@media (prefers-reduced-motion: reduce) {
  .cs-spinner { animation-duration: 2s; }
}

.cs-skeleton {
  display: block; flex-shrink: 0;
  border-radius: var(--cs-radius-xs);
  background: linear-gradient(90deg,
    var(--cs-sunken) 25%,
    color-mix(in srgb, var(--cs-sunken) 55%, var(--cs-surface)) 37%,
    var(--cs-sunken) 63%);
  background-size: 400% 100%;
  animation: cs-shimmer 1.4s ease-in-out infinite;
}
.cs-skeleton.is-circle { border-radius: 999px; }
.cs-skeleton-text { display: flex; flex-direction: column; gap: 7px; }
@keyframes cs-shimmer {
  0%   { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}
/* Ici le mouvement n'apporte rien qu'une forme grise ne dise deja. */
@media (prefers-reduced-motion: reduce) {
  .cs-skeleton { animation: none; background: var(--cs-sunken); }
}

/* ══════════════════════════════════════════════════════════════════════════
   SettingsGroup — la carte de reglages. Huit fichiers la reecrivent.
   ══════════════════════════════════════════════════════════════════════════ */

.cs-settings {
  background: var(--cs-surface);
  border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius-lg);
  overflow: hidden;
  box-shadow: var(--cs-shadow-sm);
  font-family: var(--cs-font);
}
.cs-settings__head {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 14px 18px; border-bottom: 1px solid var(--cs-border);
}
.cs-settings__head-text { flex: 1; min-width: 0; }
.cs-settings__title { margin: 0; font-size: 13.5px; font-weight: 650; color: var(--cs-text); }
.cs-settings__desc { margin: 3px 0 0; font-size: 12px; color: var(--cs-muted); line-height: 1.5; }
.cs-settings__head-actions { flex-shrink: 0; }

.cs-setting {
  display: flex; align-items: center; gap: 18px;
  padding: 13px 18px; border-bottom: 1px solid var(--cs-border);
}
.cs-setting:last-child { border-bottom: 0; }
.cs-setting__text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cs-setting__label { font-size: 13px; font-weight: 500; color: var(--cs-text); }
/* La description n'est pas decorative : un reglage dont on ne sait pas ce
   qu'il fait ne se touche pas. */
.cs-setting__hint { font-size: 11.5px; color: var(--cs-muted); line-height: 1.5; }
.cs-setting__control { flex-shrink: 0; }
.cs-setting.is-danger .cs-setting__label { color: var(--cs-danger-text); }
/* Le conteneur est declare ICI, sur `__body` : sans lui, la requete ci-dessous
   etait ANONYME et visait le conteneur ancetre le plus proche — le shell
   entier dans un `AppShell`, et rien du tout ailleurs (modale, panneau, page
   nue). Elle ne se declenchait donc jamais pour le cas qu'elle decrit : une
   carte etroite dans une page large.
   Sur `__body` plutot que `.cs-settings`, qui porte `overflow: hidden` et un
   `border-radius` : `container-type` y ajouterait un confinement inutile. */
.cs-settings__body { container-type: inline-size; container-name: cs-settings; }

/* Sur une carte etroite, le controle passe dessous plutot que d'ecraser le
   libelle : un bouton de 90px face a un libelle tronque a trois mots ne rend
   service a personne. */
@container cs-settings (max-width: 520px) {
  .cs-setting { flex-direction: column; align-items: stretch; gap: 9px; }
  .cs-setting__control { align-self: flex-start; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Segmented — le choix exclusif. `sh-seg` (soude) et `dc-chip` (pilules).
   ══════════════════════════════════════════════════════════════════════════ */

.cs-segmented {
  display: inline-flex; padding: 3px; gap: 2px;
  background: var(--cs-sunken); border-radius: var(--cs-radius);
  font-family: var(--cs-font);
}
.cs-segmented__opt {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--cs-control-h-sm); padding: 0 11px;
  border: 0; border-radius: var(--cs-radius-sm);
  background: transparent; color: var(--cs-text-2);
  font: inherit; font-size: 12.5px; font-weight: 500;
  cursor: pointer; white-space: nowrap;
  transition: background .12s, color .12s;
}
.cs-segmented__opt:hover:not(:disabled) { color: var(--cs-text); }
.cs-segmented__opt:focus-visible { outline: 2px solid var(--cs-accent); outline-offset: -1px; }
.cs-segmented__opt:disabled { opacity: .5; cursor: not-allowed; }
/* L'option retenue est SURELEVEE, pas seulement coloree : elle se lit comme
   une position dans un ensemble, pas comme un bouton actif isole. */
.cs-segmented__opt.is-on {
  background: var(--cs-surface); color: var(--cs-text); font-weight: 600;
  box-shadow: var(--cs-shadow-sm);
}
.cs-segmented__icon { display: inline-flex; width: 14px; height: 14px; }
.cs-segmented__icon svg { width: 14px; height: 14px; }
.cs-segmented--sm .cs-segmented__opt { min-height: var(--cs-control-h-xs); padding: 0 9px; font-size: 11.5px; }

/* ══════════════════════════════════════════════════════════════════════════
   CountPill — un NOMBRE. Distinct de Badge, qui porte un ETAT.
   ══════════════════════════════════════════════════════════════════════════ */

.cs-count {
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0; min-width: 20px; padding: 1px 7px;
  border-radius: 999px;
  background: var(--cs-sunken); color: var(--cs-text-2);
  font-family: var(--cs-font); font-size: 11px; font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.cs-count--accent { background: var(--cs-accent-soft); color: var(--cs-accent-text); }
.cs-count--danger { background: var(--cs-danger-bg); color: var(--cs-danger-text); }
.cs-count--success { background: var(--cs-success-bg); color: var(--cs-success-text); }
.cs-segmented__opt.is-on .cs-count { background: var(--cs-sunken); }
