/* ============================================================
   Prospectra (prospectra.cloud) — overrides spécifiques
   Chargé APRÈS theme.css + ps.theme.light.css.
   Ne duplique pas les tokens — consomme les CSS vars.
   ============================================================ */

/* --- Layout global (Lot 14.f — shell sidebar) ---
   Pre-Lot 14.f : body flex column + main.app-main centered max-width:1240px.
   Lot 14.f : grid `.ps-shell` 240px sidebar + 1fr canvas. main.app-main
   garde sa propre largeur (full canvas remaining), padding ajusté.
   Token `--ps-sidebar-width` pour cohérence + tweakable par theme override.
   Sur viewport ≤1024px : grid collapse en 1 colonne, sidebar bascule en
   drawer overlay déclenché par #ps-sidebar-toggle (hamburger top-left). */
:root {
  --ps-sidebar-width: 240px;
}
html, body { height: 100%; }
body {
  min-height: 100vh;
}

.ps-shell {
  display: grid;
  grid-template-columns: var(--ps-sidebar-width) 1fr;
  min-height: 100vh;
}

/* Lot 14.f — Wrapper de la colonne canvas (parent stable des banners
   dynamiques `#budget-banner-host` + `#onboarding-banner-host` injectés
   par app.js). Sans ce wrapper, viewHost.parentNode serait `.ps-shell`
   et les banners tomberaient dans la colonne sidebar. `min-width: 0`
   est critique : sans ça, les vues avec contenu large (table prospects,
   chart dashboard) débordent la grille au lieu d'activer le scroll
   interne. */
.app-canvas {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

main.app-main {
  width: 100%;
  padding: 32px 40px 80px;
  min-width: 0; /* anti grid overflow */
}

/* ============================================================
   Lot 14.f — Sidebar verticale gauche (refonte UI shell 2026-05-11)
   ============================================================
   Remplace l'ancien <header class="ps-header"> horizontal.
   3 sections : workspace (top) | nav (middle, scrollable) | profile (bottom sticky).
   Drawer mobile ≤1024px via class `.is-sidebar-open` posée sur `.ps-shell`. */

.ps-sidebar {
  position: sticky;
  top: 0;
  height: 100vh;
  border-right: 1px solid var(--border);
  background: var(--surface);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  z-index: 50;
}

.ps-sidebar-workspace {
  padding: 22px 18px 14px;
  border-bottom: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.ps-sidebar-nav {
  flex: 1 1 auto;
  padding: 12px 14px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.ps-sidebar-profile {
  padding: 14px 18px 18px;
  border-top: 1px solid var(--border);
  position: sticky;
  bottom: 0;
  background: var(--surface);
}

/* ─── Brand (sidebar workspace block) ─── */
.ps-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 2px 4px;
  text-decoration: none;
  color: var(--text);
}
.ps-brand-mark {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  background: linear-gradient(135deg, var(--accent), #7C3AED);
  display: grid;
  place-items: center;
  color: #fff;
  font-weight: 700;
  font-family: 'DM Sans', sans-serif;
  font-size: .95rem;
  flex-shrink: 0;
}
.ps-brand-text {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
  min-width: 0;
}
.ps-brand-name {
  font-weight: 600;
  font-family: 'DM Sans', sans-serif;
  font-size: 1rem;
  letter-spacing: -.01em;
  color: var(--text);
}
.ps-brand-sub {
  font-family: 'DM Mono', monospace;
  font-size: .65rem;
  /* Lot 14.k.3 — axe-core color-contrast WCAG 2.1 AA fix. var(--text3) = #8B90B5
     sur surface #F7F8FC = 2.92:1 (insuffisant pour 4.5:1 AA texte normal).
     Override scoped sidebar (les tokens globaux restent inchangés pour ne pas
     impacter le reste de l'app — d'autres scopes seront couverts lot par lot). */
  color: #666B8E;
  text-transform: uppercase;
  letter-spacing: .1em;
  margin-top: 2px;
}

/* ─── Workspace tenant label + super chip ─── */
.ps-workspace-tenant {
  font-size: .8rem;
  color: var(--text2);
  padding: 2px 4px;
  min-height: 0;
}
.ps-workspace-tenant:empty {
  display: none;
}
.ps-workspace-super-chip {
  align-self: flex-start;
  /* Lot 14.k.3 — color override déclaré en specificity 0,2,0 plus bas (cf.
     `.chip.ps-workspace-super-chip` près de `.chip.c-accent` L1051), pour
     gagner le combat de cascade contre `.chip.c-accent` qui sinon écrase. */
}

/* ─── Nav groups ─── */
.ps-nav-group {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.ps-nav-group + .ps-nav-group {
  margin-top: 10px;
}
.ps-nav-label {
  font-family: 'DM Mono', monospace;
  font-size: .65rem;
  font-weight: 500;
  /* Lot 14.k.3 — axe-core color-contrast WCAG 2.1 AA fix (cf. .ps-brand-sub). */
  color: #666B8E;
  text-transform: uppercase;
  letter-spacing: .12em;
  padding: 10px 8px 6px;
}
.ps-nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 7px;
  font-size: .87rem;
  font-weight: 500;
  color: var(--text2);
  text-decoration: none;
  transition: background .15s, color .15s;
}
/* Dot accent via pseudo-element (anti-effacement par translatePage qui
   pose el.textContent ; cf. i18n.js — un span enfant serait wipé). */
.ps-nav-item::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--border2, var(--border));
  flex-shrink: 0;
  transition: background .15s;
}
.ps-nav-item:hover {
  background: var(--surface2);
  color: var(--text);
}
.ps-nav-item.is-active {
  background: var(--bg);
  color: var(--text);
  box-shadow: 0 1px 0 var(--border), 0 4px 12px -8px rgba(15,17,35,.12);
}
.ps-nav-item.is-active::before {
  background: var(--accent);
}
.ps-nav-item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* Span count badge optionnel (`PS.sidebar.setNavCount(view, n)` Lot 14.f
   crée un <span class="ps-nav-count"> à la volée si appelé). */
.ps-nav-count {
  margin-left: auto;
  font-family: 'DM Mono', monospace;
  font-size: .72rem;
  font-weight: 500;
  color: var(--text3, var(--text2));
}

/* --- Badge mode (démo / production) — permanent, toujours visible ---
   Rationale (Lot 3) :
   * En DÉMO : rouge + pastille pulsante + curseur pointeur/aide = rappel
     constant que les envois sont redirigés (aucun mail chez le prospect).
     On ne veut PAS qu'un admin oublie et envoie une campagne "par erreur".
   * En PROD : vert stable (pas de pulse) = confirmation calme que la
     config est active. Pulser en prod serait anxiogène inutile.
   La pulse est appliquée sur la pastille (::before), pas le badge entier,
   pour ne pas créer d'animation distractive sur tout le shell.
   Lot 14.f : badge re-positionné dans `.ps-sidebar-workspace` (plus dans
   header top-right) — styles inchangés, contexte différent. */
.mode-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 20px;
  font-family: 'DM Mono', monospace;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  line-height: 1;
  cursor: help; /* l'attribut title sera posé par app.js */
  align-self: flex-start;
}
.mode-badge.is-demo {
  background: rgba(255,71,87,.12);
  /* Lot 14.k.3 — axe-core color-contrast WCAG 2.1 AA fix. var(--danger) = #DC2626
     sur fond chip rendu #F8E3E8 = 3.94:1 (insuffisant pour 4.5:1 AA texte normal).
     Override darken vers #C81717 → ratio ~4.78:1. Scope ciblé .is-demo (la --danger
     globale reste #DC2626 pour les autres usages : .form-error, .toast-error, etc.
     qui ont leurs propres fonds et passent déjà WCAG). */
  color: #C81717;
  border: 1px solid rgba(255,71,87,.4);
}
.mode-badge.is-prod {
  background: rgba(46,213,115,.12);
  color: var(--success);
  border: 1px solid rgba(46,213,115,.4);
}
.mode-badge::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 8px currentColor;
}
.mode-badge.is-demo::before {
  animation: mode-pulse 1.8s ease-in-out infinite;
}
@keyframes mode-pulse {
  0%, 100% { opacity: 1;   transform: scale(1); }
  50%      { opacity: .45; transform: scale(.75); }
}
@media (prefers-reduced-motion: reduce) {
  .mode-badge.is-demo::before { animation: none; }
}

/* ─── Sidebar toggle (mobile hamburger ≤1024px) ─── */
.ps-sidebar-toggle {
  position: fixed;
  top: 14px;
  left: 14px;
  z-index: 100;
  width: 40px;
  height: 40px;
  border-radius: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  display: none;
  cursor: pointer;
  font-size: 1.25rem;
  color: var(--text);
  align-items: center;
  justify-content: center;
}
.ps-sidebar-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ─── Profile menu locale sub-section (Lot 14.f) ─── */
.profile-menu-locale {
  padding: 4px 6px;
}
.profile-menu-locale-label {
  font-family: 'DM Mono', monospace;
  font-size: .65rem;
  font-weight: 500;
  color: var(--text3, var(--text2));
  text-transform: uppercase;
  letter-spacing: .1em;
  padding: 4px 6px 6px;
}
.profile-menu-locale-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.profile-menu-locale-list button[data-locale] {
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  padding: 6px 8px;
  border-radius: 6px;
  font-size: .85rem;
  color: var(--text);
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
}
.profile-menu-locale-list button[data-locale]:hover {
  background: var(--surface2);
}
.profile-menu-locale-list button[data-locale].is-active {
  color: var(--accent);
  font-weight: 600;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.profile-menu-locale-list .locale-flag {
  font-size: 1rem;
  line-height: 1;
  flex-shrink: 0;
}

/* ─── Responsive (≤1024px : sidebar drawer) ─── */
@media (max-width: 1024px) {
  .ps-shell {
    grid-template-columns: 1fr;
  }
  .ps-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 90;
    width: 280px;
    max-width: 80vw;
    height: 100vh;
    transform: translateX(-100%);
    transition: transform .25s ease;
    box-shadow: 8px 0 24px -12px rgba(0,0,0,.18);
  }
  .ps-shell.is-sidebar-open .ps-sidebar {
    transform: translateX(0);
  }
  .ps-shell.is-sidebar-open::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 85;
    background: rgba(15, 17, 35, .35);
    backdrop-filter: blur(2px);
  }
  body.is-sidebar-locked {
    overflow: hidden;
  }
  .ps-sidebar-toggle {
    display: inline-flex;
  }
  main.app-main {
    padding: 64px 20px 48px;
  }
}

/* R4-LOW-1 amigos — Respect `prefers-reduced-motion` sur le drawer mobile.
   Sans ça, les users a11y voient l'animation 0.25s à chaque open/close,
   ce qui est exclu par leur préférence système (vestibular disorders). */
@media (prefers-reduced-motion: reduce) {
  .ps-sidebar {
    transition: none;
  }
}

/* Lot 14.k R1-A11Y-MED-2 — Touch target WCAG 2.5.5 AAA 44×44 CSS px sur
   pointer:coarse (tactile mobile/tablette). Desktop souris garde le compact
   ~38px (padding:8px 10px + font:.87rem ligne ~1.3 = ~38px). On utilise
   `pointer:coarse` plutôt qu'un breakpoint width : un user tactile sur
   grand écran bénéficie aussi du fix (Surface, iPad Pro), un user souris
   sur petit laptop garde le compact. Pattern aligné avec `.btn-sm` théme.css L67. */
@media (pointer: coarse) {
  .ps-nav-item {
    min-height: 44px;
  }
  .ps-sidebar-toggle {
    min-width: 44px;
    min-height: 44px;
  }
}

/* Lot 14.k R1-A11Y-MED-3 — Skip-link WCAG 2.4.1 "Bypass blocks". Premier
   élément focusable du document → Tab depuis page load focus le skip-link.
   Hors-viewport par défaut (top: -100%), visible quand focusé. Cible
   `#view-host` (le <main> SPA, parité app.html + admin.html). Sans ça,
   un user clavier doit Tab à travers les 12 nav-items + workspace pour
   atteindre le contenu principal. */
.ps-skip-link {
  position: fixed;
  top: -100px;
  left: 16px;
  z-index: 999;
  padding: 10px 18px;
  border-radius: 8px;
  background: var(--accent);
  color: #fff;
  font-family: 'DM Sans', sans-serif;
  font-size: .9rem;
  font-weight: 600;
  text-decoration: none;
  box-shadow: 0 4px 14px rgba(91, 106, 208, .35);
  transition: top .15s ease-in-out;
}
.ps-skip-link:focus,
.ps-skip-link:focus-visible {
  top: 12px;
  outline: 2px solid #fff;
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .ps-skip-link { transition: none; }
}

/* --- Login card --- */
.login-wrap {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px 20px;
}
.login-card {
  width: 100%;
  max-width: 420px;
  padding: 32px 30px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: 0 8px 40px rgba(0,0,0,.06);
}
.login-card h1 {
  font-family: 'DM Sans', sans-serif;
  font-size: 1.5rem;
  font-weight: 700;
  margin-bottom: 4px;
}
.login-card .login-sub {
  color: var(--text2);
  font-size: .88rem;
  margin-bottom: 24px;
}
.login-card .form-row { margin-bottom: 16px; }
.login-card .form-input { width: 100%; }
.login-card .login-error {
  display: none;
  margin-top: 14px;
  padding: 10px 12px;
  background: rgba(255,71,87,.08);
  border: 1px solid rgba(255,71,87,.3);
  border-radius: 8px;
  color: var(--danger);
  font-size: .85rem;
}
.login-card .login-error.is-visible { display: block; }
/* Lot 14.c — message vert succès anti-enum (forgot-password) */
.login-card .login-success {
  display: none;
  margin-top: 14px;
  padding: 10px 12px;
  border: 1px solid var(--success);
  background: color-mix(in srgb, var(--success) 10%, transparent);
  border-radius: 8px;
  color: var(--success);
  font-size: .85rem;
  line-height: 1.4;
}
.login-card .login-success.is-visible { display: block; }
.login-card .btn { width: 100%; justify-content: center; margin-top: 10px; }
/* Lot 14.c — lien "Mot de passe oublié ?" sous le bouton login */
.login-card .login-forgot {
  margin-top: 14px;
  text-align: center;
  font-size: .82rem;
}
.login-card .login-forgot a {
  color: var(--text2);
  text-decoration: none;
  border-bottom: 1px dashed var(--text2);
}
.login-card .login-forgot a:hover {
  color: var(--text);
  border-bottom-color: var(--text);
}
.login-footer {
  text-align: center;
  color: var(--text2);
  font-size: .75rem;
  margin-top: 24px;
  font-family: 'DM Mono', monospace;
  letter-spacing: .04em;
}
/* Lot 14.e — lien KB sous le footer login. Style miroir `.login-forgot`
   (pattern `dashed underline + text2`) pour cohérence visuelle. Le lien
   KB est secondaire (l'action principale = login), donc ton subdued. */
