/* Polices auto-hébergées (charte EmotionWay) — fichiers .woff2 versionnés dans assets/fonts/,
   extraits à l'origine des paquets @fontsource/space-grotesk et @fontsource/instrument-sans
   (retirés du projet au bloc 0b-1 : plus aucune dépendance, pas de bundler dans ce projet). */
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:500;font-display:swap;src:url('/assets/fonts/space-grotesk-latin-500-normal.woff2') format('woff2')}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:700;font-display:swap;src:url('/assets/fonts/space-grotesk-latin-700-normal.woff2') format('woff2')}
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:400;font-display:swap;src:url('/assets/fonts/instrument-sans-latin-400-normal.woff2') format('woff2')}
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:500;font-display:swap;src:url('/assets/fonts/instrument-sans-latin-500-normal.woff2') format('woff2')}
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:600;font-display:swap;src:url('/assets/fonts/instrument-sans-latin-600-normal.woff2') format('woff2')}
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:700;font-display:swap;src:url('/assets/fonts/instrument-sans-latin-700-normal.woff2') format('woff2')}

:root{
  /* Couleurs : base.css (Bloc A), chargée avant ce fichier sur chaque page — seule source. */
  --radius:14px;
  /* BLOC V.3 §2 (partie 2) — hauteur réelle du bandeau d'observation (0 si absent/masqué),
     posée en JS (loadMe, dashboard.js) une fois le bandeau mesuré — décale tous les éléments
     sticky sous le header (maintabs, client-sticky) du même montant, jamais un chiffre en dur
     qui se désynchroniserait si le bandeau change de taille (retour à la ligne mobile, etc). */
  --obs-h:0px;
}
*{box-sizing:border-box;margin:0;padding:0}
/* Filet de sécurité mobile : aucun élément ne doit jamais forcer un scroll horizontal sur la
   page entière (BUG responsive) — les zones qui ont besoin de défiler horizontalement (table
   des posts, historique des collectes, onglets) le font dans leur propre conteneur
   overflow-x:auto, jamais sur html/body. */
html{overflow-x:hidden}
body{background:var(--bg);color:var(--white);font-size:15px;line-height:1.5;min-height:100vh;overflow-x:clip}
h1,h2.section,.cname,.modal-title{font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif}
/* Bloc M1 — l'en-tête de la PAGE seulement (enfant direct de body) : un sélecteur `header` nu
   rendait aussi collants, à z-index 50, les <header> internes (accueil .ajd-head, fiche lead,
   bilan) — sur téléphone, « Bonjour… » et ses compteurs passaient par-dessus le menu ouvert. */
body > header{position:sticky;top:var(--obs-h);z-index:50;background:rgba(22,23,26,.92);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
.observation-banner{position:sticky;top:0;z-index:55;display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:12px;background:var(--orange);color:var(--bg);font-weight:600;font-size:13px;padding:9px 16px;text-align:center}
.observation-banner.hidden{display:none}
.observation-exit-btn{background:var(--bg);color:var(--white);border:none;border-radius:8px;padding:6px 14px;font-weight:600;font-size:12.5px;cursor:pointer;font-family:inherit}
.hwrap{max-width:1280px;margin:0 auto;padding:13px 24px;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
/* Logo bitmap (A1) : fond blanc/orange conçu pour un fond sombre — jamais de fond clair
   derrière (le header est toujours rgba(22,23,26,.92)). */
.logo{height:28px;width:auto;display:block;flex:none}
#logoLink{display:inline-flex;align-items:center;line-height:0}
.hspacer{flex:1}

/* BLOC B — indicateur permanent de collecte, en-tête, sur toutes les pages. Discret par défaut
   (texte gris, pas de fond) ; devient visible (couleur + fond + libellé explicite) en cas
   d'échec/collecte en cours — jamais caché, cf. computeCollectStatusChip (dashboard-logic.js). */
.collect-status-chip{display:flex;align-items:center;gap:6px;font-size:11.5px;color:var(--grey-dim);
  text-decoration:none;padding:5px 10px;border-radius:20px;border:1px solid transparent;white-space:nowrap}
.collect-status-chip .short-label{display:none}
.collect-status-chip:hover{color:var(--grey);border-color:var(--line)}
.collect-status-chip .dot{width:6px;height:6px;border-radius:50%;background:var(--grey-dim);flex:none}
.collect-status-chip.ok .dot{background:var(--ok)}
.collect-status-chip.unknown .dot{background:var(--grey-dim)}
.collect-status-chip.running{color:var(--cyan);border-color:rgba(97,206,207,.3);background:rgba(97,206,207,.08)}
.collect-status-chip.running .dot{background:var(--cyan)}
.collect-status-chip.warn{color:var(--warn);border-color:rgba(245,196,81,.3);background:rgba(245,196,81,.08)}
.collect-status-chip.warn .dot{background:var(--warn)}
.collect-status-chip.err{color:var(--bad);font-weight:700;border-color:rgba(232,106,92,.35);background:rgba(232,106,92,.08)}
.collect-status-chip.err .dot{background:var(--bad)}

.center-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px}
.card{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);padding:32px;width:100%;max-width:380px}
.card h1{font-size:20px;font-weight:700;margin-bottom:6px}
.card p.sub{color:var(--grey-dim);font-size:13px;margin-bottom:22px}
label{display:block;font-size:12.5px;font-weight:600;color:var(--grey);margin:14px 0 6px}
input[type=text],input[type=password]{
  width:100%;background:var(--bg-card-hi);border:1px solid var(--line);border-radius:8px;
  color:var(--text-2);padding:10px 12px;font-family:inherit;font-size:14px;
}
input:focus{outline:2px solid var(--orange);outline-offset:1px}
/* Champs sans règle dédiée (e-mail, URL, date, nombre, heure, liste, zone de texte) : même
   apparence que les champs texte. :where() = spécificité nulle, toute règle de contexte
   existante garde la main. */
:where(input[type=email],input[type=url],input[type=date],input[type=number],input[type=time],input[type=search],select,textarea){
  background:var(--bg-card-hi);border:1px solid var(--line-strong);border-radius:8px;
  color:var(--text-2);padding:8px 10px;font-family:inherit;font-size:13.5px;line-height:1.5}
:where(select,textarea):focus{outline:2px solid var(--orange);outline-offset:1px}
/* Champ pleine largeur de sa carte ; une zone de texte garde au moins 3 lignes visibles. */
.settings-field{display:block;width:100%}
textarea.settings-field{min-height:calc(4.5em + 18px);resize:vertical}
/* Focus clavier visible sur tout élément activable, quel que soit son style. */
:where(button,a,summary,[tabindex]):focus-visible{outline:2px solid var(--orange-bright);outline-offset:2px}
.card button{
  margin-top:20px;width:100%;background:var(--orange);color:var(--bg);border:none;border-radius:8px;
  padding:11px 14px;font-family:inherit;font-size:14px;font-weight:700;cursor:pointer;
}
.card button:hover{opacity:.9}
.card button:disabled{opacity:.5;cursor:not-allowed}
.msg{margin-top:14px;font-size:13px;border-radius:8px;padding:9px 12px;display:none}
.msg.err{display:block;color:var(--bad);background:rgba(232,106,92,.1)}
.msg.ok{display:block;color:var(--ok);background:rgba(95,203,142,.1)}
.msg.info{display:block;color:var(--text-2);background:var(--bg-card-hi);border:1px solid var(--line)}
#reason-msg{margin:0 0 16px}
.forgot-link{margin:-4px 0 14px;font-size:13px;text-align:right}
.forgot-link a{color:var(--orange-bright);text-decoration:underline;text-underline-offset:2px}
.hint{font-size:12px;color:var(--grey-dim);margin-top:18px}
.hint a{color:var(--grey);text-decoration:none}
.hint a:hover{color:var(--white);text-decoration:underline}

main.app{max-width:1280px;margin:0 auto;padding:22px 24px 96px}

/* BLOC C.1 — pied de page sobre, sur toutes les pages (remplace l'ancienne note de
   développement "données réelles, lues depuis SQLite…"). Aucun jargon technique. */
footer.app-footer{max-width:1280px;margin:0 auto;padding:20px 24px 32px;display:flex;
  align-items:center;justify-content:center;gap:8px;font-size:11.5px;color:var(--grey-dim);
  flex-wrap:wrap;text-align:center}
footer.app-footer a{color:var(--grey-dim);text-decoration:none}
footer.app-footer a:hover{color:var(--grey)}
footer.app-footer .app-footer-sep{opacity:.5}
.userchip{font-size:13px;color:var(--grey);display:flex;align-items:center;gap:10px}
.userchip b{color:var(--text-2)}
/* Version compacte (avatar rond, initiale) — cachée sur desktop, remplace le texte complet sur
   mobile (BUG responsive : "Nom · rôle" + bouton pleine largeur ne tenaient pas sur une ligne
   avec le logo, forçant l'en-tête sur 2 lignes). */
.userchip-avatar{display:none;align-items:center;justify-content:center;width:28px;height:28px;
  border-radius:50%;background:var(--bg-card-hi);border:1px solid var(--line);color:var(--white);
  font-size:12px;font-weight:700;flex:none}
.badge{display:inline-flex;align-items:center;font-size:11px;font-weight:700;letter-spacing:.05em;
  color:var(--warn);background:rgba(245,196,81,.1);border-radius:999px;padding:3px 9px;text-transform:uppercase}
.linkbtn{background:none;border:1px solid var(--line);color:var(--grey);border-radius:8px;padding:6px 12px;
  font-family:inherit;font-size:13px;cursor:pointer}
.linkbtn:hover{color:var(--white);border-color:var(--grey-dim)}
.linkbtn .btn-icon{display:none}
a.linkbtn{display:inline-block;text-decoration:none}
.shell{background:var(--bg-card);border:1px dashed var(--line);border-radius:var(--radius);padding:40px 24px;
  text-align:center;color:var(--grey-dim);margin-top:24px}

/* ===== Dashboard — repris de design/maquette_dashboard_v2.html, charte EmotionWay ===== */
/* Navigation principale du PORTAIL CLIENT (l'agence a le menu à gauche, Bloc A) — collante juste
   sous l'en-tête. Bloc A : les hauteurs de l'en-tête et de cette rangée sont MESURÉES
   (layout-offsets.js → --header-h/--maintabs-h, base.css), plus jamais écrites en dur dans les
   décalages des barres collantes suivantes (.toolbar/.client-sticky/.ptl-sticky → --sticky-top). */
.maintabs{display:flex;align-items:center;gap:8px;position:sticky;top:calc(var(--obs-h) + var(--header-h));z-index:45;height:54px;background:var(--bg);border-bottom:1px solid var(--line)}
.maintab{flex:1;height:38px;display:flex;align-items:center;justify-content:center;background:var(--bg-card);border:1px solid var(--line);border-radius:9px;color:var(--grey);font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;font-weight:600;font-size:13.5px;cursor:pointer}
.maintab:hover{color:var(--white)}
.maintab.on{background:var(--bg-card-hi);color:var(--white);border-color:var(--orange)}
/* BLOC I.4 §2 — onglet verrouillé : reste visible (vitrine de ce qui est proposé), cadenas
   discret, jamais cliquable en pratique (le clic n'appelle jamais switchMainTab, voir
   wireMainTabs) — le curseur "not-allowed" le confirme visuellement avant même le clic. */
.maintab.locked{opacity:.55;cursor:not-allowed}
.maintab.locked:hover{color:var(--grey)}
.maintab.locked::after{content:'🔒';margin-left:6px;font-size:11px}
/* Explication au clic sur un onglet verrouillé (brief : jamais un refus sec) — un seul élément
   réutilisé pour tous les onglets, jamais une pastille par bouton. */
.locked-tab-explain{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);
  padding:12px 16px;font-size:13px;color:var(--grey);margin-bottom:14px}

/* Collant sous #mainTabs (REFONTE 1/2) : le sélecteur de période reste accessible pendant le
   scroll, sur le portefeuille comme en vue client. top = --sticky-top (bandeau d'observation +
   en-tête + #mainTabs, hauteurs mesurées — base.css). */
.toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:20px;position:sticky;top:var(--sticky-top);z-index:40;background:var(--bg);padding:10px 0}
/* Sur l'accueil, #toolbar est déplacé ici par JS (switchMainTab, dashboard.js), en enfant DIRECT
   de #accueil — jamais dans un slot dédié qui ne contiendrait que lui. Cause exacte du bandeau non
   collant (relecture Thomas, deuxième passe : la position:sticky elle-même n'a jamais été en
   cause) : un position:sticky est borné par la boîte de contenu de son parent — s'il est le SEUL
   enfant de ce parent, cette boîte fait exactement sa propre hauteur, donc aucune marge de
   manœuvre pour se détacher du flux : l'élément reste "collé" à sa position naturelle et défile
   avec la page, sans qu'aucun overflow ni transform ne soit en cause. #accueil (toute la section)
   est un parent assez grand pour laisser cette marge, comme #mainTabs (collant, jamais cassé) dont
   le parent est main.app en entier. */
#accueil > .toolbar{margin-bottom:14px;padding:14px 0 0}
.chip{border:1px solid var(--line);background:var(--bg-card);color:var(--grey);border-radius:999px;padding:7px 15px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit;transition:color .13s,background-color .13s,border-color .13s;display:inline-flex;align-items:center;gap:6px;margin:0}
.chip:hover{color:var(--white)}
.chip.on{background:var(--white);color:var(--bg);border-color:var(--white)}
.chip.locked{opacity:.45;cursor:not-allowed}
.chip .dot{width:8px;height:8px;border-radius:50%}
.chip:focus-visible{outline:2px solid var(--orange);outline-offset:2px}
.chip-sm{padding:4px 10px;font-size:11.5px}
.scatter-scale-toggle{display:flex;gap:4px}
.tsep{width:1px;height:22px;background:var(--line);margin:0 4px}
/* Bouton retour + nom du client (REFONTE 2) : à l'intérieur de #client, sa visibilité suit
   déjà celle de la section (plus besoin d'une classe .show séparée). */
.client-header{display:flex;align-items:baseline;gap:16px;flex-wrap:wrap;margin-bottom:18px}
.back{display:inline-flex;align-items:center;gap:8px;color:var(--grey);background:none;border:none;font-family:inherit;font-size:13.5px;font-weight:600;cursor:pointer;padding:6px 0}
.back:hover{color:var(--white)}
.client-name{font-size:26px;font-weight:700;letter-spacing:-.01em;display:flex;align-items:center;gap:10px}

/* REFONTE : bloc collant UNIQUE en vue client — nom+retour / période / onglets, une seule
   barre sticky au lieu de trois empilées. #toolbar y est déplacé par JS (jamais dupliqué).
   top = --sticky-top, même calcul que .toolbar ci-dessus. */
.client-sticky{position:sticky;top:var(--sticky-top);z-index:40;background:var(--bg);padding-top:10px;margin-bottom:18px;border-bottom:1px solid var(--line)}
.client-sticky .client-header{margin-bottom:8px}
.client-sticky .toolbar{position:static;margin-bottom:8px;padding:0}
.client-sticky .ctabs{margin:0;border-bottom:none;padding-bottom:10px}
/* Séparateur visuel entre les 2 groupes d'onglets (Général | réseaux) — Ads a migré dans
   l'onglet principal "Campagnes" (transversal, #mainTabs). */
.ctab-sep{width:1px;align-self:stretch;background:var(--line);margin:0 4px}
h2.section{font-size:13px;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--grey-dim);margin:26px 0 13px}
h2.section b{color:var(--grey)}
.hint-roadmap{font-size:12px;color:var(--grey-dim);background:var(--bg-card);border:1px dashed var(--line);border-radius:10px;padding:9px 14px;margin-bottom:18px}
.hint-roadmap b{color:var(--grey)}
/* État vide : toujours une zone délimitée (contour pointillé), jamais un texte flottant. Dans une
   cellule de tableau ou un graphique, le conteneur suffit : pas de second cadre. */
.empty-state{color:var(--grey);font-size:13px;padding:18px 20px;text-align:center;
  background:var(--bg-card);border:1px dashed var(--line-strong);border-radius:var(--radius)}
td.empty-state{background:none;border:0;border-radius:0}
.hidden{display:none!important}
.chartbox .empty-state{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:none;border:0}
.loading-state{display:flex;align-items:center;justify-content:center;gap:8px}

.spinner{width:14px;height:14px;border-radius:50%;border:2px solid var(--line);border-top-color:var(--orange);animation:spin .8s linear infinite;flex:none}
@keyframes spin{to{transform:rotate(360deg)}}

/* Squelettes de chargement (AJOUT 2) — évite que la page saute pendant un fetch, plutôt qu'un
   spinner central qui masque toute la mise en page en cours de construction. */
.skeleton{background:var(--bg-card-hi);border-radius:6px;animation:skeleton-pulse 1.4s ease-in-out infinite}
@keyframes skeleton-pulse{0%,100%{opacity:1}50%{opacity:.45}}
@media (prefers-reduced-motion: reduce){
  .skeleton{animation:none;opacity:.6}
}
.skeleton-card{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);padding:18px}
.skeleton-line{height:11px;margin-bottom:10px}
.skeleton-line:last-child{margin-bottom:0}
.skeleton-kcard{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);padding:15px 17px}
.skeleton-kcard .skeleton-line:first-child{height:9px;width:60%;margin-bottom:12px}
.skeleton-kcard .skeleton-line:last-child{height:20px;width:45%}

/* Bannière de progression d'une collecte (refresh/backfill) — sondée via /api/collect/status */
.collect-banner{display:flex;align-items:flex-start;gap:12px;background:var(--bg-card);border:1px solid var(--line);border-radius:10px;padding:10px 14px;margin-bottom:16px;font-size:13px;color:var(--grey)}
.collect-banner .spinner{margin-top:3px}
.collect-banner-main{flex:1;min-width:0}
.collect-banner-row{display:flex;align-items:baseline;justify-content:space-between;gap:10px;font-size:12px}
.collect-banner-row:first-child{margin-bottom:6px}
.collect-banner-row:last-child{margin-top:6px}
#collectBannerText{color:var(--white);font-weight:600;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.collect-progress-pct{font-family:'IBM Plex Mono',monospace;font-weight:600;color:var(--white);white-space:nowrap;flex:none}
.collect-progress-track{height:6px;border-radius:3px;background:var(--bg-card-hi);overflow:hidden}
.collect-progress-fill{height:100%;width:0;background:var(--orange);border-radius:3px;transition:width .3s}
.collect-progress-count{font-family:'IBM Plex Mono',monospace;font-size:12px;color:var(--grey);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.collect-progress-eta{font-family:'IBM Plex Mono',monospace;font-size:12px;color:var(--grey-dim);white-space:nowrap;flex:none}
/* BUG backfill interrompu : run mort détecté côté client (aucune progression depuis
   COLLECT_STALE_MINUTES) — remplace le compteur qui grimperait sans fin par un état explicite. */
.collect-banner.stale{border-color:var(--bad)}
.collect-banner.stale .spinner{display:none}
.collect-banner.stale #collectBannerText{color:var(--bad)}
#collectRelaunchBtn{font-family:inherit;font-size:12px;font-weight:600;color:var(--bg);background:var(--bad);border:none;border-radius:8px;padding:4px 10px;cursor:pointer;margin-top:0}
#collectRelaunchBtn:disabled{opacity:.6;cursor:default}

/* AJOUT : panneau admin de contrôle des collectes — BUG « mal placé » : outil technique,
   repliable, replié par défaut (une ligne résumée), déplié automatiquement seulement si une
   collecte est en cours ou si la dernière a échoué (jamais refermé automatiquement ensuite). */
.admin-panel{background:var(--bg-card);border:1px solid var(--line);border-radius:10px;margin-bottom:18px;overflow:hidden}
.panel-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;gap:10px;
  background:none;border:none;color:var(--grey);font-family:inherit;font-size:13px;font-weight:600;
  padding:13px 16px;cursor:pointer;text-align:left}
.panel-toggle:hover{color:var(--white)}
.panel-toggle .chev{transition:transform .15s;color:var(--grey-dim);flex:none}
.panel-toggle.open .chev{transform:rotate(180deg)}
.admin-panel-body{padding:14px 16px 16px;border-top:1px solid var(--line)}
.admin-panel-head{display:flex;align-items:baseline;gap:10px;margin-bottom:10px}
.admin-panel-head b{font-size:14px;color:var(--white)}
.admin-panel-actions{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
/* Les boutons de cette barre portent .settings-btn-secondary ; la liste s'aligne sur leur hauteur. */
.admin-panel-actions select{font-family:inherit;font-size:13.5px;color:var(--text-2);background:var(--bg-card-hi);border:1px solid var(--line-strong);border-radius:8px;padding:9px 12px;cursor:pointer;line-height:1.5}
.admin-panel-msg{font-size:12px;margin-top:8px}
.admin-panel-msg.ok{color:var(--ok)}
.admin-panel-msg.err{color:var(--bad)}
/* BUG responsive : le tableau n'a jamais de largeur minimale supérieure au viewport imposée à
   la PAGE — il défile dans son propre conteneur, comme .tablewrap pour les posts. */
.admin-panel-history{margin-top:12px;overflow-x:auto;-webkit-overflow-scrolling:touch}
.admin-history-table{width:100%;min-width:480px;border-collapse:collapse;font-size:12px}
.admin-history-table th{text-align:left;color:var(--grey-dim);font-weight:600;padding:4px 8px;border-bottom:1px solid var(--line)}
.admin-history-table td{padding:5px 8px;border-bottom:1px solid var(--line);color:var(--grey)}
.run-status{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;padding:2px 7px;border-radius:8px;background:rgba(148,152,160,.15);color:var(--grey)}
.run-status.ok{color:var(--ok);background:rgba(95,203,142,.12)}
.run-status.running{color:var(--warn);background:rgba(245,196,81,.12)}
.run-status.partial{color:var(--warn);background:rgba(245,196,81,.12)}
.run-status.failed,.run-status.cancelled,.run-status.error{color:var(--bad);background:rgba(232,106,92,.12)}
.run-status.skipped,.run-status.idle{color:var(--grey-dim);background:rgba(148,152,160,.12)}

/* BLOC R.1 §4 — progression source par source (Metricool/Asana/agenda) de la passe unifiée. */
.collect-sources-banner{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:16px}
.collect-source-chip{padding:3px 9px}

/* BLOC J.0 §3 — nature d'un échec de collecte (Timeout/Authentification/Marque introuvable/
   Limite API/Erreur), même langage visuel que .run-status : rouge = nécessite une action,
   orange = transitoire (se résorbe seul au run suivant), gris = non catégorisé. */
.collect-error-kind{font-size:10px;font-weight:700;letter-spacing:.02em;padding:2px 7px;border-radius:8px;
  background:rgba(148,152,160,.15);color:var(--grey);white-space:nowrap;margin-right:2px}
.collect-error-kind.bad{color:var(--bad);background:rgba(232,106,92,.12)}
.collect-error-kind.warn{color:var(--warn);background:rgba(245,196,81,.12)}
.collect-error-kind.unknown{color:var(--grey-dim);background:rgba(148,152,160,.12)}

/* Cartes clients */
.cgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:14px}
.ccard{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);padding:18px 34px 18px 18px;cursor:pointer;transition:border-color .15s,background-color .15s;position:relative;text-align:left;font-family:inherit;color:inherit;width:100%}
/* BLOC P.3 §7 — CORRECTIF : rien n'indiquait qu'une carte de marque est cliquable (on le
   découvrait au survol) — chevron permanent à droite + survol nettement plus marqué (bordure
   orange + fond légèrement relevé, pas juste un gris à peine différent). */
.ccard:hover{border-color:var(--orange);background:var(--bg-card-hi)}
.ccard:focus-visible{outline:2px solid var(--orange)}
.ccard-chevron{position:absolute;top:18px;right:14px;font-size:22px;line-height:1;color:var(--grey-dim);transition:color .15s,transform .15s}
.ccard:hover .ccard-chevron{color:var(--orange);transform:translateX(2px)}
.cname{font-weight:700;font-size:16px;display:flex;align-items:center;gap:8px;margin-bottom:2px}
.cname .inactive{font-size:10.5px;font-weight:700;color:var(--grey-dim);background:rgba(148,152,160,.12);border-radius:8px;padding:2px 7px;letter-spacing:.04em;text-transform:uppercase}
.cpastilles{display:flex;gap:6px;margin-left:auto}
.csub{color:var(--grey-dim);font-size:12px;margin-bottom:12px}