.login-card .login-kb-link {
  margin-top: 12px;
  text-align: center;
  font-size: .82rem;
}
.login-card .login-kb-link a {
  color: var(--text2);
  text-decoration: none;
  border-bottom: 1px dashed var(--text2);
}
.login-card .login-kb-link a:hover {
  color: var(--text);
  border-bottom-color: var(--text);
}
/* Lot 14.c — pages forgot/reset : footer contient un lien retour login */
.login-footer a {
  color: var(--text2);
  text-decoration: none;
  border-bottom: 1px dashed var(--text2);
  font-family: 'DM Sans', sans-serif;
  letter-spacing: 0;
}
.login-footer a:hover {
  color: var(--text);
  border-bottom-color: var(--text);
}

/* --- Lot 11.h — Footer légal pages auth (public) --- */
.auth-legal-footer {
  margin: 18px auto 0;
  max-width: 420px;
  padding: 14px 16px 0;
  border-top: 1px solid var(--border, #e3e6ea);
  text-align: center;
  font-size: .78rem;
  color: var(--text2);
  font-family: 'DM Sans', sans-serif;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.auth-legal-footer a {
  color: var(--text2);
  text-decoration: none;
  border-bottom: 1px dashed var(--text2);
  padding: 0 2px;
}
.auth-legal-footer a:hover {
  color: var(--text);
  border-bottom-color: var(--text);
}

/* Lot 11.h — Checkbox CGU sur signup / accept-invitation. */
.form-row-checkbox {
  font-size: .85rem;
  color: var(--text2);
  margin-top: 4px;
}
.form-checkbox-label {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  cursor: pointer;
}
.form-checkbox-label input[type='checkbox'] {
  margin-top: 3px;
  flex-shrink: 0;
}
.form-checkbox-label a {
  color: var(--brand-2, #2c5cdd);
  text-decoration: underline;
}

/* Lot 11.h — Footer légal sidebar (app + admin). Compact, discret. */
.ps-sidebar-legal-footer {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--border, #e3e6ea);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 4px;
  font-size: .72rem;
  color: var(--text2);
  font-family: 'DM Sans', sans-serif;
}
.ps-sidebar-legal-footer a {
  color: var(--text2);
  text-decoration: none;
  padding: 0 2px;
}
.ps-sidebar-legal-footer a:hover {
  color: var(--text);
  text-decoration: underline;
}

/* --- Cockpit dashboard cards --- */
.cockpit-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 18px;
  margin-top: 24px;
}
.cockpit-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 20px;
}
.cockpit-card h3 {
  font-family: 'DM Mono', monospace;
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--text2);
  margin-bottom: 10px;
}
.cockpit-card .value {
  font-family: 'DM Sans', sans-serif;
  font-size: 1.8rem;
  font-weight: 700;
  color: var(--text);
}

/* --- Empty state pages --- */
.empty-state {
  text-align: center;
  padding: 60px 20px;
  color: var(--text2);
}
.empty-state h2 {
  font-family: 'DM Sans', sans-serif;
  color: var(--text);
  margin-bottom: 8px;
}

/* --- Toast --- */
.toast-host {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  gap: 10px;
  pointer-events: none;
}
.toast {
  padding: 12px 16px;
  border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: 0 4px 18px rgba(0,0,0,.08);
  font-size: .88rem;
  min-width: 240px;
  max-width: 360px;
  pointer-events: auto;
  animation: toast-in .25s ease-out;
}
.toast.is-error  { border-color: rgba(255,71,87,.4);  color: var(--danger); }
.toast.is-ok     { border-color: rgba(46,213,115,.4); color: var(--success); }
.toast.is-warn   { border-color: rgba(255,165,2,.4);  color: var(--warning); }
@keyframes toast-in {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* --- Bouton occupé (pendant fetch) --- */
/* Posé par PS.ui.lockWhile — pattern défense-en-profondeur : le bouton
 * est déjà `disabled`, mais on ajoute une indication visuelle (spinner)
 * pour que l'utilisateur comprenne que son clic a été pris en compte
 * et qu'un retour arrive. Sans cela, un cliqueur impatient frappe Enter
 * plusieurs fois, pensant que rien ne se passe. */
.btn.is-busy {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}
.btn.is-busy::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 14px; height: 14px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  color: var(--text);
  animation: btn-spin 0.8s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

/* --- Utilitaires --- */
.mt-0 { margin-top: 0 !important; }
.mt-1 { margin-top: 8px; }
.mt-2 { margin-top: 16px; }
.mt-3 { margin-top: 24px; }
.mt-4 { margin-top: 32px; }
.mb-1 { margin-bottom: 8px; }
.mb-2 { margin-bottom: 16px; }
.mb-3 { margin-bottom: 24px; }
.flex       { display: flex; }
.flex-col   { display: flex; flex-direction: column; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.gap-1 { gap: 8px; }
.gap-2 { gap: 16px; }
.gap-3 { gap: 24px; }
.grow { flex: 1; }
.hidden { display: none !important; }
.text-sm { font-size: .85rem; }
.text-muted { color: var(--text2); }
.text-danger { color: var(--danger); }
.text-success { color: var(--success); }
.mono { font-family: 'DM Mono', monospace; font-size: .82rem; }
.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;
}

/* ============================================================
   Composants UI additionnels (console super-admin + app tenant)
   ============================================================ */

/* --- Domain switcher (dropdown dans le header tenant) --- */
.domain-switcher {
  position: relative;
}
.domain-switcher-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 8px;
  background: var(--surface-2, rgba(0,0,0,.04));
  border: 1px solid var(--border);
  color: var(--text);
  font-size: .85rem;
  font-weight: 500;
  cursor: pointer;
}
.domain-switcher-btn::after {
  content: '▾';
  font-size: .75rem;
  color: var(--text2);
  margin-left: 2px;
}
.domain-switcher-btn:hover { border-color: var(--text2); }
.domain-switcher-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  min-width: 240px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 32px rgba(0,0,0,.1);
  padding: 6px;
  z-index: 100;
  display: none;
}
.domain-switcher.is-open .domain-switcher-menu { display: block; }
.domain-switcher-menu button {
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  padding: 8px 10px;
  border-radius: 6px;
  font-size: .88rem;
  color: var(--text);
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
}
.domain-switcher-menu button:hover { background: var(--surface-2, rgba(0,0,0,.04)); }
.domain-switcher-menu button.is-active { color: var(--accent); font-weight: 600; }
.domain-switcher-menu .menu-sep {
  height: 1px;
  background: var(--border);
  margin: 4px 0;
}
.domain-switcher-menu .menu-hint {
  font-size: .7rem;
  color: var(--text2);
  padding: 6px 10px;
  font-family: 'DM Mono', monospace;
  text-transform: uppercase;
  letter-spacing: .06em;
}

/* --- Profile switcher (Lot 14.a) ---------------------------------
   Dropdown header pour le menu profil : email + role + last_login +
   Change password + Logout. Pattern parité domain-switcher /
   locale-switcher (mêmes patterns position absolute, same z-index,
   même visual coherence).

   Différences vs domain-switcher :
   - profile-switcher-btn affiche un avatar/email tronqué (vs nom de
     domaine).
   - profile-menu-header (premier bloc) NON cliquable — read-only avec
     email + role + last_login.
   - profile-menu-section sépare les blocs (header info | actions). */
.profile-switcher {
  position: relative;
}
.profile-switcher-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 8px;
  background: var(--surface-2, rgba(0,0,0,.04));
  border: 1px solid var(--border);
  color: var(--text);
  font-size: .85rem;
  font-weight: 500;
  cursor: pointer;
  max-width: 240px;
}
.profile-switcher-btn::after {
  content: '▾';
  font-size: .75rem;
  color: var(--text2);
  margin-left: 2px;
}
.profile-switcher-btn:hover { border-color: var(--text2); }
.profile-switcher-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.profile-switcher-email {
  display: inline-block;
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
}
.profile-switcher-menu {
  /* Lot 14.k.fix — `position: fixed` (vs `absolute` historique) pour
     échapper au clipping `overflow-y: auto` de `.ps-sidebar` parent.
     Le menu ouvre vers le HAUT (au-dessus du bouton) car le bouton est
     en bas de la sidebar sticky. Position exacte (left/bottom) calculée
     par `app.profile.js positionMenu()` au moment du open, recalculée
     au resize/scroll. Fallback `bottom: 80px; left: 16px` au cas où le
     JS n'a pas encore tiré (transition initiale) — évite un flash à
     coordonnées (0,0). */
  position: fixed;
  bottom: 80px;
  left: 16px;
  min-width: 280px;
  max-width: min(360px, calc(100vw - 24px));
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 32px rgba(0,0,0,.18);
  padding: 6px;
  z-index: 200;
  display: none;
}
.profile-switcher.is-open .profile-switcher-menu { display: block; }
.profile-switcher-menu button[role="menuitem"] {
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  padding: 8px 10px;
  border-radius: 6px;
  font-size: .88rem;
  color: var(--text);
  cursor: pointer;
  display: block;
}
.profile-switcher-menu button[role="menuitem"]:hover {
  background: var(--surface-2, rgba(0,0,0,.04));
}
.profile-switcher-menu .menu-sep {
  height: 1px;
  background: var(--border);
  margin: 4px 0;
}
.profile-menu-section {
  padding: 8px 10px;
}
.profile-menu-header strong {
  display: inline-block;
  max-width: 240px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}
.profile-menu-meta {
  margin-top: 2px;
}
.profile-menu-meta + .profile-menu-meta {
  margin-top: 0;
}

/* --- Section heading --- */
.section-tag {
  display: inline-block;
  font-family: 'DM Mono', monospace;
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--accent);
  margin-bottom: 6px;
}
.section-title {
  font-family: 'DM Sans', sans-serif;
  font-size: 1.5rem;
  font-weight: 700;
  margin-bottom: 4px;
}
.section-sub {
  color: var(--text2);
  font-size: .9rem;
  margin-bottom: 24px;
}

/* --- Tabs horizontales (admin console, settings) --- */
.tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 24px;
  overflow-x: auto;
}
.tabs button {
  background: transparent;
  border: 0;
  padding: 10px 16px;
  font-size: .88rem;
  font-weight: 500;
  color: var(--text2);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
}
.tabs button:hover { color: var(--text); }
.tabs button.is-active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* --- Data table --- */
.data-table-wrap {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  /* a11y (Lot 12.c.a11y) : `overflow-x: auto` permet le scroll horizontal
     sur mobile (375px) quand la table a 4+ colonnes. Avant le fix, le
     `overflow: hidden` écrasait silencieusement les colonnes hors-écran —
     le user mobile ne pouvait pas voir/atteindre les actions à droite
     (boutons éditer/supprimer). overflow-y reste auto via spec CSS
     (auto/visible computés en auto/auto), ce qui préserve le clipping
     border-radius sur les coins haut/bas. */
  overflow-x: auto;
}
.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: .88rem;
}
.data-table thead {
  background: var(--surface-2, rgba(0,0,0,.03));
}
.data-table th {
  text-align: left;
  padding: 12px 14px;
  font-family: 'DM Mono', monospace;
  font-size: .72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text2);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.data-table td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  vertical-align: top;
}
.data-table tr:last-child td { border-bottom: 0; }
.data-table tbody tr:hover { background: var(--surface-2, rgba(0,0,0,.02)); }
.data-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.data-table .actions { text-align: right; white-space: nowrap; }
.data-table .actions .btn-sm { margin-left: 4px; }

/* --- Status chips --- */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 12px;
  font-family: 'DM Mono', monospace;
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
  border: 1px solid var(--border);
  background: var(--surface-2, rgba(0,0,0,.03));
  color: var(--text2);
}
.chip.c-success { color: var(--success); border-color: rgba(46,213,115,.4); background: rgba(46,213,115,.08); }
.chip.c-warn    { color: var(--warning); border-color: rgba(255,165,2,.4);  background: rgba(255,165,2,.08); }
.chip.c-danger  { color: var(--danger);  border-color: rgba(255,71,87,.4);  background: rgba(255,71,87,.08); }
.chip.c-accent  { color: var(--accent);  border-color: rgba(102,126,234,.4); background: rgba(102,126,234,.08); }
/* Lot 14.k.3 — axe-core color-contrast WCAG 2.1 AA fix : .chip.c-accent applique
   color: var(--accent) = #5B6AD0 (light) sur fond chip rendu #EBEEFB = 4.11:1
   (insuffisant). Override darken vers #4756B5 → ratio ~5.53:1. Specificity 0,2,0
   ÉGALE à `.chip.c-accent` mais déclaré APRÈS dans la cascade → wins.
   Scope limité au shell (autres usages `.chip.c-accent` ailleurs gardent leur
   couleur originale — leur contraste sera audité par sous-lots dédiés). */