/* Portefeuille simplifié (REFONTE 1) — 3 informations par carte, rien de plus */
.ccard-metric{display:flex;align-items:baseline;justify-content:space-between;gap:8px;padding:8px 0;border-top:1px solid var(--line)}
.ccard-metric:first-of-type{border-top:none;padding-top:0}
.ccard-metric-label{font-size:12px;color:var(--grey)}
.ccard-metric-val{font-family:'IBM Plex Mono',monospace;font-weight:600;color:var(--white);font-size:15px}
.ccard-metric-val.up{color:var(--ok)} .ccard-metric-val.down{color:var(--bad)}
.ccard-axes{font-size:11.5px;color:var(--grey-dim);margin:-4px 0 4px}
.ccard-campaign{display:flex;align-items:center;flex-wrap:wrap;gap:6px 8px;margin-top:10px;padding-top:10px;border-top:1px solid var(--line)}
.ccard-campaign-badge{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--ok);background:rgba(95,203,142,.12);border-radius:8px;padding:2px 7px}
.ccard-campaign-cpl{font-family:'IBM Plex Mono',monospace;font-weight:600;color:var(--white);font-size:13px}
.ccard-campaign-stage{font-size:10.5px;color:var(--grey-dim)}
.netline{display:flex;align-items:center;gap:8px;margin-top:7px;font-size:13px;color:var(--grey)}
.netdot{width:8px;height:8px;border-radius:50%;flex:none}
.netline .v{font-family:'IBM Plex Mono',monospace;font-weight:600;color:var(--white);font-size:13.5px;margin-left:auto}
.netline .delta{font-family:'IBM Plex Mono',monospace;font-size:11.5px;margin-left:6px}
.netline .delta.up{color:var(--ok)}
.netline .delta.down{color:var(--bad)}
.netline .delta.flat{color:var(--grey-dim)}

/* Pastilles de vigilance (organique/Ads) — le pire des indicateurs, jamais une donnée fabriquée */
/* Bloc 0b-3b E — puce « glyphe + nom » (✓ Organique, ! Ads…) : le glyphe porte l'état sans la
   couleur, le nom dit ce qui est jugé ; la teinte n'est plus qu'un renfort. */
.pastille{display:inline-flex;align-items:center;gap:5px;height:22px;padding:0 8px 0 3px;border-radius:11px;flex:none;cursor:default;position:relative;
  background:var(--bg-card-hi);border:1px solid var(--line);font-size:11.5px;font-weight:600;color:var(--grey);white-space:nowrap}
.pastille-glyph{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:50%;
  font-size:10.5px;font-weight:800;line-height:1;color:var(--bg)}
.pastille.ok .pastille-glyph{background:var(--ok)}
.pastille.warn .pastille-glyph{background:var(--warn)}
.pastille.bad .pastille-glyph{background:var(--bad)}
.pastille.unknown .pastille-glyph{background:var(--unknown)}
.pastille-wrap{position:relative;display:inline-flex}
.pastille-pop{display:none;position:absolute;top:calc(100% + 8px);right:0;z-index:20;background:var(--bg-card-hi);border:1px solid var(--line);border-radius:10px;padding:10px 12px;width:230px;box-shadow:0 8px 24px rgba(0,0,0,.35);font-size:12px;color:var(--grey)}
.pastille-wrap:hover .pastille-pop,.pastille-wrap:focus-within .pastille-pop{display:block}

/* BLOC L.1.1 §5 — CORRECTIF : rendu initial trop voyant (cercle bordé, orange vif au repos plutôt
   qu'au survol) — refait en texte inline discret, même taille que le texte qui l'entoure, jamais
   un badge à part. `appearance:none` : un <button> garde sinon un fond/bordure natifs du
   navigateur (chrome clair selon l'OS) même avec `background:transparent` posé, ce qui produisait
   le "fond clair" signalé — jamais un survol seul (inutilisable au tactile, voir glossary.js). */
.glossary-hint{display:inline;appearance:none;-webkit-appearance:none;padding:0 1px;margin:0;border:0;
  background:none;color:var(--grey-dim);font-size:1em;font-weight:700;font-family:inherit;line-height:inherit;
  cursor:pointer;vertical-align:baseline;opacity:.6}
.glossary-hint:hover,.glossary-hint:focus-visible,.glossary-hint[aria-expanded="true"]{opacity:1;color:var(--orange-bright)}
.glossary-popover{position:fixed;z-index:60;background:var(--bg-card-hi);border:1px solid var(--line);
  border-radius:10px;padding:10px 12px;width:220px;max-width:calc(100vw - 16px);box-shadow:0 8px 24px rgba(0,0,0,.4);font-size:12px;color:var(--grey)}
.glossary-popover b{display:block;color:var(--white);font-size:12px;margin-bottom:4px}
.pastille-pop b{color:var(--white);display:block;margin-bottom:4px;font-size:12.5px}

/* KPI + panels */
.kgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(165px,1fr));gap:12px}
.kcard{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);padding:15px 17px}
.klabel{font-size:12px;color:var(--grey);font-weight:600;display:flex;align-items:center;gap:6px}
.kdot{width:8px;height:8px;border-radius:2px;flex:none}
.kval{font-family:'IBM Plex Mono',monospace;font-size:25px;font-weight:600;letter-spacing:-.02em;margin-top:4px}
.ksub{font-size:11.5px;color:var(--grey-dim);margin-top:2px}
/* BLOC M.1 §3 — variations colorées (Accueil client uniquement, où seuls des volumes sont
   affichés) : hausse = favorable, jamais l'inverse sur cette page précise — voir
   clientHomeDeltaTone, dashboard-logic.js. */
.ksub.up{color:var(--ok)}
.ksub.down{color:var(--bad)}
.duo{display:grid;grid-template-columns:1.6fr 1fr;gap:14px}
.duo2{display:grid;grid-template-columns:1fr 1fr;gap:14px}
@media(max-width:920px){.duo,.duo2{grid-template-columns:1fr}}
/* BLOC C.1 — quand le panneau voisin (vigilance) est masqué pour le rôle client, celui-ci
   reprend toute la largeur de la ligne plutôt que de laisser une colonne vide. */
.duo2 .panel-full{grid-column:1/-1}
/* BUG débordement horizontal (Accueil, "Meilleurs posts" avec de vraies légendes longues) : un
   item de grille CSS a par défaut min-width:auto (jamais 0), donc même une colonne unique ne
   force pas la carte à rétrécir sous la largeur "min-content" de son contenu — ici .fmt-row
   (badge réseau + .ptext + valeur) refusait de rétrécir sous ~500px malgré .ptext{min-width:0}
   déjà posé un niveau plus bas (qui ne suffit pas si le PARENT grid item ne rétrécit pas
   lui-même). Même correctif que .ptext, un niveau au-dessus. */
.panel{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);padding:18px;min-width:0}
.ptitle{font-size:13.5px;font-weight:700;margin-bottom:12px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.ptitle .hint{font-weight:500;color:var(--grey-dim);font-size:12px;margin-left:auto}
/* BLOC J.2.1 — abonnés gagnés mis en valeur : nombre en grand (même gabarit que .kval, les
   grands chiffres de l'accueil) en haut à droite du cadre followers, aligné avec le titre
   (couleurs ok/bad déjà utilisées pour un delta ailleurs, ex. .netline .delta — jamais
   l'orange de marque, réservé aux accents d'interface, pas à un jugement de tendance). */
.ptitle.ptitle-fol{align-items:flex-start}
.ptitle-fol-title{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.followers-gained{margin-left:auto;text-align:right;flex:none}
.followers-gained-num{font-family:'IBM Plex Mono',monospace;font-size:25px;font-weight:600;letter-spacing:-.02em;color:var(--white)}
.followers-gained.up .followers-gained-num{color:var(--ok)}
.followers-gained.down .followers-gained-num{color:var(--bad)}
.followers-gained-label{font-size:11.5px;color:var(--grey-dim);margin-top:2px}
/* BLOC N.4 §5 — total d'abonnés actuel (rôle client uniquement, renderClientFollowersTotal) :
   valeur PRINCIPALE, même gabarit que .followers-gained-num avant démotion. `.has-total` n'est
   jamais posée côté staff (retour anticipé dans la fonction) — .followers-gained-num n'y est donc
   jamais concernée par la règle de démotion juste en dessous. */
.followers-total-num{font-family:'IBM Plex Mono',monospace;font-size:25px;font-weight:600;letter-spacing:-.02em;color:var(--white)}
.followers-total-label{font-size:11.5px;color:var(--grey-dim);margin-top:2px}
.followers-total-breakdown{font-size:11px;color:var(--grey-dim);margin-top:4px}
/* Le gain redevient une valeur SECONDAIRE une fois le total affiché au-dessus. */
.followers-gained.has-total{margin-top:8px}
.followers-gained.has-total .followers-gained-num{font-size:15px}
/* Mobile : le bloc passe sous le titre plutôt que de comprimer le graphique (le panel reste
   plein écran, .chartbox n'est jamais concerné par ce wrap). */
@media(max-width:640px){
  .ptitle.ptitle-fol{flex-direction:column;align-items:flex-start}
  .ptitle-fol .followers-gained{margin-left:0;text-align:left;width:100%;margin-top:4px}
}
.chartbox{position:relative;height:250px;max-width:100%}
.chartbox canvas{max-width:100%!important}
/* BLOC N.1 — hauteur réduite sur mobile (250px est proportionnellement trop haut sur un écran
   étroit ; les infobulles Chart.js restent utilisables au tactile par défaut, aucun CSS requis
   pour ça). */
@media(max-width:640px){.chartbox{height:190px}}
/* BLOC N.4 §9 — barres horizontales "vues par réseau" (Accueil client) : compacte, pas besoin de
   la hauteur d'un graphique temporel (2-4 réseaux au plus). */
.chartbox-network-bars{height:140px;margin-top:12px}
@media(max-width:640px){.chartbox-network-bars{height:120px}}
.campaign-cpl-history{margin-top:14px}
.campaign-cpl-history .ptitle{font-size:12.5px;color:var(--grey);margin-bottom:6px}
.campaign-cpl-history-head{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}
.campaign-cpl-history-head .ptitle{margin-bottom:0}
.campaign-period-select{display:flex;gap:6px}
/* BLOC — Ads : deux panneaux distincts (brief 21/09/2026, point 6) — le premier (coût par lead)
   n'existe qu'en cas A, jamais empilé sans espace sur le second (activité, toujours affiché). */
.campaign-history-panel{margin-top:10px}
.campaign-history-panel-title{font-size:11px;font-weight:600;color:var(--grey-dim);text-transform:uppercase;letter-spacing:.03em;margin-bottom:4px}
.campaign-history-panel .chartbox{height:170px}
@media(max-width:640px){.campaign-history-panel .chartbox{height:150px}}
.chart-legend{display:flex;gap:12px;flex-wrap:wrap;font-size:11.5px;color:var(--grey);margin-top:8px}
.chart-legend span{display:inline-flex;align-items:center;gap:5px}
.chart-legend i{width:8px;height:8px;border-radius:50%;flex:none}
.chart-legend-swatch{flex:none}
.fmt-row{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--line);font-size:13px}
.fmt-row:last-child{border-bottom:none}
/* Une ligne de post avec lien (posts.link) est une vraie balise <a> (accueil-agence.js), jamais un
   gestionnaire de clic sur une div — clic milieu/droit doivent fonctionner. Reset des styles de
   lien par défaut : la ligne garde l'apparence d'une ligne, pas d'un lien bleu souligné. */
a.fmt-row{color:inherit;text-decoration:none;cursor:pointer}
a.fmt-row:hover{background:var(--bg-card-hi)}
.fmt-bar{height:8px;border-radius:4px;background:var(--bg-card-hi);flex:2;overflow:hidden}
.fmt-bar i{display:block;height:100%;border-radius:4px;background:var(--orange)}
.fmt-val{font-family:'IBM Plex Mono',monospace;font-size:12.5px;color:var(--grey);width:110px;text-align:right}

/* Vigilance — détail ligne par ligne (vue client) */
.vigilance-block{margin-top:10px}
.vigilance-row{display:grid;grid-template-columns:1fr auto auto;gap:10px;align-items:center;padding:9px 0;border-bottom:1px solid var(--line);font-size:13px}
.vigilance-row:last-child{border-bottom:none}
/* Bloc 0b-3b C5 — comparatif avant / après : colonnes de chiffres réparties sur la largeur du
   panneau (et non deux `auto` collées à droite), chiffres alignés à droite sous leur en-tête. */
.comparison-row{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) minmax(0,1fr);gap:12px}
.comparison-row .vval{text-align:right}
.comparison-head .vval{font-family:inherit;font-size:12px}
.vigilance-row .vlabel{color:var(--grey)}
.vigilance-row .vreason{display:block;font-size:11.5px;color:var(--grey-dim);margin-top:2px}
.vigilance-row .vval{font-family:'IBM Plex Mono',monospace;color:var(--white);white-space:nowrap}
.vigilance-row .vstatus{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;white-space:nowrap}
.vigilance-row .vstatus i{width:8px;height:8px;border-radius:50%}
.vstatus.ok i{background:var(--ok)} .vstatus.ok{color:var(--ok)}
.vstatus.warn i{background:var(--warn)} .vstatus.warn{color:var(--warn)}
.vstatus.bad i{background:var(--bad)} .vstatus.bad{color:var(--bad)}
.vstatus.unknown i{background:var(--unknown)} .vstatus.unknown{color:var(--grey-dim)}
/* BLOC M.2 — niveau "Information" du panneau Alertes (constat de phase, pas un défaut). */
.vstatus.info i{background:var(--grey)} .vstatus.info{color:var(--grey)}

/* BLOC M.2 §3 — au-delà de 5 informations, repliées sous une ligne "N informations" pour que
   le panneau tienne sans défilement dans le cas courant. */
.vigilance-info-group{border-top:1px solid var(--line);padding-top:9px;margin-top:9px}
.vigilance-info-group summary{cursor:pointer;color:var(--grey-dim);font-size:12.5px;font-weight:600;list-style:none}
.vigilance-info-group summary::-webkit-details-marker{display:none}
.vigilance-info-group[open] summary{margin-bottom:4px}
.vigilance-info-group .vigilance-row{padding:7px 0}

/* BLOC G.10 §3 — flux "Derniers posts" (Accueil agence) : liste DENSE (remplace les cartes de
   BLOC G.9), une ligne par post, hauteur bornée + défilement interne (jamais toute la page qui
   s'allonge pour ce panneau précisément — comme .access-audit-scroll ailleurs dans l'app).
   BLOC G.11 §3 — barre de défilement stylisée discrètement plutôt que retirée (choix : garder la
   hauteur bornée, l'accueil ne s'allonge jamais indéfiniment) : fine, sans flèches, atténuée au
   repos, seulement plus visible au survol/focus — jamais gênante visuellement, jamais absente
   au toucher (-webkit-overflow-scrolling:touch déjà natif, ces règles sont cosmétiques). */
.recent-posts-filters{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:12px}
.recent-posts-filters select{font-family:inherit;font-size:13px;color:var(--text-2);background:var(--bg-card-hi);
  border:1px solid var(--line);border-radius:8px;padding:8px 12px;min-height:44px}
.recent-posts-list{max-height:420px;overflow-y:auto;-webkit-overflow-scrolling:touch;
  scrollbar-width:thin;scrollbar-color:var(--line) transparent}
.recent-posts-list:hover,.recent-posts-list:focus-within{scrollbar-color:var(--grey-dim) transparent}
.recent-posts-list::-webkit-scrollbar{width:6px}
.recent-posts-list::-webkit-scrollbar-track{background:transparent}
.recent-posts-list::-webkit-scrollbar-thumb{background:var(--line);border-radius:3px}
.recent-posts-list:hover::-webkit-scrollbar-thumb,.recent-posts-list:focus-within::-webkit-scrollbar-thumb{background:var(--grey-dim)}
.recent-post-row{display:flex;align-items:center;gap:8px;padding:7px 4px;border-bottom:1px solid var(--line);
  cursor:pointer;font-size:12.5px;min-width:0}
.recent-post-row:last-child{border-bottom:none}
.recent-post-row:hover{background:rgba(255,255,255,.03)}

/* BLOC G.11 §2 — pastille de performance ACCESSIBLE : jamais la couleur seule. Deux signaux
   redondants, indépendants de la couleur — le libellé en toutes lettres (.recent-post-perf-label)
   et le nombre de barres remplies (.recent-post-meter-bars) — un utilisateur daltonien lit le
   niveau sans percevoir aucune teinte. La couleur (dégradé d'INTENSITÉ sur une seule teinte,
   l'orange de la charte — jamais un couple rouge/vert) reste un renfort visuel, pas le signal. */
.recent-post-perf{display:flex;align-items:center;gap:6px;flex:none}
.recent-post-meter-bars{display:inline-flex;align-items:flex-end;gap:2px;flex:none}
.recent-post-meter-bars i{display:block;width:4px;height:9px;border-radius:1px;background:var(--line)}
.recent-post-perf-label{font-size:11px;color:var(--grey-dim);white-space:nowrap}
.recent-posts-legend-item{display:inline-flex;align-items:center;gap:6px}
/* Dégradé d'intensité (une seule teinte) : plus le niveau est haut, plus la barre remplie est
   saturée/claire — jamais un changement de TEINTE (pas de rouge/vert/bleu qui se substitueraient
   les uns aux autres pour un œil daltonien, seulement plus ou moins d'orange). */
.recent-post-perf.faible .recent-post-meter-bars i.filled{background:rgba(224,160,90,.4)}
.recent-post-perf.correct .recent-post-meter-bars i.filled{background:rgba(224,160,90,.6)}
.recent-post-perf.bon .recent-post-meter-bars i.filled{background:rgba(224,160,90,.8)}
.recent-post-perf.tres_bon .recent-post-meter-bars i.filled{background:var(--orange)}
.recent-post-perf.exceptionnel .recent-post-meter-bars i.filled{background:var(--orange-bright)}

.recent-post-brand{color:var(--white);font-weight:600;flex:none;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.recent-post-date{color:var(--grey-dim);font-size:11.5px;flex:none;white-space:nowrap}
.recent-post-text{flex:1;min-width:0;color:var(--grey);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.recent-post-views{flex:none;font-family:'IBM Plex Mono',monospace;color:var(--white);white-space:nowrap;
  min-width:70px;text-align:right}
.recent-posts-legend{display:flex;gap:16px;flex-wrap:wrap;margin-top:12px;font-size:11px;color:var(--grey-dim)}

/* Table posts */
.tablewrap{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);overflow:auto}
table{width:100%;border-collapse:collapse;font-size:13.5px;min-width:940px}
th{position:sticky;top:0;background:var(--bg-card-hi);color:var(--grey);font-size:11.5px;text-transform:uppercase;letter-spacing:.06em;font-weight:700;text-align:left;padding:10px 13px;cursor:pointer;user-select:none;white-space:nowrap}
th:hover{color:var(--white)}
th .arrow{opacity:.6;font-size:10px}
td{padding:10px 13px;border-top:1px solid var(--line);vertical-align:middle}
tr.post{cursor:pointer}
tr.post:hover td{background:rgba(255,255,255,.02)}
.prow{display:flex;align-items:center;gap:10px}
.pthumb{width:36px;height:36px;border-radius:6px;object-fit:cover;flex:none;background:var(--bg-card-hi)}
/* BLOC P.2.1 §4 — vignette absente OU cassée (jetons CDN Instagram expirés) : même repli en
   dégradé uni que .recent-thumb-fallback, jamais une icône d'image cassée ni un vide qui
   fait sauter la mise en page (mêmes dimensions que .pthumb). */
.pthumb-fallback{background:linear-gradient(155deg,var(--bg-card-hi),#3a2f22 70%,var(--orange) 140%)}

/* BLOC M.1 §2 — résumé automatique de l'Accueil client : un texte, pas un cadre chargé.
   BLOC N.4 §8 — CORRECTIF : c'est la seule ligne que le client lit vraiment, elle doit dominer
   la page — retire le fond/bordure hérités de .panel (aucun encadré) et reprend le palier
   22px/600 de l'échelle typographique (bloc N.3, "valeur d'indicateur principale"). Couleur et
   police inchangées (charte N.3 non renégociée ici). */
.client-home-summary{background:none;border:none;border-radius:0;padding:0}
.client-home-summary p{margin:0;font-size:22px;font-weight:600;line-height:1.4;color:var(--text-2)}

/* BLOC M.1 §8 — encart campagnes : ton informatif et discret (jamais l'accent orange réservé aux
   vraies actions à mener, cf. .bienvenue-connect-banner) — un simple filet neutre. */
.client-home-campaign-prompt{border-left:3px solid var(--cyan)}

/* BLOC N.4 §8 — saut d'espacement entre les groupes de l'Accueil client (résumé dominant /
   3 indicateurs / graphiques / publications), 96px — jamais une valeur intermédiaire (cf. bloc
   N.3). #clientHomeMain .duo2/#clientHomeBestPostsPanel portent un margin-top:14px inline
   (dashboard.html) : !important est le seul levier CSS pour l'emporter sur un style inline,
   ciblé strictement à ces deux transitions, jamais un !important générique ailleurs. */
#clientHomeIndicators{margin-top:96px}
#clientHomeMain .duo2{margin-top:96px!important}
#clientHomeBestPostsPanel{margin-top:96px!important}
.client-home-campaign-prompt p{margin:0;font-size:13px;line-height:1.5;color:var(--grey)}

/* BLOC P.1 — espacement entre les nouveaux blocs (sommets/paliers/comparaison/records), au-dessus
   des sections existantes de l'Accueil client (jamais mélangé au rythme 96px de N.4 §8 ci-dessus,
   réservé aux groupes historiques).
   BLOC V.1 — un niveau plus profond (`>div>.panel` au lieu de `>.panel`) depuis l'ajout des
   sous-onglets Production/Résultats : Résultats est un déplacement pur dans #clientHomeResultsPanel,
   qui ne doit rien changer à son rendu (les panneaux visés restent exactement les mêmes qu'avant,
   `.duo2 .panel` — petit-enfant — toujours hors de ce sélecteur, comme avant). */
.client-home-p1-spacing>div>.panel{margin-bottom:14px}

/* ===== BLOC V.1 — Accueil client, sous-onglet Production ===== */

/* Brief 29/09/2026 — « À faire de votre côté » : en-tête plein + glyphe « ! » (éléments à
   traiter) ou carte discrète + coche (rien à faire). Le mot, le glyphe et le contraste
   plein/discret portent l'état, jamais la teinte seule. Un seul bouton, puis la liste simple. */
.cprod-todo{margin-bottom:14px;padding:0;overflow:hidden}
.cprod-todo-head{display:flex;gap:14px;align-items:flex-start;padding:18px 20px}
.cprod-todo-icon{flex:none;width:32px;height:32px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-weight:800;font-size:17px}
.cprod-kicker{font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}
.cprod-todo-title{font-weight:700;font-size:18px;line-height:1.35;margin-top:2px}
.cprod-todo-lead{margin:0;padding:14px 20px 4px;color:var(--text-2);font-size:14px;line-height:1.5}
.cprod-todo-lead p{margin:0}
.cprod-todo-steps{list-style:none;margin:4px 0 0;padding:0}
.cprod-todo-on{border:2px solid var(--orange)}
.cprod-todo-on .cprod-todo-head{background:var(--orange);color:var(--bg)}
.cprod-todo-on .cprod-todo-icon{background:var(--bg);color:var(--orange)}
.cprod-todo-off{background:transparent;border:1px solid var(--line)}
.cprod-todo-off .cprod-todo-head{color:var(--grey)}
.cprod-todo-off .cprod-todo-icon{border:2px solid var(--grey);color:var(--grey)}
.cprod-todo-off .cprod-todo-title{color:var(--white);font-size:16px}
.cprod-todo-off .cprod-todo-lead{padding:4px 0 0}
.cprod-todo-list{list-style:none;margin:0;padding:6px 20px 12px}
.cprod-todo-item{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;padding:12px 0;border-top:1px solid var(--line)}
.cprod-todo-item:first-child{border-top:0}
.cprod-todo-main{flex:1 1 220px;display:flex;flex-direction:column;gap:2px;min-width:0}
.cprod-todo-name{color:var(--white);font-weight:600;overflow-wrap:anywhere}
.cprod-todo-detail{font-size:12.5px;color:var(--text-2)}
.cprod-todo-cta{padding:14px 20px 4px}
.cprod-todo-link{white-space:nowrap}
.cprod-todo-kind{flex:0 0 86px;font-size:11px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--grey)}
/* « Toutes vos vidéos et documents » : ligne permanente, libellé + petit texte + bouton
   secondaire (mot « Voir sur Frame.io », contour), sous la carte « À faire ». */
.cprod-access{display:flex;flex-wrap:wrap;align-items:center;gap:10px 16px;margin-bottom:14px;padding:14px 20px}
.cprod-access-main{flex:1 1 240px;min-width:0}
.cprod-access-title{font-weight:600;color:var(--white)}
.cprod-access-lead{margin:2px 0 0;font-size:13px;color:var(--text-2);line-height:1.5}

/* Étapes du lot en production (et du lot suivant déplié) : chacune avec un état écrit et un
   glyphe (✓ terminée, ● en cours avec contour épais, ○ à venir avec contour pointillé). */
.cprod-steps{list-style:none;margin:4px 0 0;padding:0;display:grid;grid-template-columns:repeat(4,1fr);gap:10px}
.cprod-step{position:relative;border:1px solid var(--line);border-radius:var(--radius);padding:12px 14px 12px 38px;min-width:0}
.cprod-step-mark{position:absolute;left:14px;top:12px;font-size:14px;line-height:1.4;color:var(--grey)}
.cprod-step-name{font-size:13.5px;color:var(--text-2);font-weight:600}
.cprod-step-status{font-size:13px;color:var(--grey);margin-top:2px}
.cprod-step-date{font-size:12px;color:var(--grey-dim);margin-top:2px}
.cprod-step[data-state="done"] .cprod-step-mark{color:var(--ok)}
.cprod-step[data-state="now"]{border:2px solid var(--orange);background:var(--bg-card-hi);padding:11px 13px 11px 37px}
.cprod-step[data-state="now"] .cprod-step-mark{left:13px;top:11px;color:var(--orange)}
.cprod-step[data-state="now"] .cprod-step-name,.cprod-step[data-state="now"] .cprod-step-status{color:var(--white)}
.cprod-step[data-state="now"] .cprod-step-status{font-weight:600}
.cprod-step[data-state="next"]{border-style:dashed}
.cprod-boxes{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px}
.cprod-box{background:var(--bg-card-hi);border-radius:var(--radius);padding:12px 14px}
.cprod-box-k{font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--grey)}
.cprod-box p{margin:4px 0 0;color:var(--text-2);font-size:14px;line-height:1.5}
@media(max-width:640px){.cprod-steps{grid-template-columns:1fr 1fr}.cprod-boxes{grid-template-columns:1fr}}

/* Repliables (mois) : un vrai bouton, « Afficher » / « Masquer ». */
.cprod-fold{margin-bottom:10px;padding:0}
.cprod-fold-btn{display:flex;align-items:center;justify-content:flex-start;gap:8px;width:100%;font-weight:400;background:none;border:0;padding:14px 18px;
  color:var(--white);font:inherit;font-size:14px;text-align:left;cursor:pointer;border-radius:var(--radius)}
.cprod-fold-btn:focus-visible{outline:2px solid var(--orange);outline-offset:2px}
.cprod-fold-btn{flex-wrap:wrap}
.cprod-fold-label{font-weight:600}
.cprod-fold-part{color:var(--text-2)}
.cprod-fold-sep{color:var(--grey-dim)}
.cprod-fold-action{color:var(--orange-bright);text-decoration:underline;text-underline-offset:2px}
.cprod-fold-chevron{margin-left:auto;color:var(--grey);transition:transform .15s}
.cprod-fold-btn[aria-expanded="true"] .cprod-fold-chevron{transform:rotate(90deg)}
.cprod-fold-body{padding:0 18px 14px}

/* « Vos mois de production » : section toujours ouverte ; chaque mois est un repliable. */
.cprod-months{margin-bottom:14px}
.cprod-months-title{font-size:16px;font-weight:600;color:var(--white);margin:0 0 12px}
.cprod-ctrhead{display:flex;align-items:baseline;justify-content:space-between;gap:16px;flex-wrap:wrap;
  padding-bottom:10px;border-bottom:1px solid var(--line);margin-bottom:12px}
.cprod-ctrhead .t{font-weight:600;font-size:15px;color:var(--white)}
.cprod-ctrhead .p{font-size:13px;color:var(--grey-dim);margin-top:1px}
.cprod-ctrhead .r{font-size:13px;color:var(--grey);white-space:nowrap}
.cprod-month{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}
.cprod-month.now{border:2px solid var(--orange)}
.cprod-month .cprod-vids{padding:2px 0 0;margin-top:12px}

.cprod-vids{padding:2px 18px 12px;border-top:1px solid var(--line-soft)}
.cprod-vid{display:flex;align-items:flex-start;gap:14px;padding:11px 0;border-bottom:1px solid var(--line-soft)}
.cprod-vid:last-child{border-bottom:none}
.cprod-vdate{flex:0 0 50px;text-align:center;padding-top:1px}
.cprod-vdate .d{font-weight:600;font-size:17px;color:var(--white);line-height:1}
.cprod-vdate .m{font-size:10px;color:var(--grey-dim);text-transform:uppercase;letter-spacing:.04em;margin-top:3px}
.cprod-vbody{flex:1;min-width:0}
.cprod-vbody .t{color:var(--white);font-size:14px}
.cprod-vbody .t.anon{color:var(--grey)}
.cprod-vbody .s{font-size:12.5px;color:var(--grey);margin-top:1px}
.cprod-vstate{flex:0 0 auto;font-size:10px;font-weight:600;letter-spacing:.05em;
  text-transform:uppercase;padding:3px 9px;border-radius:7px;white-space:nowrap;margin-top:2px}
.cprod-vstate.pub{background:rgba(95,203,142,.15);color:var(--ok)}
.cprod-vstate.sch{background:rgba(224,160,90,.14);color:var(--orange)}
.cprod-vstate.unmeasured{background:rgba(245,196,81,.14);color:var(--warn)}
.cprod-vstate.prep{background:rgba(255,255,255,.05);color:var(--grey)}
/* Bloc 0b-3b C1 — téléphone : le badge d'état passe SOUS le titre (même colonne), le titre garde
   toute la largeur au lieu d'être écrasé à côté d'un badge « PUBLIÉE (STATS À VENIR) ». */
@media(max-width:640px){
  .cprod-vid{display:grid;grid-template-columns:50px minmax(0,1fr);column-gap:14px;row-gap:6px}
  .cprod-vstate{grid-column:2;justify-self:start;margin-top:0;white-space:normal}
}

.frameio-events-table td a{color:var(--orange-bright);text-decoration:underline}
.cprod-note{font-size:13.5px;color:var(--text-2);line-height:1.6;margin-top:22px}
.cprod-note b{color:var(--white);font-weight:600;display:block;margin-bottom:4px}

/* BLOC P.3 §8 — CORRECTIF : bloc fusionné, plus dense (l'ancienne grille à trois colonnes — BLOC
   P.1.1 §2 — laissait deux gros blocs presque vides à côté d'une carte de post sans image,
   disgracieux, brief). Colonne 1 : la carte du post (vignette 9/16). Colonne 2 (.summits-side) :
   les deux records + la carte de fidélité empilés, au même gabarit compact (.summit-card-sm). */
.summits-grid{display:grid;grid-template-columns:210px 1fr;gap:20px;align-items:stretch}
@media(max-width:760px){.summits-grid{grid-template-columns:1fr}}
.summits-side{display:flex;flex-direction:column;gap:12px}
.summit-card{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);padding:16px;height:100%}
.summit-card-sm{padding:13px 16px;height:auto;flex:1}
.summit-video-card{position:relative;aspect-ratio:9/16;overflow:hidden;cursor:pointer;background:var(--bg-card);
  border:1px solid var(--line);border-radius:var(--radius);height:100%}
.summit-video-card:focus-visible{outline:2px solid var(--orange);outline-offset:2px}
.summit-video-media{position:absolute;inset:0}
.summit-video-media img{width:100%;height:100%;object-fit:cover;display:block}
/* BLOC P.3 §8 — lien vers la publication d'origine, superposé en bas de la vignette (jamais
   confondu avec le clic sur la carte, qui ouvre la fiche interne — voir renderSummitVideo). */
.summit-video-link{position:absolute;left:0;right:0;bottom:0;padding:8px 12px;font-size:11.5px;
  font-weight:600;color:var(--white);background:linear-gradient(0deg,rgba(0,0,0,.65),transparent);
  text-decoration:none;text-align:right}
.summit-video-link:hover{color:var(--orange)}
/* BLOC P.3 §9 — carte de fidélité : mention positive seule, jamais de gros chiffre "hero" (pas
   un record) — même gabarit compact que les deux cartes de record juste au-dessus. */
.summit-fidelity{display:flex;align-items:center;font-size:13px;font-weight:600;color:var(--orange)}
/* BLOC P.1.1 §3 — repli typographique (vignette propre ET jumelle Instagram absentes, OU
   échec RÉEL de chargement — voir renderSummitVideoMedia, client-home-highlights.js) : dégradé,
   réseau + date en haut, texte du post en Space Grotesk. */
.summit-video-typo{position:absolute;inset:0;display:flex;flex-direction:column;justify-content:flex-start;padding:16px;
  background:linear-gradient(155deg,var(--bg-card-hi),#3a2f22 70%,var(--orange) 140%)}
.summit-video-typo-head{font-size:11.5px;color:var(--grey);text-transform:uppercase;letter-spacing:.03em;margin-bottom:10px}
.summit-video-typo-text{font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;font-weight:700;font-size:17px;
  line-height:1.35;color:var(--white);overflow:hidden;display:-webkit-box;-webkit-line-clamp:8;-webkit-box-orient:vertical}
.summit-label{font-size:12px;color:var(--grey);font-weight:600}
.summit-value-hero{font-family:'IBM Plex Mono',monospace;font-size:52px;font-weight:600;letter-spacing:-.02em;
  line-height:1.1;margin-top:6px}
/* BLOC P.3 §8 — CORRECTIF : dans le bloc fusionné, deux records tiennent désormais côte à côte
   verticalement plutôt que seuls dans leur propre grand bloc — 52px (taille d'origine, BLOC
   P.1.1 §2) déborderait du gabarit compact (.summit-card-sm). */
.summit-card-sm .summit-value-hero{font-size:26px;margin-top:4px}
.summit-sub{font-size:12px;color:var(--grey-dim);margin-top:6px}

/* BLOC P.1.1 §5 — CORRECTIF : rail avec points + ligne (l'ancienne version, du texte flottant
   sans repère visuel, est remplacée). Une ligne fine traverse la rangée, un point marque chaque
   palier (rempli --ok si franchi, plus grand et orange pour le palier en cours, creux --grey-dim
   pour les suivants), avec un libellé Franchi / Ensuite / Puis sous chacun. */
.palier-rail-label{font-size:12px;color:var(--grey);font-weight:600}
.palier-rail{position:relative;margin-top:10px}
.palier-line{position:absolute;left:9px;right:9px;top:9px;height:2px;background:var(--line)}
.palier-points{display:flex;align-items:flex-start;gap:6px;position:relative}
.palier-point{flex:1;text-align:center;min-width:0}
.palier-dot-wrap{height:18px;display:flex;align-items:center;justify-content:center}
.palier-dot{display:block;width:12px;height:12px;border-radius:50%;background:var(--bg-card-hi);
  border:2px solid var(--grey-dim);position:relative;z-index:1}
.palier-point-done .palier-dot{background:var(--ok);border-color:var(--ok)}
.palier-point-current .palier-dot{width:16px;height:16px;background:var(--orange);border-color:var(--orange)}
.palier-point-val{font-family:'IBM Plex Mono',monospace;font-size:13px;color:var(--grey-dim);margin-top:6px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.palier-point-done .palier-point-val{color:var(--ok)}
.palier-point-label{font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;margin-top:2px}
.palier-point-done .palier-point-label{color:var(--ok)}
.palier-point-future .palier-point-label{color:var(--grey-dim)}
/* Le palier en cours : encadré d'orange (brief), plus grand, avec sa barre. */
.palier-point-current{flex:1.6;background:var(--bg-card-hi);border:2px solid var(--orange);border-radius:10px;
  padding:8px 10px 10px;margin-top:-8px}
.palier-point-current .palier-dot-wrap{height:auto;margin-bottom:2px}
.palier-point-current .palier-point-val{font-size:19px;color:var(--white);font-weight:600;margin-top:2px}
.palier-bar{height:8px;border-radius:4px;background:var(--bg);overflow:hidden;margin-top:8px}
.palier-bar i{display:block;height:100%;border-radius:4px;background:var(--orange)}
.palier-remaining{font-size:11px;color:var(--grey-dim);margin-top:6px}
.palier-complete .palier-point-val{font-size:14px;color:var(--ok)}
.palier-rail-foot{font-size:11.5px;color:var(--grey-dim);margin-top:10px}
@media(max-width:640px){.palier-points{flex-wrap:wrap}.palier-point{flex:1 1 40%}.palier-point-current{flex:1 1 100%;order:-1;margin-top:0}.palier-line{display:none}}

/* BLOC P.1 §3/§4 — barre avec repère gris (mois précédent) / barre de progression (record). */
.month-compare-card,.record-card{background:var(--bg-card-hi);border:1px solid var(--line);border-radius:var(--radius);padding:15px 17px;position:relative}
.month-compare-prev{font-size:11.5px;color:var(--grey-dim);margin-top:2px}
.month-compare-bar{position:relative;height:8px;border-radius:4px;background:var(--bg);overflow:hidden;margin-top:10px}
.month-compare-bar i{display:block;height:100%;border-radius:4px;background:var(--orange)}
.month-compare-bar b{position:absolute;top:-2px;bottom:-2px;width:2px;background:var(--grey);border-radius:1px}
/* BLOC P.1 §4 — le plus proche d'être battu est cerclé d'orange, étiqueté "Tout proche". */
.record-closest{border-color:var(--orange);box-shadow:0 0 0 1px var(--orange)}
.record-badge{position:absolute;top:-9px;right:12px;background:var(--orange);color:var(--bg);font-size:10.5px;
  font-weight:700;padding:2px 8px;border-radius:999px;text-transform:uppercase;letter-spacing:.02em}
.record-values{display:flex;align-items:baseline;gap:6px;margin-top:4px}
.record-target{font-family:'IBM Plex Mono',monospace;font-size:13px;color:var(--grey-dim)}

/* BLOC M.1 §7 — bandeau de vignettes "Dernières publications", sans texte, responsive (wrap sur
   mobile plutôt qu'un débordement horizontal). */
.recent-thumb-strip{display:flex;flex-wrap:wrap;gap:8px}
.recent-thumb{width:64px;height:64px;border-radius:8px;overflow:hidden;background:var(--bg-card-hi);
  border:1px solid var(--line);padding:0;flex:none;cursor:pointer}
.recent-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.recent-thumb:hover{border-color:var(--orange-bright)}
/* BLOC P.1.1 §3 — repli en dégradé uni (vignette absente OU cassée au chargement réel, voir
   renderClientHomeRecentPosts, dashboard.js) : jamais une icône d'image brisée. */
.recent-thumb-fallback{background:linear-gradient(155deg,var(--bg-card-hi),#3a2f22 70%,var(--orange) 140%)}
.ptext{max-width:280px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ptext a{color:inherit;text-decoration:none}
.ptext a:hover{color:var(--white)}
.pdate{color:var(--grey-dim);font-size:12px;white-space:nowrap}
.num{font-family:'IBM Plex Mono',monospace;font-weight:500;white-space:nowrap}
.nettag{font-size:10px;font-weight:800;border-radius:8px;padding:2px 6px;letter-spacing:.05em}
.nettag.instagram{color:var(--orange-bright);background:rgba(242,184,115,.15)}
.nettag.facebook{color:var(--cyan);background:rgba(97,206,207,.15)}
.nettag.tiktok{color:var(--white);background:rgba(243,243,244,.12)}
.nettag.linkedin{color:var(--grey);background:rgba(148,152,160,.18)}
/* BLOC J.1 §b — badge "sponsorisé" discret (>= 20 % de part payante, voir serializeMetrics) :
   même gabarit que .nettag mais couleur neutre (--grey), jamais --bad/--warn — ce n'est pas un
   jugement de vigilance, juste une information de nature de la donnée. Répartition organique/
   payant au survol (title natif du navigateur, pas de tooltip custom pour un badge aussi discret). */
.sponsored-badge{font-size:10px;font-weight:700;border-radius:8px;padding:2px 6px;letter-spacing:.03em;
  color:var(--grey);background:rgba(148,152,160,.14);flex:none;cursor:help}
.num .sponsored-badge{margin-right:6px}
/* BLOC K.1 §1 — répartition organique/payant sous le chiffre principal (colonne Vues), visible
   directement (jamais seulement au survol) — uniquement sur les posts sponsorisés, rien sur les
   autres (pas de bruit sur la majorité des lignes). Police normale (pas monospace comme .num) :
   c'est une légende, pas une valeur à aligner en colonne. */
.views-split{font-family:'Instrument Sans',Arial,sans-serif;font-size:11px;font-weight:400;
  color:var(--grey-dim);white-space:nowrap;margin-top:3px;display:flex;align-items:center;gap:5px}
.hook{display:flex;gap:2px;width:60px}
.hook i{height:13px;flex:1;border-radius:2px;background:var(--bg-card-hi)}
.hook.hi i.f{background:var(--ok)}
.hook.mid i.f{background:var(--warn)}
.hook.lo i.f{background:var(--bad)}
.score{font-family:'IBM Plex Mono',monospace;font-weight:600;font-size:13px;border-radius:8px;padding:3px 8px;display:inline-block;min-width:42px;text-align:center}
.score.hi{color:var(--ok);background:rgba(95,203,142,.12)}
.score.mid{color:var(--warn);background:rgba(245,196,81,.12)}
.score.lo{color:var(--bad);background:rgba(232,106,92,.10)}
.legend{font-size:12px;color:var(--grey-dim);margin-top:10px}
/* BLOC F.2 — analyse de méthode interne (hook/watch/Recette), jamais pour le rôle client — voir
   loadMe(), dashboard.js. Les données brutes sont de toute façon absentes de sa réponse. */
#ptable.client-hide-recette .col-hook,
#ptable.client-hide-recette .col-watch,
#ptable.client-hide-recette .col-score{display:none}
/* BLOC K.1 §2 — vue client : Format (analyse de méthode interne, sans intérêt pour le client,
   qui sait déjà ce qu'il a publié) cède la place à J'aime/Commentaires (ce que le client veut
   voir). Vue agence inchangée : Format y reste, J'aime/Commentaires n'y apparaissent pas (déjà
   disponibles ailleurs pour le staff — fiche du post, analyse de méthode). */
#ptable.client-columns .col-format{display:none}
#ptable:not(.client-columns) .col-interactions{display:none}

/* Pagination de la table posts (jamais tout d'un coup) */
.pager{display:flex;align-items:center;justify-content:center;gap:14px;padding:12px 0;font-size:12.5px;color:var(--grey)}
.pager button:disabled{opacity:.35;cursor:not-allowed}

/* Panneau de synthèse vue client (toujours visible, tous réseaux confondus) */
.csummary-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}
.post-mini{cursor:pointer}
.post-mini:hover{background:rgba(255,255,255,.02)}
.post-mini .nettag{flex:none}
.post-mini .ptext{flex:1;min-width:0}

/* BLOC P.2.1 §8 — compteur de portefeuille à droite des sous-onglets Production/Commercial. */
.clients-view-header{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.clients-view-header .ctabs{flex:1 1 auto}
.clients-active-count{font-family:'IBM Plex Mono',monospace;font-size:12.5px;color:var(--grey);white-space:nowrap}

/* Onglets réseau + Ads de la vue client */
.ctabs{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:22px 0 16px;border-bottom:1px solid var(--line);padding-bottom:2px}
.ctab{border:none;background:none;color:var(--grey);font-family:inherit;font-size:13.5px;font-weight:600;
  padding:9px 4px;margin-right:14px;cursor:pointer;border-bottom:2px solid transparent;display:inline-flex;align-items:center;gap:6px}
.ctab:hover{color:var(--white)}
.ctab.on{color:var(--white);border-bottom-color:var(--orange)}
.ctab.empty{color:var(--grey-dim)}
.ctab-empty{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--grey-dim);background:rgba(255,255,255,.05);border-radius:8px;padding:1px 6px}

/* Filtre par format (vue client) — s'applique à tout : KPI, moyennes, vigilance, nuage de
   points, table, formats qui performent. */
.format-filter{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:18px;padding:10px 14px;background:var(--bg-card);border:1px solid var(--line);border-radius:10px;font-size:13px}
.format-filter-label{font-weight:700;color:var(--grey)}
.format-filter label{display:inline-flex;align-items:center;gap:5px;color:var(--grey);cursor:pointer}
.format-filter input[type="checkbox"]{accent-color:var(--orange);cursor:pointer}
.format-filter-summary{margin-left:auto;color:var(--grey-dim);font-size:12px}

/* Publicité — onglet principal Campagnes (transversal). Noms de classes SANS "ad"/"ads" —
   BUG bloqueur de pub : les bloqueurs cosmétiques masquent tout élément dont la classe/id
   contient ce motif, ce qui rendait toute cette section invisible en navigation normale (testé,
   confirmé) alors que l'API renvoyait des données correctes. Les libellés visibles restent
   "Ads"/"Publicité" — seul le nom technique change. */
.campaigns-filters{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:16px}
.campaigns-filters select{font-family:inherit;font-size:13px;color:var(--text-2);background:var(--bg-card);border:1px solid var(--line);border-radius:8px;padding:8px 12px;min-height:44px}
/* Cartes pleine largeur, toujours empilées verticalement (REFONTE — une campagne = une carte
   large, plus de grille multi-colonnes) : actives ET terminées ont le même niveau de détail,
   seule la sobriété visuelle diffère (bordure verte/grise, voir .campaign-card-active/-ended
   ci-dessous) — les campagnes passées sont une référence à part entière, pas une archive. */
.campaigns-grid{display:flex;flex-direction:column;gap:14px;margin-bottom:14px}
.campaign-card{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);padding:18px 20px}
.campaign-card-active{border-color:rgba(95,203,142,.35);box-shadow:0 0 0 1px rgba(95,203,142,.12) inset}
.campaign-card-ended{border-color:var(--line);opacity:.85}
.campaigns-ended-toggle{margin-top:18px}
.campaigns-ended-list{margin-top:10px}
.campaign-card-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-bottom:10px}
.campaign-client-badge{font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--grey);margin-bottom:3px}
.campaign-card-name{font-weight:700;font-size:13.5px}
.campaign-card-net{font-size:11px;color:var(--grey-dim);margin-top:2px}
.campaign-dates{font-size:11px;color:var(--grey-dim);margin-bottom:4px}
/* BLOC G.0 — données réelles vs synchronisation, distinguées mais toutes deux discrètes en
   temps normal ; la mention/alerte de décalage, elle, doit se voir. */
.campaign-freshness{font-size:11px;color:var(--grey-dim);margin-bottom:10px}
.campaign-freshness-note{font-size:10.5px;color:var(--grey-dim);margin-top:-6px;margin-bottom:10px}
/* BLOC M.2 — niveau Problème (collecte probablement en panne) : seul niveau qui garde un fond
   plein, même traitement que les autres bandeaux Problème de la carte (cohérence, brief). */
.campaign-freshness-note.campaign-freshness-alert{color:var(--white);font-weight:600;font-size:12.5px;
  background:rgba(224,92,92,.12);border:1px solid rgba(224,92,92,.4);border-radius:8px;padding:8px 12px;margin:0 0 10px}
.campaign-status{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;padding:2px 7px;border-radius:8px;color:var(--grey);background:rgba(148,152,160,.15)}
.campaign-status.active{color:var(--ok);background:rgba(95,203,142,.12)}

/* BLOC — Ads : badge de verdict, en tête de carte (refonte Résumé, vue simple) — un seul verdict
   partagé avec les deux rôles (voir computeAdsSummaryVerdict), symbole + libellé ; la couleur
   n'est qu'un renfort, jamais la seule distinction (Thomas est daltonien). */
.campaign-verdict{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;padding:2px 8px;border-radius:8px;white-space:nowrap}
.campaign-verdict i{font-style:normal;margin-right:3px}
.campaign-verdict.verdict-no-target,
.campaign-verdict.verdict-too-early{color:var(--grey);background:rgba(148,152,160,.15)}
.campaign-verdict.verdict-good{color:var(--ok);background:rgba(95,203,142,.12)}
.campaign-verdict.verdict-warn{color:var(--warn);background:rgba(245,196,81,.12)}
.campaign-verdict.verdict-bad{color:var(--bad);background:rgba(232,106,92,.15)}

/* BLOC — Ads : verdict en tête du Résumé (brief point 1) — symbole + libellé + phrase
   d'explication à trous, mêmes couleurs que le badge de tête de carte ci-dessus. */
.campaign-summary-verdict{display:flex;align-items:flex-start;gap:10px;padding:10px 12px;border-radius:10px;margin-bottom:14px;background:var(--bg-card-hi)}
.campaign-summary-verdict-symbol{font-size:22px;font-weight:700;line-height:1;flex:none;width:26px;text-align:center}
.campaign-summary-verdict-text{min-width:0;flex:1}
.campaign-summary-verdict-label{font-size:13.5px;font-weight:700}
.campaign-summary-verdict-explanation{font-size:12.5px;color:var(--grey);margin-top:2px}
.campaign-summary-verdict-cta{flex:none;align-self:center;background:none;border:1px solid var(--line);color:var(--grey);border-radius:8px;padding:6px 10px;font-family:inherit;font-size:11.5px;font-weight:600;cursor:pointer;white-space:nowrap}
.campaign-summary-verdict-cta:hover{color:var(--white)}
.campaign-summary-verdict.verdict-no-target .campaign-summary-verdict-symbol,
.campaign-summary-verdict.verdict-too-early .campaign-summary-verdict-symbol{color:var(--grey)}
.campaign-summary-verdict.verdict-good .campaign-summary-verdict-symbol{color:var(--ok)}
.campaign-summary-verdict.verdict-warn .campaign-summary-verdict-symbol{color:var(--warn)}
.campaign-summary-verdict.verdict-bad .campaign-summary-verdict-symbol{color:var(--bad)}

/* BLOC — Ads : trois chiffres du Résumé (brief point 2). */
.campaign-summary-numbers{display:grid;grid-template-columns:repeat(3,1fr);gap:10px 16px;margin-bottom:14px}
.campaign-summary-number-label{font-size:11px;color:var(--grey-dim)}
.campaign-summary-number-value{font-family:'IBM Plex Mono',monospace;font-size:20px;font-weight:600;letter-spacing:-.02em}
.campaign-summary-number-period{font-size:10.5px;color:var(--grey-dim);margin-top:1px}
@media(max-width:520px){.campaign-summary-numbers{grid-template-columns:1fr 1fr}}

/* BLOC — Ads : "Résultats commerciaux" (brief point 6) et "Détails" replié (brief point 7). */
.campaign-commercial-results{margin-top:14px}
.campaign-details-toggle{width:100%;margin-top:14px;background:none;border:1px solid var(--line);color:var(--grey);border-radius:8px;padding:7px 10px;font-family:inherit;font-size:12px;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:6px}
.campaign-details-toggle:hover{color:var(--white)}
.campaign-details-toggle .chev{transition:transform .15s}
.campaign-details-toggle.open .chev{transform:rotate(180deg)}
.campaign-details-toggle + .campaign-metrics{margin-top:10px}
.campaign-creatives-period{font-size:12px;color:var(--grey-dim);margin-bottom:8px}

/* BLOC J.2 §1 — repli par carte : page Ads très longue à défiler sans fin, chaque carte se
   replie individuellement (bouton en haut à droite, à côté du badge de statut). Repliée, le CSS
   masque tout sauf .campaign-card-head — et à l'intérieur, .campaign-card-net (réseau/leads) en
   plus : le brief ne demande que marque + nom + statut, rien d'autre. */
.campaign-card-head-right{display:flex;align-items:center;gap:8px;flex:none}
.campaign-collapse-toggle{background:none;border:1px solid var(--line);border-radius:8px;width:24px;height:24px;
  display:flex;align-items:center;justify-content:center;color:var(--grey);cursor:pointer;flex:none;font-family:inherit;padding:0}
.campaign-collapse-toggle:hover{color:var(--white)}
.campaign-collapse-toggle .chev{transition:transform .15s;font-size:11px}
.campaign-collapse-toggle.open .chev{transform:rotate(180deg)}
.campaign-card-collapsed .campaign-card-net,
.campaign-card-collapsed .campaign-dates,
.campaign-card-collapsed .campaign-freshness,
.campaign-card-collapsed .campaign-freshness-note,
.campaign-card-collapsed .campaign-card-tabs,
.campaign-card-collapsed .campaign-card-panel{display:none}
.campaign-card-collapsed .campaign-card-head{margin-bottom:0}
/* Jauge CPL continue (A2, plus visible) : piste 0→échelle avec 3 zones (vert/ambre/rouge)
   nettement contrastées, repères cible/max avec étiquette collée au trait (jamais reléguée aux
   extrémités de la barre), curseur à la valeur réelle. L'échelle va TOUJOURS au-delà du max
   (GAUGE_BASE_SCALE_FACTOR, dashboard-logic.js) : la zone rouge reste visible même quand le CPL
   est bon — repère constant. Si le CPL dépasse le max, l'échelle s'étend encore
   (GAUGE_OVERSHOOT_SCALE) pour que le curseur reste visible — jamais un curseur qui bute en bout
   de barre sans indiquer l'ampleur du dépassement. */
/* BLOC F.1 — le bas de la jauge doit réserver une bande propre pour les étiquettes cible/max :
   36px sous la piste (piste 10px + ligne de repère ~18px + libellé ~13px + marge de sécurité),
   jamais les 14px d'origine qui laissaient les étiquettes chevaucher la grille d'indicateurs
   juste en dessous. */
/* BLOC L.1 §5 — CORRECTIF : la piste ne mesurait que 10px (hauteur de la barre elle-même), donc
   les étiquettes de repère (absolument positionnées, ~34px sous le haut de la piste) débordaient
   hors de sa boîte réelle. Le texte "+X % au-dessus du max" (élément suivant, EN FLUX normal
   dans le wrap) démarrait donc bien avant la fin visuelle des étiquettes → chevauchement. Fix :
   la piste réserve désormais 50px (barre 10px + repère simple ~34px + une 2e ligne pour
   .tick-stacked ~13px de plus), `.campaign-gauge-bar` prend une hauteur EXPLICITE (10px, plus
   d'`inset:0` qui l'aurait étirée à la nouvelle hauteur de la piste). */
.campaign-gauge-wrap{margin:34px 0 12px}
.campaign-gauge-track{position:relative;height:50px}
.campaign-gauge-bar{position:absolute;top:0;left:0;right:0;height:10px;border-radius:5px;overflow:hidden;background:var(--bg-card-hi)}
.campaign-gauge-zone{position:absolute;top:0;height:100%}
.campaign-gauge-zone.ok{background:var(--ok)} .campaign-gauge-zone.warn{background:var(--warn)} .campaign-gauge-zone.bad{background:var(--bad)}
/* Le conteneur du repère n'est PLUS centré (pas de transform sur lui-même) : son bord gauche
   EST la position exacte (left:X%, posée en JS). La ligne `i` se recentre dessus indépendamment
   de l'étiquette `b`, qui elle bascule d'ancrage près des bords (tick-edge-start/-end,
   dashboard.js) pour ne jamais déborder hors de la carte à 0 %/100 % ou en largeur réduite. */
.campaign-gauge-tick{position:absolute;top:-4px;z-index:1}
.campaign-gauge-tick i{position:absolute;left:-1px;top:0;display:block;width:2px;height:18px;background:rgba(255,255,255,.55);border-radius:1px}
.campaign-gauge-tick b{position:absolute;left:0;top:21px;transform:translateX(-50%);font-size:10.5px;font-weight:700;color:var(--grey);white-space:nowrap}
.campaign-gauge-tick.tick-edge-start b{transform:translateX(0)}
.campaign-gauge-tick.tick-edge-end b{transform:translateX(-100%)}
/* Repères "cible"/"max" trop proches (g.ticksClose, dashboard-logic.js) : l'étiquette "max"
   descend d'une ligne — les DEUX traits `i` restent à leur position réelle, seul le texte se
   décale pour ne jamais chevaucher horizontalement celui de "cible". */
.campaign-gauge-tick.tick-stacked b{top:36px}
.campaign-gauge-cursor{position:absolute;top:-24px;transform:translateX(-50%);display:flex;flex-direction:column;align-items:center;gap:3px;z-index:2}
.campaign-gauge-cursor b{font-size:11.5px;font-weight:700;white-space:nowrap;background:var(--white);color:var(--bg);padding:2px 6px;border-radius:5px;line-height:1.3}
.campaign-gauge-cursor i{display:block;width:2px;height:16px;background:var(--white);border-radius:1px}
.campaign-gauge-cursor.over b{background:var(--bad);color:var(--white)}
.campaign-gauge-cursor.over i{background:var(--bad)}
.campaign-gauge-over{font-size:11px;font-weight:700;color:var(--bad);margin-top:6px}
/* auto-fit plutôt que 2 colonnes fixes : la carte pleine largeur (REFONTE) a la place pour les
   métriques Meta natives ajoutées (CPM/CPC/portée/fréquence/clics sur lien/vues page de
   destination) sans les entasser sur 2 colonnes seulement. */
.campaign-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px 14px;font-size:12.5px;color:var(--grey);margin-bottom:10px}
.campaign-metrics b{display:block;color:var(--white);font-family:'IBM Plex Mono',monospace;font-size:13.5px;font-weight:600}
.campaign-metric-calc{font-family:inherit;font-size:10px;font-weight:500;color:var(--grey-dim)}
/* BLOC F.2 — détail des conditions de jugeabilité (remplace l'ancienne phrase unique
   .campaign-judge) : une ligne par condition, visuellement distincte remplie/en attente — même
   affichage agence et client (voir renderJudgeabilityConditions, dashboard.js). */
.campaign-judge-conditions{display:flex;flex-direction:column;gap:5px}
.campaign-judge-condition{display:flex;justify-content:space-between;gap:10px;font-size:11.5px;
  padding:6px 0;border-top:1px solid var(--line-soft);color:var(--grey)}
.campaign-judge-condition:first-child{border-top:none;padding-top:0}
.campaign-judge-condition-label{color:var(--grey-dim);flex:none}
.campaign-judge-condition.met{color:var(--ok)}
.campaign-judge-condition.pending{color:var(--warn)}
.campaign-empty{color:var(--grey-dim);font-size:13px;padding:14px 4px}

/* BLOC L.1 §2 — bandeau de cohérence budgétaire (apprentissage Meta) : prime visuellement sur le
   reste de la carte (bordure marquée, fond teinté), jamais un simple texte discret perdu dans la
   grille de métriques. */
.campaign-budget-check{margin:10px 0 14px;padding:10px 12px;border-radius:8px;font-size:12.5px;line-height:1.5}
.campaign-budget-check.bad{background:rgba(224,92,92,.12);border:1px solid rgba(224,92,92,.4);color:var(--white)}
.campaign-budget-check.bad b{display:block;color:var(--bad);margin-bottom:4px;font-size:13px}
/* BLOC M.2 §4 — niveau Information (constat positif) : plus de fond teinté, seul Problème en
   garde un (brief : "la couleur pleine se mérite"). */
.campaign-budget-check.ok{background:none;border:1px solid var(--line);color:var(--grey)}
.campaign-budget-check-tip{margin-top:4px;color:var(--grey-dim)}

/* BLOC L.1 §1 — CPA structurellement intenable (e-commerce) : remplace le "+X % au-dessus du
   max" par défaut sur la jauge (voir hideOverText, dashboard.js) — même famille visuelle que le
   bandeau budgétaire ci-dessus, jamais un simple texte rouge perdu dans la carte. */
.campaign-viability-warning{margin:10px 0 14px;padding:10px 12px;border-radius:8px;font-size:12.5px;line-height:1.5;
  background:rgba(224,92,92,.12);border:1px solid rgba(224,92,92,.4);color:var(--white)}
.campaign-viability-warning b{display:block;color:var(--bad);margin-bottom:4px;font-size:13px}

/* BLOC L.1.1 §1 — cible calculée vs surcharge manuelle (panneau Paramètres, carte campagne) : la
   surcharge vit dans un bloc VISUELLEMENT distinct (encadré), la surcharge active reste visible
   comme telle, jamais confondue silencieusement avec la valeur calculée juste au-dessus. */
.campaign-target-source{margin:0 0 10px}
.campaign-target-override{margin-top:14px;padding:12px;border:1px solid var(--line);border-radius:8px;background:var(--bg-card-hi)}
.campaign-target-override .campaign-settings-subtitle{margin-top:0}
.campaign-target-override-badge{display:inline-block;margin-left:6px;padding:1px 7px;border-radius:20px;
  background:rgba(240,180,60,.16);border:1px solid rgba(240,180,60,.4);color:var(--warn);font-size:10.5px;font-weight:700}

/* Onglets internes Résumé/Paramètres (REFONTE) — même motif .ctab que la fiche client, mais
   scopé/allégé pour tenir dans une carte (marges resserrées, pas de bordure pleine largeur). */
.campaign-card-tabs{display:flex;gap:4px;margin:0 0 14px;border-bottom:1px solid var(--line)}
.campaign-card-tabs .ctab{margin-right:10px;padding:7px 2px;font-size:12.5px}
.campaign-card-panel.hidden{display:none}

/* A3 — trois indicateurs de coût alignés (remplace l'ancien bloc "Meta dit / Réel dit", jugé
   confus) : même style visuel que .campaign-metrics (titre au-dessus, chiffre en dessous),
   regroupés en cartes pour rester lisibles côte à côte même à 375px (auto-fit passe en 1
   colonne si la carte est trop étroite, jamais un texte tronqué). */
/* BLOC F.1 — rangée de 6 cartes homogènes (Résultats · CPL Meta · CPL qualifiés · Coût par
   signature · Closing réel · ROI), remplace l'ancien bloc "coût" + la ligne de texte "Closing
   réel · ROI" reléguée en dessous (supprimée, jamais un doublon). auto-fit + minmax passe déjà
   sur plusieurs lignes de lui-même en largeur réduite, plutôt que de comprimer les cartes. */
.campaign-perf-indicators{display:grid;grid-template-columns:repeat(auto-fit,minmax(100px,1fr));gap:8px 16px;margin-bottom:6px}
.campaign-cost-item{padding:4px 0}
.campaign-cost-label{font-size:10.5px;color:var(--grey-dim);margin-bottom:3px}
.campaign-cost-item b{display:block;font-family:'IBM Plex Mono',monospace;font-size:15px;color:var(--white);font-weight:600}
.campaign-cost-variance{font-size:11px;font-weight:700;color:var(--grey-dim);margin-top:4px}
.campaign-cost-variance.ok{color:var(--ok)} .campaign-cost-variance.warn{color:var(--warn)} .campaign-cost-variance.bad{color:var(--bad)}

.campaign-settings-subtitle{font-size:12px;font-weight:700;color:var(--grey);margin:14px 0 8px}
.campaign-settings-subtitle:first-child{margin-top:0}

/* Cibles économiques — PAR CAMPAGNE désormais (formulaire porté par chaque carte, plus un
   formulaire unique par client) */
.campaign-target-form{background:var(--bg);border:1px dashed var(--line);border-radius:10px;padding:12px;margin:10px 0}
.campaign-target-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:10px}
.campaign-target-grid label{display:block;margin:0 0 5px;font-size:11px;color:var(--grey)}
.campaign-target-grid input,.campaign-target-grid select{width:100%;font-family:inherit;padding:8px 10px;font-size:13px;color:var(--text-2);background:var(--bg-card-hi);border:1px solid var(--line);border-radius:8px}