.chip.ps-workspace-super-chip { color: #4756B5; }

/* --- Modals --- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.5);
  backdrop-filter: blur(4px);
  z-index: 200;
  display: none;
  align-items: flex-start;
  justify-content: center;
  padding: 60px 20px 20px;
  overflow-y: auto;
}
.modal-backdrop.is-open { display: flex; }
.modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  max-width: 560px;
  width: 100%;
  padding: 28px;
  box-shadow: 0 20px 60px rgba(0,0,0,.2);
  animation: modal-in .2s ease-out;
}
.modal.is-lg { max-width: 780px; }
.modal-title {
  font-family: 'DM Sans', sans-serif;
  font-size: 1.25rem;
  font-weight: 700;
  margin-bottom: 4px;
}
.modal-sub {
  color: var(--text2);
  font-size: .88rem;
  margin-bottom: 20px;
}
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 20px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
@keyframes modal-in {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* --- Two-column layout (list + detail) --- */
.split-view {
  display: grid;
  grid-template-columns: minmax(280px, 340px) 1fr;
  gap: 24px;
  align-items: flex-start;
}
@media (max-width: 900px) {
  .split-view { grid-template-columns: 1fr; }
}

/* --- Form helpers pour cartes de réglages --- */
.form-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 24px;
  margin-bottom: 20px;
}
.form-card h3 {
  font-family: 'DM Sans', sans-serif;
  font-size: 1.05rem;
  font-weight: 700;
  margin-bottom: 4px;
}
.form-card .form-card-sub {
  color: var(--text2);
  font-size: .85rem;
  margin-bottom: 20px;
}
.form-grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
@media (max-width: 640px) {
  .form-grid-2 { grid-template-columns: 1fr; }
}
.form-hint {
  font-size: .78rem;
  color: var(--text2);
  margin-top: 6px;
}
.form-check {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: .88rem;
  user-select: none;
}
.form-check input[type="checkbox"] { width: 16px; height: 16px; cursor: pointer; }