/* BLOC L.1.1/L.1.2 — formulaire "Modèle économique" (carte campagne, onglet Paramètres) : deux
   radios au-dessus des champs propres au modèle choisi (voir renderCampaignSettingsPanel,
   dashboard.js). */
.economic-model-type{display:flex;flex-direction:column;gap:10px;margin-bottom:14px}
.economic-model-type label{display:flex;align-items:baseline;gap:8px;font-size:13px;color:var(--text-2);cursor:pointer}
.economic-model-type .hint{margin:0}

/* BLOC L.1.2 §1 — CORRECTIF : un seul modèle affiché à la fois, ses champs alignés sur UNE ligne
   à largeurs régulières (repeat(N,1fr), jamais auto-fit qui étire irrégulièrement la dernière
   ligne). `[hidden]` doit être forcé explicitement : `.economic-model-fields` pose display:grid
   sur le conteneur ET sur ses champs `data-model` — une règle D'AUTEUR l'emporte TOUJOURS sur la
   règle native [hidden]{display:none} du user-agent, même à spécificité égale. Sans ce correctif
   ([hidden]{display:none!important} ci-dessous), un champ masqué par l'attribut `hidden` restait
   visible : la cause exacte du bug "champs des deux modèles affichés en même temps". Le
   conteneur est cadré sur 6 colonnes par défaut (lead gen) ; data-active-model="ecommerce" le
   ramène à 4 — jamais des colonnes vides pour un modèle à 4 champs. */
.economic-model-fields{display:grid;gap:10px;grid-template-columns:repeat(6,1fr)}
.economic-model-fields[data-active-model="ecommerce"]{grid-template-columns:repeat(4,1fr)}
.economic-model-fields[hidden],.economic-model-fields>[hidden]{display:none!important}
.economic-model-fields label{display:block;margin:0 0 5px;font-size:11px;color:var(--grey)}
.economic-model-fields input{width:100%;font-family:inherit;padding:8px 10px;font-size:13px;color:var(--text-2);background:var(--bg-card-hi);border:1px solid var(--line);border-radius:8px}
@media(max-width:920px){.economic-model-fields{grid-template-columns:repeat(3,1fr)}}
@media(max-width:640px){.economic-model-fields{grid-template-columns:1fr}}

.economic-model-summary{padding-top:10px;border-top:1px solid var(--line)}
/* BLOC G.5 §3 — "Enregistrer les leads réels" restait au style natif : même règle que
   .campaign-target-form ci-dessus (deux formulaires du même panneau Paramètres, un seul style).
   BLOC L.1.2 §4 — CORRECTIF : le sélecteur ciblait TOUT <button> du formulaire, y compris les
   boutons .glossary-hint posés à côté des labels (closing/marge/surcharge) — ils héritaient du
   style de soumission (fond orange, padding 8-14px, radius) et s'affichaient en gros badge.
   `[type=submit]` exclut .glossary-hint (type="button") sans toucher glossary.js. */
.campaign-target-form button[type=submit],.campaign-leads-form button[type=submit]{background:var(--orange);color:var(--bg);border:none;border-radius:8px;padding:8px 14px;font-family:inherit;font-size:13px;font-weight:700;cursor:pointer;margin-top:10px}
.campaign-target-form button[type=submit]:hover,.campaign-leads-form button[type=submit]:hover{opacity:.9}

/* Publicités (créas) d'une campagne — dépliées au clic (AJOUT 4) */
.campaign-expand-toggle{width:100%;margin-top:10px;background:none;border:1px solid var(--line);color:var(--grey);border-radius:8px;padding:7px 10px;font-family:inherit;font-size:12px;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:6px}
.campaign-expand-toggle:hover{color:var(--white)}
.campaign-expand-toggle .chev{transition:transform .15s}
.campaign-expand-toggle.open .chev{transform:rotate(180deg)}
/* A4 — tableau des publicités (remplace les lignes de texte séparées par des points, jugées peu
   lisibles) : une ligne par publicité, colonnes alignées. Défile horizontalement dans son PROPRE
   conteneur à 375px (jamais la page entière, cf. règle overflow-x en tête de fichier). */
.campaign-creatives{margin-top:8px}
.campaign-creatives-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
/* min-width resserré (colonnes compactes) pour que les 6 colonnes tiennent le plus près possible
   des ~287px de contenu disponible dans une carte à 375px — un léger défilement résiduel reste
   acceptable (le tableau défile dans son propre conteneur), mais ne doit jamais réduire l'écran
   à 2 colonnes visibles. */
.campaign-creatives-table{width:100%;min-width:330px;border-collapse:collapse;font-size:11px}
.campaign-creatives-table th{text-align:right;color:var(--grey-dim);font-weight:600;font-size:9.5px;text-transform:uppercase;letter-spacing:.01em;padding:4px 5px;border-bottom:1px solid var(--line);white-space:nowrap}
.campaign-creatives-table th:first-child{text-align:left}
.campaign-creatives-table td{padding:6px 5px;border-bottom:1px solid var(--line-soft);color:var(--grey);text-align:right;font-family:'IBM Plex Mono',monospace;white-space:nowrap;font-size:11px}
.campaign-creative-info{display:flex;align-items:center;gap:6px;text-align:left!important;font-family:inherit;min-width:88px}
.campaign-creative-thumb{width:24px;height:24px;border-radius:5px;object-fit:cover;flex:none;background:var(--bg-card-hi)}
.campaign-creative-name{font-size:11.5px;font-weight:600;color:var(--white);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:90px}
/* Hook rate/rétention/watch/ThruPlay : absents de l'API Metricool (vérifié exhaustivement,
   METRICOOL-ENDPOINTS.md) — une seule note discrète sous le tableau, jamais répétée par ligne. */
.campaign-creative-unavailable{font-size:10.5px;color:var(--grey-dim);margin-top:8px}
.campaign-creative-proxy{display:block;margin-top:2px}
/* BLOC A.2 — marque discrète sur une seule cellule (jamais la ligne) : zéro déduit, pas reçu. */
.campaign-creative-results-borrowed{color:var(--bad);border-bottom:1px dotted var(--bad);cursor:help}

/* Panneau de croissance d'un post (historique append-only) */
.modal-backdrop{position:fixed;inset:0;background:rgba(22,23,26,.7);display:flex;align-items:center;justify-content:center;padding:24px;z-index:100}
.modal-backdrop.hidden{display:none}
.modal{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);padding:22px;max-width:640px;width:100%;max-height:85vh;overflow:auto}
.modal-head{display:flex;align-items:flex-start;gap:14px;margin-bottom:14px}
.modal-head img{width:64px;height:64px;border-radius:8px;object-fit:cover;flex:none;background:var(--bg-card-hi)}
.modal-title{font-weight:700;font-size:15px;margin-bottom:4px}
.modal-sub{font-size:12.5px;color:var(--grey-dim)}
.modal-close{margin-left:auto;background:none;border:1px solid var(--line);color:var(--grey);border-radius:8px;width:32px;height:32px;cursor:pointer;font-size:16px;flex:none}
.modal-close:hover{color:var(--white)}

/* Libellé d'un destinataire de notification (ex "gérant", "comptabilité…") — voir BLOC G.8,
   Paramètres > Notifications (.notif-recipient-line/.notif-recipient-form). */
.brand-contact-label{display:inline-block;margin-left:8px;font-size:10.5px;font-weight:600;color:var(--grey-dim);background:rgba(255,255,255,.06);border-radius:8px;padding:2px 6px;text-transform:uppercase;letter-spacing:.02em}

/* BLOC G.5 §3 — panneau Collaboration (#contractFormEl) : "Enregistrer" restait au style
   natif du navigateur, seul formulaire de la fiche client sans règle dédiée. */
#contractFormEl button[type=submit]{background:var(--orange);color:var(--bg);border:none;
  border-radius:8px;padding:8px 14px;font-family:inherit;font-size:13px;font-weight:700;cursor:pointer}
#contractFormEl button[type=submit]:hover{opacity:.9}
#contractFormEl input[type=date]{font-family:inherit;font-size:13px;color:var(--text-2);
  background:var(--bg-card-hi);border:1px solid var(--line);border-radius:8px;padding:7px 10px}

/* ===== Page Paramètres (admin) ===== */
.settings-h1{font-size:24px;font-weight:700;letter-spacing:-.01em;margin-bottom:6px}
.settings-sub{color:var(--grey-dim);font-size:13.5px;margin-bottom:28px}
.settings-section{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);padding:22px 24px;margin-bottom:22px}
.settings-section h2.section{margin-top:0}
.settings-note{font-size:13px;color:var(--grey);margin-bottom:14px}
.settings-subsection{font-size:13px;font-weight:700;color:var(--grey);margin:22px 0 10px}
.settings-band-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;margin-bottom:6px}
.settings-band-grid label{display:block;font-size:12px;color:var(--grey);margin:0}
.settings-band-grid input{width:100%;margin-top:5px;font-family:inherit;padding:9px 11px;font-size:13.5px;
  color:var(--text-2);background:var(--bg-card-hi);border:1px solid var(--line);border-radius:8px}
.settings-band-grid input:focus{outline:2px solid var(--orange);outline-offset:1px}
.settings-default-note{font-size:11.5px;color:var(--grey-dim);margin:6px 0 4px}
/* BLOC G.0.3 — aperçu cron en direct (fuseau + prochaines exécutions), voir updateCronPreview
   dans settings.js. */
.cron-preview{font-size:11.5px;color:var(--grey);margin:8px 0 0;min-height:1.4em}
.cron-preview.ok{color:var(--ok)}
.cron-preview.err{color:var(--bad)}
.settings-indicator{border:1px dashed var(--line);border-radius:10px;padding:14px 16px;margin-bottom:14px}
.settings-indicator-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:10px}
.settings-indicator-head b{font-size:14px;flex:1;min-width:120px}
.settings-mode-select{font-family:inherit;font-size:12.5px;color:var(--text-2);background:var(--bg-card-hi);
  border:1px solid var(--line);border-radius:8px;padding:6px 9px}
.settings-reset-btn{background:none;border:1px solid var(--line);color:var(--grey);border-radius:8px;
  padding:6px 10px;font-family:inherit;font-size:12px;cursor:pointer}
.settings-reset-btn:hover{color:var(--white);border-color:var(--grey-dim)}
.settings-computed-empty{font-size:12.5px;color:var(--grey-dim)}
.settings-computed-readout{display:flex;gap:16px;flex-wrap:wrap;align-items:baseline;font-size:13px;color:var(--grey)}
.settings-computed-readout b{color:var(--white);font-family:'IBM Plex Mono',monospace}
.settings-computed-meta{font-size:11.5px;color:var(--grey-dim)}
.settings-computed-at{font-size:12px;color:var(--grey-dim);margin-left:10px}
.settings-btn{background:var(--orange);color:var(--bg);border:none;border-radius:8px;padding:10px 16px;
  font-family:inherit;font-size:13.5px;font-weight:700;cursor:pointer;margin-top:10px;display:inline-block;text-decoration:none}
.settings-btn:hover{opacity:.9}
/* BLOC I.4 §1 — lien Metricool expiré : vrai <button disabled> (jamais un <a> désactivé par
   onclick, bloqué par la CSP script-src-attr, voir renderBienvenueMetricool). */
.settings-btn:disabled{opacity:.4;cursor:not-allowed}
.settings-btn:disabled:hover{opacity:.4}
/* Bouton secondaire, autonome ou combiné à .settings-btn : même hauteur que le bouton principal
   (padding réduit d'un pixel pour le contour). Action destructive : .warn, toujours avec un mot
   explicite dans le libellé (Retirer, Révoquer, Purger…), jamais la teinte seule. */
.settings-btn-secondary{display:inline-flex;align-items:center;justify-content:center;gap:6px;
  background:none;border:1px solid var(--line-strong);color:var(--text-2);border-radius:8px;
  padding:9px 15px;font-family:inherit;font-size:13.5px;font-weight:600;line-height:1.5;
  cursor:pointer;text-decoration:none;white-space:nowrap}
.settings-btn-secondary:hover{color:var(--white);border-color:var(--grey);background:var(--bg-card-hi);opacity:1}
.settings-btn-secondary:disabled{opacity:.45;cursor:not-allowed}
.settings-btn-secondary:disabled:hover{color:var(--text-2);border-color:var(--line-strong);background:none}
.settings-btn-secondary.warn{color:var(--bad);border-color:rgba(232,106,92,.55)}
.settings-btn-secondary.warn:hover{border-color:var(--bad);background:rgba(232,106,92,.1)}
.settings-msg{font-size:12.5px;margin:10px 0;border-radius:8px;padding:8px 12px;display:none}
.settings-msg.err{display:block;color:var(--bad);background:rgba(232,106,92,.1)}
.settings-msg.ok{display:block;color:var(--ok);background:rgba(95,203,142,.1)}
.settings-msg.warn{display:block;color:var(--warn);background:rgba(245,196,81,.1);border:1px solid rgba(245,196,81,.3)}
.settings-list{list-style:none;margin-bottom:12px}
.settings-list-item{display:flex;gap:8px;align-items:center;margin-bottom:8px}
.settings-list-input{flex:1;font-family:inherit;padding:8px 10px;font-size:13.5px;color:var(--text-2);
  background:var(--bg-card-hi);border:1px solid var(--line);border-radius:8px}
.settings-list-remove{background:none;border:1px solid var(--line);color:var(--grey);border-radius:8px;
  width:32px;height:32px;flex:none;cursor:pointer;font-size:13px}
.settings-list-remove:hover{color:var(--bad);border-color:var(--bad)}
.settings-add-row{display:flex;gap:8px;margin-bottom:6px}
/* Brief 29/09/2026 — Paramètres → Leads, statuts des leads. */
.lead-status-list{list-style:none;margin:0 0 12px;padding:0}
.lead-status-item{display:flex;flex-wrap:wrap;gap:8px;align-items:center;padding:8px 0;border-bottom:1px solid var(--line)}
.lead-status-item .settings-list-input{flex:1 1 180px;max-width:280px}
.lead-status-glyph-select,.lead-status-add select{font-family:inherit;font-size:15px;min-width:52px;padding:6px;background:var(--bg-soft);
  color:var(--white);border:1px solid var(--line-strong);border-radius:8px}
.lead-status-archived-title{font-size:13px;color:var(--grey);margin:16px 0 6px}
.lead-status-item.archived .lead-status-archived-label{color:var(--grey);text-decoration:line-through}
.settings-add-row input{flex:1;font-family:inherit;padding:9px 11px;font-size:13.5px;color:var(--text-2);
  background:var(--bg-card-hi);border:1px solid var(--line);border-radius:8px}

/* BLOC C — panneau Accès (Paramètres > Accès). Tableau/journal réutilisent .admin-history-table
   (déjà éprouvée, historique des collectes) — défilement horizontal dans leur propre conteneur
   à 375px, jamais la page entière (règle overflow-x en tête de fichier). */
.access-summary{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:16px}
.access-summary-item{flex:1;min-width:110px;padding:4px 14px;text-align:center;border-left:1px solid var(--line-soft)}
.access-summary-item:first-child{border-left:none;padding-left:0}
.access-summary-item b{display:block;font-size:22px;font-family:'IBM Plex Mono',monospace;color:var(--white)}
.access-summary-item span{font-size:11px;color:var(--grey-dim)}

.access-credentials{background:rgba(95,203,142,.08);border:1px solid var(--ok);border-radius:10px;padding:14px 16px;margin-bottom:16px}
.access-credentials-row{display:flex;align-items:center;gap:10px;margin-bottom:6px;font-size:13px;color:var(--grey);flex-wrap:wrap}
.access-credentials-row b{font-family:'IBM Plex Mono',monospace;font-size:14px;color:var(--white);letter-spacing:.02em;word-break:break-all}
.access-credentials-warn{font-size:11.5px;color:var(--grey-dim);margin:6px 0 10px}
.access-credentials-close{background:none;border:1px solid var(--line);color:var(--grey);border-radius:8px;padding:6px 12px;font-family:inherit;font-size:12px;cursor:pointer}