/* --- Ticket / messages thread --- */
.ticket-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: calc(100vh - 260px);
  overflow-y: auto;
  padding-right: 4px;
}
.ticket-item {
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background .15s, border-color .15s;
}
.ticket-item:hover { background: var(--surface-2, rgba(0,0,0,.03)); }
.ticket-item.is-active {
  background: var(--surface-2, rgba(0,0,0,.04));
  border-color: var(--border);
}
.ticket-item .subject {
  font-weight: 600;
  font-size: .92rem;
  color: var(--text);
  margin-bottom: 4px;
}
.ticket-item .meta {
  font-size: .75rem;
  color: var(--text2);
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.ticket-message {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
  margin-bottom: 12px;
}
.ticket-message.is-staff { border-color: rgba(102,126,234,.3); background: rgba(102,126,234,.04); }
.ticket-message.is-note { border-color: rgba(255,165,2,.3); background: rgba(255,165,2,.06); }
.ticket-message .author {
  font-weight: 600;
  font-size: .85rem;
  margin-bottom: 2px;
}
.ticket-message .ts {
  font-size: .7rem;
  color: var(--text2);
  margin-bottom: 8px;
  font-family: 'DM Mono', monospace;
}
.ticket-message .body {
  font-size: .92rem;
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
}

/* --- Prospects table compact --- */
.prospects-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.prospects-toolbar .search-input { min-width: 240px; }

/* --- Dropzone CSV --- */
.dropzone {
  border: 2px dashed var(--border);
  border-radius: 12px;
  padding: 40px 20px;
  text-align: center;
  color: var(--text2);
  cursor: pointer;
  transition: border-color .2s, background .2s;
  background: var(--surface);
}
.dropzone:hover,
.dropzone.is-dragover {
  border-color: var(--accent);
  background: rgba(102,126,234,.04);
  color: var(--text);
}
.dropzone input[type="file"] { display: none; }

/* ============================================================
   Campaign Monitor (Lot 5.4) — timeline SSE temps-réel
   ============================================================ */
.ps-view { padding: 16px; max-width: 1200px; margin: 0 auto; }
.ps-view-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 8px;
}
.ps-view-head h1 { margin: 0; font-size: 1.4rem; }
.ps-view-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.ps-view-hint {
  color: var(--text-muted, #7a7f8a);
  font-size: .9rem;
  margin: 4px 0 16px;
}

.ps-timeline {
  display: flex; flex-direction: column; gap: 4px;
  max-height: calc(100vh - 220px);
  overflow-y: auto;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 8px;
  padding: 8px;
  background: var(--surface, #fff);
}
.ps-timeline-empty {
  padding: 24px; text-align: center;
  color: var(--text-muted, #7a7f8a);
}
.ps-timeline-row {
  border-left: 3px solid var(--border, #e5e7eb);
  padding: 6px 10px;
  border-radius: 4px;
  transition: background .15s;
}
.ps-timeline-row:hover { background: rgba(0,0,0,.02); }
.ps-timeline-head {
  display: flex; gap: 10px; align-items: baseline;
  cursor: pointer;
  font-size: .92rem;
}
.ps-timeline-time {
  font-family: 'DM Mono', ui-monospace, monospace;
  color: var(--text-muted, #7a7f8a);
  min-width: 68px;
}
.ps-timeline-kind { font-weight: 600; }
.ps-timeline-refs {
  color: var(--text-muted, #7a7f8a);
  font-size: .85rem;
  margin-left: auto;
}
.ps-timeline-payload {
  margin: 6px 0 2px 78px;
  padding: 8px 10px;
  font-size: .82rem;
  background: rgba(0,0,0,.03);
  border-radius: 4px;
  overflow-x: auto;
  max-height: 240px;
  white-space: pre;
}

/* Code-couleur par famille d'events — discret (ton border-left). */
.ps-timeline-row.kind-ok      { border-left-color: #22c55e; }
.ps-timeline-row.kind-err     { border-left-color: #ef4444; }
.ps-timeline-row.kind-warn    { border-left-color: #f59e0b; }
.ps-timeline-row.kind-info    { border-left-color: #3b82f6; }
.ps-timeline-row.kind-hot     { border-left-color: #a855f7; }
.ps-timeline-row.kind-neutral { border-left-color: #9ca3af; }

/* Badge de statut connexion SSE. */
.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: .82rem;
  background: rgba(0,0,0,.06);
  color: var(--text, #222);
}
.badge.is-ok   { background: rgba(34,197,94,.12);  color: #15803d; }
.badge.is-warn { background: rgba(245,158,11,.15); color: #b45309; }
.badge.is-err  { background: rgba(239,68,68,.12);  color: #b91c1c; }

/* Mobile-first : stack head + actions. */
@media (max-width: 640px) {
  .ps-view-head { flex-direction: column; align-items: stretch; }
  .ps-timeline-refs { display: none; }
  .ps-timeline-payload { margin-left: 0; }
}

/* ============================================================
   Campaigns dashboard (Lot 5.6.b) — vue #/campaigns.

   Mobile-first : 1 colonne par défaut, 2 à ≥640, 3 à ≥960.
   Le drawer de détail devient un bottom-sheet plein écran
   sur téléphone, et un slide-over 440px à droite sur desktop.

   Consomme les tokens existants (--surface, --border, --text,
   --accent, --success, --warning, --danger) — aucune couleur
   en dur hors ombres/backdrops qui sont déjà des rgba utilitaires.
   ============================================================ */

/* --- Modal helpers sémantiques (header / body / footer).
   Utilisés par les nouveaux modales (campagnes) pour un layout
   structuré. Les anciens modales (.modal-title/.modal-sub/.modal-actions)
   restent compatibles — on peut mixer selon le besoin. */
.modal-head {
  margin-bottom: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.modal-head h3 {
  font-family: 'DM Sans', sans-serif;
  font-size: 1.15rem;
  font-weight: 700;
  margin: 0;
}
.modal-body {
  font-size: .92rem;
  line-height: 1.55;
}
.modal-body p { margin: 0 0 12px; }
.modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

/* --- Form stack : champs empilés verticalement, label > input.
   Complément de .form-grid-2 (layout 2 col) pour les cas où la
   grille 2-col n'a pas de sens (< 4 champs, mobile-first). */
.form-stack {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.form-stack .form-label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: .82rem;
  font-weight: 600;
  color: var(--text2);
}
.form-stack .form-input {
  font-weight: 400;
  color: var(--text);
}

/* --- Toolbar campagnes : search + select + toggle.
   Sur mobile (< 640), chaque contrôle prend 100 % de largeur et
   s'empile verticalement. À partir de 640, on étale en ligne. */
.camp-toolbar {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
  margin: 16px 0 18px;
}
.camp-toolbar .form-input { width: 100%; }
.camp-toolbar-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  font-size: .88rem;
  color: var(--text);
  cursor: pointer;
  user-select: none;
}
.camp-toolbar-toggle input[type="checkbox"] {
  width: 16px; height: 16px; cursor: pointer;
}
@media (min-width: 640px) {
  .camp-toolbar {
    grid-template-columns: minmax(180px, 1fr) minmax(160px, 220px) auto;
    align-items: center;
  }
}

/* --- Grille des cards : 1 → 2 → 3 colonnes. */
.camp-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
}
@media (min-width: 640px) {
  .camp-grid { grid-template-columns: repeat(2, 1fr); gap: 16px; }
}
@media (min-width: 960px) {
  .camp-grid { grid-template-columns: repeat(3, 1fr); }
}

/* --- Card campagne. Cliquable (role=button tabindex=0 sur <article>). */
.camp-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 16px 18px;
  cursor: pointer;
  transition: transform .15s, box-shadow .15s, border-color .15s;
  display: flex;
  flex-direction: column;
  gap: 10px;
  /* Anti-débordement d'un nom long sur mobile. */
  min-width: 0;
}
.camp-card:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 20px rgba(0,0,0,.06);
  border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
}
.camp-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.camp-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}
.camp-card-title {
  font-family: 'DM Sans', sans-serif;
  font-size: 1rem;
  font-weight: 700;
  margin: 0;
  color: var(--text);
  /* Tronque sur 2 lignes max pour garder la card compacte. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
}
.camp-card-meta {
  margin: 0;
  font-size: .78rem;
  color: var(--text2);
  font-family: 'DM Mono', monospace;
  text-transform: uppercase;
  letter-spacing: .05em;
}
.camp-card-progress {
  position: relative;
  height: 6px;
  border-radius: 4px;
  background: var(--surface-2, rgba(0,0,0,.05));
  overflow: hidden;
}
.camp-card-progress-bar {
  position: absolute;
  inset: 0 auto 0 0;
  background: linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent) 60%, var(--success)));
  transition: width .3s ease-out;
}
.camp-card-stats {
  display: grid;
  /* < 360 px : 2×2 pour éviter d'écraser les chiffres.
     ≥ 360 px : on passe en 4 colonnes. */
  grid-template-columns: repeat(2, 1fr);
  gap: 6px;
  margin: 0;
}
@media (min-width: 360px) {
  .camp-card-stats { grid-template-columns: repeat(4, 1fr); }
}
.camp-card-stats > div {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  min-width: 0;
}
.camp-card-stats dt {
  font-size: .68rem;
  color: var(--text2);
  text-transform: uppercase;
  letter-spacing: .05em;
  font-family: 'DM Mono', monospace;
}
.camp-card-stats dd {
  margin: 0;
  font-size: .95rem;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.camp-card-rate {
  margin: 0;
  font-size: .82rem;
  color: var(--text2);
}
.camp-card-rate strong { color: var(--text); }
.camp-card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

/* --- Empty state + pager. */
.camp-empty {
  grid-column: 1 / -1;
  padding: 40px 20px;
  text-align: center;
  color: var(--text2);
  font-size: .92rem;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: 14px;
}
.camp-empty small {
  display: inline-block;
  margin-top: 6px;
  font-size: .8rem;
}
.camp-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin: 20px 0 0;
  color: var(--text2);
  font-size: .85rem;
}

/* --- Drawer : détail de campagne.
   Mobile (< 720px) : bottom-sheet plein écran qui remonte du bas.
   Desktop (≥ 720px) : slide-over depuis la droite, 440 px.

   La logique d'affichage est portée par l'attribut [hidden] (posé
   par le JS) — pas de classe .is-open : plus prévisible et honore
   nativement aria-hidden pour les lecteurs d'écran. */
.camp-drawer-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.5);
  backdrop-filter: blur(4px);
  z-index: 180;
  animation: camp-drawer-fade .2s ease-out;
}
.camp-drawer-backdrop[hidden] { display: none; }
.camp-drawer {
  position: fixed;
  z-index: 190;
  background: var(--surface);
  border: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  box-shadow: -10px 0 40px rgba(0,0,0,.18);

  /* Mobile-first : bottom-sheet */
  inset: auto 0 0 0;
  max-height: 92vh;
  border-radius: 18px 18px 0 0;
  animation: camp-drawer-slide-up .22s ease-out;
}
.camp-drawer[hidden] { display: none; }
@media (min-width: 720px) {
  .camp-drawer {
    inset: 0 0 0 auto;
    max-height: none;
    width: min(440px, 100vw);
    border-radius: 0;
    border-left: 1px solid var(--border);
    animation: camp-drawer-slide-left .22s ease-out;
  }
}
.camp-drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
  /* Sticky sur mobile pour garder le bouton ✕ accessible en scroll. */
  position: sticky;
  top: 0;
  background: var(--surface);
  z-index: 1;
}
.camp-drawer-head h3 {
  font-family: 'DM Sans', sans-serif;
  font-size: 1.05rem;
  font-weight: 700;
  margin: 0;
  word-break: break-word;
}
.camp-drawer-body {
  padding: 18px 20px 28px;
  overflow-y: auto;
  flex: 1 1 auto;
  font-size: .92rem;
  line-height: 1.55;
}
.camp-drawer-subtitle {
  font-family: 'DM Mono', monospace;
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--text2);
  margin: 20px 0 10px;
}
.camp-drawer-subtitle:first-child { margin-top: 0; }
.camp-drawer-meta {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
  margin: 0;
}
.camp-drawer-meta > div {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 10px;
  padding: 6px 0;
  border-bottom: 1px dashed var(--border);
  align-items: baseline;
}
.camp-drawer-meta dt {
  font-size: .78rem;
  color: var(--text2);
  font-family: 'DM Mono', monospace;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.camp-drawer-meta dd {
  margin: 0;
  font-size: .9rem;
  color: var(--text);
  word-break: break-word;
}
.camp-drawer-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

/* --- KPIs stats 7 j dans le drawer. */
.camp-stats-kpi {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin: 0;
}
@media (min-width: 480px) {
  .camp-stats-kpi { grid-template-columns: repeat(4, 1fr); }
}
.camp-stats-kpi > div {
  background: var(--surface-2, rgba(0,0,0,.03));
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.camp-stats-kpi dt {
  font-size: .68rem;
  color: var(--text2);
  text-transform: uppercase;
  letter-spacing: .05em;
  font-family: 'DM Mono', monospace;
}
.camp-stats-kpi dd {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* --- Animations respectent prefers-reduced-motion. */
@keyframes camp-drawer-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes camp-drawer-slide-up {
  from { transform: translateY(16px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}
@keyframes camp-drawer-slide-left {
  from { transform: translateX(16px); opacity: 0; }
  to   { transform: translateX(0);    opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .camp-drawer,
  .camp-drawer-backdrop,
  .camp-card { animation: none; transition: none; }
}

/* ============================================================
   Drawer tabs — Stats / Timeline (Lot 6.e.2)
   ============================================================ */
.camp-drawer-tabs {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--border);
  margin: -2px -4px 16px;
  /* Rend les onglets stickys en haut du body drawer — pratique sur
     une timeline longue, l'admin garde le bouton Stats visible. */
  position: sticky;
  top: 0;
  background: var(--surface, #fff);
  z-index: 2;
}
.camp-drawer-tab {
  flex: 1 1 auto;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: 10px 14px;
  font: inherit;
  color: var(--text2);
  cursor: pointer;
  font-weight: 600;
  font-size: .88rem;
  transition: color .15s, border-color .15s;
}
.camp-drawer-tab:hover { color: var(--text); }
.camp-drawer-tab.is-active {
  color: var(--accent, #2563eb);
  border-bottom-color: var(--accent, #2563eb);
}
.camp-drawer-tab:focus-visible {
  outline: 2px solid var(--accent, #2563eb);
  outline-offset: -2px;
  border-radius: 4px;
}

/* --- Timeline dans le drawer (liste compacte). */
.camp-drawer-timeline {
  margin-top: 4px;
}
.camp-drawer-timeline-toolbar {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 10px;
  flex-wrap: wrap;
}
.camp-drawer-timeline-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.camp-drawer-timeline-row {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
  background: var(--surface-2, rgba(0,0,0,.015));
}
.camp-drawer-timeline-head {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 10px;
  align-items: baseline;
  cursor: pointer;
  font-size: .85rem;
}
.camp-drawer-timeline-head:focus-visible {
  outline: 2px solid var(--accent, #2563eb);
  outline-offset: 2px;
  border-radius: 4px;
}
.camp-drawer-timeline-time {
  font-family: 'DM Mono', monospace;
  font-size: .74rem;
  color: var(--text2);
  white-space: nowrap;
}
.camp-drawer-timeline-kind {
  font-weight: 600;
  color: var(--text);
}
.camp-drawer-timeline-refs {
  font-size: .72rem;
  color: var(--text2);
  font-family: 'DM Mono', monospace;
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.camp-drawer-timeline-payload {
  margin: 8px 0 0;
  padding: 8px 10px;
  background: rgba(0,0,0,.04);
  border-radius: 6px;
  font-family: 'DM Mono', monospace;
  font-size: .72rem;
  max-height: 200px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
}
/* Lot 13.r — commentaire saisi par l'admin lors d'une transition
   start/pause/resume/cancel (cf. modale ACTION_MODAL_SPEC). Rendu en
   italique sous le label de l'event timeline avec citation typographique
   FR « ... ». Indent + couleur muted pour hiérarchie visuelle (le
   commentaire est un nice-to-have, pas l'info principale de l'event).
   Demande user verbatim 2026-05-01 : « dans la timeline on devrait
   voir les commentaires de lancement d'arrêt ». */
.camp-drawer-timeline-comment {
  margin: 6px 0 0 24px;
  font-size: .82rem;
  color: var(--text2);
  line-height: 1.4;
  word-break: break-word;
}
/* Lot 13.s — badge "Auto-pause" affiché avant le label kind quand
   payload.trigger commence par 'auto_pause_'. Distingue visuellement
   une pause système (auto-pause-watcher) d'une pause manuelle admin.
   Couleur warning (orange) volontaire — c'est un signal opérationnel,
   pas une erreur ; l'admin doit cliquer dessus pour comprendre. */
.camp-drawer-timeline-badge {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 4px;
  font-size: .68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  margin-right: 6px;
  vertical-align: middle;
}
/* R1 amigos MED-3 (Lot 13.s) — aligné sur le token design system existant
   `var(--warning)` + rgba hardcoded (cf. `.chip.c-warn` ligne 496 :
   color=warning, border+background=rgba 255,165,2). Évite d'introduire
   de nouveaux tokens non-définis (--warn / --warn-bg / --warn-border). */
.camp-drawer-timeline-badge-auto-pause {
  background: rgba(255, 165, 2, .08);
  color: var(--warning);
  border: 1px solid rgba(255, 165, 2, .4);
}
/* Lot 13.t — badge vert "Reprise planifiée" affiché sur campaign_resumed
   quand payload.trigger === 'scheduled_resume'. Distingue visuellement
   une reprise auto par le worker scheduled-resume-watcher d'une reprise
   manuelle admin.
   Lot 13.t.fix R-prod-4 — utilise `color-mix(in srgb, var(--success) ...)`
   pour théme-aware (le token success diffère entre dark `#2ed573` et
   light `#059669` — un rgba hardcoded créerait drift visuel en light).
   `color-mix` supporté Chrome 111+, Firefox 113+, Safari 16.2+ (mai 2023). */
.camp-drawer-timeline-badge-scheduled-resume {
  background: color-mix(in srgb, var(--success) 8%, transparent);
  color: var(--success);
  border: 1px solid color-mix(in srgb, var(--success) 40%, transparent);
}
/* Lot 13.t — badge bleu "Reprise prévue le X" affiché sur campaign_paused
   quand payload.scheduled_resume_at est posé. Information visuelle pour
   l'admin : la pause manuelle inclut une reprise auto planifiée.
   Lot 13.t.fix R-prod-4 — `color-mix` théme-aware (cf. badge ci-dessus). */
.camp-drawer-timeline-badge-resume-planned {
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
}
@media (max-width: 480px) {
  .camp-drawer-timeline-head {
    grid-template-columns: 1fr;
    gap: 2px;
  }
  .camp-drawer-timeline-refs { text-align: left; }
}

/* ─────────────────────────────────────────────────────────────
   Segment builder (Lot 6.e.3) — UI campagnes create/edit
   ─────────────────────────────────────────────────────────── */
.camp-segment {
  margin: 12px 0;
  padding: 12px 14px;
  background: rgba(0, 0, 0, .03);
  border: 1px solid rgba(0, 0, 0, .08);
  border-radius: 8px;
}
.camp-segment-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}
.camp-segment-count {
  font-family: 'DM Mono', monospace;
  font-weight: 600;
  font-size: .95rem;
  color: var(--ink, #1a1a1a);
  padding: 2px 8px;
  background: var(--accent-soft, rgba(70, 130, 240, .12));
  border-radius: 12px;
  white-space: nowrap;
}
.camp-segment-count.is-error {
  background: rgba(220, 70, 70, .12);
  color: var(--danger, #b84242);
}
.camp-segment-hint {
  margin: 0 0 10px;
  font-size: .78rem;
  color: var(--muted, #666);
  line-height: 1.4;
}
.camp-segment-hint code {
  font-family: 'DM Mono', monospace;
  background: rgba(0, 0, 0, .06);
  padding: 1px 5px;
  border-radius: 4px;
}
.camp-segment-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px 12px;
}
.camp-segment-grid .form-label {
  margin: 0;
}
.form-label--inline {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  grid-column: 1 / -1;
  font-size: .85rem;
}
.form-label--inline input[type="checkbox"] {
  width: auto;
  margin: 0;
}
@media (max-width: 480px) {
  .camp-segment-grid {
    grid-template-columns: 1fr;
  }
}

/* ============================================================
   Lot 6.e.5 — Bannière warning timezone (prospects sans country
   NI timezone_override → fallback UTC mauvaise delivrabilité)
   ------------------------------------------------------------
   Deux niveaux :
   - normal (orange) : une partie des prospects sans timezone ;
   - critical (rouge) : 100 % du segment sans timezone.
   Hidden par défaut via l'attribut HTML `hidden`. Le rendu utilise
   `display: block` parce que la valeur par défaut `display: inline`
   de certains user-agents colle mal avec le padding interne.
   ============================================================ */
.camp-segment-tz-warning {
  display: block;
  margin: 10px 0 6px;
  padding: 10px 12px;
  border-radius: 8px;
  background: rgba(255, 159, 28, .12);
  border: 1px solid rgba(255, 159, 28, .4);
  color: #8a4a00;
  font-size: .82rem;
  line-height: 1.5;
}
.camp-segment-tz-warning[hidden] {
  /* Anti-double-source-of-truth : si un dev oublie `hidden=true` et
     met juste `innerHTML=''`, on veut quand même que le bloc
     n'apparaisse pas comme une barre vide. */
  display: none;
}
.camp-segment-tz-warning strong {
  font-weight: 700;
}
.camp-segment-tz-warning code {
  font-family: 'DM Mono', monospace;
  background: rgba(0, 0, 0, .08);
  padding: 1px 5px;
  border-radius: 4px;
}
.camp-segment-tz-warning.is-critical {
  background: rgba(220, 53, 69, .10);
  border-color: rgba(220, 53, 69, .45);
  color: #8a2a2a;
}

/* ============================================================
   Lot 6.e.4 — Preview 3 mails (bloc sous le form d'édition)
   ============================================================ */
.camp-preview {
  margin-top: 16px;
  padding: 12px 14px;
  background: var(--surface-2, #f5f6fa);
  border-radius: 10px;
  border: 1px solid var(--border-soft, rgba(0, 0, 0, .08));
}
.camp-preview-head {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 10px;
}
.camp-preview-hint {
  font-size: .78rem;
  color: var(--muted, #666);
  line-height: 1.4;
}
.camp-preview-out {
  margin-top: 10px;
}
.camp-preview-out:empty {
  margin-top: 0;
}
.camp-preview-loading {
  margin: 0;
  font-size: .85rem;
  color: var(--muted, #666);
  font-style: italic;
}
.camp-preview-error {
  margin: 0;
  font-size: .85rem;
  color: var(--danger, #b84242);
  background: rgba(220, 70, 70, .08);
  padding: 8px 10px;
  border-radius: 6px;
}
.camp-preview-warning {
  margin: 0 0 8px;
  font-size: .8rem;
  color: var(--warning, #b07a20);
  background: rgba(240, 170, 50, .12);
  padding: 6px 10px;
  border-radius: 6px;
}
.camp-preview-budget {
  margin: 0 0 10px;
  font-size: .75rem;
  color: var(--muted, #666);
  font-family: 'DM Mono', monospace;
}
.camp-preview-empty {
  margin: 0;
  font-size: .85rem;
  color: var(--muted, #666);
}
.camp-preview-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.camp-preview-sample {
  background: var(--surface, #fff);
  border: 1px solid var(--border-soft, rgba(0, 0, 0, .08));
  border-radius: 8px;
  padding: 10px 12px;
}
.camp-preview-sample > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.camp-preview-sample > summary::-webkit-details-marker {
  display: none;
}
.camp-preview-sample-subject {
  font-weight: 600;
  font-size: .92rem;
  color: var(--ink, #1a1a1a);
}
.camp-preview-sample-meta {
  font-size: .75rem;
  color: var(--muted, #666);
  font-family: 'DM Mono', monospace;
}
.camp-preview-sample-body {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px dashed var(--border-soft, rgba(0, 0, 0, .08));
  white-space: pre-wrap;
  font-size: .88rem;
  line-height: 1.5;
  color: var(--ink, #1a1a1a);
}
.camp-preview-sample-cost {
  margin: 8px 0 0;
  font-size: .72rem;
  color: var(--muted, #666);
  font-family: 'DM Mono', monospace;
}

/* ============================================================
   Lot 6.f — Drawer "Dry-run" emphase
   ------------------------------------------------------------
   Quand `campaigns.dry_run = true`, le metaRow "Dry-run" affiche
   "oui (redirect SMTP forcé)" en emphase orange (couleur "warn"
   déjà utilisée dans le thème) pour que l'admin voie d'un coup
   d'œil que les envois vont aller vers le destinataire démo et
   non vers les vrais prospects. Pas bloquant (c'est un choix
   légitime), juste visible.
   ============================================================ */
.camp-dryrun-on {
  color: var(--warn, #b45309);
}

/* ============================================================
   Lot 9.b — Dashboard cockpit (KPI tiles + Chart.js)
   ------------------------------------------------------------
   Vue host : `app.views.dashboard.js`. Ce bloc CSS s'occupe :
     - du header (titre + sélecteur de période + toggle démo),
     - de la grille de KPI tiles (4 héro tiles),
     - de la grille de charts (donut + bar) avec sécurité hauteur,
     - des skeletons pendant le fetch,
     - de la légende custom du donut.
   ============================================================ */

.dash-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  margin-bottom: 22px;
}
.dash-header .section-tag,
.dash-header .section-title,
.dash-header .section-sub { margin-bottom: 4px; }
.dash-header .section-sub { margin-bottom: 0; }

.dash-controls {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

/* --- Period selector (segmented control 7/30/90 j) --- */
.dash-period {
  display: inline-flex;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 3px;
  gap: 0;
}
.dash-period-btn {
  appearance: none;
  background: transparent;
  border: 0;
  padding: 7px 14px;
  border-radius: 7px;
  font-family: 'DM Mono', monospace;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--text2);
  cursor: pointer;
  transition: background .18s ease, color .18s ease, transform .12s ease;
}
.dash-period-btn:hover {
  color: var(--text);
}
.dash-period-btn.is-active {
  background: var(--accent);
  color: #fff;
  box-shadow: 0 2px 8px rgba(91, 106, 208, .25);
}
.dash-period-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* --- Toggle "Inclure démo" --- */
.dash-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: .82rem;
  color: var(--text2);
  cursor: pointer;
  user-select: none;
}
.dash-toggle input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  cursor: pointer;
}
.dash-toggle:hover { color: var(--text); }

/* --- KPI tiles grid : héro --- */
.dash-kpi-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
}
@media (max-width: 960px) {
  .dash-kpi-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
  .dash-kpi-grid { grid-template-columns: 1fr; }
}

.dash-kpi-tile {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 120px;
  transition: border-color .2s ease, transform .15s ease, box-shadow .2s ease;
}
.dash-kpi-tile::before {
  /* accent bar latéral subtil — repère visuel de hiérarchie */
  content: '';
  position: absolute;
  left: 0;
  top: 14px;
  bottom: 14px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--accent);
  opacity: 0;
  transition: opacity .2s ease;
}
.dash-kpi-tile:hover {
  border-color: rgba(91, 106, 208, .35);
  transform: translateY(-1px);
  box-shadow: 0 6px 24px rgba(91, 106, 208, .08);
}
.dash-kpi-tile:hover::before { opacity: .6; }

.dash-kpi-label {
  font-family: 'DM Mono', monospace;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text2);
  margin: 0;
}
.dash-kpi-value {
  font-family: 'DM Sans', sans-serif;
  font-size: 1.95rem;
  font-weight: 700;
  line-height: 1.05;
  color: var(--text);
  letter-spacing: -.01em;
}
.dash-kpi-muted {
  color: var(--text2);
  font-weight: 500;
  font-size: 1.45rem;
}
.dash-kpi-foot {
  font-size: .78rem;
  color: var(--text2);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: auto;
}
.dash-kpi-foot .chip {
  font-size: .7rem;
}
/* Lien discret "Voir les prompts" dans la tile Coût IA — scope tile,
   pour ne pas leaker un comportement de lien à toute foot KPI. */
.dash-kpi-tile .dash-kpi-link {
  font-family: 'DM Mono', monospace;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px dashed transparent;
  transition: border-color .15s ease, color .15s ease;
  margin-left: auto;
}
.dash-kpi-tile .dash-kpi-link:hover {
  border-bottom-color: var(--accent);
}
.dash-kpi-tile .dash-kpi-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

/* --- Charts grid (donut + bar) --- */
.dash-charts-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-top: 18px;
}
@media (max-width: 880px) {
  .dash-charts-grid { grid-template-columns: 1fr; }
}

.dash-chart-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.dash-chart-header {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.dash-chart-title {
  font-family: 'DM Sans', sans-serif;
  font-size: 1rem;
  font-weight: 700;
  margin: 0;
  color: var(--text);
}
.dash-chart-sub {
  font-size: .8rem;
  color: var(--text2);
  margin: 0;
}
.dash-chart-canvas-wrap {
  position: relative;
  /* Hauteur fixe : Chart.js avec maintainAspectRatio:false a besoin
     d'un parent dimensionné — sinon le canvas s'effondre à 0px. */
  height: 240px;
}
.dash-chart-canvas-wrap canvas {
  max-width: 100%;
  max-height: 100%;
}
.dash-chart-empty {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 30px 20px;
  text-align: center;
  color: var(--text2);
  font-size: .9rem;
  border: 1px dashed var(--border);
  border-radius: 10px;
}

/* --- Légende custom donut --- */
.dash-chart-legend {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px 16px;
  font-size: .82rem;
}
@media (max-width: 520px) {
  .dash-chart-legend { grid-template-columns: 1fr; }
}
.dash-legend-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
}
.dash-legend-swatch {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex-shrink: 0;
}
.dash-legend-label {
  flex: 1;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.dash-legend-val {
  font-family: 'DM Mono', monospace;
  color: var(--text);
  font-weight: 500;
  font-size: .78rem;
  white-space: nowrap;
}

/* --- Tiles secondaires sous le bar chart (refus + désinscriptions) --- */
.dash-chart-secondary-tiles {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
@media (max-width: 520px) {
  .dash-chart-secondary-tiles { grid-template-columns: 1fr; }
}
.dash-chart-tile {
  background: var(--bg, #FAFBFE);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  cursor: help;
  transition: border-color .15s ease;
}
.dash-chart-tile:hover {
  border-color: rgba(91, 106, 208, .35);
}
.dash-chart-tile-label {
  font-family: 'DM Mono', monospace;
  font-size: .68rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text2);
}
.dash-chart-tile-value {
  font-family: 'DM Sans', sans-serif;
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--text);
}

/* --- Section opérationnelle (mode + DNS + deliverability) --- */
.dash-ops {
  border-top: 1px solid var(--border);
  padding-top: 28px;
}
.dash-ops-header {
  margin-bottom: 14px;
}
.dash-ops-title {
  font-family: 'DM Sans', sans-serif;
  font-size: 1.05rem;
  font-weight: 700;
  margin: 0 0 4px 0;
  color: var(--text);
}
.dash-ops-sub {
  font-size: .82rem;
  color: var(--text2);
  margin: 0;
}

/* --- Skeleton loaders --- */
.dash-skeleton {
  position: relative;
  overflow: hidden;
  background: linear-gradient(
    90deg,
    var(--surface) 0%,
    var(--surface2, #ECEEF8) 50%,
    var(--surface) 100%
  );
  background-size: 200% 100%;
  animation: dash-skeleton-shimmer 1.4s ease-in-out infinite;
  border-color: transparent !important;
}
.dash-skeleton-line {
  height: 10px;
  border-radius: 5px;
  background: rgba(91, 106, 208, .1);
  margin-bottom: 10px;
}
.dash-skeleton-line--short { width: 40%; }
.dash-skeleton-line--mid   { width: 60%; }
.dash-skeleton-line--big   { width: 80%; height: 26px; margin-bottom: 14px; }
@keyframes dash-skeleton-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .dash-skeleton { animation: none; }
}

/* ============================================================
   Lot 9.c — Vue Membres (Réglages → Membres)
   ------------------------------------------------------------
   Le gros du visuel est servi par les classes `.data-table`,
   `.chip` et `.form-card` existantes — on n'ajoute ici que les
   touches spécifiques à l'onglet Membres : surlignage subtil
   de la ligne « moi » et `.actions` cellule droite stable.
   ============================================================ */

/* Ligne « vous » dans le tableau membres : fond très subtil pour
   que l'admin se repère du premier coup d'œil sans dominer la grille. */
.data-table.members-table tr.is-self {
  background: color-mix(in srgb, var(--accent) 5%, transparent);
}
.data-table.members-table tr.is-self:hover {
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}

/* `.actions` dans la table invitations — stable même quand vide
   (sinon la colonne se rétracte et fait sauter la grille). */
.data-table.invitations-table td.actions {
  min-width: 100px;
}

/* ============================================================
   Lot 10.a.2 — Onboarding wizard "1ère campagne ≤ 30 min"
   ------------------------------------------------------------
   KPI commercial du SaaS — différenciateur vs Lemlist/Apollo/
   Instantly. Visuel rassurant (vert succès quand step coché),
   progression claire, CTA prominent + lien Skipper discret.
   ============================================================ */

/* --- Header section --- */
.onb-header {
  margin-bottom: 28px;
}
.onb-header .section-tag {
  font-size: .75rem;
}

/* --- Progress bar --- */
.onb-progress {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 28px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 16px 20px;
}
.onb-progress-track {
  flex: 1;
  height: 8px;
  background: var(--surface-2, rgba(0, 0, 0, .06));
  border-radius: 4px;
  overflow: hidden;
}
.onb-progress-fill {
  height: 100%;
  /* Fallback Safari iOS 15.x / vieux Firefox sans `color-mix` (revue passe 8 Q1
     cross-browser). Sans ce premier `background`, le 2e stop du gradient devient
     `unset` → fill quasi-invisible (~3% mobile FR concerné). La cascade applique
     le gradient color-mix sur les browsers récents (Safari iOS 16.2+, FF 113+). */
  background: var(--accent);
  background: linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent) 70%, var(--success)));
  border-radius: 4px;
  transition: width .35s cubic-bezier(.34, 1.56, .64, 1);
}
.onb-progress-label {
  font-family: 'DM Mono', monospace;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--text2);
  white-space: nowrap;
}
@media (prefers-reduced-motion: reduce) {
  .onb-progress-fill { transition: none; }
}

/* --- Step cards --- */
#onb-steps {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: 28px;
}
.onb-step {
  display: grid;
  grid-template-columns: 56px 1fr auto;
  gap: 18px;
  align-items: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 20px 22px;
  transition: border-color .2s ease, transform .15s ease, box-shadow .2s ease;
}
.onb-step:hover {
  border-color: rgba(91, 106, 208, .35);
  transform: translateY(-1px);
  box-shadow: 0 6px 24px rgba(91, 106, 208, .08);
}
.onb-step.is-done {
  /* Fallback Safari iOS 15.x / vieux Firefox sans `color-mix` (revue passe 8 Q1
     cross-browser). Sans fallback, le `color-mix` devient `unset` → background
     transparent, contraste step-done insuffisant. rgba équivalent visuel
     du `color-mix(in srgb, var(--success) 4%, var(--surface))`. */
  background: rgba(46, 213, 115, .04);
  background: color-mix(in srgb, var(--success) 4%, var(--surface));
  border-color: rgba(46, 213, 115, .35);
}
.onb-step.is-done:hover {
  border-color: rgba(46, 213, 115, .55);
  box-shadow: 0 6px 24px rgba(46, 213, 115, .1);
}

.onb-step-num {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--surface-2, rgba(0, 0, 0, .06));
  border: 2px solid var(--border);
  color: var(--text2);
  font-family: 'DM Sans', sans-serif;
  font-weight: 700;
  font-size: 1.15rem;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: all .25s ease;
}
.onb-step.is-done .onb-step-num {
  background: var(--success);
  border-color: var(--success);
  color: #fff;
  font-size: 1.4rem;
  box-shadow: 0 4px 14px rgba(46, 213, 115, .3);
}

.onb-step-body {
  min-width: 0; /* prevents grid blowout on long descriptions */
}
.onb-step-title {
  font-family: 'DM Sans', sans-serif;
  font-size: 1.05rem;
  font-weight: 700;
  margin: 0 0 4px 0;
  color: var(--text);
}
.onb-step-desc {
  font-size: .88rem;
  line-height: 1.55;
  color: var(--text2);
  margin: 0;
}

.onb-step-action {
  flex-shrink: 0;
}
.onb-step-action .btn {
  white-space: nowrap;
}

/* --- Footer (Terminer + Skipper) --- */
.onb-footer {
  margin-top: 8px;
  text-align: center;
}
.onb-footer-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}
.btn.btn-lg {
  padding: 14px 32px;
  font-size: 1rem;
  font-weight: 600;
}
/* Disabled state SSOT pour tous les .btn — le browser default réduit
   l'opacité légèrement mais c'est invisible sur un primary saturé.
   Ajout d'un style explicite (revue Lot 10.a.2 passe 1 D1) pour
   que le user voie que le bouton "Terminer l'onboarding" est inactif
   tant que les 4 steps ne sont pas tous cochés. */
.btn:disabled,
.btn[disabled] {
  opacity: .45;
  cursor: not-allowed;
  box-shadow: none;
  filter: grayscale(.3);
}
.btn:disabled:hover,
.btn[disabled]:hover {
  /* Pas d'animation hover sur disabled — le user ne devrait pas
     croire qu'il peut interagir. */
  transform: none;
}
.onb-footer-hint {
  margin: 0;
}
.onb-skip-link {
  color: var(--text2);
  text-decoration: underline;
  text-decoration-style: dotted;
  margin-left: 4px;
}
.onb-skip-link:hover {
  color: var(--text);
  text-decoration-style: solid;
}

/* --- Responsive : empile vertical sur mobile (<= 600px) --- */
@media (max-width: 600px) {
  .onb-step {
    grid-template-columns: 44px 1fr;
    grid-template-rows: auto auto;
  }
  .onb-step-action {
    grid-column: 1 / -1;
    margin-top: 6px;
  }
  .onb-step-action .btn {
    width: 100%;
  }
  .onb-progress {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
  }
  .onb-progress-label {
    text-align: center;
  }
}

/* ================================================================
   Lot 10.a.3 — Sticky onboarding resume banner
   ================================================================
   POURQUOI
   Quand l'admin clique un CTA depuis le wizard et atterrit sur
   /settings/smtp (ou autre vue), il a perdu la trace du wizard.
   Cette bannière persiste en haut de toutes les vues (sauf
   #/onboarding) pour que le KPI commercial `time-to-first-campaign
   ≤ 30 min` ne casse pas à cause d'une UX qui isole le user.

   DESIGN
   - Bandeau plein-largeur, gradient subtle accent → light pour
     premium-look (50€/mois SaaS, pas une popup criarde).
   - Compteur prominent "X étapes restantes" + CTA primary.
   - Mobile-first : empile sur <600px (icône + texte + CTA full-width).
   - prefers-reduced-motion : skippe le hover lift.
   ================================================================ */
.ps-onb-banner {
  /* Lot 14.f — position relative + z-index défensif pour garantir que
     le hit-test du CTA `.btn-primary` ne soit pas intercepted par la
     sidebar sticky (z-index:50). Le banner vit dans .app-canvas (col 2
     grille) et n'overlapping pas spatialement, mais Playwright peut
     être conservateur sur les stacking contexts (sidebar sticky +
     overflow-y:auto crée potentiellement un context cross-column). */
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin: 0 0 16px;
  padding: 12px 18px;
  border-radius: 12px;
  /* Fallback Safari iOS 15.x / FF <113 (parité Lot 10.a.2 passe 8 Q1) —
     sans fallback, le `color-mix` devient `unset` et le bandeau
     transparent. La cascade applique le gradient sur browsers récents. */
  background: rgba(91, 106, 208, .06);
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--accent) 8%, var(--surface)) 0%,
    color-mix(in srgb, var(--accent) 4%, var(--surface)) 100%
  );
  border: 1px solid rgba(91, 106, 208, .25);
  box-shadow: 0 2px 8px rgba(91, 106, 208, .04);
  transition: box-shadow .2s ease, transform .15s ease;
}
.ps-onb-banner:hover {
  box-shadow: 0 4px 14px rgba(91, 106, 208, .08);
  transform: translateY(-1px);
}
.ps-onb-banner-icon {
  font-size: 1.35rem;
  line-height: 1;
  flex-shrink: 0;
}
.ps-onb-banner-text {
  flex: 1 1 auto;
  font-size: .92rem;
  color: var(--text);
}
.ps-onb-banner-text strong {
  font-weight: 600;
  color: var(--accent);
}
.ps-onb-banner-cta {
  flex-shrink: 0;
  white-space: nowrap;
}
/* État « tout est prêt » (revue passe 4 PO Q1) — l'admin a coché
   les 4 steps mais n'a pas cliqué Terminer. Tonalité plus chaude
   (success vert) pour signaler l'imminence de la complétion + inviter
   à finaliser. Fallback rgba avant color-mix (Safari iOS 15.x). */
.ps-onb-banner.is-ready {
  background: rgba(46, 213, 115, .07);
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--success) 10%, var(--surface)) 0%,
    color-mix(in srgb, var(--success) 5%, var(--surface)) 100%
  );
  border-color: rgba(46, 213, 115, .35);
}
.ps-onb-banner.is-ready .ps-onb-banner-text strong {
  /* Contraste WCAG AA (revue passe 5 PO Q1) — `var(--success)` (#2ed573)
     sur fond gradient success 5-10% donne ~3.1:1, sous le minimum AA
     4.5:1 sur petit texte. On darkene à 65% via color-mix avec black,
     ce qui donne ~#1e8b4a (≈5.2:1 sur surface clair). Fallback hardcoded
     pour Safari iOS 15.x / FF <113 (parité Lot 10.a.2 passe 8 Q1). */
  color: #1e8b4a;
  color: color-mix(in srgb, var(--success) 65%, black);
}
@media (max-width: 600px) {
  .ps-onb-banner {
    padding: 10px 14px;
    gap: 10px;
  }
  .ps-onb-banner-text {
    flex: 1 1 100%;
    order: 2;
  }
  .ps-onb-banner-cta {
    flex: 1 1 100%;
    order: 3;
    text-align: center;
  }
}
@media (prefers-reduced-motion: reduce) {
  .ps-onb-banner { transition: none; }
  .ps-onb-banner:hover { transform: none; }
}

/* ================================================================
   Lot 10.a.4 — Locale switcher (i18n)
   ================================================================
   Variante compacte du domain-switcher : on n'affiche que le drapeau
   (icône uniquement, pas de label tronqué dans le header), et on
   ouvre un dropdown avec le nom complet de chaque langue dans sa
   propre écriture (français, English, Deutsch, ...) — anti-confusion
   pour un user qui débarque dans une langue qu'il ne lit pas.
   ================================================================ */
.locale-switcher {
  position: relative;
}
.locale-switcher-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 10px;
  border-radius: 8px;
  background: var(--surface-2, rgba(0,0,0,.04));
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 1rem;
  cursor: pointer;
  line-height: 1;
}
.locale-switcher-btn::after {
  content: '▾';
  font-size: .65rem;
  color: var(--text2);
  margin-left: 2px;
}
.locale-switcher-btn:hover { border-color: var(--text2); }
.locale-switcher-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.locale-switcher-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  min-width: 180px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 32px rgba(0,0,0,.1);
  padding: 6px;
  z-index: 100;
  display: none;
}
.locale-switcher.is-open .locale-switcher-menu { display: block; }
.locale-switcher-menu button {
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  padding: 8px 10px;
  border-radius: 6px;
  font-size: .9rem;
  color: var(--text);
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
}
.locale-switcher-menu button:hover { background: var(--surface-2, rgba(0,0,0,.04)); }
.locale-switcher-menu button.is-active {
  color: var(--accent);
  font-weight: 600;
  background: rgba(91, 106, 208, .06);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.locale-switcher-menu .locale-flag {
  font-size: 1.05rem;
  line-height: 1;
  flex-shrink: 0;
}
.locale-switcher-menu .locale-label {
  flex: 1;
}

@media (max-width: 600px) {
  .locale-switcher-menu {
    right: 0;
    min-width: 160px;
  }
}

/* ============================================================
   Lot 10.h.B — Bibliothèque + Wizard prompts
   ============================================================
   Design SSOT — pas de couleurs hardcodées : on réutilise les custom
   properties existantes (`--c-text`, `--c-muted`, `--c-border`,
   `--c-bg-card`, `--c-accent`). Tout est responsive mobile-first.
   prefers-reduced-motion respecté en désactivant les transitions.
   ============================================================ */

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap;
  border: 0;
}

/* ─── Form helpers utilisés par les nouveaux modules */

.form-required { color: var(--danger); margin-left: 2px; }

.form-checks {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 6px 12px;
}
.form-checks .form-check { margin: 0; }

.form-group.is-inline {
  display: inline-flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
}
.form-group.is-inline.is-grow { flex: 1 1 200px; }

.wizard-form.is-2col {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
}
@media (min-width: 720px) {
  .wizard-form.is-2col { grid-template-columns: 1fr 1fr; }
}

/* ─── Source badge (chip) — vue prompts existante */

.chip.prompts-source-chip {
  font-weight: 500;
  letter-spacing: 0.01em;
}

/* ─── Skeleton loaders communs */

.prompts-skel { display: flex; flex-direction: column; gap: 12px; padding: 16px 0; }
.prompts-skel-line {
  height: 12px;
  border-radius: 6px;
  background: linear-gradient(90deg, rgba(255,255,255,.04) 25%, rgba(255,255,255,.08) 50%, rgba(255,255,255,.04) 75%);
  background-size: 200% 100%;
  animation: prompts-skel-shimmer 1.4s ease infinite;
}
.prompts-skel-line.is-lg { height: 22px; max-width: 60%; }
.prompts-skel-grid {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.prompts-skel-card {
  height: 180px;
  border-radius: 12px;
  background: linear-gradient(90deg, rgba(255,255,255,.04) 25%, rgba(255,255,255,.08) 50%, rgba(255,255,255,.04) 75%);
  background-size: 200% 100%;
  animation: prompts-skel-shimmer 1.6s ease infinite;
}
@keyframes prompts-skel-shimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .prompts-skel-line, .prompts-skel-card { animation: none; }
}

/* ─── Bibliothèque — barre de filtres */

.prompts-filters {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px 14px;
  margin: 16px 0;
  position: sticky;
  top: var(--ps-sticky-top, 0);
  z-index: 1;
}
.prompts-filters-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
}

/* ─── Bibliothèque — grille cards */

.prompts-grid {
  display: grid;
  gap: 16px;
  grid-template-columns: 1fr;
  margin-top: 8px;
}
@media (min-width: 720px)  { .prompts-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .prompts-grid { grid-template-columns: repeat(3, 1fr); } }

.prompts-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.prompts-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
  border-color: var(--accent);
}
@media (prefers-reduced-motion: reduce) {
  .prompts-card { transition: none; }
  .prompts-card:hover { transform: none; }
}

.prompts-card-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.prompts-card-meta {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.prompts-card-kind {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text2);
}
.prompts-card-title {
  font-size: 1.05rem;
  font-weight: 600;
  margin: 0;
  line-height: 1.3;
  color: var(--text);
}
.prompts-card-desc {
  margin: 0;
  font-size: 0.9rem;
  color: var(--text2);
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.prompts-card-rate-wrap { font-size: 0.85rem; }
.prompts-card-rate {
  display: inline-block;
  background: rgba(102,126,234,.18);
  color: var(--accent);
  padding: 4px 10px;
  border-radius: 999px;
  font-weight: 500;
  font-size: 0.8rem;
}
.prompts-card-tags {
  display: flex; flex-wrap: wrap; gap: 6px;
  min-height: 22px;
}
.prompts-card-foot {
  display: flex; gap: 8px; justify-content: flex-end;
  margin-top: auto;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}

/* ─── Variables documentées (modal preview + result wizard) */

.prompts-vars {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex; flex-direction: column;
  gap: 8px;
}
.prompts-vars li {
  background: var(--surface-2, rgba(255,255,255,.03));
  border-left: 3px solid var(--accent);
  padding: 10px 12px;
  border-radius: 0 8px 8px 0;
  display: flex; flex-direction: column; gap: 4px;
}
.prompts-var-desc { color: var(--text2); font-size: 0.85rem; }
.prompts-var-ex {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 2px 6px;
  font-size: 0.85rem;
  align-self: flex-start;
}

.prompts-preview-meta {
  display: flex; flex-wrap: wrap; gap: 12px;
  font-size: 0.85rem;
  color: var(--text2);
}

.prompts-rationale {
  margin: 0;
  background: var(--surface-2, rgba(255,255,255,.03));
  border-left: 3px solid var(--success);
  padding: 10px 12px;
  border-radius: 0 8px 8px 0;
  line-height: 1.55;
  color: var(--text);
}

/* ─── Wizard — stepper */

.wizard-stepper {
  margin: 16px 0 8px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.wizard-stepper-progress {
  height: 4px;
  background: var(--border);
  border-radius: 2px;
  overflow: hidden;
}
.wizard-stepper-bar {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--purple));
  transition: width 0.3s ease;
  border-radius: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .wizard-stepper-bar { transition: none; }
}
.wizard-stepper-list {
  list-style: none; padding: 0; margin: 0;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
}
.wizard-stepper-btn {
  width: 100%;
  background: transparent;
  border: 0;
  cursor: pointer;
  padding: 8px 6px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  border-radius: 8px;
  color: var(--text2);
  font: inherit;
}
.wizard-stepper-btn:disabled { cursor: default; opacity: 0.6; }
.wizard-stepper-btn:not(:disabled):hover { background: var(--surface-2, rgba(255,255,255,.03)); }
.wizard-stepper-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.wizard-stepper-num {
  width: 28px; height: 28px;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--border);
  color: var(--text2);
  font-weight: 600;
  font-size: 0.85rem;
  transition: background 0.18s ease, color 0.18s ease;
}
@media (prefers-reduced-motion: reduce) {
  .wizard-stepper-num { transition: none; }
}
.wizard-stepper-title {
  font-size: 0.78rem;
  text-align: center;
  line-height: 1.2;
}
.wizard-stepper-item.is-current .wizard-stepper-num {
  background: var(--accent);
  color: #fff;
}
.wizard-stepper-item.is-current .wizard-stepper-title {
  color: var(--text);
  font-weight: 600;
}
.wizard-stepper-item.is-done .wizard-stepper-num {
  background: var(--success);
  color: #fff;
  font-size: 0;            /* masque le numéro pour laisser place au ::before */
}
.wizard-stepper-item.is-done .wizard-stepper-num::before {
  content: "✓";
  font-size: 0.95rem;
}

@media (max-width: 700px) {
  .wizard-stepper-title { display: none; }
  .wizard-stepper-list { gap: 8px; }
}

/* ─── Wizard — step body */

.wizard-step {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 22px;
  margin-top: 16px;
}
.wizard-step-head {
  margin: 0 0 16px;
}
.wizard-step-head h3 {
  margin: 0 0 4px;
  font-size: 1.15rem;
  font-weight: 600;
}
.wizard-form {
  display: flex; flex-direction: column; gap: 16px;
}
.wizard-form .form-group { margin: 0; }

.wizard-skel {
  display: flex; flex-direction: column; gap: 12px;
}
.wizard-result-skel {
  text-align: center;
  padding: 32px 16px;
  display: flex; flex-direction: column; gap: 12px;
  align-items: center;
}
.wizard-result-skel h3 { margin: 0; font-size: 1.05rem; }
.wizard-result-skel .prompts-skel-line {
  width: min(560px, 100%);
}

.wizard-result {
  display: flex; flex-direction: column; gap: 18px;
}

/* ─── Wizard — action bar (sticky bottom on mobile) */

.wizard-actions {
  margin-top: 18px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 0 4px;
  border-top: 1px solid var(--border);
}
.wizard-actions-left { flex: 1 1 auto; }
.wizard-actions-mid {
  flex: 0 0 auto;
  font-size: 0.85rem;
  color: var(--text2);
  font-variant-numeric: tabular-nums;
}
.wizard-actions-right {
  flex: 1 1 auto;
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}
.wizard-progress-label { white-space: nowrap; }

@media (max-width: 600px) {
  .wizard-actions { flex-wrap: wrap; }
  .wizard-actions-mid { order: -1; flex: 1 1 100%; text-align: center; }
}

/* --- Alerts (Lot 10.h.B.3 + 10.h.B.4 — bandeaux info/warning/danger) ---
 *
 * Pass 10 amigos F4 — les classes `.alert.alert-*` étaient utilisées dans
 * `app.views.prospects.js` (Lot 10.h.B.3 — preview email warnings) et
 * `app.views.prompts.wizard.{render,modals}.js` (Lot 10.h.B.4 — bandeau
 * cross-domain + warning activate) sans CSS associé → bandeaux affichés
 * comme `<div>` plain sans style visuel (UX dégradée). On définit ici
 * les 3 variantes en réutilisant les vars du design system :
 *   - `.alert-info`     → `--accent` (bleu/violet, ton informatif neutre).
 *   - `.alert-warning`  → `--warning` (orange, attention modérée).
 *   - `.alert-danger`   → `--danger` (rouge, erreur bloquante).
 *
 * Pattern aligné `.chip.c-*` (mêmes alphas RGB pour border + bg). `role`
 * ARIA est posé côté JS (`role="status"` polite ou `role="alert"` selon
 * sévérité).
 */
.alert {
  padding: 0.625rem 0.875rem;
  border-radius: 6px;
  border: 1px solid var(--border, rgba(255, 255, 255, 0.12));
  background: var(--surface-2, rgba(255, 255, 255, 0.03));
  font-size: 0.9rem;
  line-height: 1.45;
}
.alert + .alert,
.alert.mt-2 { margin-top: 0.5rem; }
.alert-info {
  color: var(--accent);
  border-color: rgba(102, 126, 234, 0.4);
  background: rgba(102, 126, 234, 0.08);
}
.alert-warning {
  color: var(--warning);
  border-color: rgba(255, 165, 2, 0.4);
  background: rgba(255, 165, 2, 0.08);
}
.alert-danger {
  color: var(--danger);
  border-color: rgba(255, 71, 87, 0.4);
  background: rgba(255, 71, 87, 0.08);
}
/* Le `<strong>` dans les clés `_html` reprend la couleur héritée pour
   garder le contraste cohérent (vs blanc/dark theme par défaut). */
.alert strong { color: inherit; font-weight: 600; }

/* --- Wizard strategy chip selector (Lot 10.h.B.2.SPA) ---
 *
 * Chip selector "Stratégie" (3 chips role=radio) visible UNIQUEMENT à
 * l'étape 1 quand kind=cold_email. Aligné avec le design system
 * `.chip.c-accent` (gradient accent→purple) pour cohérence Lot 10.h.B.
 *
 * A11y : roving tabindex côté JS (orchestrator wizard.js), aria-checked
 * toggle, focus visible distinct (anti-régression keyboard nav).
 */
.wizard-strategy-section {
  margin-top: 4px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  grid-column: 1 / -1; /* span sur form 2-col parent */
}
.wizard-strategy-group {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.wizard-strategy-chip {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding: 12px 14px;
  min-width: 180px;
  flex: 1 1 200px;
  text-align: left;
  border: 1px solid var(--border, rgba(255, 255, 255, 0.12));
  border-radius: 10px;
  background: var(--surface-2, rgba(255, 255, 255, 0.03));
  color: var(--text2);
  cursor: pointer;
  font: inherit;
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
@media (prefers-reduced-motion: reduce) {
  .wizard-strategy-chip { transition: none; }
}
.wizard-strategy-chip:hover {
  border-color: rgba(102, 126, 234, 0.5);
  color: var(--text);
  background: rgba(102, 126, 234, 0.06);
}
.wizard-strategy-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.wizard-strategy-chip.is-selected,
.wizard-strategy-chip[aria-checked="true"] {
  color: #fff;
  border-color: rgba(102, 126, 234, 0.8);
  background: linear-gradient(135deg, var(--accent), var(--purple));
}
.wizard-strategy-chip-label {
  font-weight: 600;
  font-size: 0.95rem;
  line-height: 1.25;
}
.wizard-strategy-chip-sub {
  font-size: 0.78rem;
  line-height: 1.35;
  opacity: 0.85;
}
@media (max-width: 600px) {
  .wizard-strategy-chip { min-width: 100%; }
}


/* --- Capacités & limites (Lot 10.j) ---
 *
 * Grille responsive de 4 cards (Email / IMAP / LLM / Rate limits) +
 * skeleton loader pendant le fetch initial. Réutilise les vars CSS
 * du design system (--surface, --border, --text, --accent) — pas de
 * tokens hardcoded.
 */
.capacities-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
  margin-top: 16px;
}
@media (max-width: 700px) {
  .capacities-grid { grid-template-columns: 1fr; }
}
.capacities-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 20px 22px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.capacities-card-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  color: var(--text);
  border-bottom: 1px solid var(--border);
  padding-bottom: 8px;
}
.capacities-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.capacities-row-label {
  font-size: 0.78rem;
  color: var(--text2);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.capacities-row-value {
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.capacities-row-hint {
  font-size: 0.78rem;
  color: var(--text2);
  font-style: italic;
}
.capacities-note {
  margin: 4px 0 0;
  padding: 8px 10px;
  background: rgba(102, 126, 234, 0.06);
  border-left: 3px solid var(--accent);
  border-radius: 0 6px 6px 0;
  font-size: 0.85rem;
  color: var(--text2);
  line-height: 1.45;
}
.capacities-skel {
  opacity: 0.6;
}

/* ============================================================
   Lot 13.f.10 PR2 — Listes prospects (Settings → prospect-lists)
   Différenciateurs commerciaux : santé inline + source visible +
   drag-sort native HTML5 (CSP-safe, zéro lib externe).
   ============================================================ */

/* Drag-sort handle + visuels d'état (dragging / drop-target).
   Finding amigos F-DRAG-CURSOR (PR2-A) : `<tr draggable="true">` permet
   le drag depuis n'importe quelle cellule. Poser `cursor:grab` UNIQUEMENT
   sur la cellule handle créait une incohérence visuelle (curseur texte
   ailleurs alors que le drag fonctionnait). Solution : `grab` sur la
   `.pl-row` entière + `grabbing` pendant le drag actif. */
.pl-table tr.pl-row { cursor: grab; }
.pl-table tr.pl-row:active,
.pl-table tr.pl-row.is-dragging { cursor: grabbing; }
.pl-table .pl-drag-cell {
  text-align: center;
  color: var(--text-muted, #7a7f8a);
  user-select: none;
  vertical-align: middle;
}
.pl-drag-handle {
  display: inline-block;
  font-size: 0.95rem;
  letter-spacing: -1px;
  line-height: 1;
  opacity: 0.6;
  transition: opacity 0.15s;
}
.pl-table tr.pl-row:hover .pl-drag-handle { opacity: 1; }
.pl-table tr.pl-row.is-dragging {
  opacity: 0.4;
  background: var(--surface-2, rgba(0,0,0,0.04));
}
.pl-table tr.pl-row.is-drop-target {
  outline: 2px solid var(--accent, #667eea);
  outline-offset: -2px;
}

/* Badges santé inline — 5 états avec couleurs sémantiques.
   Cohérent avec `services/prospectListStats.ts` HEALTH_THRESHOLDS. */
.pl-health {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid transparent;
  font-size: 0.78rem;
  font-weight: 500;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.pl-health.is-healthy {
  color: var(--success);
  border-color: rgba(46, 213, 115, 0.4);
  background: rgba(46, 213, 115, 0.08);
}
.pl-health.is-warning {
  color: var(--warning);
  border-color: rgba(255, 165, 2, 0.4);
  background: rgba(255, 165, 2, 0.08);
}
.pl-health.is-critical {
  color: var(--danger);
  border-color: rgba(255, 71, 87, 0.4);
  background: rgba(255, 71, 87, 0.08);
}
.pl-health.is-idle,
.pl-health.is-empty {
  color: var(--text-muted, #7a7f8a);
  border-color: var(--border, rgba(0, 0, 0, 0.12));
  background: var(--surface-2, rgba(0, 0, 0, 0.03));
}

/* Empty-state centré sous la table. */
.pl-table tbody td .text-sm {
  display: inline-block;
  margin-top: 4px;
}

/* ============================================================
 * Lot 13.f.10 PR2-B — drag-sort 3 modes + dette technique
 * ============================================================ */

/* D-9 (PR2-B) — overlay translucide pendant re-fetch (loading state polish).
 * La table reste visible mais grisée + bloque les pointer events.
 * Évite le flash blanc "Chargement…" entre 2 fetches. */
.pl-table.is-syncing {
  opacity: 0.6;
  pointer-events: none;
  transition: opacity 200ms ease;
}

/* F-PO3 (PR2-B) — highlight ligne déplacée 1.5s post-reorder.
 * Anim CSS pure, pas de JS pour le timing. */
@keyframes pl-just-moved {
  0%   { background: rgba(34, 197, 94, 0.18); }
  100% { background: transparent; }
}
.pl-table tr.pl-row.is-just-moved {
  animation: pl-just-moved 1.5s ease-out;
}

/* F-A1 (PR2-B) — handle focusable visible au focus clavier. */
.pl-drag-handle:focus-visible {
  outline: 2px solid var(--accent, #5b8cff);
  outline-offset: 2px;
  border-radius: 3px;
  opacity: 1;
}

/* D-13 (PR2-B) — boutons mobile reorder ↑↓.
 * Affichés UNIQUEMENT sur pointer:coarse (tactile). En desktop souris,
 * masqués pour ne pas polluer la colonne actions. CSS @media couvre
 * iPad + smartphones natifs ; les laptops tactiles voient les 2 modes
 * mais c'est gracieusement dégradé. */
.pl-mobile-reorder {
  display: none;
  margin-right: 4px;
}
.pl-mobile-reorder .btn {
  padding: 2px 6px;
  font-size: 14px;
  min-width: 28px;
}
@media (pointer: coarse) {
  .pl-mobile-reorder { display: inline-flex; gap: 2px; }
  /* Sur tactile, la handle drag est moins ergonomique (pas de souris) :
   * on la garde présente pour cohérence visuelle (sémantique tri) mais
   * elle ne capture pas le tap (les boutons ↑↓ sont la voie canonique). */
  .pl-drag-handle { opacity: 0.5; cursor: default; }
}

/* Lot 13.f.10.ter PR2-B — bouton 🧹 Nettoyer contextuel sur santé warn/crit.
 * Le bouton est rendu seulement par le JS quand stat.health ∈ {warning,
 * critical} ; ici on lui donne juste un style discret amber pour que ce
 * soit visible sans crier (différenciateur élégant, pas alarmiste). */
.pl-cleanup-btn {
  color: var(--warning, #d97706);
}
.pl-cleanup-btn:hover {
  background: rgba(217, 119, 6, 0.08);
}

/* ============================================================
 * Lot 13.f.9 + 13.f.9.bis (PR2-D) — switcher progressive disclosure
 * + tooltip breakdown survol. Préfixe `.pl-switcher` pour le composant
 * `app.views.prospects.list-switcher.js`, `.pl-tt` pour le tooltip.
 * Caché si count ≤ 1 (logique JS) — backend prêt à fournir N listes.
 * ============================================================ */
.prospects-list-switcher-host {
  display: inline-flex;
  margin-right: 8px;
}
.prospects-list-switcher-host[hidden] {
  display: none;
}
.pl-switcher {
  position: relative;
  display: inline-flex;
}
/* R7-LOW-3 : skeleton loading pendant fetch initial /api/prospect-lists. */
.pl-switcher-loading {
  align-items: center;
  padding: 4px 10px;
}
.pl-switcher-skel {
  display: inline-block;
  width: 140px;
  height: 16px;
  border-radius: 4px;
  background: linear-gradient(90deg, var(--surface-subtle, #f3f4f6) 25%, var(--border, #e5e7eb) 50%, var(--surface-subtle, #f3f4f6) 75%);
  background-size: 200% 100%;
  animation: pl-switcher-skel-pulse 1.2s ease-in-out infinite;
}
@keyframes pl-switcher-skel-pulse {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
.pl-switcher-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  background: var(--surface-subtle, #f3f4f6);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  cursor: pointer;
  font: inherit;
}
.pl-switcher-btn:hover { background: var(--surface, #e5e7eb); }
.pl-switcher-btn[aria-expanded="true"] {
  background: var(--surface, #e5e7eb);
  outline: 2px solid var(--accent, #5b8cff);
  outline-offset: 2px;
}
.pl-switcher-current {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.pl-switcher-cur-label { white-space: nowrap; }
.pl-switcher-title { font-weight: 600; }
.pl-switcher-counts { white-space: nowrap; }
.pl-switcher-caret { font-size: 10px; opacity: 0.6; }

.pl-switcher-menu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 100;
  min-width: 280px;
  margin-top: 4px;
  background: var(--surface-card, #fff);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
  padding: 6px 0;
}
.pl-switcher-search-wrap { padding: 6px 10px; }
.pl-switcher-search {
  width: 100%;
  padding: 4px 8px;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 4px;
  font: inherit;
}
.pl-switcher-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 320px;
  overflow-y: auto;
}
.pl-switcher-mi {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
  width: 100%;
  padding: 6px 12px;
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
  font: inherit;
}
.pl-switcher-mi:hover,
.pl-switcher-mi:focus {
  background: var(--surface-subtle, #f3f4f6);
  outline: none;
}
.pl-switcher-mi.is-current {
  background: rgba(91, 140, 255, 0.08);
  font-weight: 600;
}
.pl-switcher-mi-line,
.pl-switcher-mi-meta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.pl-switcher-mi-meta { justify-content: space-between; }
.pl-switcher-empty {
  padding: 8px 12px;
  text-align: center;
}
.pl-switcher-footer {
  border-top: 1px solid var(--border, #e5e7eb);
  padding: 6px 12px;
  display: flex;
  justify-content: flex-end;
}
.pl-switcher-manage {
  font-size: 13px;
  color: var(--accent, #5b8cff);
  text-decoration: none;
}
.pl-switcher-manage:hover { text-decoration: underline; }

/* Tooltip breakdown 13.f.9.bis — élément flottant unique partagé,
 * positionné par JS via getBoundingClientRect. role="tooltip" pour A11y. */
.pl-switcher-tooltip {
  position: fixed;
  z-index: 200;
  width: 280px;
  background: var(--surface-card, #fff);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  padding: 10px 12px;
  pointer-events: none;
  font-size: 13px;
}
.pl-switcher-tooltip[hidden] { display: none; }
.pl-tt-section { margin-bottom: 8px; }
.pl-tt-section:last-child { margin-bottom: 0; }
.pl-tt-h {
  font-weight: 600;
  margin-bottom: 4px;
  font-size: 12px;
  color: var(--text-muted, #6b7280);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.pl-tt-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.pl-tt-list li {
  padding: 1px 0;
}
.pl-tt-line { line-height: 1.4; }
.pl-tt-loading { padding: 6px 0; text-align: center; }

/* ============================================================
 * Lot 13.l — bloc d'aide collapsible sous textarea (modal Prompt)
 *
 * <details class="form-help"> natif HTML5 (CSP-safe, accessible
 * clavier+screen-reader natif, pas de JS). Utilisé dans le modal
 * "Nouvelle version de prompt" pour expliquer system_prompt vs
 * user_template + lister les 14 variables disponibles.
 * ============================================================ */
.form-help {
  margin-top: 6px;
  padding: 6px 10px;
  background: var(--ps-bg-subtle, #f7f7f9);
  border-left: 3px solid var(--ps-accent, #4a7afe);
  border-radius: 3px;
  font-size: 0.875rem;
  line-height: 1.5;
}
.form-help summary {
  cursor: pointer;
  user-select: none;
  font-weight: 500;
  color: var(--ps-text-strong, #1a1a2e);
}
.form-help summary:hover {
  color: var(--ps-accent, #4a7afe);
}
.form-help[open] summary {
  margin-bottom: 6px;
}
.form-help p {
  margin: 4px 0;
  color: var(--ps-text, #4a4a5e);
}
.form-help a {
  color: var(--ps-accent, #4a7afe);
  text-decoration: underline;
}
.form-help-vars {
  list-style: none;
  margin: 4px 0;
  padding: 0;
}
.form-help-vars li {
  padding: 2px 0;
  font-size: 0.85rem;
}
.form-help-vars code {
  background: var(--ps-code-bg, #ececf2);
  padding: 1px 4px;
  border-radius: 2px;
  font-size: 0.85em;
  margin-right: 4px;
}

/* ============================================================
 * Lot 13.d — Settings → Plan : usage cards & banners
 * ============================================================ */

.ps-plan-price {
  font-size: 1.6rem;
  font-weight: 700;
  color: var(--ps-text, #1f1f2c);
  line-height: 1.1;
}

/* Bandeau trial — vert si encore actif, neutre si terminé. */
.ps-plan-banner {
  margin-top: 12px;
  padding: 10px 14px;
  border-radius: 6px;
  font-size: 0.9rem;
  font-weight: 500;
}
.ps-plan-banner--trial {
  background: color-mix(in srgb, var(--success, #16a34a) 12%, transparent);
  border-left: 3px solid var(--success, #16a34a);
  color: var(--ps-text, #1f1f2c);
}
.ps-plan-banner--trial-ended {
  background: var(--surface-subtle, #f5f5f8);
  border-left: 3px solid var(--ps-muted, #94949f);
  color: var(--ps-muted, #4a4a5e);
}
/* Lot 13.d.bis — Bandeau "LLM fourni par PerfShop" sur le tab Plan
 * pour les tenants `uses_internal_llm` (plan wedding_event 9€/mo).
 * Couleur info bleue pour différencier du trial vert. */
.ps-plan-banner--hosted-llm {
  background: color-mix(in srgb, var(--info, #2563eb) 10%, transparent);
  border-left: 3px solid var(--info, #2563eb);
  color: var(--ps-text, #1f1f2c);
}

/* Grid responsive 1-3 colonnes selon la largeur. */
.ps-plan-usage-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  margin-top: 12px;
}

.ps-plan-usage-card {
  background: var(--surface, #ffffff);
  border: 1px solid var(--ps-border, #e6e6ec);
  border-radius: 8px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.ps-plan-usage-card__title {
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ps-muted, #6b6b78);
}
.ps-plan-usage-card__value {
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--ps-text, #1f1f2c);
}
.ps-plan-usage-card__sub {
  font-size: 0.78rem;
  color: var(--ps-muted, #6b6b78);
  margin-top: -2px;
}

/* Barre de progression — couleur via accent variable de la card. */
.ps-plan-usage-card__bar {
  margin-top: 6px;
  height: 6px;
  background: var(--surface-subtle, #f5f5f8);
  border-radius: 3px;
  overflow: hidden;
}
.ps-plan-usage-card__bar-fill {
  height: 100%;
  background: var(--ps-accent, #4a7afe);
  transition: width 240ms ease-out;
}

/* Coloration par seuil d'usage (calculée côté JS via usageClass). */
.ps-plan-usage-card--neutral .ps-plan-usage-card__bar-fill {
  background: var(--ps-accent, #4a7afe);
}
.ps-plan-usage-card--warning {
  border-color: color-mix(in srgb, var(--warning, #d97706) 50%, var(--ps-border, #e6e6ec));
}
.ps-plan-usage-card--warning .ps-plan-usage-card__bar-fill {
  background: var(--warning, #d97706);
}
.ps-plan-usage-card--danger {
  border-color: color-mix(in srgb, var(--danger, #dc2626) 50%, var(--ps-border, #e6e6ec));
}
.ps-plan-usage-card--danger .ps-plan-usage-card__bar-fill {
  background: var(--danger, #dc2626);
}

/* ===================================================================
   Lot 13.e.3 — Galerie templates emails : grille cards + filtres
   ===================================================================
   Refonte vue `#/email-templates` en grille de cards 4/5 (parité
   maquette Claude Design). Préserve la table tenant historique pour
   le toggle "Liste" (Lot 13.e.1.B).
   =================================================================== */

/* ─── Toolbar (search + chips filtres + view toggle) ─── */
.email-templates-gallery .page-toolbar {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: stretch;
  padding: 12px 0 20px;
  border-bottom: 1px solid var(--ps-border, #e6e6ec);
  margin-bottom: 24px;
}
.tpl-toolbar-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.tpl-search {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--ps-surface-soft, #fafbfd);
  border: 1px solid var(--ps-border, #e6e6ec);
  border-radius: 8px;
  padding: 8px 12px;
  max-width: 360px;
  flex: 1 1 240px;
}
.tpl-search input {
  background: none;
  border: none;
  outline: none;
  flex: 1;
  font-size: 0.87rem;
  color: var(--ps-text, #0f1123);
  min-width: 0;
}
.tpl-search:focus-within {
  border-color: var(--ps-accent, #5b6ad0);
  background: #fff;
  box-shadow: 0 0 0 4px rgba(91, 106, 208, 0.1);
}
.tpl-search svg {
  width: 14px;
  height: 14px;
  color: var(--ps-text-muted, #8b90b5);
  flex-shrink: 0;
}

/* ─── Chips filtres (source + catégorie) ─── */
.tpl-filters {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.tpl-filters .chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: 999px;
  background: transparent;
  border: 1px solid var(--ps-border, #e6e6ec);
  color: var(--ps-text-muted, #525879);
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.15s;
}
.tpl-filters .chip:hover {
  border-color: var(--ps-border-strong, #d6daeb);
  color: var(--ps-text, #0f1123);
}
.tpl-filters .chip.is-active {
  background: var(--ps-text, #0f1123);
  color: #fff;
  border-color: var(--ps-text, #0f1123);
}
.tpl-filters .chip .n {
  font: 500 0.7rem/1 var(--font-mono, "DM Mono", monospace);
  opacity: 0.55;
  margin-left: 4px;
}

/* ─── Toggle grid/list ─── */
.tpl-view-toggle {
  display: inline-flex;
  padding: 3px;
  background: var(--ps-surface-strong, #f2f4fa);
  border-radius: 8px;
  gap: 2px;
  margin-left: auto;
}
.tpl-view-toggle button {
  padding: 5px 10px;
  font-size: 0.78rem;
  color: var(--ps-text-muted, #525879);
  border-radius: 5px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: none;
  border: 0;
  cursor: pointer;
}
.tpl-view-toggle button.is-on {
  background: #fff;
  color: var(--ps-text, #0f1123);
  box-shadow: 0 1px 2px rgba(15, 17, 35, 0.06);
}
.tpl-view-toggle svg { width: 12px; height: 12px; }

/* ─── Grille cards ─── */
.tpl-card-grid {
  display: grid;
  gap: 22px;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.tpl-card {
  background: #fff;
  border: 1px solid var(--ps-border, #e6e6ec);
  border-radius: 14px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  cursor: pointer;
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s;
}
.tpl-card:hover {
  transform: translateY(-2px);
  border-color: var(--ps-border-strong, #d6daeb);
  box-shadow: 0 12px 32px -16px rgba(15, 17, 35, 0.18),
              0 2px 6px -2px rgba(15, 17, 35, 0.06);
}
.tpl-card-preview {
  aspect-ratio: 4 / 5;
  background: var(--ps-surface-soft, #fafbfd);
  position: relative;
  overflow: hidden;
  border-bottom: 1px solid var(--ps-border, #e6e6ec);
}
.tpl-card-preview-iframe {
  position: absolute;
  inset: 0;
  width: 200%;
  height: 200%;
  border: 0;
  transform: scale(0.5);
  transform-origin: top left;
  pointer-events: none;
  background: #fff;
}
.tpl-card-preview-fallback {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: var(--ps-text-muted, #8b90b5);
  font: 500 0.78rem/1 var(--font-mono, "DM Mono", monospace);
}

/* ─── Card corner badges (source) ─── */
.tpl-card-corner {
  position: absolute;
  top: 12px;
  left: 12px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(6px);
  border: 1px solid var(--ps-border, #e6e6ec);
  padding: 4px 8px;
  border-radius: 999px;
  font: 500 0.67rem/1 var(--font-mono, "DM Mono", monospace);
  color: var(--ps-text-muted, #525879);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  z-index: 1;
}
.tpl-card-corner .pip {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--ps-text-muted, #8b90b5);
}
.tpl-card-corner.s-gallery .pip,
.tpl-card-corner.s-forked_from_gallery .pip { background: #5b6ad0; }
.tpl-card-corner.s-ai_generated .pip { background: #7c3aed; }
.tpl-card-corner.s-blank .pip { background: var(--ps-text-muted, #8b90b5); }

.tpl-card-locale {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 24px;
  height: 24px;
  background: #fff;
  border: 1px solid var(--ps-border, #e6e6ec);
  border-radius: 50%;
  display: grid;
  place-items: center;
  font: 600 0.62rem/1 var(--font-mono, "DM Mono", monospace);
  color: var(--ps-text-muted, #525879);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  z-index: 1;
}

/* ─── Card body (titre + meta + actions) ─── */
.tpl-card-body {
  padding: 16px 18px 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex: 1;
}
.tpl-card-title {
  font-size: 0.98rem;
  font-weight: 600;
  letter-spacing: -0.012em;
  line-height: 1.25;
  color: var(--ps-text, #0f1123);
}
.tpl-card-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.78rem;
  color: var(--ps-text-muted, #8b90b5);
  flex-wrap: wrap;
}
.tpl-card-meta .cat {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--ps-surface-strong, #f2f4fa);
  color: var(--ps-text-muted, #525879);
  font: 500 0.73rem/1.4 inherit;
}
.tpl-card-meta .cat .swatch {
  width: 6px;
  height: 6px;
  border-radius: 2px;
}
.tpl-card-meta .cat.c-mariage .swatch { background: #c9a37a; }
.tpl-card-meta .cat.c-b2b .swatch { background: #5b6ad0; }
.tpl-card-meta .cat.c-evenementiel .swatch { background: #7c3aed; }
.tpl-card-meta .cat.c-relance .swatch { background: #0d9488; }
.tpl-card-meta .cat.c-newsletter .swatch { background: #d97706; }
.tpl-card-meta .sep { opacity: 0.4; }
.tpl-card-meta .updated {
  font: 500 0.73rem/1 var(--font-mono, "DM Mono", monospace);
}
.tpl-card-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 4px;
}
.tpl-card-actions .btn { padding: 6px 12px; font-size: 0.82rem; }

/* ─── Gallery panel inline (déployable) ─── */
.tpl-gallery-panel {
  margin-top: 32px;
  padding: 24px 0;
  border-top: 2px dashed var(--ps-border-strong, #d6daeb);
}
.tpl-gallery-panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}
.tpl-gallery-panel-header h2 { font-size: 1.4rem; margin: 0; }
.tpl-gallery-empty {
  padding: 48px 24px;
  text-align: center;
  color: var(--ps-text-muted, #525879);
}

/* ─── Footnote + empty grid ─── */
.tpl-footnote {
  margin-top: 48px;
  padding-top: 24px;
  border-top: 1px solid var(--ps-border, #e6e6ec);
  font: 500 0.73rem/1.5 var(--font-mono, "DM Mono", monospace);
  color: var(--ps-text-muted, #8b90b5);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
  justify-content: space-between;
}
.tpl-empty {
  padding: 80px 24px;
  text-align: center;
  background: var(--ps-surface-soft, #fafbfd);
  border: 1px dashed var(--ps-border-strong, #d6daeb);
  border-radius: 14px;
  color: var(--ps-text-muted, #525879);
}

/* ─── Admin email-themes ─── */
.admin-email-themes-table .mjml-preview {
  height: 320px;
  width: 100%;
  border: 1px solid var(--ps-border, #e6e6ec);
  border-radius: 8px;
  background: #fff;
}
.admin-email-themes-form textarea.mjml-source {
  font: 13px/1.45 var(--font-mono, "DM Mono", monospace);
  min-height: 280px;
  width: 100%;
  resize: vertical;
}

/* Lot 13.e.4.B — `.c-danger` standalone (hors `.chip.c-danger`) — hard delete
 * UI titre + bouton. Gotcha #35 : vérifier classe avant innerHTML use. */
h1.c-danger, h2.c-danger, h3.c-danger, p.c-danger,
.form-help.c-danger,
[data-hard-delete-error].c-danger {
  color: var(--danger);
}
.btn.c-danger {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
  box-shadow: none;
}
.btn.btn-ghost.c-danger {
  background: transparent;
  border-color: var(--danger);
  color: var(--danger);
}
.btn.btn-ghost.c-danger:hover {
  background: rgba(255, 71, 87, 0.08);
}

/* Lot 13.e.4.B — modale form admin grid 2 colonnes (form + live preview) */
.admin-email-themes-form-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 24px;
}
.admin-email-themes-form-fields {
  min-width: 0;
}
.admin-email-themes-form-preview {
  position: sticky;
  top: 16px;
  align-self: start;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.admin-email-themes-form-preview-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.admin-email-themes-form-preview-header h3 {
  margin: 0;
  font-size: 14px;
  color: var(--ps-text-muted, #525879);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.admin-email-themes-form-preview-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}
.admin-email-themes-form-preview .form-inline-toggle {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: var(--ps-text-muted, #525879);
}
.admin-email-themes-form-preview iframe.mjml-preview {
  width: 100%;
  height: 500px;
  border: 1px solid var(--ps-border, #e6e6ec);
  border-radius: 8px;
  background: #fff;
}

/* ─── Responsive ─── */
@media (max-width: 920px) {
  .admin-email-themes-form-grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .admin-email-themes-form-preview {
    position: static;
  }
  .admin-email-themes-form-preview iframe.mjml-preview {
    height: 360px;
  }
}
@media (max-width: 720px) {
  .tpl-card-grid { grid-template-columns: 1fr; }
  .tpl-filters,
  .tpl-toolbar-row { overflow-x: auto; flex-wrap: nowrap; }
}