.access-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;margin-bottom:8px}
.access-table{min-width:640px}
.access-status{font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;padding:2px 8px;border-radius:8px;background:rgba(148,152,160,.15);color:var(--grey);white-space:nowrap}
.access-status.active{color:var(--ok);background:rgba(95,203,142,.12)}
.access-status.pending{color:var(--warn);background:rgba(245,196,81,.12)}
.access-status.revoked{color:var(--bad);background:rgba(232,106,92,.12)}
.access-status.expired{color:var(--bad);background:rgba(232,106,92,.12)}
.access-actions{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.access-actions button{font-size:11.5px;padding:5px 10px;white-space:nowrap}
.access-actions button.warn{color:var(--bad);border-color:rgba(232,106,92,.4)}
.access-revoked-note{color:var(--grey-dim);font-size:12px}

/* BLOC E.1 — identifiant Metricool (blog_id), discret sous le nom de marque : même format que
   le journal ("brand #6156149"), c'est la clé qui relie les deux. */
.access-blogid{display:block;font-size:10.5px;color:var(--grey-dim);margin-top:1px}

/* BLOC D — e-mail de test (Accès), formulaire d'activation/renvoi avec choix lien/manuel. */
.access-test-email{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:16px}
.access-test-email input{font-family:inherit;font-size:12.5px;color:var(--text-2);background:var(--bg-card-hi);
  border:1px solid var(--line);border-radius:8px;padding:7px 10px;min-width:200px;flex:1}
.access-test-email .settings-msg{margin:0}

.access-inline-form{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.access-inline-form input{font-family:inherit;font-size:12.5px;color:var(--text-2);background:var(--bg-card-hi);
  border:1px solid var(--line);border-radius:8px;padding:6px 9px;min-width:150px}
.access-inline-form button{font-size:11.5px;padding:5px 10px;margin-top:0}
.access-radio{display:flex;align-items:center;gap:5px;font-size:11.5px;color:var(--grey);white-space:nowrap;margin:0}

/* BLOC E.1 — journal plafonné à ~10 lignes visibles (jamais étiré sur toute la page), au-delà
   scrollable dans son propre conteneur, en-tête sticky à l'intérieur de cette zone (pas de la
   page). Pagination partagée (createPaginatedList, paginatedList.js) : la page suivante se
   charge quand le pied de liste, placé dans cette zone, devient visible. Noms de classe hérités
   du journal, génériques dans leur usage réel. */
.access-audit-scroll{max-height:390px;overflow-y:auto;overflow-x:auto;-webkit-overflow-scrolling:touch;
  border:1px solid var(--line);border-radius:10px}
.access-audit-table{min-width:480px}
.access-audit-scroll thead th{position:sticky;top:0;background:var(--bg-card);z-index:1}

/* BLOC G.6 — visibilité des notifications (Paramètres > Notifications) */
.notif-paused-banner{background:rgba(232,106,92,.12);border:1px solid var(--bad);color:var(--bad);
  border-radius:10px;padding:12px 16px;font-size:13px;font-weight:700;margin-bottom:18px}
.notif-pause-toggle{display:flex;align-items:center;gap:8px;font-size:13.5px;color:var(--text-2);cursor:pointer;margin:0}
.notif-pause-toggle input{width:auto;margin:0}
.notif-agency-card{border-bottom:1px solid var(--line-soft);padding:0 0 16px;margin-bottom:16px;
  display:flex;flex-wrap:wrap;gap:6px 20px;align-items:center;font-size:13px;color:var(--grey)}
.notif-agency-card b{color:var(--white)}
.notif-agency-card .settings-btn-secondary{margin-top:0;margin-left:auto}
.notif-row-disabled{opacity:.6}
.notif-actions{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px}
.notif-actions button{font-size:11.5px;padding:5px 10px;white-space:nowrap;margin-top:0}
.notif-status{font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;padding:2px 8px;border-radius:8px;white-space:nowrap}
.notif-status.ok{color:var(--ok);background:rgba(95,203,142,.12)}
.notif-status.err{color:var(--bad);background:rgba(232,106,92,.12)}
.notif-status.warn{color:var(--warn);background:rgba(245,196,81,.12)}
.digest-preview-modal{max-width:680px}
.digest-preview-frame{width:100%;height:60vh;border:1px solid var(--line);border-radius:8px;background:#fff}

/* BLOC G.8 — liste unique "Marques" (remplace les anciens tableaux "Destinataires par marque" /
   "Notifications programmées"), un bloc div par marque plutôt qu'un tableau — naturellement
   responsive (empile en colonne sur mobile, voir BLOC G.9), sans conteneur à faire défiler. */
.notif-brand-row{border-top:1px solid var(--line-soft);padding:14px 0;margin-bottom:0}
.notif-brand-row:first-child{border-top:none;padding-top:0}
.notif-brand-row-simple{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;padding:10px 0;border-top:1px solid var(--line-soft)}
.notif-brand-row-simple:first-child{border-top:none;padding-top:0}
.notif-brand-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:6px}
.notif-brand-row-simple .notif-brand-head{margin-bottom:0}
.notif-brand-name{font-weight:700;color:var(--white);font-size:13.5px}
.notif-channel-badge{color:var(--ok);background:rgba(95,203,142,.1)}
.notif-no-channel{font-size:11px;color:var(--grey-dim)}
.notif-csv-note{font-size:11.5px;color:var(--grey-dim)}
.notif-suspended{font-size:12.5px;font-weight:600;color:var(--warn);border:1px solid var(--line);border-radius:8px;padding:8px 12px;margin:8px 0}
.notif-brand-meta{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:10px;font-size:12.5px;color:var(--grey)}
.notif-cadence-summary{background:none;border:none;color:var(--grey);font-family:inherit;font-size:12.5px;cursor:pointer;padding:0;text-decoration:underline dotted;text-underline-offset:3px}
.notif-cadence-summary:hover{color:var(--white)}
.notif-cadence-form{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.notif-cadence-form select,.notif-cadence-form input[type=time]{font-family:inherit;font-size:12.5px;color:var(--text-2);
  background:var(--bg-card);border:1px solid var(--line);border-radius:8px;padding:5px 8px}
.notif-cadence-times{display:flex;gap:6px}
.notif-brand-recipients{display:flex;flex-direction:column;gap:6px}
.notif-recipient-line{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;
  width:100%;text-align:left;background:var(--bg-card);border:1px solid var(--line);border-radius:8px;
  padding:8px 12px;font-family:inherit;font-size:12.5px;color:var(--text-2);cursor:pointer}
.notif-recipient-line:hover{border-color:var(--grey-dim)}
.notif-recipient-channels{font-size:11px;color:var(--grey-dim);white-space:nowrap}
.notif-recipient-form{display:flex;gap:8px;flex-wrap:wrap;align-items:center;background:var(--bg-card);
  border:1px solid var(--line);border-radius:8px;padding:10px 12px}
.notif-recipient-form input[type=email],.notif-recipient-form input[type=text]{font-family:inherit;font-size:12.5px;color:var(--text-2);
  background:var(--bg-card-hi);border:1px solid var(--line);border-radius:8px;padding:6px 10px}
.notif-recipient-form label{display:flex;align-items:center;gap:5px;font-size:12px;color:var(--grey);margin:0}
.notif-recipient-form button{font-size:11.5px;padding:5px 10px;margin-top:0}
/* BLOC G.8 §4 — case Leads cochable mais visuellement neutralisée sans source CSV (jamais
   disabled="" — reste soumise telle quelle, voir renderRecipientForm). */
.notif-checkbox-muted{opacity:.5}
/* BLOC G.8 §7 — un avertissement = une ligne (<summary>), détail complet au clic (<details>
   natif, accessible clavier/tactile — pas seulement au survol, utile sur mobile BLOC G.9). */
.notif-warning-item{margin-top:6px;font-size:12.5px}
.notif-warning-item summary{cursor:pointer;color:var(--warn)}
.notif-warning-detail{margin:4px 0 0 16px;color:var(--grey)}

/* BLOC G.2/G.3/G.4 — vue Leads (principale + par campagne) */
.leads-toolbar{margin-bottom:10px;display:flex;gap:10px}

/* BLOC G.4 §7 — style natif du navigateur en rupture avec la charte sombre : harmonisé sur le
   même motif que .campaigns-filters select (déjà utilisé ailleurs dans l'app). Largeur bornée +
   troncature (§7 ⚠️) — un nom de campagne long, ou une ancienne valeur d'erreur, ne doit jamais
   élargir le sélecteur au point de déborder. */
#leadsCampaignFilter{font-family:inherit;font-size:13px;color:var(--text-2);background:var(--bg-card);
  border:1px solid var(--line);border-radius:8px;padding:8px 12px;min-height:44px;
  max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* BLOC G.4 §7 — mêmes règles que .campaign-target-grid input/select et .campaign-target-form
   button (déjà utilisées pour les cibles économiques) — jamais deux styles de formulaire
   différents dans le même panneau Paramètres. */
.leads-source-form input,.leads-source-form select{width:100%;max-width:360px;font-family:inherit;
  padding:8px 10px;font-size:13px;color:var(--text-2);background:var(--bg-card-hi);
  border:1px solid var(--line);border-radius:8px}
.leads-source-form button[type=submit]{margin-top:0;background:var(--orange);color:var(--bg);border:none;
  border-radius:8px;padding:8px 14px;font-family:inherit;font-size:13px;font-weight:700;cursor:pointer}
/* BLOC G.9 — seul tableau de l'app qui n'était pas défilable horizontalement (audit mobile) :
   colonnes Téléphone/E-mail/Réponses inaccessibles sur petit écran. Scroll de secours ici
   (mêmes règles que .access-table-wrap) ; en dessous de 640px la bascule en cartes prend le
   relais (voir @media(max-width:640px) plus bas), le scroll ne sert alors qu'entre 640px et la
   largeur complète du tableau. */
#leadsScroll{overflow-x:auto;-webkit-overflow-scrolling:touch} /* écran large : hauteur fixe, voir plus bas */
.leads-table{min-width:720px}
/* Réponses au formulaire : JAMAIS de troncature (brief §3) — hauteur de ligne variable,
   une paire question/réponse par ligne, largeur confortable pour rester lisible. */
.leads-table td{vertical-align:top}
.leads-answers{min-width:260px;max-width:420px;white-space:normal}
.lead-answer-row{padding:2px 0}
.lead-answer-row+.lead-answer-row{border-top:1px solid var(--line)}
/* Hiérarchie visuelle (brief G.3 §1) : le nom du lead ressort, les réponses restent en retrait —
   même principe de contraste que .hint (grey-dim) ailleurs dans l'app. */
.lead-answer-q{color:var(--grey-dim);margin-right:6px}
.lead-answer-a{color:var(--grey)}
.lead-campaign-cell{max-width:220px}
.lead-name{font-weight:700;color:var(--white)}
.lead-num{color:var(--grey-dim);text-align:right}
/* BLOC G.10 §1 — tel:/mailto: RESTENT des liens (clic direct depuis le client mail/téléphone),
   mais sans l'AIR d'un lien sur desktop (souligné bleu par défaut = casse la lecture du tableau,
   brief) : même couleur que le texte courant, changement discret au survol seulement. Sur
   mobile, l'apparence de lien redevient utile (on veut appeler/écrire d'un doigt) — voir la
   règle .leads-table a[href^] dans @media(max-width:640px), qui prend le dessus là (déclarée
   après, cascade), jamais l'inverse. */
.leads-table a[href^="tel:"],.leads-table a[href^="mailto:"]{color:inherit;text-decoration:none}
.leads-table a[href^="tel:"]:hover,.leads-table a[href^="mailto:"]:hover{color:var(--white)}
/* BLOC G.4 §6 — séparation renforcée : alternance de fond ET bordure marquée (les deux, pas
   l'un ou l'autre — G.3 ne suffisait pas), pour que les 2 lignes de réponses restent visuellement
   RATTACHÉES à leur lead (jamais "flottantes" entre deux prospects) — chaque <tr> reste l'unité
   visuelle complète (date→réponses), la bande de fond en fait un bloc perçu comme un tout. */
.leads-table tbody tr{border-bottom:3px solid var(--line)}
.leads-table tbody tr:nth-child(even){background:rgba(255,255,255,.025)}
/* Brief 29/09/2026 (constats Amelot) — lignes compactes : marges verticales réduites, date et
   téléphone sur une seule ligne, pour qu'environ 8 leads tiennent sur un écran d'ordinateur. */
.leads-table td{padding:6px 10px}
.leads-table .lead-date,.leads-table .lead-phone{white-space:nowrap}
.access-audit-footer{font-size:11.5px;color:var(--grey-dim);text-align:center;padding:8px 0 0}
/* Bouton « Réessayer » du pied de liste (erreur de chargement) — style natif jamais laissé passer. */
.access-audit-footer .paginated-retry{font-size:11.5px;font-family:inherit;margin:0 0 0 4px;padding:3px 9px}
.access-audit-scroll .access-audit-footer{padding:8px 0}
/* Filtres au-dessus d'un journal (Paramètres → Accès, → Notifications). */
.audit-filters{display:flex;flex-wrap:wrap;gap:10px 18px;align-items:center;margin:0 0 10px;font-size:12.5px;color:var(--grey)}
.audit-filter{display:flex;align-items:center;gap:6px;margin:0;white-space:nowrap}
.audit-filter select{font-family:inherit;font-size:12.5px;color:var(--text-2);background:var(--bg-card-hi);
  border:1px solid var(--line);border-radius:8px;padding:5px 8px;max-width:220px}

/* BLOC G.4 §4/§5 — en-têtes triables + compteur mis en évidence. */
.leads-header-row{display:flex;justify-content:space-between;align-items:flex-end;flex-wrap:wrap;gap:10px;margin-bottom:10px}
.leads-sortable{cursor:pointer;user-select:none;white-space:nowrap}
.leads-sortable:hover{color:var(--white)}
.leads-sortable.sort-active{color:var(--orange-bright)}
.sort-indicator{display:inline-block;margin-left:4px;font-size:10px}
.leads-summary-highlight{text-align:right}
.leads-summary-count{font-family:'IBM Plex Mono',monospace;font-size:22px;font-weight:700;color:var(--white)}
.leads-summary-date{font-size:12px;color:var(--grey-dim)}
/* Brief 29/09/2026 — onglet Leads : sélecteur de campagne, compteurs par statut, filtres, statut et
   note. L'état actif se lit à la forme (bordure épaisse, marqueur ▸, soulignement), jamais à la
   seule couleur. */
.leads-campaign-picker{display:flex;flex-wrap:wrap;gap:8px}
.leads-campaign-btn{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line-strong);background:var(--bg-card);
  color:var(--text-2);font-family:inherit;font-size:13px;font-weight:600;border-radius:10px;padding:7px 12px;cursor:pointer;max-width:340px}
.leads-campaign-btn:hover{color:var(--white)}
.leads-campaign-btn.on{border:2px solid var(--orange);color:var(--white);font-weight:700;padding:6px 11px}
.leads-campaign-mark:empty{display:none}
.leads-campaign-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.leads-campaign-count{font-family:'IBM Plex Mono',monospace;font-size:12px;background:rgba(255,255,255,.07);border-radius:8px;padding:1px 7px}
.leads-status-counters{display:flex;flex-wrap:wrap;align-items:center;gap:4px 6px;margin:4px 0 10px}
.leads-status-count{border:1px solid transparent;background:none;color:var(--text-2);font-family:inherit;font-size:13px;border-radius:8px;padding:4px 8px;cursor:pointer}
.leads-status-count:hover{color:var(--white);border-color:var(--line-strong)}
.leads-status-count.on{border:2px solid var(--white);color:var(--white);text-decoration:underline}
.leads-status-sep{color:var(--grey-dim)}
.lead-status-glyph{display:inline-block;min-width:1em;text-align:center}
.leads-filters{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:12px}
.leads-filter-menus{display:contents}
.leads-multi{position:relative}
.leads-multi summary{list-style:none;cursor:pointer;border:1px solid var(--line-strong);border-radius:8px;padding:6px 10px;font-size:13px;
  color:var(--text-2);max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.leads-multi summary::-webkit-details-marker{display:none}
.leads-multi summary::after{content:' ▾'}
.leads-multi[open] summary{color:var(--white);border-color:var(--white)}
.leads-multi-count{font-weight:700;color:var(--white)}
.leads-multi-menu{position:absolute;z-index:30;top:calc(100% + 4px);left:0;min-width:220px;max-width:360px;max-height:320px;overflow:auto;
  background:var(--bg-card-hi);border:1px solid var(--line-strong);border-radius:10px;padding:6px;box-shadow:0 8px 24px rgba(0,0,0,.4)}
.leads-multi-menu label{display:flex;gap:8px;align-items:center;padding:5px 6px;font-size:13px;color:var(--text-2);cursor:pointer;border-radius:6px}
.leads-multi-menu label:hover{background:rgba(255,255,255,.05)}
.leads-search{flex:1 1 220px;min-width:200px;max-width:340px;font-family:inherit;font-size:13px;background:var(--bg-soft);color:var(--white);
  border:1px solid var(--line-strong);border-radius:8px;padding:7px 10px}
.leads-match-count{font-size:12.5px;color:var(--grey)}
.lead-status-select{font-family:inherit;font-size:13px;background:var(--bg-soft);color:var(--white);border:1px solid var(--line-strong);
  border-radius:8px;padding:5px 6px;max-width:200px}
.lead-note-cell{min-width:220px}
/* Case Note (brief 30/09/2026) : texte de la note sur 3 lignes au plus, points de suspension,
   texte complet au survol ; un clic ouvre la fiche du lead. Styles : leads-panel.css. */
/* Colonnes de questions : largeur bornée, le texte long passe à la ligne ; l'en-tête est tronqué,
   l'intitulé complet s'affiche au survol (title). */
.lead-answer-cell{min-width:120px;white-space:normal}
.lead-answer-text{max-width:240px;overflow-wrap:anywhere}
.lead-q-label{display:inline-block;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}
/* « Voir comme ce client » : statut et note désactivés — grisés ET bordure pointillée (la forme,
   pas seulement la teinte), avec la mention « Lecture seule en vue agence » au-dessus du tableau. */
.lead-status-select:disabled,.lead-panel-note:disabled{opacity:.55;border-style:dashed;cursor:not-allowed}
.leads-readonly-note{font-size:12.5px;color:var(--grey);margin:0 0 8px}
.leads-readonly-note a{color:var(--white);text-decoration:underline}
/* Une seule campagne : son nom en titre, sans bouton. */
.leads-campaign-title{display:flex;align-items:center;gap:8px;font-size:16px;font-weight:700;color:var(--white);margin:0;min-width:0}
/* Graphique « Volume de leads » replié par défaut sur une ligne (leads-volume-panel.js). */
.leads-volume-panel{margin-bottom:12px;padding-top:10px;padding-bottom:10px}
.leads-volume-toggle{display:flex;flex-wrap:wrap;align-items:center;gap:6px;width:100%;background:none;border:none;padding:0;
  font-family:inherit;font-size:13px;color:var(--grey);text-align:left;cursor:pointer}
.leads-volume-title{font-weight:700;color:var(--white)}
.leads-volume-action{text-decoration:underline;color:var(--text-2)}
.leads-volume-toggle:hover .leads-volume-action{color:var(--white)}
.leads-volume-toggle[aria-expanded="true"]+.chartbox{margin-top:10px}
/* Colonnes fixes sur écran large : N° et Nom à gauche, Statut et Note à droite ; seules les
   colonnes du milieu défilent dans #leadsScroll. Fond opaque (le zébrage des lignes paires est
   rejoué par-dessus) et séparation par une ombre intérieure, qui suit la cellule collante
   (une bordure du tableau fusionné resterait en place). Les décalages de Nom et de Statut sont
   mesurés sur les en-têtes (updateStickyOffsets, leads-tab.js). Sous 640 px : cartes. */
@media(min-width:641px){
  .leads-table .lead-sticky{position:sticky;z-index:2;background:var(--bg)}
  .leads-table tbody tr:nth-child(even) .lead-sticky{background:linear-gradient(rgba(255,255,255,.025),rgba(255,255,255,.025)),var(--bg)}
  .leads-table .lead-sticky-num{left:0}
  .leads-table .lead-sticky-name{left:var(--leads-sticky-name-left,0px)}
  .leads-table .lead-sticky-status{right:var(--leads-sticky-status-right,0px)}
  .leads-table .lead-sticky-note{right:0}
  .leads-table .lead-sticky-edge-left{box-shadow:inset -2px 0 0 var(--line-strong)}
  .leads-table .lead-sticky-edge-right{box-shadow:inset 2px 0 0 var(--line-strong)}
}
/* Tableau façon tableur sur écran large : #leadsScroll a une hauteur fixe (--leads-scroll-h :
   fenêtre moins ce qui est au-dessus, 360 px minimum, calculée par updateScrollHeight,
   leads-tab.js) et ses propres défilements vertical et horizontal, toujours accessibles. La ligne
   d'en-têtes reste en haut ; le coin où une colonne fixe croise l'en-tête passe au-dessus de tout
   (cellules 2 < en-têtes 3 < coins 4). Le trait sous l'en-tête est une ombre intérieure, qui suit
   l'en-tête collant. Le pied de liste reste à gauche quand on défile vers la droite. Sous 640 px :
   aucune de ces règles, les cartes restent dans la page. */
@media(min-width:641px){
  #leadsScroll{height:var(--leads-scroll-h,360px);overflow:auto}
  .leads-table thead th{position:sticky;top:0;z-index:3;background:var(--bg);box-shadow:inset 0 -1px 0 var(--line-strong)}
  .leads-table thead th.lead-sticky{z-index:4}
  .leads-table thead th.lead-sticky-edge-left{box-shadow:inset -2px 0 0 var(--line-strong),inset 0 -1px 0 var(--line-strong)}
  .leads-table thead th.lead-sticky-edge-right{box-shadow:inset 2px 0 0 var(--line-strong),inset 0 -1px 0 var(--line-strong)}
  #leadsScroll .access-audit-footer{position:sticky;left:0;padding:8px 0}
}

/* BLOC I.2 — onglet Onboarding, mise en forme "document professionnel" (brief : premier contact
   client avec l'app). Largeur de lecture bornée (§3) : posée sur #onboardingDetail lui-même
   (bandeau + méta + éditeur + rendu en héritent tous), pas sur un sous-conteneur séparé. */
#onboardingDetail{max-width:760px;margin:0 auto;width:100%}

/* BLOC I.2.1 §b — l'onglet Onboarding masque .toolbar (dashboard.js, `tab === 'onboarding'`),
   qui est la seule source de la marge de 20px sous #mainTabs sur les autres onglets — sans elle
   le contenu (bandeau dégradé ou grille de marques) collait directement sous la barre d'onglets. */
#onboardingMain{margin-top:20px}

/* BLOC P.1.1 §9 — même situation que #onboardingMain ci-dessus : .toolbar (seule source du gap
   sous #mainTabs sur Organique/Ads/Leads) est désormais masqué sur l'Accueil client aussi (§1,
   sélecteur de période retiré) — sans cette règle, le premier bloc touchait la barre d'onglets.
   Vérifié : aucun autre onglet ne partage déjà exactement 48px (Onboarding a 20px, Organique/
   Campagnes ~26-28px selon leur propre premier élément) — valeur posée ici telle que demandée,
   pas une valeur partagée réutilisable. */
#clientHomeMain{margin-top:48px}

/* §1 — bandeau généré par JS (renderOnboardingHeader, dashboard.js), jamais par l'éditeur :
   nom de marque + date viennent de l'app. Texte foncé (var(--bg)) : contraste garanti sur toute
   l'étendue du dégradé orange -> turquoise, contrairement à du blanc qui s'effacerait côté cyan.
   L'auteur n'y figure jamais (voir .onboarding-updated plus bas, staff uniquement). */
.onboarding-header{background:linear-gradient(120deg,var(--orange) 0%,var(--cyan) 100%);
  border-radius:var(--radius);padding:26px 30px;margin-bottom:20px;color:var(--bg)}

/* BLOC I.4 §1 — vidéo de présentation (onglet Bienvenue) : ratio 16:9 responsive (technique
   padding-top classique, aucune dépendance externe) — jamais une hauteur fixe qui déborderait ou
   laisserait des bandes vides selon la largeur du panneau. */
.bienvenue-video-wrap{position:relative;width:100%;padding-top:56.25%;border-radius:10px;overflow:hidden;background:var(--bg-card-hi)}
.bienvenue-video-wrap iframe{position:absolute;inset:0;width:100%;height:100%;border:0}

/* BLOC L.2.1 §2 — bandeau de connexion Metricool, en tête de l'onglet Bienvenue : la seule
   action que le client doit accomplir, donc visuellement accentuée (fond + bordure teintés
   orange, filet de gauche) plutôt qu'un panneau neutre comme les autres. */
.bienvenue-connect-banner{background:rgba(224,160,90,.1);border:1px solid rgba(224,160,90,.4);border-left:3px solid var(--orange-bright)}
.onboarding-header-eyebrow{font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;opacity:.72}
.onboarding-header-title{font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;
  font-size:26px;font-weight:700;line-height:1.25;margin:6px 0 10px;word-break:break-word}
.onboarding-header-date{font-size:12.5px;font-weight:600;opacity:.78}

/* Ligne discrète sous le bandeau : réservée à l'auteur (staff uniquement dans les faits —
   `updatedBy` n'est jamais renvoyé par l'API pour le rôle client, voir routes/clients.js). La
   date, elle, est déjà dans le bandeau ci-dessus : jamais dupliquée ici. */
.onboarding-updated{margin-bottom:14px}

/* BLOC S.1 §1 — code marque : ligne compacte, admin uniquement (voir dashboard.js openOnboarding),
   distincte de l'éditeur riche en dessous (pas la même action d'enregistrement). */
.onboarding-code-marque{display:flex;align-items:center;gap:8px;margin-bottom:16px;flex-wrap:wrap}
.onboarding-code-marque label{font-size:12.5px;color:var(--grey-dim)}
.onboarding-code-marque input{font-family:'IBM Plex Mono',monospace;text-transform:uppercase;background:var(--bg-card);border:1px solid var(--line);border-radius:8px;color:var(--white);padding:6px 10px;width:130px;font-size:13px}
.onboarding-code-marque .hint{margin:0;color:var(--bad)}

/* BLOC S.1 §5 — filet de sécurité : codes Asana sans marque, masqué tant que la liste est vide. */
#asanaOrphanCodesBanner{font-size:12.5px;color:var(--warn);background:rgba(245,196,81,.08);border:1px solid rgba(245,196,81,.3);border-radius:10px;padding:9px 14px;margin-bottom:14px}
#asanaOrphanCodesBanner code{font-family:'IBM Plex Mono',monospace;background:rgba(245,196,81,.15);border-radius:5px;padding:1px 6px;margin-left:3px}

/* BLOC G.1 §4 — même filet de sécurité pour les tournages d'agenda sans marque, peuplé en
   permanence par construction (prospects/interne/one-shots) : liste scrollable + bouton "ignorer
   définitivement" par ligne, jamais un simple texte qui deviendrait illisible. */
#agendaUnmatchedBanner{font-size:12.5px;color:var(--warn);background:rgba(245,196,81,.08);border:1px solid rgba(245,196,81,.3);border-radius:10px;padding:9px 14px;margin-bottom:14px}
.agenda-unmatched-list{list-style:none;margin:6px 0 0;padding:0;max-height:180px;overflow-y:auto}
.agenda-unmatched-list li{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:3px 0}
.agenda-unmatched-list button{font-size:11.5px;white-space:nowrap}

/* Zone lecture (client + aperçu admin) : contenu HTML sanitisé affiché tel quel, donc typographie
   posée ici (l'éditeur n'apporte que la structure sémantique, h1/h2/p/ul/ol/li/a/strong/em/u).
   BLOC L.0/L.0.1 — CORRECTIF définitif : `break-word` cassait des mots qui tenaient dans la
   ligne, `normal` (posé ensuite) ne cassait plus rien et laissait des lignes déborder à droite.
   `overflow-wrap:anywhere` : ne casse que quand AUCUN point de rupture naturel n'existe sur la
   ligne (mots normaux intacts, seule une URL longue et non coupable casse) — propriété héritée,
   posée une seule fois ici, s'applique à tous les descendants (p, li, h1, h2 compris). */
.onboarding-content{max-width:100%;color:rgba(243,243,244,.82);line-height:1.75;overflow-wrap:break-word;word-break:normal;min-width:0}
/* BLOC I.2.1 §d — la barre n'est plus posée directement sur h1 (qui resterait pleine largeur de
   colonne) : `display:table` fait du titre une boîte qui épouse la largeur de son texte, donc
   son border-bottom (la barre) aussi. Beaucoup d'air au-dessus (rythme vertical) — contraste
   volontaire avec le peu d'espace entre un Titre 2 et son contenu, voir plus bas. */
.onboarding-content h1{display:table;font-size:14.5px;font-weight:800;color:var(--orange-bright);
  text-transform:uppercase;letter-spacing:.07em;margin:44px 0 14px;padding-bottom:9px;
  border-bottom:3px solid;border-image:linear-gradient(90deg,var(--orange),var(--cyan)) 1;overflow-wrap:break-word;word-break:normal;min-width:0}
.onboarding-content h2{font-size:16px;font-weight:600;color:var(--white);margin:20px 0 6px;overflow-wrap:break-word;word-break:normal;min-width:0}
.onboarding-content h1:first-child,.onboarding-content h2:first-child{margin-top:0}
/* Filet de séparation entre sections de Titre 1 : posé sur l'élément qui PRÉCÈDE le h1 (`:has(+
   h1)`, jamais sur le h1 lui-même — devenu `display:table`, un border-top dessus serait aussi
   limité à la largeur du texte, alors que ce filet doit couvrir toute la colonne). Absent avant
   le tout premier titre (rien à séparer). */
.onboarding-content > :not(h1):has(+ h1){padding-bottom:28px;border-bottom:1px solid var(--line)}
/* Premier paragraphe sous un Titre 1 : légèrement plus grand et plus clair, sert d'accroche de
   section (le reste du texte reste au gabarit courant). */
.onboarding-content h1 + p{font-size:16px;color:rgba(243,243,244,.96)}
.onboarding-content p{margin:0 0 12px;overflow-wrap:break-word;word-break:normal;min-width:0}
.onboarding-content ul,.onboarding-content ol{margin:0 0 14px;padding-left:22px}
/* BLOC K.1 §3 — bug : une liste à puces suivant immédiatement une liste numérotée (ou
   l'inverse) n'a aucune marge entre les deux (chacune n'a que margin-bottom, jamais de
   margin-top) — les deux blocs paraissent fusionnés. Deux listes consécutives de MÊME type
   restent collées (lecture normale d'une liste qui continue). */
.onboarding-content ol + ul,.onboarding-content ul + ol{margin-top:14px}
.onboarding-content li{margin-bottom:8px;line-height:1.5;overflow-wrap:break-word;word-break:normal;min-width:0}
/* Puces en chevron orange (jamais la puce ronde par défaut) ; interligne resserré ci-dessus par
   rapport aux paragraphes (1.5 contre 1.75). */
.onboarding-content ul{list-style-type:'▸  '}
.onboarding-content ul>li::marker{color:var(--orange-bright)}
/* Numérotation sur deux chiffres (01, 02…) via le style de compteur natif `decimal-leading-zero`
   — jamais un compteur CSS manuel, ce style existe déjà pour ce cas précis. */
.onboarding-content ol{list-style-type:decimal-leading-zero}
.onboarding-content ol>li::marker{color:var(--orange-bright);font-weight:600}
.onboarding-content strong,.onboarding-content b{color:var(--white);font-weight:700}
.onboarding-content a{color:var(--orange-bright);text-decoration:none;word-break:break-word}
.onboarding-content a:hover{text-decoration:underline}
/* Titre 2 immédiatement suivi d'une liste : encadré motif "Ce qu'on fait / Ce qu'on ne fait pas"
   — fond légèrement plus sombre que les cartes (--bg-card-hi), coins arrondis. Le h2 et la liste
   sont deux frères (HTML plat produit par Quill, pas de wrapper) : la boîte est simulée en
   fusionnant leurs bords (radius haut sur le h2, radius bas sur la liste, marge nulle entre eux). */
.onboarding-content h2:has(+ ul),.onboarding-content h2:has(+ ol){
  background:var(--bg-card-hi);border-radius:10px 10px 0 0;margin-bottom:0;padding:14px 16px 6px}
.onboarding-content h2:has(+ ul) + ul,.onboarding-content h2:has(+ ol) + ol{
  background:var(--bg-card-hi);border-radius:0 0 10px 10px;margin-top:0;padding:6px 18px 16px 34px}

/* BLOC O.2 — sous-onglet Contrats : liste verticale de fiches (pas la grille .cgrid, un contrat
   n'est pas une marque) ; statut calculé, même langage de couleur que les badges existants
   (vert actif/.ccard-campaign-badge, gris neutre/.ctab-empty — jamais une 3e palette). */
.contracts-list{display:flex;flex-direction:column;gap:14px;margin-top:14px}
.contract-status{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;border-radius:8px;padding:2px 7px;flex:none}
.contract-status-ok{color:var(--ok);background:rgba(95,203,142,.12)}
.contract-status-warn{color:var(--warn);background:rgba(245,196,81,.1)}
.contract-status-dim{color:var(--grey-dim);background:rgba(255,255,255,.05)}
/* BLOC O.4 §5 — "en production" ressort volontairement en orange de marque (seule exception à la
   règle "jamais l'orange pour un état" : c'est précisément le statut qui doit sauter aux yeux —
   "c'est là qu'il y a du travail"). */
.contract-status-orange{color:var(--orange-bright);background:rgba(224,160,90,.14)}

/* BLOC O.4 — carte repliée par défaut : seuls titre/badge/dates/durée sont visibles tant qu'on
   n'a pas cliqué (brief : "les cycles écrasent le texte du contrat, qui est l'information
   principale"). Le bouton-toggle porte toute cette zone ; le corps déplié (texte + cycles +
   Modifier) est un frère du bouton, jamais un enfant — pas de bouton imbriqué. */
.contract-card-toggle{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;
  width:100%;text-align:left;background:none;border:none;color:inherit;font-family:inherit;
  padding:0;cursor:pointer}
.contract-card-toggle-main{min-width:0;flex:1}
.contract-card-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:6px}
.contract-title{font-size:18px;font-weight:600;color:var(--white)}
.contract-dates{font-size:14px;font-weight:600;color:var(--text-2)}
/* Bloc 0b-3b — aide sous « Date de fin » (formulaire de contrat), collée au champ. */
.contract-date-fin-help{display:block;margin-top:4px;font-weight:400;line-height:1.4}
.contract-meta{font-size:11px;color:var(--grey-dim);margin-top:2px}
/* Chevron : indicateur de repliabilité — vers le bas replié, vers le haut déplié. */
.contract-card-chevron{color:var(--grey-dim);font-size:13px;line-height:1;flex:none;margin-top:2px;
  transition:transform .15s}
.contract-card-toggle.expanded .contract-card-chevron{transform:rotate(180deg)}
.contract-card-toggle:hover .contract-card-chevron{color:var(--grey)}
.contract-card-body{margin-top:14px}

/* BLOC O.4 §3 — piste des cycles repliée derrière une ligne unique (brief : "ne pas dérouler les
   trois cycles dans la carte"). Repliée : phase en cours en --orange-bright, ses dates en blanc,
   tient sur une seule ligne (Version finale ne passe jamais à la ligne). Dépliée : chaque cycle
   sur sa propre ligne, rang affiché, même gabarit que la vue Production (phases passées en --ok,
   phase en cours encadrée en orange). */
.contract-cycle-wrap{margin-bottom:14px}
.contract-cycle-toggle{display:flex;align-items:center;gap:7px;width:100%;text-align:left;
  background:none;border:none;color:inherit;font-family:inherit;font-size:12.5px;padding:4px 0;
  cursor:pointer;white-space:nowrap;overflow:hidden}
.contract-cycle-chevron{color:var(--grey-dim);font-size:10px;flex:none;transition:transform .15s}
.contract-cycle-toggle.expanded .contract-cycle-chevron{transform:rotate(180deg)}
.contract-cycle-summary{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--grey-dim)}
.contract-cycle-summary-phase{color:var(--orange-bright)}
.contract-cycle-summary-dates{color:var(--white);font-weight:600}
.contract-cycle-toggle:hover .contract-cycle-summary{color:var(--grey)}
.contract-cycle{font-size:11.5px;color:var(--grey-dim);margin-bottom:12px;line-height:1.6}
.contract-cycle-phase b{color:var(--grey);font-weight:600}
.contract-cycle-phase-current{color:var(--ok)}
.contract-cycle-phase-current b{color:var(--ok)}
.contract-cycle-sep{margin:0 6px;color:var(--grey-dim)}
/* BLOC O.4 §3 — un contrat au rythme mensuel/bimensuel a plusieurs cycles : rang affiché devant
   chaque ligne de piste, seulement quand il y a plus d'un cycle (un contrat "groupé" n'en a pas
   besoin, un seul cycle = aucune ambiguïté). */
.contract-cycle-rank{color:var(--grey);font-weight:600;margin-right:6px}

/* BLOC O.4 — vues Production/Commercial de la liste des marques : lignes pleine largeur (pas la
   grille .cgrid, trop d'info horizontale par ligne pour tenir en carte étroite). */
.clients-view-group-title{color:var(--grey-dim);font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;margin:24px 0 10px}
.clients-view-group-title:first-child{margin-top:0}
.pcard{display:block;width:100%;text-align:left;font-family:inherit;color:inherit;background:var(--bg-card);
  border:1px solid var(--line);border-radius:var(--radius);padding:14px 18px;margin-bottom:10px;cursor:pointer;transition:border-color .15s}
.pcard:hover{border-color:var(--grey-dim)}
.pcard:focus-visible{outline:2px solid var(--orange)}
.pcard-row{display:flex;align-items:center;justify-content:space-between;gap:18px}
.pcard-sub{color:var(--grey-dim);font-size:12px;margin-top:3px}
.pcard-email{color:var(--orange);font-size:12px;text-decoration:none;display:inline-block;margin-top:4px}
.pcard-email:hover{text-decoration:underline}
/* BLOC O.4 (refonte vue Commercial) — chiffre en évidence : 24px/700, coloré selon l'urgence. */
/* BLOC C.2 §8 — le grand chiffre ne se replie jamais (overflow tronqué plutôt que 2 lignes) ;
   valeur + unité seules ("126 j"), "restants" en dessous (.pcard-highlight-sub, ci-dessous). */
.pcard-highlight{font-family:'IBM Plex Mono',monospace;font-weight:700;font-size:24px;white-space:nowrap;
  text-align:right;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.pcard-highlight-sub{font-size:10px;color:var(--grey-dim);text-align:right;margin-top:1px}
.pcard-highlight.ok{color:var(--ok)}
.pcard-highlight.warn{color:var(--warn)}
.pcard-highlight.bad{color:var(--bad)}
.pcard-highlight.dim{color:var(--grey-dim)}

.pcard-col-name{min-width:0}
.pcard-name{font-size:15.5px;font-weight:600;color:var(--white)}
.pcard-contract-title{font-size:12px;color:var(--grey);margin-top:5px}

/* BLOC O.4 (refonte vue Commercial) — même gabarit de ligne que la vue Production, colonne de
   droite à largeur fixe (150px) : un chiffre + son libellé, puis un filet fin et l'état de
   signature — toujours les deux blocs, jamais l'un à la place de l'autre. */
.pcard-row-commercial{display:grid;grid-template-columns:1fr 150px;gap:20px;align-items:start}
/* BLOC C.2 §8 — min-width:0 : sans ça, un item de grille garde par défaut la taille min-content de
   son contenu (le grand chiffre nowrap, ou la ligne secondaire longue) et peut déborder de son
   propre rail de 150px au lieu de s'y tronquer — c'est ce qui repliait la ligne secondaire sur
   3 lignes et poussait la hauteur de la carte (cas CARS FOR YOU). */
.pcard-col-highlight{text-align:right;min-width:0}
.pcard-signed-divider{height:1px;background:rgba(255,255,255,.06);margin:8px 0}
/* La ligne secondaire se tronque (une seule ligne, ellipsis) plutôt que de forcer la hauteur de la
   carte ; le texte complet reste lisible via l'attribut title (voir commercialHighlightHtml). */
.pcard-signed-state{font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.pcard-signed-yes{color:var(--ok);font-weight:600}
.pcard-signed-no{color:var(--grey-dim)}

/* BLOC C.2 — bloc "Statistiques" en tête du sous-onglet Commercial : chiffres clés + graphique en
   barres empilées, en CSS pur (voir design/statistiques-v2.html, disposition/états repris, calcul
   propre — src/views/assets/commercial-stats.js). Classes préfixées comstat- pour ne jamais
   percuter les classes génériques (.chart/.col/.axis/.tip/...) déjà utilisées ailleurs. */
.comstat{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);padding:20px 22px;margin-bottom:22px}
.comstat-title{font-size:14px;font-weight:700;color:var(--white);margin-bottom:16px}
/* BLOC C.7 §3 — six indicateurs en cartes distinctes (jamais du texte libre côte à côte, qui
   débordait sur deux lignes) : grille qui se réorganise selon la largeur disponible, une carte
   par indicateur, jamais moins de ~148px pour rester lisible. */
.comstat-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:12px;margin-bottom:22px}
.comstat-kpi{background:var(--bg-card-hi);border:1px solid var(--line);border-radius:10px;padding:14px 16px;min-width:0}
.comstat-kpi-n{font-family:'IBM Plex Mono',monospace;font-weight:700;font-size:26px;color:var(--white);line-height:1.1;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.comstat-kpi-n.up{color:var(--ok)}
.comstat-kpi-n.dn{color:var(--bad)}
.comstat-kpi-l{font-size:12px;color:var(--grey);margin-top:3px}
.comstat-kpi-d{font-size:11px;color:var(--grey-dim);margin-top:1px}

.comstat-ctrl{display:flex;align-items:center;gap:8px;flex-wrap:wrap;background:var(--bg-card-hi);border-radius:10px;padding:8px 12px;margin-bottom:22px}
.comstat-lbl{font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--grey-dim)}
.comstat-sep{width:1px;height:16px;background:var(--line);margin:0 4px}
.comstat-rb{font-family:inherit;font-size:12px;color:var(--grey);background:var(--bg-card);border:1px solid var(--line);
  border-radius:8px;padding:5px 10px;cursor:pointer;transition:color .15s,background-color .15s,border-color .15s}
.comstat-rb:hover{color:var(--text-2,var(--white));background:var(--bg-card-hi)}
.comstat-rb[aria-pressed="true"]{color:var(--white);border-color:var(--orange);background:var(--bg-card-hi)}
.comstat-rb:focus-visible{outline:2px solid var(--orange);outline-offset:2px}

.comstat-wrap{position:relative}
/* BLOC C.7 §5 — mois au-dessus (jamais de border-top ici désormais, le filet passe sous les
   valeurs) ; le graphique lui-même reste au milieu. */
.comstat-axis{display:grid;gap:8px;padding-bottom:8px;margin-bottom:6px}
.comstat-axis span{text-align:center;font-size:11px;color:var(--grey);text-transform:capitalize;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}
.comstat-axis span.comstat-now-label{color:var(--orange)}
.comstat-axis small{display:block;font-size:9.5px;color:var(--grey-dim)}

/* BLOC C.7 §4 — graphique combiné : courbe de revenu (SVG, axe gauche) au premier plan, barres du
   nombre de marques (axe droit) en arrière-plan discret. `position:relative` sert de repère pour
   la courbe/les points superposés en position:absolute, indépendants du gabarit grid des colonnes. */
.comstat-chart{display:grid;gap:8px;align-items:end;height:220px;position:relative}
.comstat-line-svg{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:1;overflow:visible}
.comstat-line{fill:none;stroke:var(--orange);stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}
.comstat-line-next{stroke-dasharray:5 4;opacity:.55}
.comstat-dot{position:absolute;width:6px;height:6px;margin:-3px 0 0 -3px;border-radius:50%;background:var(--orange);
  box-shadow:0 0 0 2px var(--bg-card);pointer-events:none;z-index:2}
.comstat-dot-next{opacity:.8}
/* Bloc 0b-3b E3 — point « à venir » CREUX (forme), plus seulement plus pâle (teinte) : un point
   passé est plein, un point à venir est un anneau, comme la courbe passe du plein aux tirets. */
.comstat-dot.comstat-dot-next{background:var(--bg-card);box-shadow:inset 0 0 0 1.5px var(--orange),0 0 0 2px var(--bg-card);width:8px;height:8px;margin:-4px 0 0 -4px}
.comstat-col{display:flex;flex-direction:column;justify-content:flex-end;height:100%;position:relative;cursor:default;z-index:3}
/* Barres = nombre de marques, arrière-plan discret (la courbe ci-dessus porte la donnée
   principale, brief : "c'est elle qui doit sauter aux yeux") : opacité réduite au repos, remontée
   au survol pour rester lisible sans jamais dominer visuellement la courbe. */
.comstat-stack{display:flex;flex-direction:column;justify-content:flex-end;height:100%;opacity:.42;transition:opacity .15s}
.comstat-col:hover .comstat-stack{opacity:.8}
.comstat-seg{border-radius:3px}
.comstat-seg.comstat-half{border-radius:5px 5px 0 0;margin-bottom:2px}
.comstat-col:hover .comstat-seg{filter:brightness(1.18)}
.comstat-past .comstat-full{background:var(--cyan)}
.comstat-past .comstat-half{background:repeating-linear-gradient(135deg,rgba(97,206,207,.75) 0 5px,rgba(97,206,207,.25) 5px 10px);
  box-shadow:inset 0 0 0 1px rgba(97,206,207,.6)}
.comstat-now .comstat-full{background:var(--orange)}
.comstat-now .comstat-half{background:repeating-linear-gradient(135deg,rgba(224,160,90,.8) 0 5px,rgba(224,160,90,.3) 5px 10px);
  box-shadow:inset 0 0 0 1px rgba(224,160,90,.7)}
.comstat-next .comstat-full{background:rgba(224,160,90,.42)}
.comstat-next .comstat-half{background:repeating-linear-gradient(135deg,rgba(224,160,90,.35) 0 5px,rgba(224,160,90,.1) 5px 10px);
  box-shadow:inset 0 0 0 1px rgba(224,160,90,.35)}
.comstat-col.comstat-now .comstat-stack{outline:1px solid rgba(224,160,90,.35);outline-offset:3px;border-radius:8px}

/* BLOC C.7 §5 — valeurs (montant + nombre de marques) EN DESSOUS du graphique, sur deux lignes,
   jamais superposées en position:absolute par-dessus les barres (illisible, tassé). */
.comstat-values{display:grid;gap:8px;border-top:1px solid var(--line);padding-top:8px;margin-top:2px}
.comstat-val{display:flex;flex-direction:column;align-items:center;gap:1px;min-width:0;
  font-family:'IBM Plex Mono',monospace;color:var(--white)}
.comstat-val-amt{font-weight:700;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.comstat-val-n{font-weight:400;font-size:10.5px;color:var(--grey)}
.comstat-val.comstat-next{color:var(--grey)}

/* .av-hover-tip (Accueil agence, survol des barres vidéo) : même infobulle, classe DIFFÉRENTE —
   contrairement à .comstat-tip (Commercial/Production), toujours injectée en JS au moment du
   rendu (une seule dans le DOM à la fois), celle-ci vit en statique dans dashboard.html (BLOC
   Accueil agence). Un même nom de classe aurait rendu `document.querySelector('.comstat-tip')`
   ambigu dès que les deux sections ont été rendues au moins une fois dans la même page. */
.comstat-tip,.av-hover-tip{position:absolute;z-index:20;background:var(--bg-card-hi);border:1px solid var(--line);border-radius:10px;
  padding:12px 14px;min-width:200px;max-width:260px;pointer-events:none;opacity:0;transform:translateY(4px);
  transition:opacity .12s,transform .12s;box-shadow:0 12px 30px rgba(0,0,0,.5)}
.comstat-tip.on,.av-hover-tip.on{opacity:1;transform:translateY(0)}
.comstat-tip h4,.av-hover-tip h4{font-size:13px;font-weight:700;color:var(--white);text-transform:capitalize;margin-bottom:2px}
.comstat-tip-tot{font-size:11px;color:var(--grey-dim);margin-bottom:9px}
.comstat-tip ul{list-style:none;display:flex;flex-direction:column;gap:5px}
.comstat-tip li{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--white)}
.comstat-tip li i{width:7px;height:7px;border-radius:2px;flex:0 0 auto;font-style:normal}
.comstat-tip li i.f{background:var(--cyan)}
.comstat-tip li i.h{background:repeating-linear-gradient(135deg,rgba(97,206,207,.8) 0 3px,transparent 3px 6px);
  box-shadow:inset 0 0 0 1px rgba(97,206,207,.7)}
.comstat-tip li b{margin-left:auto;font-family:'IBM Plex Mono',monospace;font-weight:400;font-size:11px;color:var(--grey-dim)}
.comstat-tip-none{font-size:12px;color:var(--grey-dim)}

.comstat-legend{display:flex;gap:18px;flex-wrap:wrap;align-items:center;margin-top:20px;font-size:11.5px;color:var(--grey)}
.comstat-key{display:flex;align-items:center;gap:6px}
.comstat-sw{width:12px;height:12px;border-radius:3px}
.comstat-sw-line{width:16px;height:4px;border-radius:2px;background:var(--orange);align-self:center}
.comstat-sw-revenue{flex:none;align-self:center}
.comstat-sw-past{background:var(--cyan)}
.comstat-sw-now{background:var(--orange)}
.comstat-sw-next{background:rgba(224,160,90,.42)}
.comstat-sw-half{background:repeating-linear-gradient(135deg,rgba(97,206,207,.75) 0 4px,rgba(97,206,207,.2) 4px 8px);
  box-shadow:inset 0 0 0 1px rgba(97,206,207,.6)}
.comstat-warn{background:var(--bg-card-hi);border-radius:10px;padding:13px 16px;margin-top:20px;
  border-left:3px solid var(--warn);font-size:12.5px;color:var(--grey);max-width:88ch}
.comstat-warn b{color:var(--warn);font-weight:700}

@media (max-width:600px){
  /* BLOC C.7 §3 — sur téléphone, les cartes passent en colonne unique : jamais un chiffre ou un
     libellé coupé/débordant (brief). */
  .comstat-kpis{grid-template-columns:1fr;gap:10px}
  .comstat-ctrl{gap:6px}
}

/* §4 — Zone édition (admin) : actions + éditeur Quill vendored (thème "snow") reskinné en sombre,
   cohérent avec le reste de l'app (le blanc natif jurait dans l'interface sombre) — icônes de
   la barre d'outils recolorées dans la charte (plus le bleu Quill natif). */
/* BLOC L.0 §5 — rappel discret des raccourcis Markdown, entre l'éditeur et les actions
   (Enregistrer/Aperçu) : jamais dans la barre d'outils, qui reste minimale (brief I.1 §2). */
.onboarding-editor-hint{margin:10px 0}
.onboarding-editor-hint code{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--grey);background:rgba(255,255,255,.06);padding:1px 5px;border-radius:4px}
.onboarding-editor-actions{display:flex;gap:10px;align-items:center;margin-bottom:12px;flex-wrap:wrap}
/* BLOC O.2 — classe partagée (l'id #onboardingQuillWrap reste pour le ciblage JS existant) :
   même reskin sombre pour tout éditeur riche créé via richTextEditor.js, y compris les contrats
   (contracts.js), jamais un second jeu de règles dupliqué par conteneur. */
.quill-wrap{background:var(--bg-card-hi);border-radius:10px;overflow:hidden;border:1px solid var(--line);max-width:100%;margin-bottom:18px}
.quill-wrap .ql-toolbar.ql-snow{border:none;border-bottom:1px solid var(--line);background:var(--bg-card)}
.quill-wrap .ql-container.ql-snow{border:none;min-height:220px;font-size:14px;background:var(--bg-card-hi)}
.quill-wrap .ql-editor{color:var(--white)}
.quill-wrap .ql-editor.ql-blank::before{color:var(--grey-dim);font-style:normal}
.quill-wrap .ql-snow .ql-stroke{stroke:var(--grey)}
.quill-wrap .ql-snow .ql-fill,.quill-wrap .ql-snow .ql-stroke.ql-fill{fill:var(--grey)}
.quill-wrap .ql-snow .ql-picker{color:var(--grey)}
#onboardingQuillWrap .ql-snow .ql-picker-options{background:var(--bg-card-hi);border-color:var(--line)}
#onboardingQuillWrap .ql-snow.ql-toolbar button:hover,
#onboardingQuillWrap .ql-snow .ql-picker-label:hover{color:var(--orange-bright)}
#onboardingQuillWrap .ql-snow.ql-toolbar button:hover .ql-stroke{stroke:var(--orange-bright)}
#onboardingQuillWrap .ql-snow.ql-toolbar button:hover .ql-fill{fill:var(--orange-bright)}
#onboardingQuillWrap .ql-snow.ql-toolbar button.ql-active,
#onboardingQuillWrap .ql-snow .ql-picker-label.ql-active,
#onboardingQuillWrap .ql-snow .ql-picker-item.ql-selected{color:var(--orange-bright)}
#onboardingQuillWrap .ql-snow.ql-toolbar button.ql-active .ql-stroke{stroke:var(--orange-bright)}
#onboardingQuillWrap .ql-snow.ql-toolbar button.ql-active .ql-fill{fill:var(--orange-bright)}
#onboardingQuillWrap .ql-snow .ql-tooltip{background:var(--bg-card-hi);border:1px solid var(--line);color:var(--white);box-shadow:0 6px 20px rgba(0,0,0,.4)}
#onboardingQuillWrap .ql-snow .ql-tooltip input[type=text]{background:var(--bg-card);color:var(--white);border:1px solid var(--line);border-radius:4px}
#onboardingQuillWrap .ql-snow .ql-tooltip a.ql-action,
#onboardingQuillWrap .ql-snow .ql-tooltip a.ql-remove{color:var(--orange-bright)}

/* §6 — responsive : bandeau/titres resserrés, largeur de lecture qui suit l'écran. */
@media (max-width:640px){
  .onboarding-header{padding:20px 18px}
  .onboarding-header-title{font-size:21px}
}

/* BLOC G.3 §6 — Paramètres d'une campagne : 3 sections nettement séparées (cibles économiques /
   leads réels / source CSV), chacune encadrée — jamais juste des <h4> qui se suivent. */
.campaign-settings-block{border:1px solid var(--line);border-radius:10px;padding:14px;margin-top:14px}
.campaign-settings-block:first-child{margin-top:0}
.campaign-settings-block .campaign-settings-subtitle{margin-top:0}

/* BLOC G.3 §7 — nombre de leads Meta visible sur la carte campagne, sans ouvrir l'onglet. */
.campaign-leads-badge{color:var(--grey-dim);font-size:12px}

/* BLOC G.4 §1 — alerte admin uniquement : source CSV avec des lignes en erreur de permission
   Meta (accès Business Manager à régulariser). */
.leads-permission-warning{color:var(--bad);background:rgba(232,106,92,.1);border:1px solid rgba(232,106,92,.35);
  border-radius:8px;padding:8px 10px;font-size:12.5px;margin-bottom:10px}

/* Échec du dernier import CSV — visible dans l'interface (client ET staff), pas seulement dans
   les journaux serveur (voir renderLeadsMainSummary / loadCampaignLeadsPanel, dashboard.js). */
.leads-import-error-banner{color:var(--bad);background:rgba(232,106,92,.1);border:1px solid rgba(232,106,92,.35);
  border-radius:8px;padding:8px 10px;font-size:12.5px;margin-bottom:10px}

/* BLOC G.3 §8 — groupes de la vue Leads agence (marques avec campagne active / avec des leads
   en base / le reste), séparés visuellement par un titre discret. */
.leads-portfolio-group-title{grid-column:1/-1;color:var(--grey-dim);font-size:12px;
  text-transform:uppercase;letter-spacing:.04em;margin:14px 0 4px}
.leads-portfolio-group-title:first-child{margin-top:0}

/* BLOC F — toasts (notifications éphémères, dashboard.js + settings.js, voir toast.js). Empilés
   en haut à droite, au-dessus de tout (y compris la boîte de dialogue de confirmation). */
.toast-container{position:fixed;top:16px;right:16px;z-index:300;display:flex;flex-direction:column;gap:8px;
  max-width:360px}
.toast{display:flex;align-items:flex-start;gap:8px;background:var(--bg-card-hi);border:1px solid var(--line);
  border-radius:10px;padding:11px 12px;font-size:13px;line-height:1.4;color:var(--white);cursor:pointer;
  box-shadow:0 6px 20px rgba(0,0,0,.35);animation:toast-in .18s ease-out}
.toast-msg{flex:1;white-space:pre-line}
.toast-close{flex:none;background:none;border:none;color:inherit;opacity:.6;font-size:16px;line-height:1;
  cursor:pointer;padding:0}
.toast-close:hover{opacity:1}
.toast-success{border-color:rgba(95,203,142,.4);background:rgba(95,203,142,.12)}
.toast-error{border-color:rgba(232,106,92,.45);background:rgba(232,106,92,.14)}
.toast-info{border-color:var(--line);background:var(--bg-card-hi)}
.toast-out{animation:toast-out .16s ease-in forwards}
@keyframes toast-in{from{opacity:0}to{opacity:1}}
@keyframes toast-out{from{opacity:1}to{opacity:0}}

/* BLOC F — boîte de dialogue maison remplaçant confirm() (voir confirmDialog.js). Même langage
   visuel que .modal-backdrop/.modal (fond assombri, panneau bg-card), classes séparées pour ne
   jamais interférer avec le modal de croissance de post déjà existant. */
.confirm-backdrop{position:fixed;inset:0;background:rgba(22,23,26,.7);display:flex;align-items:center;
  justify-content:center;padding:24px;z-index:250}
.confirm-dialog{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);
  padding:22px;max-width:420px;width:100%}
.confirm-title{font-weight:700;font-size:15px;margin-bottom:8px;font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif}
.confirm-message{font-size:13px;color:var(--grey);line-height:1.5}
.confirm-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:18px}
.confirm-actions button{margin-top:0}
.confirm-ok.confirm-destructive{background:var(--bad);color:var(--white)}

/* ===== Responsive mobile ===== BUG : ce bloc DOIT rester le DERNIER du fichier. Toutes les
   règles ci-dessus (.ctabs, .ctab, .modal-close, .campaign-expand-toggle...) sont déclarées
   sans media query PLUS LOIN que ne l'était un ancien bloc mobile placé au milieu du fichier —
   à spécificité égale, la règle la plus tardive dans le fichier gagne, donc un bloc mobile
   placé avant sa règle de base est silencieusement écrasé sur tous les écrans, y compris
   mobile. C'est ce qui s'est produit ici (onglets qui continuaient à s'enrouler sur 3 lignes
   malgré un `@media` qui semblait pourtant correct) : déplacé en fin de fichier, vérifié à
   375/390px. */
@media (max-width:640px){
  .admin-panel-actions{flex-direction:column;align-items:stretch}
  .admin-panel-actions button,.admin-panel-actions select{width:100%;min-height:44px}
  /* BUG responsive : le panneau admin (boutons + tableau) doit tenir dans les limites de sa
     carte sur petit écran — la carte elle-même ne pousse jamais la largeur de la page (voir
     .admin-panel-history overflow-x:auto plus haut pour le tableau). */
  .panel-toggle{padding:12px 12px;min-height:44px}
  .admin-panel-body{padding:12px 12px 12px}
  .admin-panel-actions{gap:6px}

  /* REFONTE : bloc collant compacté sur mobile — la cible n'est pas de sacrifier les zones
     tactiles (44px mini, cf. Apple HIG) mais de réduire tout le reste (marges, paddings
     verticaux) au strict minimum pour que le bloc collant (en-tête + nav principale + période +
     onglets) reste aussi bas que possible. #mainTabs est un AJOUT sur la pile déjà compactée
     lors du précédent correctif responsive — sa hauteur mobile (44px, pile la cible tactile,
     sans marge superflue) est comptée dans le nouvel offset .toolbar/.client-sticky ci-dessous. */
  .hwrap{padding:6px 14px;gap:8px}
  .logo{height:20px}
  .userchip-full{display:none}
  .userchip{gap:0}
  .userchip-avatar{display:inline-flex}
  /* Chip de collecte (BLOC B) : la phrase complète ("Dernière collecte : aujourd'hui 15:56 ·
     OK") forçait l'en-tête sur 3 lignes à 375px — version courte (dot + 1 mot), même discipline
     que userchip-full/userchip-avatar ci-dessus. */
  .collect-status-chip{padding:5px 8px;gap:4px}
  .collect-status-chip .full-label{display:none}
  .collect-status-chip .short-label{display:inline}
  /* #logout-btn/#settings-btn seulement : .linkbtn est réutilisée telle quelle par la
     pagination de la table posts (← Précédent / Suivant →), qui doit garder son texte. */
  #logout-btn{width:44px;height:44px;padding:0;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;flex:none}
  #logout-btn .btn-text{display:none}
  #logout-btn .btn-icon{display:inline;font-size:17px;line-height:1}
  .pager .linkbtn{min-height:44px}

  /* En-tête global compacté (6px + bouton 44px + 6px). #mainTabs compacté à 44px pile (zone
     tactile minimale, sans padding vertical superflu). Les barres collantes suivent seules :
     leurs décalages lisent les hauteurs mesurées (--sticky-top, base.css). */
  /* Bloc 0b-3b C1 — six onglets ne tiennent pas sur une ligne à 375 px (le dernier était coupé,
     les libellés débordaient de leur bouton) : grille de trois colonnes, deux rangées, chaque
     onglet entier et accessible (44 px de haut, zone tactile). La hauteur mesurée suit seule
     (--maintabs-h, layout-offsets.js). */
  .maintabs{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px;height:auto;padding:6px 0}
  .maintab{height:44px;font-size:12.5px;min-width:0;padding:0 4px;white-space:nowrap}

  .client-sticky{padding-top:4px}
  .client-header{gap:8px;margin-bottom:4px;align-items:center}
  .back{min-height:44px;padding:0 2px}
  .client-name{font-size:18px}
  .client-sticky .toolbar{margin-bottom:4px;padding:2px 0}
  #accueil > .toolbar{margin-bottom:8px;padding-top:8px}
  .chip{min-height:44px;padding:0 13px}

  /* Onglets : une seule ligne à défilement horizontal (jamais 3 lignes qui s'enroulent) — les
     séparateurs de groupe restent donc toujours au bon endroit, plus besoin de raccourcir le
     badge "aucune donnée". Barre de défilement masquée (purement esthétique, le défilement au
     doigt reste natif). */
  .ctabs{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;gap:3px;padding-bottom:4px}
  .ctabs::-webkit-scrollbar{display:none}
  .client-sticky .ctabs{padding-bottom:4px}
  .ctab{padding:0 8px;margin-right:6px;font-size:12.5px;min-height:44px;white-space:nowrap;flex:none}
  .ctab-sep{margin:0 2px;flex:none}
  .ctab-empty{white-space:nowrap}

  /* Filtres de l'onglet Campagnes : empilés verticalement plutôt que 3 selects côte à côte
     (auraient débordé ou été trop étroits pour leur texte à 375px). */
  .campaigns-filters{flex-direction:column}
  .campaigns-filters select{width:100%}

  /* BLOC O.4 — vue Commercial : le grand chiffre passe sous le texte plutôt que de comprimer une
     ligne déjà dense sur 375px. Vue Production : colonnes empilées, la grille de phases repasse
     à 2×2 (4 colonnes trop étroites pour "Version finale" à 375px, toujours sans retour à la
     ligne à l'intérieur d'une case — même garde-fou qu'en desktop). */
  .pcard-row{flex-direction:column;align-items:flex-start;gap:8px}
  .pcard-row-production{grid-template-columns:1fr;gap:10px}
  .pcard-row-commercial{grid-template-columns:1fr;gap:10px}
  .pcard-highlight,.pcard-highlight-sub,.pcard-col-highlight{text-align:left}
  .pcard-phase-grid{grid-template-columns:repeat(2,1fr)}

  /* Autres zones tactiles ≥44px sur mobile (posts, pagination, modale) */
  .pager button{min-height:44px;padding:0 10px}
  .modal-close{width:44px;height:44px}
  .campaign-expand-toggle{min-height:44px}
  #collectRelaunchBtn{min-height:44px;padding:0 12px}

  /* Page Paramètres : sections pleine largeur, champs empilés (le grid auto-fit desktop
     produirait des colonnes trop étroites pour leur label à 375px), boutons/inputs ≥44px. */
  .settings-section{padding:16px 14px}
  .settings-band-grid{grid-template-columns:1fr}
  .settings-band-grid input{min-height:44px}
  .settings-indicator-head{gap:8px}
  .settings-btn, .settings-btn-secondary, .settings-reset-btn{min-height:44px}
  .settings-list-remove{width:44px;height:44px}
  .settings-add-row{flex-direction:column}
  .settings-add-row input{min-height:44px}

  /* BLOC G.9 — leads en cartes empilées (brief : "bien plus utilisable qu'un tableau qu'on fait
     glisser"), CSS-only sur la structure de tableau existante (aucun changement de rendu JS à
     part les data-label posés dans renderLeadRow, dashboard.js) : chaque <tr> devient une carte,
     chaque <td> une ligne "libellé : valeur" via data-label + ::before, dans l'ordre du DOM
     (Date, Campagne, N°, Nom, Téléphone, E-mail, Réponses). Vaut pour le tableau principal
     (#leadsMainBody) ET le panneau par campagne (loadCampaignLeadsPanel, dashboard.js) — même
     classe .leads-table dans les deux cas, jamais deux styles à maintenir. */
  .leads-table{min-width:0}
  .leads-table thead{display:none}
  .leads-table,.leads-table tbody,.leads-table tr,.leads-table td{display:block;width:100%}
  .leads-table tr.lead-row{border:1px solid var(--line);border-radius:10px;padding:4px 14px;margin-bottom:10px;background:var(--bg-card-hi)}
  .leads-table tbody tr:nth-child(even){background:var(--bg-card-hi)} /* zébrage desktop neutralisé : chaque carte a déjà son propre fond */
  .leads-table td{padding:8px 0;border:none;border-top:1px solid var(--line)}
  .leads-table td:first-child{border-top:none}
  .leads-table td[data-label]::before{content:attr(data-label);display:block;font-size:10.5px;font-weight:700;
    text-transform:uppercase;letter-spacing:.03em;color:var(--grey-dim);margin-bottom:2px}
  .leads-table .lead-campaign-cell,.leads-table .leads-answers{max-width:none}
  .leads-table .lead-answer-cell,.leads-table .lead-note-cell{max-width:none;min-width:0}
  .lead-status-select{max-width:none;width:100%}
  .leads-search{max-width:none}
  .leads-campaign-btn{max-width:100%}
  .leads-multi-menu{max-width:calc(100vw - 32px)}
  .leads-table a[href^="tel:"],.leads-table a[href^="mailto:"]{color:var(--orange);text-decoration:none;word-break:break-all}

  /* BLOC G.10 §3 — "Derniers posts" : la date (moins essentielle que réseau/marque/vues) cède la
     place plutôt que de forcer un débordement horizontal ; la marque se resserre au lieu de
     pousser le texte hors de la ligne. */
  .recent-post-date{display:none}
  .recent-post-brand{max-width:70px}
  /* BLOC G.11 §2 — le libellé de performance reste affiché (accessibilité, jamais masqué), mais
     borné + tronqué comme les autres champs plutôt que de forcer un débordement. */
  .recent-post-perf-label{max-width:56px;overflow:hidden;text-overflow:ellipsis}
}

/* BLOC P.2 — frise temporelle Production (production-timeline.js). Grille CSS unique partagée
   par la règle et par chaque carte : --ptl-who (colonne marque) + N colonnes de semaine égales.
   ⚠️ color-mix() volontairement évité (compat navigateur) : chaque teinte de phase est une liste
   "r,g,b" (--c-rgb, posée en style inline par bloc) combinée à des rgba() explicites ci-dessous —
   jamais une couleur calculée à la volée. */
:root{
  --ptl-who:230px;
  /* BLOC P.5 §2 — rampe froide : le vert et le rouge sont réservés au statut de vérification
     (couleur ci-dessous), plus jamais utilisés par une phase (l'ancienne palette faisait
     apparaître la Version finale en vert, indistinguable d'un bloc validé). */
  --ptl-scen-rgb:143,108,232; --ptl-tour-rgb:90,134,234; --ptl-v1-rgb:58,169,224; --ptl-vf-rgb:47,201,214;
}
/* BLOC C.7 §8 — position:relative sert de repère à l'infobulle unique (.comstat-tip, composant
   partagé avec le graphique Commercial, voir hoverTip.js) : positionnée hors du flux, jamais
   clippée par le défilement horizontal de .ptl-body. */
.ptl{font-size:13px;position:relative}
/* BLOC P.6 pt.5 — bloc collant UNIQUE : couches + navigation + bandeau des mois + règle des
   semaines. La couche des couches (.ptl-layers) vivait hors de .ptl-head et défilait seule ;
   désormais les deux sont enveloppées dans .ptl-sticky, seul élément sticky de la frise (jamais
   .ptl-head en plus, deux sticky indépendants se chevaucheraient). Repose sur
   body{overflow-x:clip} (BLOC P.4) : ne pas y toucher.  */
.ptl-sticky{position:sticky;top:var(--sticky-top);z-index:20;background:var(--bg);padding-top:6px}
.ptl-head{background:var(--bg)}
.ptl-nav{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:10px}
/* §4 — ces trois classes sont les seules du module posées sur un <button> ; sans ces propriétés,
   l'élément garde son chrome natif (fond blanc, cadre gris) puisque style.css n'a aucun reset
   générique `button{}` (chaque composant de l'app stylise ses propres boutons). */
.ptl-arrow,.ptl-today,.ptl-wsz{font-family:'Instrument Sans',Arial,sans-serif;color:var(--grey);
  background:var(--bg-card);border:1px solid var(--line);border-radius:10px;padding:7px 12px;
  cursor:pointer;transition:color .15s,background .15s}
.ptl-arrow:hover,.ptl-today:hover,.ptl-wsz:hover{color:var(--text-2);background:var(--bg-card-hi)}
.ptl-arrow:focus-visible,.ptl-today:focus-visible,.ptl-wsz:focus-visible{outline:2px solid var(--orange);outline-offset:2px}
.ptl-arrow{font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;padding:6px 12px;font-size:15px}
.ptl-window{font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;font-size:14px;color:var(--white);min-width:170px;text-align:center}
.ptl-sep{width:1px;height:18px;background:var(--line);margin:0 2px}
.ptl-hint{font-size:12px;color:var(--grey-dim)}
.ptl-today,.ptl-wsz{font-size:12.5px}
.ptl-wsz[aria-pressed="true"]{color:var(--white);border-color:var(--orange);background:var(--bg-card-hi)}

/* BLOC P.5 §1 — barre de couches (Vérification Asana/Publication/Détail au jour/Trous de contrat),
   quatre cases à cocher, actives par défaut, état conservé d'une visite à l'autre (localStorage,
   voir production-timeline.js). */
.ptl-layers{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;background:var(--bg-card);
  border-radius:11px;padding:8px 14px}
.ptl-layers-lbl{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--grey-dim);margin-right:2px}
.ptl-layer{display:flex;align-items:center;gap:7px;font-family:'Instrument Sans',Arial,sans-serif;font-size:12.5px;
  color:var(--grey);cursor:pointer;padding:5px 11px;border-radius:9px;border:1px solid var(--line);
  background:transparent;user-select:none}
.ptl-layer:hover{color:var(--text-2);background:var(--bg-card-hi)}
.ptl-layer:focus-visible{outline:2px solid var(--orange);outline-offset:2px}
.ptl-layer .box{width:13px;height:13px;border-radius:4px;border:1.5px solid var(--grey-dim);position:relative;flex:0 0 auto}
.ptl-layer[aria-pressed="true"]{color:var(--white);background:var(--bg-card-hi)}
.ptl-layer[aria-pressed="true"] .box{background:var(--orange);border-color:var(--orange)}
.ptl-layer[aria-pressed="true"] .box::after{content:"";position:absolute;left:3.5px;top:1px;width:3px;height:7px;
  border:solid #231604;border-width:0 1.8px 1.8px 0;transform:rotate(42deg)}

.ptl-rail{background:var(--bg-soft);border-radius:12px 12px 0 0;overflow:hidden}
.ptl-mrow,.ptl-wrow{display:grid}
.ptl-mrow{height:22px;align-items:end}
.ptl-mcell{font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;font-size:10px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--grey-dim);padding:0 0 4px 9px;border-left:1px solid var(--line);white-space:nowrap;overflow:hidden}
.ptl-mcell.on{color:var(--orange)}
.ptl-wrow{border-top:1px solid var(--line);border-bottom:2px solid var(--line)}
.ptl-rlbl{padding:9px 0 8px 16px;font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--grey-dim);align-self:center}
.ptl-tick{padding:7px 2px;text-align:center;border-left:1px solid var(--line-soft);min-width:0}
.ptl-tick.ms{border-left:1px solid var(--line)}
.ptl-tick.now{background:rgba(224,160,90,.1)}
.ptl-tick b{display:block;font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;font-weight:500;font-size:12.5px;color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ptl-tick i{display:block;font-style:normal;font-size:10px;color:var(--grey-dim);white-space:nowrap;overflow:hidden}
.ptl-tick.now b{color:var(--orange)}
.ptl-tick.now i{color:var(--orange-bright)}

.ptl-body .clients-view-group-title{margin-top:26px}
.ptl-card{padding:0;overflow:hidden}
.ptl-cg{display:grid;row-gap:5px;padding:11px 0}
.ptl-who{grid-row:1/3;padding:0 16px;display:flex;flex-direction:column;justify-content:center;gap:1px;min-width:0}
.ptl-who b{font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;font-weight:600;font-size:14.5px;color:var(--white);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ptl-who span{font-size:11.5px;color:var(--grey-dim)}
/* Brief 01/10/2026 — motif du groupe sous le nom ; « en retard » porté par le mot ET la graisse. */
.ptl-who .ptl-why{color:var(--white)}
.ptl-who .ptl-why.late{font-weight:700}
.ptl-band{grid-row:1/3;border-left:1px solid var(--line-soft);height:100%}
.ptl-band.ms{border-left:1px solid var(--line)}
.ptl-band.now{background:rgba(224,160,90,.055)}

.ptl-ph{grid-row:1;margin:0 3px;border-radius:8px;padding:6px 8px 7px;position:relative;min-width:0;overflow:hidden;
  display:flex;flex-wrap:wrap;align-items:center;column-gap:4px;row-gap:2px;
  background:rgba(var(--c-rgb),.13);box-shadow:inset 0 0 0 1px rgba(var(--c-rgb),.26)}
.ptl-ph .ptl-k{flex:1 1 auto;min-width:0;font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;font-size:9px;letter-spacing:.09em;text-transform:uppercase;
  color:rgb(var(--c-rgb));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ptl-ph .ptl-dt{flex-basis:100%;font-size:11px;color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ptl-ph.is-done{background:rgba(var(--c-rgb),.07);box-shadow:inset 0 0 0 1px rgba(var(--c-rgb),.15)}
.ptl-ph.is-done .ptl-k{color:var(--grey-dim)}
.ptl-ph.is-done .ptl-dt{color:var(--grey-dim)}
.ptl-ph.is-live{background:rgba(var(--c-rgb),.24);box-shadow:inset 0 0 0 1.5px var(--orange)}
.ptl-ph.is-live .ptl-dt{color:var(--white);font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif}
.ptl-ph.clipL{border-top-left-radius:0;border-bottom-left-radius:0;margin-left:0}
.ptl-ph.clipR{border-top-right-radius:0;border-bottom-right-radius:0;margin-right:0}

/* BLOC P.5 §3 — vérification Asana posée SUR le bloc de phase, sans sous-ligne. Deux états
   seulement, la texture porte l'information (la couleur ne fait que la renforcer) : lisible en
   niveaux de gris, jamais un jaune/rouge indistinguable (Thomas). */
.ptl-vsym{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:14px;height:14px;
  border-radius:4px;font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;font-weight:600;font-size:11px;
  line-height:1;margin-right:5px}
.ptl-vmark{display:inline-flex;align-items:center;justify-content:center;font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;
  font-size:9px;letter-spacing:.05em;padding:1px 6px;border-radius:5px;background:rgba(255,255,255,.14);color:#fff;margin-left:5px}
.ptl-cnt{margin-left:auto;font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;font-size:10px;color:var(--grey-dim)}
/* Validé : plat, discret, liseré plein à gauche + coche, aucun libellé. */
.ptl-ph.v-ok{background:rgba(95,203,142,.16);box-shadow:inset 0 0 0 1px rgba(95,203,142,.5),inset 5px 0 0 var(--ok);padding-left:13px}
.ptl-ph.v-ok .ptl-k{color:var(--ok)}
.ptl-ph.v-ok .ptl-vsym{background:var(--ok);color:#0c2417}
.ptl-ph.v-ok .ptl-cnt{color:var(--ok)}
/* Manquant, encore actionnable : hachures diagonales + cerclage 3px + croix + le mot MANQUE —
   jamais un état masqué par un simple changement de teinte (lisible même sans percevoir le rouge). */
.ptl-ph.v-bad{background:repeating-linear-gradient(135deg,rgba(232,106,92,.5) 0 6px,rgba(232,106,92,.16) 6px 12px)!important;
  box-shadow:inset 0 0 0 3px var(--bad)!important}
.ptl-ph.v-bad .ptl-k,.ptl-ph.v-bad .ptl-dt{color:#fff!important}
.ptl-ph.v-bad .ptl-vsym{background:#fff;color:#16171a}
.ptl-ph.v-bad .ptl-cnt{color:#fff}
/* BLOC P.6 pt.1 — manquant mais passé (semaine de la phase écoulée) : mêmes hachures, très
   atténuées, bloc assombri — jamais de croix ni de mot MANQUE (plus rien d'actionnable). La nuance
   passe UNIQUEMENT par l'atténuation/l'assombrissement, jamais une teinte différente. */
.ptl-ph.v-bad-past{background:repeating-linear-gradient(135deg,rgba(232,106,92,.14) 0 6px,rgba(232,106,92,.04) 6px 12px)!important;
  box-shadow:inset 0 0 0 1px rgba(232,106,92,.18)!important;filter:brightness(.72)}
/* BLOC P.7 — vérification inconclusive (erreur d'appel Asana) : jamais un bloc nu ni la teinte
   d'un manque confirmé — l'ambre "à vérifier" est distinct des deux issues connues (v-ok/v-bad). */
.ptl-ph.v-unv{box-shadow:inset 0 0 0 1.5px var(--warn);outline:none}
.ptl-ph.v-unv .ptl-vsym{background:var(--warn);color:#3a2a05}
.ptl-ph.v-unv .ptl-cnt{color:var(--warn)}
/* BLOC S.2 §4 — validé avec réserve (échéance à 5 jours ou moins de la fenêtre attendue) :
   troisième état, jamais confondu avec v-ok (plein) ni v-unv (cerclage plein ambre) — cerclage
   POINTILLÉ, une forme distincte plutôt qu'une teinte de plus (brief : rouge/vert non
   distinguables par tous, Thomas). */
.ptl-ph.v-reserve{background:rgba(224,160,90,.16);box-shadow:none;outline:2px dashed var(--orange);outline-offset:-2px}
.ptl-ph.v-reserve .ptl-k{color:var(--orange-bright)}
.ptl-ph.v-reserve .ptl-vsym{background:var(--orange);color:#3a2405}
.ptl-ph.v-reserve .ptl-cnt{color:var(--orange-bright)}
/* §9 — les libellés de statut (MANQUE/agenda, compte 7/5) disparaissent en premier (~100px de
   colonne, seuil .ptl-dense), les hachures/cerclage/symboles restent visibles à toutes les tailles. */
.ptl-dense .ptl-vmark,.ptl-dense .ptl-cnt{display:none}

/* BLOC P.5 §5 — synthèse dans la colonne de gauche, sous le nom et le contrat. */
.ptl-who .ptl-check{display:inline-flex;align-items:center;font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;
  font-size:11.5px;padding:2px 8px;border-radius:7px;margin-top:4px;align-self:flex-start}
.ptl-who .ptl-check.ok{background:rgba(95,203,142,.18);color:var(--ok);font-weight:600;padding:1px 9px}
.ptl-who .ptl-check.bad{background:var(--bad);color:#fff;font-weight:600}
.ptl-who .ptl-check.unv{background:rgba(245,196,81,.18);color:var(--warn);font-weight:600}
.ptl-who .ptl-check.reserve{background:rgba(224,160,90,.18);color:var(--orange-bright);font-weight:600}
.ptl-who .ptl-check.n{color:var(--grey-dim);background:transparent;padding-left:0}

/* BLOC P.5 §7 — couche Détail au jour : sept cases par semaine, toutes les semaines/marques. */
.ptl-days{margin:0 3px;height:15px;display:flex;gap:1px}
.ptl-d{flex:1;border-radius:3px;background:rgba(255,255,255,.045);display:flex;align-items:center;justify-content:center;
  font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;font-size:8.5px;color:transparent;overflow:hidden;
  min-width:0;cursor:default}
.ptl-d.we{background:rgba(255,255,255,.02)}
.ptl-d.pub{background:var(--ok);color:#0c2417}
.ptl-d.sch{background:transparent;box-shadow:inset 0 0 0 1.2px var(--orange);color:var(--orange)}
.ptl-tiny .ptl-days{height:9px}
.ptl-tiny .ptl-d{font-size:0}

.ptl-prog{flex-basis:100%;height:2px;background:rgba(255,255,255,.1);border-radius:2px;margin-top:6px;overflow:hidden}
.ptl-prog i{display:block;height:100%;background:var(--orange)}
.ptl-badge{margin-top:5px;display:inline-block;font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;font-size:9px;
  letter-spacing:.05em;text-transform:uppercase;padding:2px 6px;border-radius:6px;white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.ptl-badge.mid{background:rgba(245,196,81,.15);color:var(--warn)}
.ptl-badge.end{background:rgba(232,106,92,.16);color:var(--bad)}
.ptl-badge.start{background:rgba(97,206,207,.14);color:var(--cyan)}

.ptl-pub{grid-row:2;margin:0 3px;height:18px;border-radius:5px;background:var(--orange);
  display:flex;align-items:center;padding:0 8px;font-family:'Space Grotesk','Instrument Sans',Arial,sans-serif;font-size:10px;
  color:#201504;white-space:nowrap;overflow:hidden}
.ptl-pub.clipL{border-top-left-radius:0;border-bottom-left-radius:0;margin-left:0}
.ptl-pub.clipR{border-top-right-radius:0;border-bottom-right-radius:0;margin-right:0}
.ptl-gap{grid-row:2;margin:0 3px;height:18px;border-radius:5px;display:flex;align-items:center;padding:0 8px;
  font-size:10px;color:var(--bad);white-space:nowrap;overflow:hidden;
  background:repeating-linear-gradient(135deg,rgba(232,106,92,.2) 0 5px,transparent 5px 10px);
  box-shadow:inset 0 0 0 1px rgba(232,106,92,.32)}
.ptl-gap.clipL{border-top-left-radius:0;border-bottom-left-radius:0;margin-left:0}
.ptl-gap.clipR{border-top-right-radius:0;border-bottom-right-radius:0;margin-right:0}
.ptl-empty{grid-row:1/3;grid-column:2/-1;font-size:12px;color:var(--grey-dim);display:flex;align-items:center;padding-left:12px}

/* §8 — dégradation mesurée sur la largeur réelle des colonnes (production-timeline.js,
   applyDensity) : sous ~96px/colonne les dates disparaissent, sous ~58px les libellés aussi. */
.ptl-dense .ptl-ph .ptl-dt,.ptl-dense .ptl-badge{display:none}
/* §5 — jamais un en-tête tronqué avec des points de suspension : sous le seuil intermédiaire, la
   plage de fin ("→ 16 août") disparaît d'abord ; sous le seuil le plus bas, le jour disparaît
   aussi et il ne reste que le bandeau des mois + le quadrillage vide. */
.ptl-dense .ptl-tick i{display:none}
.ptl-tiny .ptl-tick b{display:none}
.ptl-tiny .ptl-ph{padding:0;height:22px}
.ptl-tiny .ptl-ph .ptl-k,.ptl-tiny .ptl-ph .ptl-dt,.ptl-tiny .ptl-badge,.ptl-tiny .ptl-prog{display:none}
.ptl-tiny .ptl-pub,.ptl-tiny .ptl-gap{height:10px;font-size:0;padding:0}
.ptl-tiny .ptl-cg{row-gap:4px}

/* §11 — sous ~1000px, la règle disparaît et les cartes repassent en pile verticale datée. */
@media(max-width:1000px){
  .ptl-rail{display:none}
  .ptl-sticky{position:static}
  .ptl-cg{grid-template-columns:1fr!important;row-gap:7px;padding:12px}
  .ptl-who,.ptl-ph,.ptl-pub,.ptl-gap,.ptl-empty{grid-row:auto!important;grid-column:auto!important;margin:0}
  .ptl-band{display:none}
}

/* BLOC P.8 — largeur téléphone (<640px, classe posée par renderProductionTimeline sur mesure de
   largeur, jamais un second @media : c'est le seul moyen de couvrir ce comportement par un test
   DOM, jsdom n'évaluant aucun @media). Le bloc ci-dessus (tablette, <1000px) oubliait .ptl-days
   dans son reset ligne/colonne : cette case de grille gardait sa position de grille explicite
   (posée par dayCellsHtml), ce qui recréait des colonnes de grille implicites très étroites et
   écrasait toute la carte dedans (Thomas, iPhone : libellé de contrat éclaté mot par mot, libellés
   et dates de phase tronqués par l'ellipsis dans la colonne écrasée, barres Publication/trou de
   contrat qui débordent de leur carte). */
.ptl.ptl-mobile .ptl-who,
.ptl.ptl-mobile .ptl-ph,
.ptl.ptl-mobile .ptl-pub,
.ptl.ptl-mobile .ptl-gap,
.ptl.ptl-mobile .ptl-empty,
.ptl.ptl-mobile .ptl-days{grid-row:auto!important;grid-column:auto!important;margin:0}
.ptl.ptl-mobile .ptl-ph .ptl-k,
.ptl.ptl-mobile .ptl-ph .ptl-dt{white-space:normal;overflow:visible;text-overflow:clip}
.ptl.ptl-mobile .ptl-pub,
.ptl.ptl-mobile .ptl-gap{height:auto;white-space:normal;overflow:visible;padding:6px 8px}
.ptl.ptl-mobile .ptl-badge{white-space:normal;overflow:visible;text-overflow:clip;max-width:none}

/* ===== Lot 3 — fiche client (Clients → un client) ===== */
.client-fiche-summary{display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap;margin:10px 0 0}
.fiche-facts-line{display:flex;gap:18px;flex-wrap:wrap;font-size:13px;color:var(--text-2)}
.fiche-facts-line b{color:var(--white)}
.fiche-actions{display:flex;gap:8px;flex-wrap:wrap;align-items:flex-start}
.client-fiche-missing{margin-top:14px;border:1px solid rgba(245,196,81,.35);background:rgba(245,196,81,.06);border-radius:12px;padding:14px 16px}
.client-fiche-missing.fiche-missing-none{border-color:var(--line);background:var(--bg-card)}
.fiche-missing-title{margin:0 0 8px;font-size:13.5px;color:var(--warn);display:flex;align-items:center;gap:8px}
.fiche-missing-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.fiche-missing-list li{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;font-size:13.5px}
.fiche-missing-glyph{font-weight:800;color:var(--warn);margin-right:8px}
.fiche-ok-line{margin:10px 0 0;font-size:12.5px;color:var(--grey)}
.fiche-missing-none .fiche-ok-line{margin:0}
.fiche-ok-line b{color:var(--ok)}
.fiche-tab-count{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--warn);margin-left:6px}
.fiche-card{margin-bottom:14px}
.fiche-card-head{display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:8px}
.fiche-card-title{margin:0 0 6px;font-size:14px}
.fiche-card-head .fiche-card-title{margin:0}
.fiche-facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin:12px 0}
.fiche-facts dt{font-size:12px;color:var(--grey);font-weight:600}
.fiche-facts dd{margin:2px 0 0;word-break:break-word}
.fiche-yes{color:var(--ok);font-weight:700}
.fiche-no{color:var(--grey-dim)}
.fiche-fail{color:var(--bad);font-weight:700}
.fiche-pending{color:var(--text-2);font-style:italic}
.fiche-info-banner{border:1px solid rgba(97,206,207,.35);background:rgba(97,206,207,.06);border-radius:10px;padding:11px 14px;font-size:13px;color:var(--text-2)}
.fiche-info-banner span{font-weight:700;margin-right:6px}
.fiche-inline-form{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-top:10px}
.fiche-inline-form input{font-family:inherit;font-size:13px;color:var(--text-2);background:var(--bg-card-hi);border:1px solid var(--line);border-radius:8px;padding:7px 10px;min-width:0;flex:1 1 220px}
.fiche-inline-form input[type=date]{flex:0 1 170px}
.fiche-inline-form .settings-btn{margin-top:0}
/* Projets Frame.io : une ligne par projet, ID en chasse fixe, « Retirer » aligné à droite. */
.frameio-project-list{list-style:none;margin:10px 0 0;padding:0;border:1px solid var(--line);border-radius:10px}
.frameio-project{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 8px 8px 14px;border-top:1px solid var(--line)}
.frameio-project:first-child{border-top:0}
.frameio-project code{font-family:'IBM Plex Mono',monospace;font-size:13px;color:var(--text-2);overflow-wrap:anywhere;min-width:0}
/* Comptes Frame.io de l'agence : Enregistrer sous le champ ; « C'est l'agence » tient dans sa cellule. */
#frameioAgencyAccountsForm .settings-btn{margin-top:10px}
.frameio-agency-add{padding:5px 10px;font-size:12px}
.fiche-recipients-table{min-width:520px}
.fiche-link{white-space:nowrap;color:var(--orange-bright);text-decoration:underline;text-underline-offset:2px}
.fiche-link:hover{color:var(--white)}
@media(max-width:760px){.fiche-facts{grid-template-columns:minmax(0,1fr)}}

/* Brief 03/10/2026 — bilans mensuels (monthly-reports-tab.js, monthly-report-view.js,
   settings-monthly-reports.js). Avis = glyphe + mot, jamais la teinte seule. */
.ctab-badge{font-size:11px;font-weight:700;color:var(--bg);background:var(--orange);border-radius:8px;padding:1px 7px;margin-left:4px}
.mreport-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:12px 18px;margin:12px 0}
.mreport-toolbar select{font:inherit;background:var(--bg-card);color:var(--white);border:1px solid var(--line);border-radius:8px;padding:4px 8px}
.mreport-counts{display:flex;flex-wrap:wrap;gap:8px 14px}
.mreport-count,.mreport-advice{font-weight:600;white-space:nowrap}
.mreport-attention{margin:0;padding-left:18px;font-size:13px;color:var(--text-2)}
.mreport-list td{vertical-align:top}
.mreport-actions{white-space:nowrap}
.mreport-review-panel{display:flex;flex-direction:column;gap:14px;margin-top:12px}
.mreport-review-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 10px}
#monthlyReportNoteForm{display:flex;flex-direction:column;gap:6px}
#monthlyReportNoteForm textarea{font:inherit;background:var(--bg-card);color:var(--white);border:1px solid var(--line);border-radius:10px;padding:10px;resize:vertical}
.mreport-preview-title{margin:8px 0 0}
/* Finitions bilans (brief 03/10/2026) — mise en page validée : cartes, gros chiffres, barres
   chiffrées (la barre complète le chiffre écrit, jamais seule), étapes en cases. Les deux barres se
   distinguent par leur libellé ET leur remplissage (plein / hachuré), pas par la seule teinte. */
.mreport{display:flex;flex-direction:column;gap:14px;min-width:0}
.mreport-header h3{margin:0;font-size:20px}
.mreport-frozen{margin:4px 0 0;color:var(--grey);font-size:13px}
.mreport-card{background:var(--bg-card);border:1px solid var(--line);border-radius:var(--radius);padding:16px 18px;min-width:0}
.mreport-card-title{margin:0 0 8px;font-size:13px;font-weight:600;color:var(--text-2)}
.mreport-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:14px}
.mreport-big{margin:0;display:flex;align-items:baseline;flex-wrap:wrap;gap:6px}
.mreport-big-num{font-size:32px;font-weight:700;line-height:1.1;color:var(--white)}
.mreport-big-unit{font-size:14px;color:var(--text-2)}
.mreport-card-detail{list-style:none;margin:8px 0 0;padding:0;font-size:13px;color:var(--text-2);display:flex;flex-direction:column;gap:2px}
.mreport-muted{margin:0;color:var(--text-2)}
.mreport-bars{display:flex;flex-direction:column;gap:10px}
.mreport-bar-row{display:grid;grid-template-columns:minmax(110px,180px) 1fr auto;align-items:center;gap:10px}
.mreport-bar-label{font-size:13.5px;color:var(--text-2)}
.mreport-bar-track{height:12px;border-radius:6px;background:var(--bg-card-hi);overflow:hidden}
.mreport-bar-fill{display:block;height:100%;border-radius:6px}
.mreport-bar-row[data-bar="month"] .mreport-bar-fill{background:var(--orange)}
.mreport-bar-row[data-bar="habit"] .mreport-bar-fill{background:repeating-linear-gradient(135deg,var(--grey) 0 4px,transparent 4px 7px);border:1px solid var(--grey);box-sizing:border-box}
.mreport-bar-value{font-weight:700;white-space:nowrap}
.mreport-compare{margin:12px 0 4px;font-weight:600}
.mreport-best-text{margin:0 0 6px;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;color:var(--white)}
.mreport-best-meta{margin:0;color:var(--text-2);font-size:13.5px}
.mreport-best-judged{margin:8px 0 0;display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:13.5px}
.mreport-verdict{display:inline-flex;align-items:center;gap:4px;padding:2px 10px;border-radius:999px;border:1px solid var(--line-strong);background:var(--bg-card-hi);font-weight:600;white-space:nowrap}
.mreport-post-link{margin-top:12px}
.mreport-table-wrap{overflow-x:auto}
.mreport-steps{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px}
.mreport-step{border:1px solid var(--line-strong);border-radius:10px;padding:10px 12px;display:flex;flex-direction:column;gap:2px}
.mreport-step-label{font-weight:600}
.mreport-step-dates{font-size:13px;color:var(--text-2)}
.mreport-step[data-step="publication"]{border-style:dashed}
@media (max-width:640px){.mreport-bar-row{grid-template-columns:1fr auto}.mreport-bar-track{grid-column:1 / -1;grid-row:2}.mreport-big-num{font-size:28px}}
.mreport-table{border-collapse:collapse;width:100%;font-size:13.5px}
.mreport-table th,.mreport-table td{text-align:left;padding:6px 8px;border-top:1px solid var(--line)}
.mreport-note{font-size:12px;color:var(--grey)}
.mreport-note-text{margin:0;white-space:pre-wrap}
/* B2 — Paramètres → Bilans : le mois prend le style des autres champs, « Préparer maintenant »
   aligné sur le bas du champ, espace franc avant « Publication automatique ». */
.mreport-prepare-form{margin-top:22px;display:flex;flex-direction:column;gap:6px}
.mreport-prepare-row{grid-template-columns:minmax(160px,240px) auto;justify-content:start;align-items:end;gap:12px 16px}
.mreport-prepare-row .settings-btn-secondary{min-height:40px}
.mreport-auto-publish-title{margin-top:32px}
@media (max-width:640px){.mreport-prepare-row{grid-template-columns:1fr}.mreport-prepare-row .settings-btn-secondary{width:100%;min-height:44px}}
/* B2 — publication : actions de la relecture, message de confirmation, sélecteur « Autre mois » du portail. */
.mreport-publish-state{font-weight:600}
.mreport-client-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;margin:4px 0 14px}
.mreport-client-toolbar select{font:inherit;background:var(--bg-card);color:var(--white);border:1px solid var(--line);border-radius:8px;padding:6px 10px}
