/* ═══════════════════════════════════════════════════════════════════════════
   Arkensai · components.css · v2.34 · 2026-07-10
   ═══════════════════════════════════════════════════════════════════════════

   CHANGELOG
   ─────────
   v2.34 (2026-07-10) — Fix UX popover connecteurs MCP (4 remontées François)
   
     4 problèmes identifiés factuellement sur la popover Connecteurs
     (module mcp_connectors_v2.js) et corrigés dans un bloc dédié en fin
     de fichier (voir section "v2.34 UX FIXES"). Approche : overrides
     chirurgicaux plutôt que modifs inline des blocs v2.32/v2.33 →
     traçabilité + rollback trivial.
     
     BUG 1 — Popover débordait (texte "Activé pour ce chat" en 4 lignes
       verticales à droite).
       CAUSE FACTUELLE : .mcp-item était en `display: flex` SANS
       `flex-direction: column`. Les 2 enfants .mcp-item__row (width:100%)
       et .mcp-item__toggle-row étaient donc côte à côte horizontalement,
       le toggle-row débordait à droite. Le CSS .mcp-item__toggle-row a
       margin-top + border-top dashed qui PROUVE qu'il était pensé en
       dessous — juste le container qui avait été oublié en flex-direction
       column.
       FIX : override .mcp-item { flex-direction: column; align-items: stretch; }
     
     BUG 2 — Latence perçue 5s au clic (blanc + texte "Chargement…" plat).
       FIX côté JS (mcp_connectors v2.1 livré 10/07) : spinner SVG +
       preload au boot. Nouveaux styles ci-dessous pour animer le spinner.
       AJOUTS : .mcp-loading-state, .mcp-spinner__icon, @keyframes mcp-spin.
     
     BUG 3 — Toggle OFF invisible en mode sombre (fond du slider quasi
       identique au fond de la popover).
       CAUSE FACTUELLE : .mcp-toggle__slider utilisait var(--c-bg-muted)
       comme background. Or :
         - Dark : --c-bg-muted #181014 vs --c-bg #0F0809 → écart 9 pts RGB
         - Light : --c-bg-muted #F2EDE5 vs --c-bg #FAF7F5 → écart 8 pts RGB
       Contraste bien trop faible dans les 2 modes.
       FIX : override .mcp-toggle__slider { background: var(--c-line-strong); }
             → Dark : #3A2A2F vs #0F0809 → écart ~40 pts (visible)
             → Light : #D4C9B8 vs #FAF7F5 → écart ~35 pts (visible)
     
     BUG 4 — Texte "Activé pour ce chat" trop long.
       FIX côté JS (mcp_connectors v2.1) : "Actif pour ce chat" / "Pour ce chat".
       Aucune modif CSS requise.

   v2.33 (2026-07-08 — Sprint MCP-2) — Toggle "Activer pour ce chat" + bandeaux
     · .mcp-item__row              — nouvelle structure ligne principale
     · .mcp-item__tool-count       — badge "N tools" à côté du nom
     · .mcp-item__toggle-row       — ligne toggle en dessous de l'item
     · .mcp-toggle                 — switch (label + input + slider)
     · .mcp-toggle__slider         — piste + curseur du switch
     · .mcp-toggle__label          — texte "Activer pour ce chat"
     · .mcp-item.is-active         — bordure/halo accent quand toggle ON
     · .mcp-banner                 — bandeau info dans le popover
     · .mcp-banner--info           — bleu info (feature globale OFF)
     · .mcp-banner--warn           — orange warn (modèle sans tools)
   
   Toutes les couleurs utilisent les variables Arkensai (--c-bg-elevated,
   --c-fg, --c-line, --c-accent, --c-eco, --c-warn, --c-info).

   v2.32 (2026-07-08) — Styles connecteurs MCP (module mcp_connectors_v1.js)
     · .mcp-item                — item serveur MCP dans popover-mcp-list
     · .mcp-item__icon          — pastille icône emoji (48px)
     · .mcp-item__main          — nom + description
     · .mcp-item__status        — badge statut (connecté / non / non accessible)
     · .mcp-status--ok          — vert (var(--c-eco))
     · .mcp-status--off         — neutre (var(--c-fg-muted))
     · .mcp-status--disabled    — grisé (var(--c-fg-subtle))
   
   Utilise uniquement les vraies variables Arkensai (--c-bg-elevated,
   --c-fg, --c-line, --c-eco, --c-fg-muted, --c-fg-subtle, etc.).

   v2.30 (2026-07-08) — 🎨 FIX VISUEL DÉFINITIF modale "Mes agents"
     
     CONSTAT (François, capture 08/07 09:21 avec v2.28 déployée) :
       "Le fond est gris foncé comme la fenêtre agent.
        Ça ressemble à une surcouche de gris."
     
     DIAGNOSTIC FACTUEL FINAL
       v2.28 déployée utilisait factuellement des variables CSS INEXISTANTES :
         - background: var(--c-surface)  ← INEXISTANTE
         - border: 1px solid var(--c-border)  ← INEXISTANTE
       
       Rendu navigateur factuel :
         - var() non résolue → CSS fallback à `initial` (transparent)
         - Modale techniquement transparente → laisse voir le backdrop grisé
         - Résultat : sensation "surcouche grise" (backdrop visible à travers)
     
     FIX v2.30 — Combinaison de 2 corrections
     
     1. FIX VARIABLES (repris de v2.29 non déployée)
        Remplacement systématique des variables inexistantes par les vraies
        variables Arkensai (theme-arkensai.css) :
          var(--c-surface)        → var(--c-bg-elevated)  [#FFFFFF clair, #1A1014 sombre]
          var(--c-surface-hover)  → var(--c-bg-hover)
          var(--c-text)           → var(--c-fg)
          var(--c-text-muted)     → var(--c-fg-muted)
          var(--c-border)         → var(--c-line)
          var(--f-size-*)         → var(--fs-*)
          var(--f-family-mono)    → var(--f-mono)
          var(--radius-xs)        → var(--radius-sm)
     
     2. FIX VISUEL — Bordure d'accent rouge Arkensai (Option C validée François)
        La modale prend une bordure marquée avec la couleur d'accent Arkensai
        (rouge bordeaux #A11D2A clair / #E11D2E sombre) pour créer une
        séparation visuelle nette avec le backdrop, quel que soit le thème.
        
        Ajouts précis :
          .pa-modal-v1 :
            - border: 2px solid var(--c-accent)   [cadre rouge marqué]
            - box-shadow renforcée pour "détacher" la modale du fond
            - border-radius légèrement augmenté pour cohérence visuelle
        
        Résultat visuel attendu :
          - Thème clair : modale blanche cadre rouge sur backdrop grisé beige
          - Thème sombre : modale bordeaux foncé cadre rouge vif sur backdrop noir
     
     LEÇON MÉTHODOLOGIQUE CRITIQUE CAPITALISÉE DURABLEMENT
       Avant tout style CSS utilisant var(--*), TOUJOURS grep exhaustif de
       theme-arkensai.css + design-tokens.css pour identifier les VRAIS noms
       de variables. Ne JAMAIS deviner par convention.
       
       Convention Arkensai réelle (à retenir) :
       - Fonds  : --c-bg / --c-bg-elevated / --c-bg-muted / --c-bg-hover
       - Texte  : --c-fg / --c-fg-muted / --c-fg-subtle / --c-fg-on-accent
       - Lignes : --c-line / --c-line-strong
       - Accent : --c-accent / --c-accent-fg / --c-accent-soft / --c-accent-hover
       - Tailles: --fs-xs/sm/base/md/lg/xl/2xl/3xl (PAS --f-size-*)
       - Polices: --f-display / --f-sans / --f-mono (PAS --f-family-*)

   v2.29 (2026-07-08) — Fix variables CSS hallucinées (NON DÉPLOYÉE)
     
     CONSTAT (François, 2026-07-08 après test v2.28) :
       "L'affichage fenêtre toujours gris foncée comme le reste de l'écran."
     
     CAUSE FACTUELLE
       Mes styles .pa-modal-v1__* et .pa-popover-item__* (livrés v2.27) 
       utilisaient des variables CSS INEXISTANTES dans le design system 
       Arkensai (theme-arkensai.css) :
         - var(--c-surface)        → INEXISTANTE (vraie : --c-bg-elevated)
         - var(--c-surface-hover)  → INEXISTANTE (vraie : --c-bg-hover)
         - var(--c-text)           → INEXISTANTE (vraie : --c-fg)
         - var(--c-text-muted)     → INEXISTANTE (vraie : --c-fg-muted)
         - var(--c-border)         → INEXISTANTE (vraie : --c-line)
         - var(--c-accent-soft)    → OK (existe)
         - var(--c-danger)         → OK (existe)
         - var(--f-size-sm/xs/lg)  → INEXISTANTES (vraies : --fs-sm/xs/lg)
         - var(--f-family-mono)    → INEXISTANTE (vraie : --f-mono)
         - var(--radius-xs)        → INEXISTANTE (utiliser --radius-sm)
         - var(--sp-*)             → OK (existent)
         - var(--radius-sm/lg)     → OK (existent)
       
       Résultat visuel factuel : CSS fallback à `initial`/`inherit` →
       modale sans background défini → hérite du body → aucun contraste
       vs backdrop → sensation "gris foncée comme le reste".
     
     AUTO-CRITIQUE HONNÊTE
       Erreur d'hallucination CSS. J'ai supposé des noms de variables
       "classiques" (--c-surface, --c-text) au lieu de grep factuellement
       theme-arkensai.css AVANT d'écrire les styles.
     
     FIX v2.29 — Remplacement systématique par vraies variables Arkensai
       var(--c-surface)        → var(--c-bg-elevated)
       var(--c-surface-hover)  → var(--c-bg-hover)
       var(--c-text)           → var(--c-fg)
       var(--c-text-muted)     → var(--c-fg-muted)
       var(--c-border)         → var(--c-line)
       var(--f-size-sm)        → var(--fs-sm)
       var(--f-size-xs)        → var(--fs-xs)
       var(--f-size-lg)        → var(--fs-lg)
       var(--f-family-mono)    → var(--f-mono)
       var(--radius-xs)        → var(--radius-sm)
     
     LEÇON MÉTHODOLOGIQUE CAPITALISÉE DURABLEMENT
       Avant d'écrire des styles CSS utilisant var(--*), TOUJOURS grep
       exhaustif de theme-arkensai.css + design-tokens.css pour identifier
       les vrais noms de variables. Ne jamais deviner par "convention".

   v2.28 (2026-07-08 matin) — Fix visuel modale agents personnels v1
     · CONSTAT (capture François 08/07 09:09) :
       Le fond de la modale laissait voir le texte de l'app derrière
       (backdrop trop transparent en thème clair).
       La bottom bar restait partiellement visible sous la modale.
     
     · FIX v2.28 (partiel — n'a pas résolu le vrai problème car les
       variables CSS étaient hallucinées, voir v2.29)
       - .pa-modal-v1__overlay : backdrop rgba(0,0,0,.72) au lieu de .55
       - backdrop-filter: blur(8px) au lieu de 4px
       - Ajout backdrop-filter: -webkit-backdrop-filter pour Safari

   v2.27 (2026-07-07 soir) — Refonte agents personnels (Session 1)
     · Ajout des styles pour le module PersonalAgents (personal_agents_v1.js) :
         .pa-popover-item             — item enrichi du popover Perso
         .pa-popover-item__actions    — icônes ✏️/🗑 par item
         .pa-modal-v1__overlay        — nouvelle modale création/édition
         .pa-modal-v1                 — corps de modale, 1 colonne (Variante B)
         .pa-modal-v1__section        — bloc form (label + input/select)
         .pa-modal-v1__input/select/textarea
         .pa-modal-v1__status         — feedback validation
     · Ajouts en fin de fichier — aucune modification des styles existants.
     · Design tokens Arkensai : consomme uniquement var(--c-*), var(--sp-*),
       var(--f-*), var(--radius-*) — aucune couleur en dur.
     · Responsive : bottom sheet automatique sous 640px.
     · Les fixes v2.25 (.pa-modal-overlay.open) et v2.26 (.pa-form.open) sont
       PRÉSERVÉS pour la rétro-compat des pages qui utilisent encore l'ancien
       design (admin/prefs/usage/editorial). Nettoyage Session 2 backlog.

   v2.26 (2026-07-04) — 🔥 FIX clic "+ Créer un agent" ne s'affiche pas
     · MOTIVATION (François, 2026-07-04) :
       "Lorsque je clique sur créer mes agents, rien ne se passe (bis)"
       → Après le fix v2.25 sur .pa-modal-overlay, la modal s'ouvrait bien,
         mais le clic sur "+ Créer un agent" DANS la modal ne faisait rien.
     
     · CAUSE FACTUELLE
       Bug structurel IDENTIQUE à celui de v2.25, sur un autre élément :
         - core.js openPaForm() fait form.classList.add('open')
         - components.css v2.22-v2.25 : .pa-form.visible { display: block }
         - style_platform_v1.css legacy : .pa-form.open { display: block }
       
       → Le formulaire recevait bien la classe .open côté DOM, mais le CSS
         Arkensai attendait .visible → display: none persistait.
       
       Audit CSS/JS croisé effectué en v2.26 :
         · .pa-modal-overlay : JS='.open', CSS v2.25=.open + .visible ✅
         · .pa-form          : JS='.open', CSS v2.25=.visible ❌ → FIX v2.26
         · .pa-docs-panel    : JS='style.display=block' (pas de classe) — OK
         · .sidebar          : JS='.open', CSS ancien confirmé — OK
     
     · FIX v2.26 — Support des 2 classes (.open ET .visible) sur .pa-form
       Ajout de .pa-form.open { display: block } en cohérence avec le JS.
       .visible conservée pour rétro-compat.
     
     · IMPACT UX
       Clic sur "+ Créer un agent" (dans modal "Mes agents personnels")
       ouvre correctement le formulaire de création. User peut enfin
       créer son premier agent personnel.
     
     · BACKWARD COMPAT : totale — ajout PUR d'une règle CSS.
     
     · BACKLOG UX (François, 2026-07-04)
       "C'est assez redondant : cliquer pour ajouter des agents, puis
        tomber sur cette nouvelle fenêtre pour créer un agent."
       → À traiter en Phase UX v2.27+ :
         Option 1 : Skip popover si aucun agent → clic ouvre directement la modal
         Option 2 : Modal ouvre directement le formulaire si liste vide
         Option 3 : Fusion popover + modal (design unifié)
         Décision à cadrer avant refactor.

   v2.25 (2026-07-03) — 🔥 FIX modal "Gérer mes agents" ne s'affiche pas
     · MOTIVATION (François, 2026-07-03) :
       "Lorsque je clique sur créer mes agents, rien ne se passe."
     
     · CAUSE FACTUELLE
       Divergence historique entre le JS et le CSS :
         - core.js (openProfileModal) fait overlay.classList.add('open')
         - components.css v2.22-v2.24 : .pa-modal-overlay.visible { display: flex }
         - style_platform_v1.css legacy : .pa-modal-overlay.open { display: flex }
       
       → La modal recevait bien la classe .open côté DOM (visible dans
         DevTools), mais le CSS Arkensai n'avait pas de règle pour .open
         → display: none persistait malgré le clic.
       
       Ce bug existait depuis la migration vers le design system Arkensai
       (retrait de style_platform_v1.css). N'a été détecté que maintenant
       car la feature "agents personnels" n'était pas activée en prod ab2c
       avant le 2026-07-03.
     
     · FIX v2.25 — Support des 2 classes (.open ET .visible)
       Ajout de .pa-modal-overlay.open { display: flex } en cohérence
       avec le JS existant.
       .visible conservée pour rétro-compat éventuelle (ne casse rien).
     
     · IMPACT UX
       Clic sur "Gérer mes agents" (popover personal) ouvre correctement
       la modal → user peut cliquer "+ Créer un agent" → formulaire actif.
     
     · BACKWARD COMPAT : totale — ajout PUR d'une règle CSS.

   v2.24 (2026-07-03) — 🔥 FIX RÉEL débordement composer (le patch v2.23 était
                           insuffisant)
     · MOTIVATION : après déploiement de v2.23, François confirme que le
       bouton Envoyer reste caché quand un long nom de collection RAG est
       sélectionné. Le patch v2.23 ciblait .entry-btn__indicator avec
       max-width + flex-shrink:1, mais SANS EFFET.
     · CAUSE FACTUELLE RÉELLE identifiée :
         .composer__bar > * { flex-shrink: 0; }  (ligne ~1863)
       impose flex-shrink: 0 à TOUS les enfants directs de .composer__bar,
       dont .entry-btn. Résultat : .entry-btn garde sa taille intrinsèque
       (incluant l'indicator interne à max-width: 120px, mais rien
       n'empêche le bouton entier de prendre 200px+).
       Combiné avec .composer__bar { overflow-x: auto; scrollbar-width: none; },
       le débordement se produit MAIS reste invisible (pas de scrollbar).
       Le bouton Envoyer est physiquement présent mais hors du viewport.
     · FIX RÉEL v2.24 :
       1. Override flex-shrink: 1 sur .entry-btn.has-selection ciblé
          (uniquement quand un indicator est présent — quand le bouton
          affiche juste "Documents" sans nom de collection, il garde
          sa taille naturelle).
       2. Ajout min-width: 0 pour permettre le rétrécissement flex.
       3. .entry-btn__label reste white-space: nowrap (jamais wrap).
       4. .entry-btn__indicator garde max-width mais devient plus
          agressif (80px au lieu de 120px) sur les tailles moyennes.
       5. Nouveau : media query intermédiaire @media (max-width: 1200px)
          qui réduit encore l'indicator à 60px.

   v2.23 (2026-07-03) — Fix débordement composer + feedback micro + bloc RSE image
     · MOTIVATION 1 : capture François 2026-07-03 — sur le bouton
       Documents, le nom du répertoire sélectionné (via .entry-btn__indicator)
       s'étend sans limite → sur écran étroit desktop (mais >900px, donc
       hors media mobile qui masque déjà l'indicator), la barre composer
       déborde et le bouton Envoyer sort du viewport.
     · FIX 1 : ajout de max-width: 120px + overflow: hidden + text-overflow: ellipsis
       + flex-shrink: 1 + min-width: 0 sur .entry-btn__indicator (bloc ligne
       2631 de v2.22). La media query mobile (ligne 3482) reste inchangée
       car l'indicator est déjà masqué en display:none à ≤900px.

     · MOTIVATION 2 : refonte module voice (core_v46_0.js) — feedback
       visuel actif du micro pendant l'enregistrement (Web Speech local
       ou fallback Vertex cloud). L'ancien CSS .btn-mic.recording n'était
       pas appliqué au nouveau design system .composer__tool.
     · FIX 2 : nouvelles classes .composer__tool--recording (rouge foncé
       + waveform SVG animé en ::before) et .composer__tool--transcribing
       (opacité + spinner). Animation composer-tool-pulse + waveform-bars.
       Support mode dark via @media prefers-color-scheme + [data-theme="dark"].
       Rétro-compat classe .recording historique préservée.

     · MOTIVATION 3 : bloc impact RSE sous les images (ui_v1_9.js) —
       CO2 + énergie + eau + équivalence km voiture, comme pour les
       bulles text. Nécessite le style .output-card__impact et
       .impact-main / .impact-sep / .impact-equiv (déjà présents pour
       .msg__impact, réutilisables tels quels).
     · FIX 3 : ajout de .output-card__impact avec padding + border-top
       + margin-top pour séparer visuellement de l'image. Les enfants
       (.impact-metric, .impact-sep, .impact-equiv) héritent des styles
       existants sans changement.

   v2.22 (2026-06-30) — Impact RSE avec icônes signature + couleurs seuils
     · Nouveau bloc .impact-metric (et sous-éléments __icon / __value)
       remplaçant l'ancien .impact-value sur la ligne d'impact RSE.
     · Icônes Lucide à gauche de chaque valeur : leaf (CO₂), zap (énergie),
       droplet (eau). Couleur SIGNATURE STABLE (vert/jaune/bleu) — l'icône
       garde toujours la même couleur, c'est un repère visuel constant.
     · Valeur colorée selon SEUIL (low/mid/high) :
         - low  → vert eco
         - mid  → gris muted (neutre)
         - high → rouge + bold (alerte)
       Seuils dans ui_v1.js _rseLevelClass().
     · L'ancien .impact-value et ses variants restent en place pour
       rétrocompatibilité (ex : bandeau meta image output-card).

   v2.21 (2026-06-30) — Étape 2a UI RSE : pastilles région dynamiques
     · Nouveaux variants .region-pill--low/mid/high/critical : couleur
       de fond et bordure basées sur l'intensité carbone du mix
       électrique régional (lu depuis _REGION_DATA en JS).
         - low      (< 100 g/kWh)  → vert  eco
         - mid      (100-250)      → ambre clair
         - high     (250-400)      → orange
         - critical (> 400)        → rouge
     · Nouveau .region-pill--pending : variante placeholder discrète
       (dashed + italique + opacity réduite) affichée pendant la
       résolution région (entre l'envoi du prompt et l'arrivée du META).
     · Nouveau .impact-value--secondary : style pour les valeurs
       énergie (Wh) et eau (mL) dans .msg__impact détaillé. Couleur
       muted, taille légèrement réduite, marqueur ::before plus petit.
     · Nouveau .impact-sep : séparateur "·" entre les 3 valeurs RSE
       dans .impact-main.

   v2.20 (2026-06-27) — Bouton 🌿 RSE : vert + mobile only

   RÔLE
   ────
   Définit les styles de TOUS les composants UI de la plateforme.
   Consomme uniquement les variables CSS définies dans :
     - design-tokens.css     (tokens abstraits)
     - theme-arkensai.css    (ou theme-client-<name>.css)

   ⚠️ AUCUNE COULEUR EN DUR DANS CE FICHIER.
   Tout passe par var(--c-*), var(--f-*), var(--sp-*), etc.
   Si une couleur ne correspond à aucun token, c'est un signe qu'il faut
   en créer un nouveau dans design-tokens + theme-arkensai.

   STRUCTURE
   ─────────
    1. RESET & BASE
    2. SCREENS (login, change-password)
    3. APP CONTAINER
    4. HEADER
    5. SIDEBAR + OVERLAY
    6. USER DROPDOWN
    7. EMPTY STATE
    8. THREAD (chat history)
    9. MESSAGES (user + assistant + meta + impact RSE)
   10. COMPOSER
   11. PANNEAU OUTILS & MCP
   12. MODAL AGENTS PERSONNELS (compat legacy)
   13. UTILITAIRES & ICÔNES
   14. RESPONSIVE

   CHANGELOG
   ─────────
   v2.20 (2026-06-27) — Bouton 🌿 RSE : vert + mobile only
     · #rse-toggle-btn : display:none par défaut (desktop), visible
       uniquement en ≤ 1100px où le panneau RSE est masqué.
     · Couleur de la feuille : var(--c-eco) au lieu de var(--c-fg-muted).
       Cohérence avec le hero CO₂e du panneau RSE qui utilise déjà --c-eco.
     · Hover : background vert très clair pour rester dans le thème.

   v2.19 (2026-06-27) — Fix tronquage greeting sur mobile
     · .empty-state utilisait `justify-content: center` + `overflow-y: auto`.
       Sur mobile, quand le contenu (greeting + lede + 6 cards) dépasse la
       hauteur visible, le centrage faisait sortir le haut par le viewport
       → "Bonjour [prénom]" tronqué.
     · Fix : sur ≤ 640px, `justify-content: flex-start` + padding-top
       qui respecte env(safe-area-inset-top) pour la notch iOS.

   v2.18 (2026-06-27) — Bloc stats RSE Option C + mode bottom sheet mobile
     · Nouveaux styles .rse-panel__stats--c, .rse-stat-c, .rse-stat-c__value
       (Fraunces italique 26px), .rse-stat-c__label (mono uppercase),
       .rse-stats-c__divider (dashed), .rse-stat-c--accent (rouge).
     · Ancien .rse-panel__stats / .rse-stat conservés pour compat.
     · Mode "bottom sheet" mobile pour le panneau RSE :
       .rse-panel.is-open-mobile (override le display:none du breakpoint
       1100px). position:fixed bottom + animation slide-up + respect du
       safe-area-inset-bottom (iOS / Android).
     · .rse-sheet-backdrop : overlay sombre dismissable (animation fade-in).

   v2.17 (2026-06-26) — Image générée : responsive mobile + bandeau meta
     · #output-media img : ajout height:auto + display:block. La résolution
       NATIVE de l'image (en base64 dans src) reste préservée pour la
       copie / téléchargement ; seule la taille AFFICHÉE est réduite.
       L'image rentre maintenant entièrement dans l'écran mobile.
     · Nouveau style .output-card__meta : bandeau meta similaire à
       .msg__meta-detailed des bulles texte, inséré par script_v43 (v45.1)
       en haut de l'output-card quand une image est générée. Affiche
       modèle + région + durée + placeholders tokens/€/CO2 (en attendant
       le câblage backend Livraison 3).

   v2.16 (2026-06-26) — Bouton "Outils" mobile
     · Styles .mobile-mode-btn : bouton compact icône + label + chevron,
       background muted, accent au survol/actif. Caché par défaut (desktop),
       affiché en mobile via media query.
     · Media query ≤640px revue : les 6 .entry-btn sont CACHÉS, le
       .mobile-mode-btn est AFFICHÉ. Gaps/paddings de la barre restaurés
       à valeurs normales (plus besoin de compresser).
     · Annulation des optimisations extrêmes de v2.15 (gap 3px, padding 4px,
       dividers cachés). Avec un seul bouton mode, il y a largement la place
       pour des paddings ergonomiques.

   v2.15 (2026-06-26) — Fix barre Android + clavier (100dvh)
     · Cause RÉELLE du bug "le bas de la page est caché derrière la barre
       Android ET derrière le clavier virtuel" :
       #app-content utilisait height:100vh, qui correspond à la hauteur
       TOTALE du viewport (incluant la zone réservée à la barre Android
       et la zone que le clavier va recouvrir). Donc tout ce qui était en
       bas du composer était rendu sous ces zones, inaccessible.
     · Fix : utilisation de 100dvh (Dynamic Viewport Height) qui exclut
       automatiquement la barre Android et se réduit quand le clavier
       virtuel apparaît. Le contenu remonte tout seul.
     · Bonus : popovers desktop (85vh→85dvh) et bottom sheets mobile
       (70vh→70dvh) bénéficient du même fix.
     · Fallback 100vh conservé pour les très vieux navigateurs (<2022).

     · BUG SECONDAIRE découvert après le fix dvh : la barre composer
       débordait à droite sur très petit écran (~64px de trop sur 400px),
       cachant Connecteurs + bouton envoyer.
     · Optimisations mobile ≤640px supplémentaires :
         - gap composer__bar : 6px → 3px (-33px)
         - padding composer__bar : 8px → 4px (-8px)
         - dividers .composer__divider : cachés (-18px)
       Total gain : ~59px. La barre rentre maintenant dans 400px avec
       25px de marge.

   v2.14 (2026-06-26) — flex-wrap:nowrap composer__bar
     · Le bottom sheet popover ET le composer étaient masqués par la barre
       de navigation système Android (3 icônes du bas, ~48px) ou la home
       indicator iOS. Sur la capture utilisateur : la ligne avec
       "Connecteurs" + bouton envoyer était invisible.
     · Fix : utilisation de env(safe-area-inset-bottom) pour respecter
       automatiquement la safe area du device (variable CSS standard
       fournie par les navigateurs mobiles).
         - .popover (mobile) : bottom + padding-bottom = safe-area-inset-bottom
         - .composer-wrap    : padding-bottom += safe-area-inset-bottom
     · Prérequis : meta viewport contient viewport-fit=cover (déjà OK
       dans index v9.12).

   v2.12 (2026-06-26) — Mode icône progressif
     · Annulation totale des tentatives v2.9 (position absolute) et v2.10
       (zone scrollable) — toutes deux insuffisantes.
     · Approche correcte : la barre composer est un simple flex container.
       Quand la fenêtre se réduit, des media queries cachent progressivement
       les labels textuels (mais GARDENT les icônes) :
         - ≤ 1024px : entry-btn passent en icône seule (Conv, Image, Agent,
                      Docs, Mes ag., Connect.)
         - ≤  640px : label du modèle aussi caché
     · Résultat : TOUS les 6 entry-btn restent accessibles quelle que soit
       la largeur de la fenêtre. Le bouton envoyer reste à droite, jamais
       superposé (poussé par le spacer flex:1).
     · Validé visuellement via test-composer-v2.html.

   v2.11 (2026-06-26) — Tentative sélecteur flex-shrink (ANNULÉE en v2.12)
   v2.10 (2026-06-26) — Tentative restructuration 2 zones (ANNULÉE en v2.12)
   v2.9  (2026-06-26) — Tentative position absolute (ANNULÉE en v2.12)
   v2.8  (2026-06-26) — Fix espace vide entre thread et panneau RSE
     · .btn-send : position:absolute + right:var(--sp-2). Sort du flow de
       la barre composer pour rester collé à droite QUEL QUE SOIT le scroll
       horizontal de la barre. Toujours visible, même sur fenêtre étroite.
     · .composer__bar : padding-right:52px pour réserver l'espace du
       bouton envoyer (zone scrollable s'arrête juste avant). Pas de
       superposition possible avec le dernier entry-btn.
     · .composer-wrap et .app-main : min-width:0 ajouté pour autoriser la
       compression en width. Sans ça, la largeur intrinsèque de la barre
       composer (modèle + 6 entry-btn + outils ~1020px) imposait une
       largeur minimale à la fenêtre du navigateur.
     · Résultat : la fenêtre peut maintenant être réduite jusqu'à très
       étroite. Les entry-btn disparaissent progressivement à droite
       (overflow-x:auto silencieux), le bouton envoyer reste pour soumettre.

   v2.8 (2026-06-26) — Fix espace vide entre thread et panneau RSE
     · Suppression du padding-right inutile sur #app-content. Le panneau RSE
       étant en position:fixed, il ne prend pas de place dans le flux normal.
       Le padding-right créait un espace vide visible entre le scrollbar du
       thread et le panneau RSE (cf. capture utilisateur).
     · Thread + composer (max-width 1100px chacun) sont maintenant centrés
       sur toute la largeur de la fenêtre. Le panneau RSE flotte à droite
       en superposition, sans toucher au layout.
     · Media query 1100px simplifié (plus de padding à neutraliser).

   v2.7 (2026-06-26) — Fix bouton envoyer perdu en fenêtre réduite
     · .composer__bar-spacer : flex:1 1 0 → flex:0 0 auto + width:0.
     · Conséquence : le bouton envoyer ne se positionne plus à l'extrême
       droite du composer, mais se colle DIRECTEMENT aux 6 entry-btn.
     · Résultat : en réduisant la fenêtre, le bouton envoyer reste
       collé à son groupe et ne sort plus de la zone visible.

   v2.6 (2026-06-26) — Pas de changement CSS, juste suivi de version
     · Aligné avec design-tokens v1.3 (thread + composer à 1100px) et
       index v9.10 (6ème entry-btn "Image"). Aucun style nouveau requis :
       le nouveau bouton hérite des styles .entry-btn existants.

   v2.5 (2026-06-26) — Alignement composer / thread à 880px (annulé en v2.6)
     · La vraie cause : --composer-max était à 880px (= --thread-max), ce qui
       limitait inutilement la largeur du composer alors que les côtés sont
       largement disponibles. Dissociation faite dans design-tokens v1.1 :
       --thread-max reste 880px (lecture), --composer-max passe à 1100px.
     · .entry-btn : revenu à padding 6px 10px / gap 6px / font 12.5px
       (plus besoin de les compresser maintenant qu'on a 220px en plus).
     · Tous les autres fix v2.3 conservés (flex-shrink, spacer compressible,
       overflow-x silencieux) comme filet de sécurité.
     · Marge réelle après fix : ~156px sur grand écran. Confortable.

   v2.3 (2026-06-26) — Fix cadrage composer (tentative incomplète)
     · .composer__bar : overflow-x:auto + scrollbar masquée (filet de sécurité
       si la barre déborde). Gap réduit 8→6px.
     · Tous les enfants de .composer__bar (.composer__model, .composer__tool,
       .entry-btn, .composer__divider, .btn-send) protégés par flex-shrink:0
       pour que rien ne soit jamais écrasé.
     · .entry-btn : padding 6px 10px → 5px 8px, gap 6→5px, font-size 12.5→12px.
       Gagne ~30-40px sur les 5 entry-btn = la barre rentre dans 880px.
     · .composer__bar-spacer : flex:1 → flex:1 1 0 + min-width:0. Le spacer
       peut désormais se compresser à 0 si la barre dépasse, ce qui maintient
       le bouton submit À L'INTÉRIEUR du composer (cause principale du bug
       sur la capture où le bouton envoyer sortait du carré du composer).

   v2.2 (2026-06-26) — Livraison 2f : popover modèle Auto/Manuel
     · Bouton .composer__model :
         - max-width réduit 280→200px pour ne plus être tronqué.
         - flex-shrink:0 + cursor:pointer + border transparent (qui devient
           accent au hover/active).
         - .is-auto : style info bleu (mode routeur intelligent visible).
     · .composer__model-hint masqué par défaut (n'apparaît plus dans la barre).
     · .popover--model : variante popover 380px de large (vs 360 par défaut).
     · .popover-model__mode : grid 1fr 1fr pour les 2 tabs Auto/Manuel.
     · .mode-tab : tab cliquable avec title (Fraunces italique) + hint (mono).
                   État .is-active = fond accent-soft + border accent.
     · .popover-model__auto-info : pavé encart vertical avec border-left
                                   accent, icône + texte explicatif.

   v2.1 (2026-06-26) — Livraison 2e : entry-btn Conversation
     · Ajout .entry-btn.is-current : surbrillance subtile du bouton
       correspondant au mode courant (background muted + border line-strong
       + icône en accent). Combiné avec .is-active : priorité à l'accent.
     · Ajout .entry-btn.is-disabled : opacity 0.4 + cursor not-allowed +
       neutralisation du hover. Garde pointer-events:auto pour que le
       tooltip explicatif reste accessible au survol.

   v2.0 (2026-06-26) — Livraison 2d : Panneau RSE Stratégie 4
     · Nouvelle section 13.5 dédiée au panneau RSE :
         - .rse-panel : position fixed à droite, centré verticalement,
                        max-height contrainte, scroll interne discret.
         - .rse-panel__header / __collapse-btn : titre Fraunces italique
                        + bouton chevron-right pour replier.
         - .rse-hero : grand chiffre 52px Fraunces italique vert eco
                       + unité "g CO₂e" en sans + label mono uppercase.
         - .rse-hero__num em.is-pulsing : animation @keyframes rse-pulse
                       (vert → rouge accent → vert, 0.6s) sur incrément.
         - .rse-equiv-list : 3 équivalences avec icône ronde verte
                       (voiture, douche, arbre).
         - .rse-panel__stats : grille 2x2 stats compactes (Conv./Jour).
         - .rse-mini-pill : pill verticale (56px) avec chiffre + unité
                       + flèche chevron-left, visible en état replié.
     · body.has-rse-panel #app-content : padding-right dynamique 264px
                       (déployé) → 80px (replié) avec transition 0.25s.
     · @media max-width:1100px : masque le panneau et retire le padding.
     · Variables CSS : --rse-panel-w (240), --rse-panel-w-mini (56),
                       --rse-panel-margin (12).

   v1.9 (2026-06-26) — Livraison 2c : cumuls 3 niveaux
     · Nouveau bloc .composer__cumuls remplaçant l'ancien .composer__session.
     · .cumul-line : ligne stats horizontale avec label en mono uppercase.
     · .cumul-conversation : niveau 2 (session courante), label en accent rouge.
     · .cumul-day : niveau 3 (jour), label en gris muted.
     · .stat-placeholder : style italique discret pour valeurs €/CO₂e
                          en attente du câblage backend.
     · .composer__attribution-line : ligne dédiée pour "Propulsé par Arkensai"
                                     alignée à droite, sous les cumuls.
     · .meta-real : style pour les valeurs tokens patchées (vs placeholders)
                    dans la meta-detailed des bulles assistant.

   v1.8 (2026-06-26) — Livraison 2b : metadata RSE + fix bouton envoyer
     · Fix critique : .btn-send avait perdu sa taille à cause d'un flex
       parent qui le compressait quand les entry points avaient un label
       de sélection long ("Expert Technique" par ex.). Ajout de
       flex-shrink:0 + min-width:36px sur .btn-send, .composer__tool, .entry-btn.
     · Refonte des styles meta-detailed/impact/actions :
         - .msg__meta-detailed : border-bottom au lieu de margin (séparateur
           plus visible avec le texte de réponse).
         - .meta-web : badge bleu compact avec icône globe pour signaler
           qu'une recherche web a été utilisée.
         - .meta-placeholder : style discret italique pour les valeurs pas
           encore câblées (tokens, coût, CO₂e) avec opacity 0.6 + tooltip
           explicatif. Disparaîtra automatiquement quand backend câblera.
         - .region-pill : icône drapeau Lucide à gauche pour clarifier.
         - .icon--xs : 10x10 pour utilisation inline dans la meta.
         - .msg__actions / .msg-action : boutons Copier/Regénérer en
           monospace uppercase, hover discret, état .copied vert.
         - .impact-value--placeholder : variante grisée + tooltip.

   v1.7 (2026-06-26) — Livraison 2.5 : white-label complet
     · Refonte section BRAND (.brand, .brand-logo, .brand__name, .brand__sub) :
         - .brand-logo : background-image: var(--brand-logo-url) avec
           fallback SVG inline visible si la var vaut 'none'.
         - .brand-logo--lg : variante grande taille (login screen, 36px).
         - .brand-logo__fallback : SVG inline absolu dans .brand-logo, masqué
           via body[data-brand-img] quand image client présente.
         - .brand__name::before : content: var(--brand-name, 'Arkensai').
         - .brand__sub::before  : content: var(--brand-subtitle, 'Multimodal Agent').
         - .login-brand : styles dédiés (gros logo + nom Fraunces).
     · Plus aucun texte de marque ni logo en dur dans le HTML : 100%
       paramétrable depuis theme-client-*.css.

   v1.6 (2026-06-26) — Livraison 2a : réparation visuelle des messages
     · Refonte de la section 9 (MESSAGES) pour cibler les VRAIES classes
       générées par script_v42 (ligne 1767-1778) :
         .bubble, .bubble-user, .bubble-assistant, .bubble-ts, .agent-output
       (avant, le CSS ciblait .user-message / .msg--user inexistantes dans
       le DOM, donc aucun style ne s'appliquait → bulles transparentes).
     · .bubble-user : fond rouge carmin (--c-accent), aligné à droite,
       coin inférieur droit rogné (pattern chat moderne).
     · .bubble-assistant : filet rouge 2px à gauche, pleine largeur, fond
       transparent. Markdown rendu propre (h1-h4, ul/ol, code, blockquote,
       table, hr) avec polices Arkensai (Fraunces pour titres).
     · .agent-output : variante avec filet vert eco + badge "AGENT".
     · .bubble-ts : timestamp discret en monospace, gris.
     · Styles préservés pour les conventions du mockup v3 (.msg, .msg--user,
       .msg__bubble, .msg__meta-detailed, .region-pill, .msg__impact) qui
       seront utilisées en Livraison 2b (wrapping post-rendu des messages
       assistant avec metadata RSE).
     · Aucune couleur hardcodée — tout via var(--c-*).

   v1.5 (2026-06-26) — Livraison 1 : entry points + popovers
     · Ajout section 12.5 : .entry-btn (4 boutons du composer avec
       indicateur de sélection courante) + .popover (popover ancrée au-dessus
       du bouton trigger, animation popover-in en glissement vertical).
     · États : hover, is-active (popover ouverte), has-selection (valeur choisie).
     · .popover__list scrollable avec min-height:0 (fix Flexbox standard).
     · Statuts MCP (popover__item-status / --ok) en monospace verte.
     · Responsive : mobile masque les labels des entry-btn (icônes seules),
       les popovers basculent en bottom sheet plein écran (UX native).
     · Diviseurs verticaux .composer__divider entre les groupes de boutons.

   v1.4 (2026-06-26) — Fix : vignettes de fichiers uploadés
     · Quand un utilisateur uploadait une image dans le panneau Outils,
       elle s'affichait en TAILLE RÉELLE (souvent 2000+px) au lieu d'une
       vignette compacte, cassant la mise en page du panneau.
     · Cause : script_v42 génère dynamiquement <div class="file-thumb">
       avec un <img> dedans, mais components.css n'avait aucun style pour
       cette classe ni ses enfants (.file-name, .remove-file, .file-doc, etc.).
     · Fix : ajout de styles complets pour les vignettes — carré 80x80,
       image en object-fit:cover, nom en surimpression dégradé en bas,
       bouton suppression circulaire en haut droite, variante .file-doc
       pour audio/PDF avec icône centrée.

   v1.3 (2026-06-26) — Fix : override du display:block inline imposé par v42
     · Le fix min-height:0 (v1.2) ne suffisait pas car script_v42 force
       #app-content.style.display = 'block' (ligne 608) après login, ce
       qui écrase la règle CSS "display:flex" via la priorité inline.
       Conséquence : #app-content n'était jamais en flex column → header,
       main et composer s'empilaient en bloc → composer poussé hors écran.
     · Fix : sélecteur d'attribut CSS qui détecte le inline style "block"
       et le remplace par "flex !important". Le display:none initial reste
       intact (pas matché par le sélecteur).

   v1.2 (2026-06-26) — Fix : scroll interne du thread + composer en bas
     · Au fur et à mesure que la conversation s'allongeait, le composer
       disparaissait sous l'écran et aucun ascenseur n'apparaissait.
     · Cause : bug Flexbox classique — un enfant flex a min-height:auto
       par défaut, donc .thread ne pouvait pas rétrécir sous la taille de
       son contenu, ce qui poussait .app-main et donc .composer-wrap hors
       écran sans déclencher overflow-y:auto.
     · Fix : ajout min-height:0 sur .app-main, .empty-state et .thread.
       Maintenant .thread est bien contraint → scroll interne s'active →
       composer reste sticky en bas.

   v1.1 (2026-06-26) — Fix : masquer définitivement le web-search-toggle
     · Le checkbox #web-search-toggle apparaissait à l'écran après une
       réponse parce que script_v42 fait style.display='flex' en inline
       (lignes 2192, 2613). Solution : forcer display:none !important
       sur .web-search-row + #web-search-toggle + #web-search-picto.
       L'élément reste dans le DOM (v42 lit toujours .checked), mais
       n'est plus jamais visible à l'utilisateur.

   v1.0 (2026-06-25) — Création initiale

   ═══════════════════════════════════════════════════════════════════════════ */


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 1. RESET & BASE
   ╚═══════════════════════════════════════════════════════════════════════════ */

*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html, body {
  height: 100%;
}

html { color-scheme: light; }
[data-theme="dark"] { color-scheme: dark; }

body {
  font-family: var(--f-sans);
  font-size: var(--fs-base);
  line-height: var(--lh-normal);
  color: var(--c-fg);
  background: var(--c-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow: hidden; /* on gère le scroll dans .thread uniquement */
}

button {
  font: inherit;
  color: inherit;
  background: transparent;
  border: 0;
  cursor: pointer;
}

a {
  color: inherit;
  text-decoration: none;
}

input, textarea, select {
  font: inherit;
  color: inherit;
}

/* Icônes */
.icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}
.icon--sm { width: 14px; height: 14px; }
.icon--lg { width: 22px; height: 22px; }
.icon--xl { width: 28px; height: 28px; }

/* Accessibilité — texte caché visuellement */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 2. SCREENS (login, change-password)
   ╚═══════════════════════════════════════════════════════════════════════════ */

#login-screen,
#change-password-screen {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--c-bg);
  z-index: var(--z-elevated);
}

.login-box,
.change-pwd-box {
  background: var(--c-bg-elevated);
  border: 1px solid var(--c-line);
  border-radius: var(--radius-lg);
  padding: var(--sp-8);
  max-width: 400px;
  width: calc(100% - var(--sp-8));
  box-shadow: var(--shadow-lg);
}

.login-brand {
  font-family: var(--f-display);
  font-size: var(--fs-xl);
  font-weight: 500;
  letter-spacing: -0.02em;
  margin-bottom: var(--sp-2);
  color: var(--c-fg);
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.login-sub {
  font-size: var(--fs-sm);
  color: var(--c-fg-muted);
  margin-bottom: var(--sp-6);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.btn-sso,
.btn-full {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  width: 100%;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius);
  font-size: var(--fs-base);
  font-weight: 500;
  cursor: pointer;
  transition: all var(--d-fast);
  margin-bottom: var(--sp-2);
}

.btn-sso-azure {
  background: #fff;
  color: #1F1F1F;
  border: 1px solid var(--c-line-strong);
}
.btn-sso-azure:hover { background: #F5F5F5; }

.btn-sso-google {
  background: #fff;
  color: #1F1F1F;
  border: 1px solid var(--c-line-strong);
}
.btn-sso-google:hover { background: #F5F5F5; }

#local-login-form form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}

#local-login-form input,
#change-password-form input {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--c-line-strong);
  border-radius: var(--radius);
  background: var(--c-bg);
  color: var(--c-fg);
  font-size: var(--fs-base);
  transition: border-color var(--d-fast), box-shadow var(--d-fast);
}
#local-login-form input:focus,
#change-password-form input:focus {
  outline: 0;
  border-color: var(--c-accent);
  box-shadow: 0 0 0 3px var(--c-accent-soft);
}

.btn-full {
  background: var(--c-accent);
  color: var(--c-accent-fg);
  border: 0;
}
.btn-full:hover { background: var(--c-accent-hover); }

#login-error,
#change-password-error {
  color: var(--c-danger);
  font-size: var(--fs-sm);
  margin-top: var(--sp-3);
  min-height: 16px;
}

.change-pwd-notice {
  background: var(--c-accent-soft);
  border-left: 3px solid var(--c-accent);
  padding: var(--sp-3) var(--sp-4);
  border-radius: 3px;
  font-size: var(--fs-sm);
  color: var(--c-fg);
  margin-bottom: var(--sp-4);
}


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 3. APP CONTAINER — structure principale
   ╚═══════════════════════════════════════════════════════════════════════════ */

#app-content {
  display: flex;
  flex-direction: column;
  /* v2.15 : 100dvh (Dynamic Viewport Height) au lieu de 100vh.
     - 100vh  : hauteur totale (inclut zone sous barre Android et zone que
                le clavier virtuel masque) → le contenu en bas devient
                inaccessible quand barre/clavier sont là.
     - 100dvh : hauteur dynamique réelle visible. Se réduit auto quand
                la barre Android est présente ou le clavier s'affiche.
                → le composer reste TOUJOURS au-dessus.
     Fallback 100vh pour les très vieux navigateurs (rare en 2026). */
  height: 100vh;
  height: 100dvh;
  width: 100vw;
  background: var(--c-bg);
  position: relative;
  overflow: hidden;
}

/* IMPORTANT : script_v42 fait appContent.style.display = 'block' (ligne 608)
   pour révéler l'app après login. L'inline style écrase nos règles CSS.
   On utilise un sélecteur d'attribut pour intercepter ce cas précis et
   forcer display:flex — sans casser le display:none initial (qui reste
   géré normalement par l'inline style="display:none;" du HTML). */
#app-content[style*="display: block"],
#app-content[style*="display:block"] {
  display: flex !important;
}

#logout-btn {
  display: none !important; /* logout passe par le dropdown */
}


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 4. HEADER (56px)
   ╚═══════════════════════════════════════════════════════════════════════════ */

.app-header {
  height: var(--header-h);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 0 var(--sp-5);
  border-bottom: 1px solid var(--c-line);
  background: var(--c-bg);
  flex-shrink: 0;
  z-index: var(--z-header);
}

.btn-icon {
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius);
  color: var(--c-fg-muted);
  transition: background var(--d-fast), color var(--d-fast);
}
.btn-icon:hover {
  background: var(--c-bg-hover);
  color: var(--c-fg);
}
.btn-icon--sm { width: 28px; height: 28px; }

/* v2.20 : Bouton RSE 🌿 dans le header
   ────────────────────────────────────
   - Caché en desktop (>1100px) car le panneau RSE est déjà visible
     en permanence à droite → bouton redondant.
   - Visible en tablette/mobile (≤1100px) où le panneau est masqué et
     accessible uniquement via ce bouton (bottom sheet).
   - Feuille colorée en vert (--c-eco) pour renforcer la sémantique
     écologie et cohérence avec le hero CO₂e du panneau. */
#rse-toggle-btn {
  display: none;
  color: var(--c-eco);
}
#rse-toggle-btn:hover {
  color: var(--c-eco);
  background: rgba(46, 125, 50, 0.10);
}
@media (max-width: 1100px) {
  #rse-toggle-btn {
    display: inline-flex;
  }
}

/* ─── BRAND (white-label v2.5) ─────────────────────────────────────────────
   Le contenu textuel (nom + sous-titre) est injecté via ::before depuis les
   variables CSS --brand-name et --brand-subtitle.
   Le logo utilise --brand-logo-url en background-image. Si la variable
   vaut "none" (par défaut pour Arkensai), le fallback SVG inline reste
   visible. Sinon le SVG est masqué et l'image client s'affiche.
   ─────────────────────────────────────────────────────────────────────── */
.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  font-family: var(--f-display);
  font-size: var(--fs-lg);
  font-weight: 500;
  letter-spacing: -0.015em;
  color: var(--c-fg);
}

/* Conteneur du logo — taille fixe, image en background si définie */
.brand-logo {
  display: inline-block;
  position: relative;
  width: var(--brand-logo-h, 28px);
  height: var(--brand-logo-h, 28px);
  flex-shrink: 0;
  background-image: var(--brand-logo-url, none);
  background-position: center;
  background-size: contain;
  background-repeat: no-repeat;
}

/* Variante grande taille (login screen) */
.brand-logo--lg {
  width: 36px;
  height: 36px;
}

/* SVG inline fallback : visible UNIQUEMENT si --brand-logo-url vaut none.
   Sinon (image custom définie) on le masque. */
.brand-logo__fallback {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
/* Quand --brand-logo-url est définie (≠ "none"), on cache le SVG fallback.
   On utilise un sélecteur qui détecte que background-image est non-vide :
   l'astuce est d'inverser via :not — mais CSS pur ne peut pas comparer une
   var à 'none'. On utilise donc une convention :
   - .brand-logo--has-image  → CSS ajoute cette classe quand l'URL est définie
   Pour éviter du JS supplémentaire, on bascule via un attribut data-* posé
   par le theme-client-X.css en utilisant body[data-brand-img]. */
body[data-brand-img] .brand-logo__fallback {
  display: none;
}

/* Nom de la plateforme — injecté par CSS */
.brand__name {
  font-family: var(--f-display);
  font-weight: 500;
}
.brand__name::before {
  content: var(--brand-name, 'Arkensai');
}

/* Sous-titre — injecté par CSS */
.brand__sub {
  font-family: var(--f-sans);
  font-size: var(--fs-sm);
  font-weight: 400;
  color: var(--c-fg-muted);
}
.brand__sub::before {
  content: var(--brand-subtitle, 'Multimodal Agent');
}

/* Séparateur "·" entre nom et sous-titre */
.brand__sep {
  color: var(--c-fg-subtle);
  margin: 0 var(--sp-1);
}

.app-header__spacer { flex: 1; }

/* Login screen — alignement spécifique */
.login-brand {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-family: var(--f-display);
  font-size: var(--fs-xl);
  font-weight: 500;
  letter-spacing: -0.02em;
  margin-bottom: var(--sp-2);
  color: var(--c-fg);
}

.user-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 4px var(--sp-3) 4px var(--sp-1);
  border: 1px solid var(--c-line);
  border-radius: var(--radius-full);
  color: var(--c-fg);
  font-size: var(--fs-sm);
  font-weight: 500;
  cursor: pointer;
  transition: background var(--d-fast);
}
.user-chip:hover { background: var(--c-bg-hover); }

.user-avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--c-accent);
  color: var(--c-accent-fg);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
}

.user-chip__info {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.2;
}

.user-chip .user-name {
  font-size: 12.5px;
  font-weight: 500;
  color: var(--c-fg);
}
.user-chip .user-role {
  font-size: 10px;
  font-weight: 400;
  color: var(--c-fg-subtle);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.user-chevron {
  color: var(--c-fg-subtle);
  transition: transform var(--d-fast);
}
.user-chip.open .user-chevron {
  transform: rotate(180deg);
}


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 5. SIDEBAR + OVERLAY
   ╚═══════════════════════════════════════════════════════════════════════════ */

.sidebar-overlay {
  position: absolute;
  inset: 0;
  background: rgba(15, 8, 9, 0.35);
  z-index: var(--z-overlay);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--d-base);
}
.sidebar-overlay.open {
  opacity: 1;
  pointer-events: auto;
}

.sidebar {
  position: absolute;
  top: 0; left: 0; bottom: 0;
  width: var(--sidebar-w);
  background: var(--c-bg-elevated);
  border-right: 1px solid var(--c-line);
  display: flex;
  flex-direction: column;
  z-index: var(--z-sidebar);
  box-shadow: var(--shadow-lg);
  transform: translateX(-100%);
  transition: transform var(--d-base) var(--ease-out);
}
.sidebar.open {
  transform: translateX(0);
}

.sidebar__header {
  padding: var(--sp-4);
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--c-line);
}

.sidebar__title {
  font-family: var(--f-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--c-fg-muted);
}

.sidebar__newbtn {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: var(--sp-3) var(--sp-3) var(--sp-2);
  padding: 10px var(--sp-3);
  background: var(--c-fg);
  color: var(--c-bg);
  border-radius: var(--radius);
  font-size: var(--fs-sm);
  font-weight: 500;
  transition: opacity var(--d-fast);
}
.sidebar__newbtn:hover { opacity: 0.9; }

.sidebar__search {
  margin: var(--sp-2) var(--sp-3) var(--sp-3);
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 8px var(--sp-3);
  background: var(--c-bg);
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  font-size: var(--fs-sm);
  color: var(--c-fg-subtle);
}
.sidebar__search input {
  flex: 1;
  background: transparent;
  border: 0;
  outline: 0;
  font-size: var(--fs-sm);
  color: var(--c-fg);
}
.sidebar__search input::placeholder { color: var(--c-fg-subtle); }

.sidebar__list,
.sidebar-sessions {
  flex: 1;
  overflow-y: auto;
  padding: 0 var(--sp-2) var(--sp-3);
}

.sidebar__footer {
  border-top: 1px solid var(--c-line);
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--c-fg-muted);
}

/* Quota widget (préservé) */
.quota-widget {
  margin-bottom: var(--sp-3);
}
.quota-header {
  display: flex;
  justify-content: space-between;
  font-family: var(--f-mono);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--c-fg-muted);
  margin-bottom: var(--sp-2);
}
.quota-pct { color: var(--c-eco); font-weight: 500; }
.quota-bar-track {
  height: 4px;
  background: var(--c-bg-muted);
  border-radius: 2px;
  overflow: hidden;
}
.quota-bar-fill {
  height: 100%;
  background: var(--c-eco);
  width: 0;
  transition: width var(--d-base);
}
.quota-detail {
  display: flex;
  justify-content: space-between;
  margin-top: var(--sp-1);
  font-family: var(--f-mono);
  font-size: 10.5px;
  color: var(--c-fg-subtle);
}


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 6. USER DROPDOWN
   ╚═══════════════════════════════════════════════════════════════════════════ */

.user-dropdown {
  position: absolute;
  top: calc(var(--header-h) + 4px);
  right: var(--sp-5);
  width: 260px;
  background: var(--c-bg-elevated);
  border: 1px solid var(--c-line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  z-index: var(--z-dropdown);
  display: none;
  overflow: hidden;
}
.user-dropdown.open { display: block; }

.dropdown-header {
  padding: var(--sp-3) var(--sp-4);
}
.dropdown-user-full {
  font-size: var(--fs-base);
  font-weight: 500;
  color: var(--c-fg);
}
.dropdown-user-email {
  font-size: var(--fs-xs);
  color: var(--c-fg-muted);
  margin-top: 2px;
}

.dropdown-divider {
  height: 1px;
  background: var(--c-line);
}

.dropdown-item {
  display: flex !important;
  align-items: center;
  gap: var(--sp-2);
  padding: 10px var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--c-fg);
  cursor: pointer;
  transition: background var(--d-fast);
}
.dropdown-item:hover { background: var(--c-bg-hover); }
.dropdown-item.danger { color: var(--c-danger); }
.dropdown-item.danger:hover { background: var(--c-accent-soft); }


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 7. EMPTY STATE (accueil quand chat vide)
   ╚═══════════════════════════════════════════════════════════════════════════ */

.app-main {
  flex: 1;
  min-height: 0; /* CRITIQUE : permet à .app-main de rétrécir et donne à .thread l'espace contraint pour scroller en interne (sinon .thread grandit à l'infini et pousse le composer hors écran) */
  min-width: 0;  /* v2.9 : permet la compression en width pour que la fenêtre puisse être réduite sous la largeur intrinsèque du composer. */
  overflow: hidden;
  position: relative;
  display: flex;
  flex-direction: column;
}

.empty-state {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: var(--sp-8);
  text-align: center;
  overflow-y: auto;
}

.empty-state__greeting {
  font-family: var(--f-display);
  font-weight: 300;
  font-size: var(--fs-3xl);
  line-height: var(--lh-tight);
  letter-spacing: -0.025em;
  color: var(--c-fg);
  margin-bottom: var(--sp-3);
}

.empty-state__greeting em {
  font-style: italic;
  color: var(--c-accent);
}

.empty-state__lede {
  font-size: var(--fs-md);
  color: var(--c-fg-muted);
  margin-bottom: var(--sp-10);
  max-width: 46ch;
}

.shortcut-grid {
  display: grid;
  grid-template-columns: repeat(2, 240px);
  gap: var(--sp-3);
}

.shortcut {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-4);
  background: var(--c-bg-elevated);
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  text-align: left;
  transition: all var(--d-fast);
  cursor: pointer;
}
.shortcut:hover {
  border-color: var(--c-line-strong);
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}

.shortcut__icon {
  width: 32px; height: 32px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--c-bg-muted);
  border-radius: var(--radius);
  color: var(--c-fg-muted);
}

.shortcut__label {
  display: block;
  font-weight: 500;
  font-size: 13.5px;
  color: var(--c-fg);
  margin-bottom: 2px;
}

.shortcut__hint {
  display: block;
  font-size: var(--fs-sm);
  color: var(--c-fg-muted);
  line-height: 1.4;
}


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 8. THREAD (chat history)
   ╚═══════════════════════════════════════════════════════════════════════════ */

.thread {
  flex: 1;
  min-height: 0; /* CRITIQUE : couple avec .app-main min-height:0 pour activer overflow-y:auto au lieu de grandir à l'infini */
  overflow-y: auto;
  padding: var(--sp-6) var(--sp-5);
}

#chat-history {
  max-width: var(--thread-max);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}

#chat-toolbar {
  max-width: var(--thread-max);
  margin: var(--sp-4) auto 0;
  display: flex;
  gap: var(--sp-2);
  align-items: center;
  font-family: var(--f-mono);
  font-size: var(--fs-xs);
  color: var(--c-fg-subtle);
}
#chat-toolbar button {
  padding: 4px var(--sp-2);
  border-radius: var(--radius-sm);
  color: var(--c-fg-muted);
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition: all var(--d-fast);
}
#chat-toolbar button:hover {
  background: var(--c-bg-hover);
  color: var(--c-fg);
}

#loading {
  max-width: var(--thread-max);
  margin: var(--sp-4) auto;
  padding: var(--sp-4);
}
.loading-inner {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--fs-sm);
  color: var(--c-fg-muted);
}
.spinner {
  width: 16px; height: 16px;
  border: 2px solid var(--c-line);
  border-top-color: var(--c-accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin {
  to { transform: rotate(360deg); }
}

.output-card,
#output-card {
  max-width: var(--thread-max);
  margin: 0 auto;
  background: var(--c-bg-elevated);
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  padding: var(--sp-4);
}

/* v2.17 — Image générée : responsive (rentre dans le viewport mobile)
   ───────────────────────────────────────────────────────────────────
   La résolution NATIVE est préservée dans le src (base64) — seule la
   taille d'affichage est réduite. La copie / téléchargement utilisent
   la résolution d'origine. */
#output-media img {
  max-width: 100%;
  height: auto;       /* préserve le ratio à la réduction */
  display: block;     /* évite tout espace inline parasite */
  margin: 0 auto;     /* centrage si l'image est plus petite que le conteneur */
}

/* v2.17 — Bandeau meta pour image générée (modèle + region + durée)
   Ajouté par script_v43 quand une image est rendue dans #output-card.
   Visuellement aligné avec .msg__meta-detailed des bulles texte. */
.output-card__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  margin-bottom: var(--sp-3);
  border-bottom: 1px dashed var(--c-line);
  font-family: var(--f-mono);
  font-size: 11px;
  color: var(--c-fg-muted);
}
.output-card__meta strong {
  font-family: var(--f-sans);
  font-size: 12px;
  color: var(--c-fg);
  font-weight: 600;
}
.output-card__meta .meta-sep {
  color: var(--c-fg-subtle);
  font-weight: 400;
}
.output-card__meta .meta-placeholder {
  color: var(--c-fg-subtle);
  font-style: italic;
}


/* ═══════════════════════════════════════════════════════════════════════════
   v2.23 (2026-07-03) — Bloc impact RSE sous l'image (compatible ui_v1_9.js)
   ─────────────────────────────────────────────────────────────────────────────
   Symétrique à .msg__impact des bulles text. Structure :
     .output-card__impact
       .impact-main
         .impact-metric--co2      : 🍃 valeur CO₂e
         .impact-metric--energy   : ⚡ valeur Wh
         .impact-metric--water    : 💧 valeur mL
       .impact-equiv              : équivalence km voiture
   Les enfants (.impact-metric, .impact-sep, .impact-equiv) héritent
   des styles existants (déclarés pour .msg__impact plus bas).
   ═══════════════════════════════════════════════════════════════════════════ */

.output-card__impact {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1, 4px);
  padding: var(--sp-3) var(--sp-4);
  margin-top: var(--sp-2);
  border-top: 1px solid var(--c-line);
  font-size: 12.5px;
  color: var(--c-fg-muted);
}
.output-card__impact .impact-main {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.output-card__impact .impact-equiv {
  font-size: 11.5px;
  color: var(--c-fg-subtle);
  font-style: italic;
}

/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 9. MESSAGES (user / assistant / meta / impact RSE)
   ╚═══════════════════════════════════════════════════════════════════════════
   script_v42.js (ligne 1767-1778) génère les messages avec ces classes :
     <div class="bubble bubble-user">…<span class="bubble-ts">…</span></div>
     <div class="bubble bubble-assistant">…<span class="bubble-ts">…</span></div>
     <div class="bubble bubble-assistant agent-output">…</div>  (réponse d'agent)

   On cible donc EXACTEMENT ces classes. Le sélecteur #chat-history est
   en display:flex; flex-direction:column; gap:24px; (cf. ci-dessus).
   ─────────────────────────────────────────────────────────────────────────── */

/* ─── Conteneur du chat ─── */
#chat-history {
  font-size: var(--fs-md);
  line-height: var(--lh-loose);
  color: var(--c-fg);
}

/* ─── Bulle utilisateur (rouge carmin, alignée à droite) ─── */
.bubble-user {
  background: var(--c-accent);
  color: var(--c-accent-fg);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-lg);
  border-bottom-right-radius: 4px;
  max-width: 75%;
  align-self: flex-end;
  margin-left: auto;
  word-wrap: break-word;
  word-break: break-word;
  position: relative;
}

/* La bulle user n'a pas de Markdown rendu — c'est du texte brut échappé.
   Mais on garde la cohérence pour les liens/code si jamais ils apparaissent. */
.bubble-user code {
  background: rgba(255, 255, 255, 0.15);
  color: inherit;
  font-family: var(--f-mono);
  font-size: 13px;
  padding: 1px 5px;
  border-radius: 3px;
}
.bubble-user a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ─── Bulle assistant (filet rouge à gauche, pleine largeur) ─── */
.bubble-assistant {
  background: transparent;
  border-left: 2px solid var(--c-accent);
  padding: var(--sp-1) 0 var(--sp-1) var(--sp-4);
  max-width: 100%;
  align-self: flex-start;
  color: var(--c-fg);
  word-wrap: break-word;
  word-break: break-word;
  position: relative;
}

/* Variante agent spécialisé : filet plus marqué + petit badge */
.bubble-assistant.agent-output {
  border-left-color: var(--c-eco);
  border-left-width: 3px;
}
.bubble-assistant.agent-output::before {
  content: 'Agent';
  position: absolute;
  top: -8px;
  left: -2px;
  background: var(--c-eco);
  color: var(--c-accent-fg);
  font-family: var(--f-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.08em;
  padding: 2px 6px;
  border-radius: 3px;
  text-transform: uppercase;
}

/* ─── Markdown rendu dans les réponses assistant ─── */
.bubble-assistant p {
  margin-bottom: var(--sp-3);
}
.bubble-assistant p:last-child {
  margin-bottom: 0;
}
.bubble-assistant h1,
.bubble-assistant h2,
.bubble-assistant h3,
.bubble-assistant h4 {
  font-family: var(--f-display);
  font-weight: 500;
  color: var(--c-fg);
  margin-top: var(--sp-4);
  margin-bottom: var(--sp-2);
  letter-spacing: -0.01em;
}
.bubble-assistant h1 { font-size: var(--fs-xl); }
.bubble-assistant h2 { font-size: var(--fs-lg); }
.bubble-assistant h3 { font-size: var(--fs-md); }
.bubble-assistant h1:first-child,
.bubble-assistant h2:first-child,
.bubble-assistant h3:first-child {
  margin-top: 0;
}

.bubble-assistant ul,
.bubble-assistant ol {
  margin: 0 0 var(--sp-3) var(--sp-5);
  padding: 0;
}
.bubble-assistant li {
  margin-bottom: var(--sp-1);
}
.bubble-assistant li:last-child {
  margin-bottom: 0;
}

.bubble-assistant strong {
  font-weight: 600;
  color: var(--c-fg);
}
.bubble-assistant em {
  font-style: italic;
}

.bubble-assistant code {
  font-family: var(--f-mono);
  font-size: 12.5px;
  background: var(--c-bg-muted);
  color: var(--c-fg);
  padding: 1px 5px;
  border-radius: 3px;
  word-break: break-word;
}

.bubble-assistant a {
  color: var(--c-accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.bubble-assistant a:hover {
  text-decoration-thickness: 2px;
}

.bubble-assistant blockquote {
  border-left: 2px solid var(--c-line-strong);
  padding-left: var(--sp-3);
  margin: var(--sp-3) 0;
  color: var(--c-fg-muted);
  font-style: italic;
}

.bubble-assistant hr {
  border: 0;
  border-top: 1px solid var(--c-line);
  margin: var(--sp-4) 0;
}

.bubble-assistant table {
  border-collapse: collapse;
  margin: var(--sp-3) 0;
  font-size: var(--fs-sm);
  width: 100%;
}
.bubble-assistant th,
.bubble-assistant td {
  border: 1px solid var(--c-line);
  padding: 6px var(--sp-2);
  text-align: left;
}
.bubble-assistant th {
  background: var(--c-bg-muted);
  font-weight: 500;
}

/* ─── Timestamp (généré par v42 en fin de bulle) ─── */
.bubble-ts {
  display: block;
  margin-top: var(--sp-2);
  font-family: var(--f-mono);
  font-size: 10.5px;
  color: var(--c-fg-subtle);
  letter-spacing: 0.02em;
}

/* Sur la bulle user (fond rouge), le timestamp doit être lisible sur rouge */
.bubble-user .bubble-ts {
  color: rgba(255, 255, 255, 0.65);
}

/* ─── Code-fence (blocs de code rendus par v42 via marked.js) ─── */
.bubble-assistant pre {
  margin: var(--sp-3) 0;
  padding: var(--sp-3) var(--sp-4);
  background: var(--c-bg-muted);
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  overflow-x: auto;
  font-family: var(--f-mono);
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--c-fg);
}
.bubble-assistant pre code {
  background: transparent;
  padding: 0;
  font-size: inherit;
}

/* Highlight.js (chargé par index.html) — on respecte ses classes */
.bubble-assistant pre code.hljs {
  background: transparent;
  padding: 0;
}

/* ─── Conventions du mockup v3 — gardées pour compatibilité future (Livraison 2b) ─── */
.msg--user .msg__bubble {
  background: var(--c-accent);
  color: var(--c-accent-fg);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-lg);
  border-bottom-right-radius: 4px;
  max-width: 75%;
  align-self: flex-end;
  margin-left: auto;
}
.msg--assistant .msg__bubble {
  background: transparent;
  border-left: 2px solid var(--c-accent);
  padding-left: var(--sp-4);
  max-width: 100%;
}

/* Meta enrichie sous le message assistant (Livraison 2b — enrichi par script_v43) */
.msg__meta-detailed {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--c-line);
  font-family: var(--f-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.04em;
  color: var(--c-fg-subtle);
}
.msg__meta-detailed .meta-sep {
  color: var(--c-line-strong);
  margin: 0 2px;
}
.msg__meta-detailed strong {
  color: var(--c-fg);
  font-weight: 600;
  letter-spacing: 0;
  font-family: var(--f-sans);
  font-size: 12px;
}

/* Indicateur web search dans la meta (globe) */
.meta-web {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 6px;
  background: var(--c-info, #1F6FBF);
  background: color-mix(in srgb, var(--c-info, #1F6FBF) 12%, transparent);
  color: var(--c-info, #1F6FBF);
  border-radius: 3px;
  font-weight: 500;
  font-family: var(--f-sans);
  font-size: 10.5px;
  letter-spacing: 0;
  cursor: help;
}
.meta-web .icon {
  width: 12px;
  height: 12px;
}

/* Placeholder pour les valeurs pas encore câblées (tokens, coût, CO₂e) */
.meta-placeholder {
  color: var(--c-fg-subtle);
  font-style: italic;
  opacity: 0.6;
  cursor: help;
}

/* Pastille régionale */
.region-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 6px;
  background: var(--c-bg-elevated);
  border: 1px solid var(--c-line);
  border-radius: 3px;
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: var(--c-fg-muted);
  cursor: help;
  font-family: var(--f-sans);
}
.region-pill__icon {
  width: 12px;
  height: 12px;
  color: var(--c-accent);
}
.region-pill__flag {
  font-weight: 600;
  font-size: 10px;
  color: var(--c-accent);
}
.region-pill__city { font-weight: 500; color: var(--c-fg); }
.region-pill__energy { color: var(--c-eco); font-weight: 500; }

/* v2.21 — Variants couleur pastille selon intensité carbone du mix grid */
.region-pill--low     { border-color: var(--c-eco);    background: color-mix(in srgb, var(--c-eco) 6%, var(--c-bg-elevated)); }
.region-pill--low     .region-pill__energy { color: var(--c-eco); }
.region-pill--mid     { border-color: var(--c-warn);   background: color-mix(in srgb, var(--c-warn) 6%, var(--c-bg-elevated)); }
.region-pill--mid     .region-pill__energy { color: var(--c-warn); }
.region-pill--high    { border-color: var(--c-warn);   background: color-mix(in srgb, var(--c-warn) 10%, var(--c-bg-elevated)); }
.region-pill--high    .region-pill__energy { color: var(--c-warn); font-weight: 600; }
.region-pill--critical { border-color: var(--c-danger); background: color-mix(in srgb, var(--c-danger) 8%, var(--c-bg-elevated)); }
.region-pill--critical .region-pill__energy { color: var(--c-danger); font-weight: 600; }

/* v2.21 — Pastille placeholder pendant la résolution (avant arrivée du META) */
.region-pill--pending {
  opacity: 0.5;
  font-style: italic;
  border-style: dashed;
}
.region-pill--pending .region-pill__flag,
.region-pill--pending .region-pill__city {
  color: var(--c-fg-subtle);
}

/* Variante xs des icônes pour la meta */
.icon--xs { width: 10px; height: 10px; }

/* Ligne d'impact RSE */
.msg__impact {
  margin-top: var(--sp-4);
  padding-top: var(--sp-3);
  border-top: 1px dashed var(--c-line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--sp-2);
}
.impact-main {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-family: var(--f-mono);
  font-size: var(--fs-sm);
  color: var(--c-fg-muted);
}
.impact-value {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 500;
}
.impact-value::before {
  content: '';
  width: 8px; height: 8px;
  border-radius: 50%;
  background: currentColor;
}
.impact-value--green  { color: var(--c-eco); }
.impact-value--orange { color: var(--c-warn); }
.impact-value--red    { color: var(--c-danger); }

/* v2.21 — Valeurs secondaires (énergie / eau) dans le détail msg__impact */
.impact-value--secondary {
  color: var(--c-fg-subtle);
  font-weight: 400;
  font-size: 0.92em;
}
.impact-value--secondary::before {
  background: var(--c-fg-subtle);
  opacity: 0.5;
  width: 6px;
  height: 6px;
}
.impact-sep {
  color: var(--c-fg-subtle);
  opacity: 0.5;
  margin: 0 2px;
}

.impact-value--placeholder {
  color: var(--c-fg-subtle);
  font-style: italic;
  opacity: 0.6;
  cursor: help;
}
.impact-value--placeholder::before {
  background: var(--c-fg-subtle);
  opacity: 0.4;
}

/* ───────────────────────────────────────────────────────────────────────────
   v2.22 — IMPACT MÉTRIQUES AVEC ICÔNES (CO₂, énergie, eau)
   ─────
   Structure :
     <span class="impact-metric impact-metric--{co2|energy|water}
                                 impact-metric--{low|mid|high}">
       <svg class="impact-metric__icon">…</svg>
       <span class="impact-metric__value">0,1 g CO₂e</span>
     </span>
   Règle visuelle :
     - L'icône a une couleur SIGNATURE STABLE (vert/jaune/bleu) selon
       la métrique — elle ne change jamais. C'est un repère immédiat.
     - La VALEUR change de couleur selon le seuil (low/mid/high).
       Seuils définis côté JS dans _rseLevelClass().
   ─────────────────────────────────────────────────────────────────────────── */
.impact-metric {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-weight: 500;
  font-family: var(--f-mono);
  font-size: var(--fs-sm);
}
.impact-metric__icon {
  flex-shrink: 0;
  width: 13px;
  height: 13px;
}
.impact-metric__value {
  white-space: nowrap;
}

/* Icônes — couleur SIGNATURE STABLE par métrique (ne change pas) */
.impact-metric--co2    .impact-metric__icon { color: var(--c-eco); }
.impact-metric--energy .impact-metric__icon { color: var(--c-warn); }
.impact-metric--water  .impact-metric__icon { color: #2b8fb5; } /* bleu eau */

/* Valeurs — couleur selon SEUIL (low / mid / high) */
.impact-metric--low  .impact-metric__value { color: var(--c-eco); }
.impact-metric--mid  .impact-metric__value { color: var(--c-fg-muted); }
.impact-metric--high .impact-metric__value { color: var(--c-danger); font-weight: 600; }

.impact-equiv {
  color: var(--c-fg-subtle);
  font-family: var(--f-sans);
  font-size: var(--fs-sm);
  font-style: italic;
}
.impact-equiv strong {
  color: var(--c-fg-muted);
  font-weight: 500;
  font-style: normal;
}

/* Boutons d'action sous chaque réponse assistant (Copier / Régénérer) */
.msg__actions {
  display: flex;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
  padding-top: var(--sp-2);
}
.msg-action {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 8px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-family: var(--f-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--c-fg-subtle);
  cursor: pointer;
  transition: all var(--d-fast);
}
.msg-action:hover {
  background: var(--c-bg-hover);
  color: var(--c-fg);
  border-color: var(--c-line);
}
.msg-action .icon {
  width: 12px;
  height: 12px;
}
.msg-action.copied {
  color: var(--c-eco);
  background: color-mix(in srgb, var(--c-eco) 8%, transparent);
}

/* Code-fence (utilisé par highlight.js custom) */
.code-fence {
  margin: var(--sp-3) 0;
  background: var(--c-bg-muted);
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  overflow: hidden;
}
.code-fence__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px var(--sp-3);
  border-bottom: 1px solid var(--c-line);
  background: var(--c-bg);
  font-family: var(--f-mono);
  font-size: var(--fs-xs);
  color: var(--c-fg-muted);
  letter-spacing: 0.04em;
}
.code-fence__body,
.code-fence pre {
  padding: var(--sp-3) var(--sp-4);
  font-family: var(--f-mono);
  font-size: 12.5px;
  line-height: 1.6;
  overflow-x: auto;
  background: var(--c-bg-muted);
}


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 10. COMPOSER (input bar du bas)
   ╚═══════════════════════════════════════════════════════════════════════════ */

.composer-wrap {
  border-top: 1px solid var(--c-line);
  background: var(--c-bg);
  /* v2.13 : padding-bottom prend en compte la safe area Android/iOS pour
     que le composer ne soit pas masqué par la barre de navigation système
     (3 icônes du bas sur Android, home indicator sur iOS). */
  padding: var(--sp-3) var(--sp-5) calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  flex-shrink: 0;
  /* v2.9 : autoriser la compression en width pour que la fenêtre puisse
     se réduire en dessous de la largeur intrinsèque de la barre composer.
     Le contenu interne (barre) gérera son propre overflow-x. */
  min-width: 0;
}

.composer {
  /* Composer aligné EXACTEMENT sur les bords du thread (même largeur 880px,
     même centrage) pour une cohérence visuelle parfaite. Le filet
     overflow-x:auto sur .composer__bar gère les rares cas de débordement
     de quelques pixels selon le rendu polices.
     ───────────────────────────────────────────────────────────────────── */
  max-width: var(--composer-max);
  margin: 0 auto;
  background: var(--c-bg-elevated);
  border: 1px solid var(--c-line-strong);
  border-radius: var(--radius-lg);
  transition: border-color var(--d-fast), box-shadow var(--d-fast);
}
.composer:focus-within {
  border-color: var(--c-accent);
  box-shadow: 0 0 0 4px var(--c-accent-soft);
}

.composer__textarea,
#prompt {
  width: 100%;
  min-height: 56px;
  max-height: 220px;
  padding: var(--sp-3) var(--sp-4);
  font-family: var(--f-sans);
  font-size: var(--fs-md);
  line-height: var(--lh-normal);
  color: var(--c-fg);
  background: transparent;
  border: 0;
  outline: 0;
  resize: none;
  display: block;
}
.composer__textarea::placeholder,
#prompt::placeholder { color: var(--c-fg-subtle); }

.composer__bar {
  /* v2.14 : flex-wrap: nowrap explicite pour que les boutons ne passent
     JAMAIS sur 2 lignes (sinon la 2ème ligne se retrouve cachée derrière
     la barre Android en mobile). Combiné aux media queries qui passent
     les boutons en mode icône, tout rentre sur 1 ligne.
     overflow-x: auto silencieux comme filet de sécurité si jamais ça
     déborde quand même. */
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 6px;
  padding: var(--sp-2);
  border-top: 1px solid var(--c-line);
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.composer__bar::-webkit-scrollbar { display: none; }

/* Tous les enfants flex-shrink: 0 pour garder leur taille intrinsèque */
.composer__bar > * {
  flex-shrink: 0;
}

/* v2.12 : règle flex-shrink unifiée sur enfants directs de .composer__bar
   (cf. plus haut). L'ancienne règle qui ciblait .composer__bar-scroll
   est devenue obsolète avec le retour à la structure plate. */

.composer__model {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 6px var(--sp-3);
  border-radius: var(--radius);
  font-size: 13px;
  font-weight: 500;
  color: var(--c-fg);
  background: var(--c-bg-muted);
  transition: background var(--d-fast);
  max-width: 200px;
  flex-shrink: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
  border: 1px solid transparent;
}
.composer__model:hover {
  background: var(--c-bg-hover);
  border-color: var(--c-line);
}
.composer__model.is-active {
  background: var(--c-accent-soft);
  border-color: var(--c-accent);
  color: var(--c-accent);
}
.composer__model.is-active .icon { color: var(--c-accent); }
.composer__model .icon { color: var(--c-accent); flex-shrink: 0; }

/* Badge "Auto" qui remplace le nom du modèle quand le routeur est actif */
.composer__model.is-auto #model-badge::after {
  content: '';
}
.composer__model.is-auto {
  background: color-mix(in srgb, var(--c-info, #1F6FBF) 12%, transparent);
  color: var(--c-info, #1F6FBF);
  border-color: var(--c-info, #1F6FBF);
}
.composer__model.is-auto .icon { color: var(--c-info, #1F6FBF); }

/* Hint masqué par défaut (n'apparaît plus que pour debug) */
.composer__model-hint {
  display: none;
  font-size: 11px;
  font-weight: 400;
  color: var(--c-fg-subtle);
}

.composer__tool {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius);
  color: var(--c-fg-muted);
  transition: all var(--d-fast);
}
.composer__tool:hover {
  background: var(--c-bg-hover);
  color: var(--c-fg);
}
.composer__tool--active {
  color: var(--c-accent);
  background: var(--c-accent-soft);
}
.composer__tool--ghost {
  color: var(--c-fg-subtle);
}

/* ═══════════════════════════════════════════════════════════════════════════
   v2.23 (2026-07-03) — États dictée vocale (compatible core_v46_0.js)
   ─────────────────────────────────────────────────────────────────────────────
   .composer__tool--recording   : enregistrement en cours (Web Speech ou Vertex)
   .composer__tool--transcribing : transcription cloud en cours (Vertex uniquement)
   
   L'icône micro d'origine est masquée et remplacée par un waveform SVG
   animé via ::before (aucun asset externe requis).
   
   Classe historique .recording gardée pour rétro-compat (core.js ancien).
   ═══════════════════════════════════════════════════════════════════════════ */

.composer__tool--recording {
  background: rgba(192, 57, 43, 0.12);
  border: 1px solid #c0392b;
  color: #c0392b;
  animation: composer-tool-pulse 1.4s ease-in-out infinite;
}

.composer__tool--recording svg {
  display: none;
}

.composer__tool--recording::before {
  content: '';
  display: inline-block;
  width: 16px;
  height: 16px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23c0392b' stroke-width='2' stroke-linecap='round'><line x1='4' y1='9' x2='4' y2='15'/><line x1='9' y1='5' x2='9' y2='19'/><line x1='14' y1='7' x2='14' y2='17'/><line x1='19' y1='10' x2='19' y2='14'/></svg>");
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  animation: waveform-bars 0.9s ease-in-out infinite;
}

.composer__tool--transcribing {
  opacity: 0.7;
  cursor: wait;
  color: var(--c-accent);
  border: 1px solid var(--c-accent);
}
.composer__tool--transcribing svg {
  animation: transcribing-spin 1.2s linear infinite;
}

/* Rétro-compat : ancienne classe .recording du CSS v42 */
.composer__tool.recording:not(.composer__tool--recording) {
  background: rgba(192, 57, 43, 0.12);
  border: 1px solid #c0392b;
  color: #c0392b;
}

@keyframes composer-tool-pulse {
  0%, 100% { box-shadow: 0 0 0 0    rgba(192, 57, 43, 0.35); }
  50%      { box-shadow: 0 0 0 4px  rgba(192, 57, 43, 0); }
}

@keyframes waveform-bars {
  0%, 100% { transform: scaleY(1);    opacity: 1; }
  50%      { transform: scaleY(1.15); opacity: 0.7; }
}

@keyframes transcribing-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Mode dark (rouge légèrement plus vif pour contraste) */
[data-theme="dark"] .composer__tool--recording {
  background: rgba(231, 76, 60, 0.18);
  border-color: #e74c3c;
  color: #e74c3c;
}
[data-theme="dark"] .composer__tool--recording::before {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23e74c3c' stroke-width='2' stroke-linecap='round'><line x1='4' y1='9' x2='4' y2='15'/><line x1='9' y1='5' x2='9' y2='19'/><line x1='14' y1='7' x2='14' y2='17'/><line x1='19' y1='10' x2='19' y2='14'/></svg>");
}

.composer__bar-spacer {
  /* v2.12 : spacer flex:1 qui pousse le bouton envoyer à droite.
     Combiné avec les media queries plus bas (mode icône), tout reste
     accessible quelle que soit la largeur. */
  flex: 1 1 auto;
  min-width: 0;
}

.btn-send {
  /* v2.12 : flex item simple, taille fixe 36×36px, flex-shrink: 0 pour
     ne JAMAIS être écrasé. Le spacer juste avant le pousse à droite. */
  width: 36px;
  height: 36px;
  min-width: 36px;
  min-height: 36px;
  flex-shrink: 0;
  background: var(--c-accent);
  color: var(--c-accent-fg);
  border-radius: var(--radius);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background var(--d-fast);
}
.btn-send:hover { background: var(--c-accent-hover); }
.btn-send:disabled {
  background: var(--c-bg-hover);
  color: var(--c-fg-subtle);
  cursor: not-allowed;
}

/* Aussi : les boutons composer__tool et entry-btn ne doivent pas être
   écrasés. On les protège tous d'un coup. */
.composer__tool,
.entry-btn {
  flex-shrink: 0;
}

/* Active tools chips */
.active-tools {
  max-width: var(--composer-max);
  margin: 0 auto var(--sp-2);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  align-items: center;
  font-size: var(--fs-sm);
  color: var(--c-fg-muted);
}
.active-tools__label {
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--c-fg-subtle);
}
.tool-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px var(--sp-2);
  background: var(--c-bg-elevated);
  border: 1px solid var(--c-line);
  border-radius: 12px;
  font-size: 11.5px;
  font-weight: 500;
  color: var(--c-fg);
}
.tool-chip::before {
  content: '';
  width: 6px; height: 6px;
  background: var(--c-eco);
  border-radius: 50%;
}

/* Cumul session */
.composer__session {
  max-width: var(--composer-max);
  margin: var(--sp-3) auto 0;
  padding-top: var(--sp-3);
  border-top: 1px dashed var(--c-line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  font-family: var(--f-mono);
  font-size: var(--fs-xs);
  color: var(--c-fg-subtle);
}
.session-stats {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.session-label {
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--c-fg-subtle);
  font-size: 10px;
}
.session-stats .stat {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.session-stats .stat strong {
  color: var(--c-fg);
  font-weight: 500;
}
.session-stats .stat-co2 strong { color: var(--c-eco); }
.session-stats .stat-co2.is-orange strong { color: var(--c-warn); }
.session-stats .stat-co2.is-red strong    { color: var(--c-danger); }

.composer__attribution { color: var(--c-fg-subtle); }
.composer__attribution a {
  color: var(--c-fg-muted);
  border-bottom: 1px dotted var(--c-line-strong);
  transition: color var(--d-fast);
}
.composer__attribution a:hover { color: var(--c-accent); }

.meta-sep {
  color: var(--c-line-strong);
}


/* ─── CUMULS 3 NIVEAUX (Livraison 2c) ─────────────────────────────────────
   .composer__cumuls contient 3 lignes empilées :
     1. .cumul-conversation : cumul session courante
     2. .cumul-day          : cumul aujourd'hui
     3. .composer__attribution-line : "Propulsé par Arkensai"
   Toutes en monospace discret, séparées par des filets fins.
   ─────────────────────────────────────────────────────────────────────────── */

.composer__cumuls {
  max-width: var(--composer-max);
  margin: var(--sp-3) auto 0;
  padding-top: var(--sp-3);
  border-top: 1px dashed var(--c-line);
  font-family: var(--f-mono);
  font-size: var(--fs-xs);
  color: var(--c-fg-subtle);
}

.cumul-line {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: 4px 0;
}

.cumul-line + .cumul-line {
  border-top: 1px dotted var(--c-line);
}

.cumul-label {
  display: inline-block;
  min-width: 100px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--c-fg-muted);
  font-size: 10px;
  font-weight: 500;
}

.cumul-conversation .cumul-label {
  color: var(--c-accent);
}

.cumul-line .stat {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.cumul-line .stat strong {
  color: var(--c-fg);
  font-weight: 500;
}

/* Stats placeholders (€/CO₂e en attente du câblage backend) */
.cumul-line .stat-placeholder {
  opacity: 0.55;
  font-style: italic;
  cursor: help;
}
.cumul-line .stat-placeholder strong {
  color: var(--c-fg-subtle);
  font-weight: 400;
}

/* CO₂e en eco vert */
.cumul-line .stat-co2 strong { color: var(--c-eco); }
.cumul-line .stat-co2.stat-placeholder strong { color: var(--c-fg-subtle); }

/* Ligne attribution finale, alignée à droite */
.composer__attribution-line {
  padding-top: var(--sp-2);
  padding-bottom: 2px;
  text-align: right;
  font-size: 10.5px;
}

/* Patch valeur réelle vs placeholder pour la meta-detailed dans la bulle */
.msg__meta-detailed .meta-real {
  color: var(--c-fg);
  font-weight: 500;
  font-style: normal;
  opacity: 1;
}


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 11. PANNEAU OUTILS & MCP
   ╚═══════════════════════════════════════════════════════════════════════════ */

.tools-panel-overlay {
  position: absolute;
  inset: 0;
  background: rgba(15, 8, 9, 0.35);
  z-index: var(--z-overlay);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--d-base);
}
.tools-panel-overlay.open {
  opacity: 1;
  pointer-events: auto;
}

.tools-panel {
  position: absolute;
  top: 0; right: 0; bottom: 0;
  width: var(--tools-w);
  background: var(--c-bg-elevated);
  border-left: 1px solid var(--c-line);
  display: flex;
  flex-direction: column;
  z-index: var(--z-tools-panel);
  box-shadow: -16px 0 48px -16px rgba(15, 8, 9, 0.15);
  transform: translateX(100%);
  transition: transform var(--d-base) var(--ease-out);
}
.tools-panel.open {
  transform: translateX(0);
}

.tools-panel__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-4);
  border-bottom: 1px solid var(--c-line);
}

.tools-panel__title {
  font-family: var(--f-display);
  font-size: var(--fs-lg);
  font-weight: 400;
  color: var(--c-fg);
}
.tools-panel__title em { font-style: italic; }

.tools-panel__body {
  flex: 1;
  overflow-y: auto;
  padding: var(--sp-3) 0;
}

.tools-section {
  padding: var(--sp-3) var(--sp-4);
}
.tools-section + .tools-section {
  border-top: 1px solid var(--c-line);
}

.tools-section__label {
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--c-fg-subtle);
  margin-bottom: var(--sp-2);
}

.field-group {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.field-select,
select.field-select,
input.field-select {
  width: 100%;
  padding: 8px var(--sp-3);
  background: var(--c-bg);
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  font-size: var(--fs-sm);
  color: var(--c-fg);
  outline: 0;
  transition: border-color var(--d-fast), box-shadow var(--d-fast);
}
.field-select:focus {
  border-color: var(--c-accent);
  box-shadow: 0 0 0 3px var(--c-accent-soft);
}

/* Upload zone fichiers */
.upload-zone-compact {
  position: relative;
  padding: var(--sp-3);
  border: 1px dashed var(--c-line-strong);
  border-radius: var(--radius);
  text-align: center;
  cursor: pointer;
  transition: all var(--d-fast);
}
.upload-zone-compact:hover {
  border-color: var(--c-accent);
  background: var(--c-accent-soft);
}
.upload-zone-compact.drag-over {
  border-color: var(--c-accent);
  background: var(--c-accent-soft);
}
.upload-zone-compact input[type="file"] {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}
.uz-label {
  font-size: var(--fs-sm);
  color: var(--c-fg-muted);
}
.uz-label span {
  color: var(--c-accent);
  text-decoration: underline;
}

.url-input-compact {
  width: 100%;
  padding: 8px var(--sp-3);
  background: var(--c-bg);
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  font-size: var(--fs-sm);
  color: var(--c-fg);
  outline: 0;
}
.url-input-compact:focus {
  border-color: var(--c-accent);
  box-shadow: 0 0 0 3px var(--c-accent-soft);
}

/* Previews (vignettes fichiers uploadés générées par script_v42) */
#file-previews:not(:empty) {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}

/* Carré vignette — 80x80 fixe, contenu rogné en cover */
.file-thumb {
  position: relative;
  width: 80px;
  height: 80px;
  border-radius: var(--radius);
  border: 1px solid var(--c-line);
  background: var(--c-bg-muted);
  overflow: hidden;
  flex-shrink: 0;
  transition: border-color var(--d-fast), transform var(--d-fast);
}
.file-thumb:hover {
  border-color: var(--c-line-strong);
  transform: translateY(-1px);
}

/* L'image qui remplit la vignette */
.file-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Variante pour docs non-image (audio, PDF, doc) */
.file-thumb.file-doc {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--c-bg-elevated);
}

.file-doc-icon {
  font-size: 28px;
  line-height: 1;
  color: var(--c-fg-muted);
}

/* Nom du fichier en surimpression en bas de la vignette */
.file-thumb .file-name {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 2px 6px;
  background: linear-gradient(to top, rgba(15, 8, 9, 0.85) 0%, rgba(15, 8, 9, 0.4) 70%, transparent 100%);
  color: #FFFFFF;
  font-family: var(--f-mono);
  font-size: 9.5px;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  letter-spacing: 0.02em;
}

/* Pour les vignettes doc (fond clair), nom en couleur sombre */
.file-thumb.file-doc .file-name {
  background: transparent;
  position: static;
  padding: var(--sp-1) 4px 0;
  color: var(--c-fg-muted);
  text-align: center;
}

/* Bouton croix de suppression en haut droite */
.file-thumb .remove-file {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: rgba(15, 8, 9, 0.7);
  color: #FFFFFF;
  font-size: 14px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  transition: background var(--d-fast);
  z-index: 2;
}
.file-thumb .remove-file:hover {
  background: var(--c-danger);
}

/* Quota dans le panneau outils */
.quota-num {
  font-family: var(--f-display);
  font-size: var(--fs-2xl);
  font-weight: 400;
  color: var(--c-fg);
}
.quota-num.warn  { color: var(--c-warn); }
.quota-num.alert { color: var(--c-danger); }


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 12. MODAL AGENTS PERSONNELS (compat legacy)
   ╚═══════════════════════════════════════════════════════════════════════════ */

.pa-modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(15, 8, 9, 0.5);
  z-index: var(--z-modal-overlay);
  align-items: center;
  justify-content: center;
}
.pa-modal-overlay.visible { display: flex; }
/* v2.25 (2026-07-03) — Support classe .open utilisée par core.js openProfileModal().
   Correction d'un mismatch historique JS/CSS depuis la migration vers le design
   system Arkensai. Les 2 classes fonctionnent (rétro-compat totale). */
.pa-modal-overlay.open    { display: flex; }

.pa-modal {
  background: var(--c-bg-elevated);
  border-radius: var(--radius-lg);
  width: 720px;
  max-width: calc(100vw - var(--sp-8));
  max-height: 85vh;
  max-height: 85dvh;  /* v2.15 : dvh pour respecter la zone visible dynamique */
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-lg);
}

.pa-modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--c-line);
}
.pa-modal-title {
  font-family: var(--f-display);
  font-size: var(--fs-lg);
  font-weight: 500;
  color: var(--c-fg);
}
.pa-modal-sub {
  font-size: var(--fs-sm);
  color: var(--c-fg-muted);
  margin-top: 2px;
}
.pa-modal-close {
  background: transparent;
  font-size: 22px;
  color: var(--c-fg-muted);
  padding: 0 var(--sp-2);
  cursor: pointer;
}
.pa-modal-close:hover { color: var(--c-fg); }

.pa-modal-body {
  padding: var(--sp-4) var(--sp-5);
  overflow-y: auto;
}

.pa-form,
.pa-docs-panel {
  display: none;
  background: var(--c-bg-muted);
  border-radius: var(--radius);
  padding: var(--sp-4);
  margin-top: var(--sp-3);
}
.pa-form.visible { display: block; }
/* v2.26 (2026-07-04) — Support classe .open utilisée par core.js openPaForm().
   Même bug structurel que .pa-modal-overlay (fixé en v2.25). Les 2 classes
   fonctionnent (rétro-compat totale). Débloque le clic "+ Créer un agent". */
.pa-form.open    { display: block; }

.pa-form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
  margin-bottom: var(--sp-3);
}
.pa-form-group label {
  display: block;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--c-fg-muted);
  margin-bottom: 4px;
}
.pa-form-group input,
.pa-form-group select,
.pa-form-group textarea {
  width: 100%;
  padding: 8px var(--sp-3);
  background: var(--c-bg);
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  font-size: var(--fs-sm);
  color: var(--c-fg);
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 8px var(--sp-3);
  border-radius: var(--radius);
  font-size: var(--fs-sm);
  font-weight: 500;
  transition: all var(--d-fast);
  cursor: pointer;
}
.btn-primary {
  background: var(--c-accent);
  color: var(--c-accent-fg);
}
.btn-primary:hover { background: var(--c-accent-hover); }
.btn-ghost {
  background: transparent;
  color: var(--c-fg-muted);
  border: 1px solid var(--c-line);
}
.btn-ghost:hover {
  background: var(--c-bg-hover);
  color: var(--c-fg);
}
.btn-sm { font-size: 12px; padding: 6px var(--sp-3); }
.btn-xs { font-size: 11px; padding: 4px var(--sp-2); }


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 12.5 ENTRY POINTS DU COMPOSER (v9.2 - Livraison 1) + POPOVERS
   ╚═══════════════════════════════════════════════════════════════════════════
   Les 4 boutons (Agent · Documents · Mes agents · Connecteurs) remplacent
   l'ancien gros panneau ⊕. Chaque bouton ouvre une popover ancrée au-dessus.
   ─────────────────────────────────────────────────────────────────────────── */

/* Diviseur fin entre groupes dans la barre du composer */
.composer__divider {
  width: 1px;
  height: 18px;
  background: var(--c-line);
  margin: 0 4px;
  flex-shrink: 0;
}

/* Bouton d'un entry point */
.entry-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: var(--radius);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--c-fg-muted);
  background: transparent;
  border: 1px solid transparent;
  transition: all var(--d-fast);
  cursor: pointer;
  white-space: nowrap;
}
.entry-btn:hover {
  background: var(--c-bg-hover);
  color: var(--c-fg);
}
.entry-btn .icon {
  color: var(--c-fg-subtle);
  transition: color var(--d-fast);
}
.entry-btn:hover .icon {
  color: var(--c-accent);
}

/* État actif (popover ouverte) */
.entry-btn.is-active {
  background: var(--c-accent-soft);
  border-color: var(--c-accent);
  color: var(--c-accent);
}
.entry-btn.is-active .icon { color: var(--c-accent); }

/* État "a une sélection courante" — gris légèrement plus marqué + label visible */
.entry-btn.has-selection {
  background: var(--c-bg-muted);
  color: var(--c-fg);

  /* v2.24 (2026-07-03) — FIX RÉEL débordement composer
     Override du .composer__bar > * { flex-shrink: 0 } de la ligne ~1863
     pour permettre au bouton (avec son indicator interne) de rétrécir
     lorsque la barre manque de place. Sans ce override, le .entry-btn
     garde sa largeur intrinsèque et pousse le btn-send hors du viewport
     via l'overflow-x:auto silencieux (scrollbar-width:none) du parent. */
  flex-shrink: 1;
  min-width: 0;
  max-width: 220px;
}
.entry-btn.has-selection .icon { color: var(--c-accent); }
.entry-btn.has-selection .entry-btn__label {
  /* Le label du mode ("Documents", "Agent", "Mes agents"…) reste toujours
     visible, jamais tronqué — c'est l'ancrage de compréhension pour l'user.
     Seul .entry-btn__indicator (le nom de collection) est susceptible d'être
     tronqué via ses propres règles ellipsis. */
  flex-shrink: 0;
  white-space: nowrap;
}

/* ─── État MODE COURANT (v9.8 / 2e) ─────────────────────────────────────
   Marque visuellement le bouton du mode en cours. Subtil mais distinct
   des autres états (pas aussi marqué que .is-active qui = popover ouverte).
   ────────────────────────────────────────────────────────────────────── */
.entry-btn.is-current {
  background: var(--c-bg-muted);
  border-color: var(--c-line-strong);
  color: var(--c-fg);
  font-weight: 500;
}
.entry-btn.is-current .icon { color: var(--c-accent); }
/* Le mode courant + popover ouverte = priorité à is-active (accent fort) */
.entry-btn.is-current.is-active {
  background: var(--c-accent-soft);
  border-color: var(--c-accent);
}

/* ─── État DÉSACTIVÉ (mode dont la liste est vide) ───────────────────────
   Bouton grisé non cliquable, mais reste visible pour signaler que la
   feature existe (avec tooltip explicatif au survol).
   ────────────────────────────────────────────────────────────────────── */
.entry-btn.is-disabled {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: auto; /* on garde le pointer-events pour le tooltip */
}
.entry-btn.is-disabled:hover {
  background: transparent;
  border-color: transparent;
  color: var(--c-fg-muted);
}
.entry-btn.is-disabled .icon { color: var(--c-fg-subtle); }

.entry-btn__label {
  font-family: var(--f-sans);
}

/* Indicateur sous le label : label tronqué de la sélection courante */
.entry-btn__indicator {
  display: inline-block;
  font-family: var(--f-mono);
  font-size: 10.5px;
  font-weight: 400;
  color: var(--c-accent);
  letter-spacing: 0;
  padding-left: 6px;
  border-left: 1px solid var(--c-line);
  margin-left: 2px;

  /* v2.24 (2026-07-03) — Limitation largeur AGRESSIVE pour laisser la
     place au reste du composer (surtout btn-send).
     v2.23 mettait max-width: 120px, insuffisant. v2.24 → 80px.
     Combiné à flex-shrink: 1 sur .entry-btn.has-selection (parent),
     l'ensemble bouton+indicator rétrécit correctement. */
  max-width: 80px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
  flex-shrink: 1;
  min-width: 0;
}
.entry-btn__indicator:empty {
  display: none;
}

/* ─── BOUTON OUTILS MOBILE (Livraison 2g — v2.16) ──────────────────────────
   Bouton qui remplace les 6 entry-btn en mobile. Affiche l'icône du mode
   courant + label "Outils" + chevron. Au clic, ouvre #popover-mode-mobile.
   Caché par défaut (desktop), affiché par le media query mobile.
   ─────────────────────────────────────────────────────────────────────── */
.mobile-mode-btn {
  display: none; /* desktop : caché. Mobile : display:inline-flex (media query). */
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: var(--c-bg-muted);
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-size: 13px;
  font-weight: 500;
  color: var(--c-fg);
  cursor: pointer;
  flex-shrink: 0;
  white-space: nowrap;
  transition: all var(--d-fast);
}
.mobile-mode-btn:hover {
  background: var(--c-bg-hover);
  border-color: var(--c-line);
}
.mobile-mode-btn.is-active {
  background: var(--c-accent-soft);
  border-color: var(--c-accent);
  color: var(--c-accent);
}
.mobile-mode-btn__icon {
  color: var(--c-accent);
  flex-shrink: 0;
}
.mobile-mode-btn__chevron {
  color: var(--c-fg-subtle);
  width: 12px;
  height: 12px;
}
.mobile-mode-btn.is-active .mobile-mode-btn__chevron {
  color: var(--c-accent);
}

/* ─── POPOVERS ────────────────────────────────────────────────────────── */
.popover {
  position: fixed;
  width: 360px;
  max-width: calc(100vw - 24px);
  max-height: 480px;
  background: var(--c-bg-elevated);
  border: 1px solid var(--c-line-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  z-index: var(--z-modal);
  display: none;
  flex-direction: column;
  overflow: hidden;
  transform-origin: bottom center;
  animation: popover-in var(--d-fast) var(--ease-out);
}
.popover.open {
  display: flex;
}
.popover.popover--below {
  transform-origin: top center;
}

@keyframes popover-in {
  from { opacity: 0; transform: translateY(6px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0)  scale(1); }
}

.popover__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--c-line);
  flex-shrink: 0;
}

.popover__title {
  font-family: var(--f-display);
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--c-fg);
  letter-spacing: -0.01em;
}
.popover__title em {
  font-style: italic;
  color: var(--c-accent);
}

.popover__search {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--c-line);
  background: var(--c-bg);
  flex-shrink: 0;
}
.popover__search .icon {
  color: var(--c-fg-subtle);
}
.popover__search-input {
  flex: 1;
  background: transparent;
  border: 0;
  outline: 0;
  font-size: var(--fs-sm);
  font-family: var(--f-sans);
  color: var(--c-fg);
}
.popover__search-input::placeholder { color: var(--c-fg-subtle); }

.popover__list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: var(--sp-1);
}

.popover__item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-sm);
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
  transition: background var(--d-fast);
  color: var(--c-fg);
}
.popover__item:hover {
  background: var(--c-bg-hover);
}
.popover__item.is-active {
  background: var(--c-accent-soft);
  color: var(--c-accent);
}
.popover__item.is-active .popover__item-name {
  color: var(--c-accent);
  font-weight: 500;
}

.popover__item-icon {
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--c-bg-muted);
  border-radius: var(--radius-sm);
  font-size: 16px;
  flex-shrink: 0;
}

.popover__item-main {
  flex: 1;
  min-width: 0;
}

.popover__item-name {
  font-size: 13px;
  font-weight: 500;
  color: var(--c-fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.popover__item-hint {
  font-size: 11.5px;
  color: var(--c-fg-muted);
  margin-top: 1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.popover__item-check {
  color: var(--c-accent);
  flex-shrink: 0;
}

/* Statut MCP (Connecté / Non connecté) */
.popover__item-status {
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  padding: 2px 6px;
  border-radius: 3px;
  background: var(--c-bg-muted);
  color: var(--c-fg-subtle);
  flex-shrink: 0;
}
.popover__item-status--ok {
  background: rgba(45, 122, 59, 0.12);
  color: var(--c-eco);
}

.popover__empty {
  padding: var(--sp-6) var(--sp-4);
  text-align: center;
  font-size: var(--fs-sm);
  color: var(--c-fg-muted);
  line-height: var(--lh-loose);
}

.popover__footer {
  padding: var(--sp-2) var(--sp-3);
  border-top: 1px solid var(--c-line);
  flex-shrink: 0;
}
.popover__footer .btn {
  width: 100%;
  justify-content: center;
}

.popover__sublist {
  padding: var(--sp-2) var(--sp-3) var(--sp-3);
  border-top: 1px dashed var(--c-line);
  flex-shrink: 0;
}
.popover__sublist-label {
  font-family: var(--f-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--c-fg-subtle);
  margin-bottom: var(--sp-2);
}


/* ─── POPOVER MODÈLE (Livraison 2f) ─────────────────────────────────────────
   Popover spécifique pour le choix du modèle, avec tabs Auto/Manuel en haut
   et liste filtrable en bas (en mode Manuel).
   ─────────────────────────────────────────────────────────────────────────── */

.popover--model {
  width: 380px;
  max-width: calc(100vw - 24px);
}

/* Tabs Auto / Manuel — sous l'en-tête */
.popover-model__mode {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  padding: var(--sp-3) var(--sp-3) 0;
  flex-shrink: 0;
}

.mode-tab {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: var(--sp-2) var(--sp-3);
  background: var(--c-bg);
  border: 1px solid var(--c-line);
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-align: left;
  transition: all var(--d-fast);
}
.mode-tab:hover {
  background: var(--c-bg-hover);
  border-color: var(--c-line-strong);
}
.mode-tab.is-active {
  background: var(--c-accent-soft);
  border-color: var(--c-accent);
}
.mode-tab__title {
  font-family: var(--f-display);
  font-style: italic;
  font-weight: 500;
  font-size: 14px;
  color: var(--c-fg);
}
.mode-tab.is-active .mode-tab__title {
  color: var(--c-accent);
}
.mode-tab__hint {
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--c-fg-subtle);
}
.mode-tab.is-active .mode-tab__hint {
  color: var(--c-accent);
  opacity: 0.85;
}

/* Pavé informatif en mode Auto */
.popover-model__auto-info {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-4);
  margin: var(--sp-3);
  background: var(--c-bg-muted);
  border-radius: var(--radius-sm);
  border-left: 2px solid var(--c-accent);
}
.popover-model__auto-info .icon {
  color: var(--c-accent);
  flex-shrink: 0;
  margin-top: 1px;
}
.popover-model__auto-text {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--c-fg-muted);
}
.popover-model__auto-text strong {
  display: block;
  color: var(--c-fg);
  font-weight: 500;
  margin-bottom: 4px;
  font-size: 13px;
}

/* Wrap liste modèles (mode Manuel) */
.popover-model__list-wrap {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1;
}


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 13. UTILITAIRES — éléments legacy preserved
   ╚═══════════════════════════════════════════════════════════════════════════
   Certains éléments générés par script_v42 ont des classes spécifiques.
   On ajoute ici un minimum vital pour qu'ils ne s'affichent pas cassés.
   ─────────────────────────────────────────────────────────────────────────── */

.card {
  background: var(--c-bg-elevated);
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  padding: var(--sp-4);
}
.card-title {
  font-family: var(--f-display);
  font-size: var(--fs-lg);
  font-weight: 500;
  margin-bottom: var(--sp-2);
}

.output-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--sp-3);
}

/* Sessions sidebar items (gérés par script_v42) */
.session-item,
.sidebar-sessions > div {
  padding: 8px var(--sp-2);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background var(--d-fast);
  font-size: var(--fs-sm);
}
.session-item:hover,
.sidebar-sessions > div:hover { background: var(--c-bg-hover); }

/* Modèle mode toggle (caché par défaut en v9, on garde les styles si réaffiché) */
.model-mode-switch {
  position: relative;
  display: inline-block;
  width: 32px;
  height: 18px;
}
.model-mode-switch input { opacity: 0; width: 0; height: 0; }
.model-mode-slider {
  position: absolute;
  inset: 0;
  background: var(--c-bg-muted);
  border-radius: 9px;
  transition: background var(--d-fast);
  cursor: pointer;
}
.model-mode-slider::before {
  content: '';
  position: absolute;
  left: 2px; top: 2px;
  width: 14px; height: 14px;
  background: var(--c-bg-elevated);
  border-radius: 50%;
  transition: transform var(--d-fast);
}
.model-mode-switch input:checked + .model-mode-slider {
  background: var(--c-accent);
}
.model-mode-switch input:checked + .model-mode-slider::before {
  transform: translateX(14px);
}

/* Web search toggle — conservé fonctionnellement dans le DOM pour que
   script_v42 puisse lire/écrire .checked (activation de la recherche web),
   mais jamais visible à l'utilisateur. L'état "web search actif" est
   représenté visuellement via les chips actifs sous le composer.
   Le !important est nécessaire car script_v42 force style.display='flex'
   en inline quand la task le requiert.
   ───────────────────────────────────────────────────────────────────── */
.web-search-row,
#web-search-row,
#web-search-toggle,
#web-search-picto {
  display: none !important;
}


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 13.5 PANNEAU RSE — Stratégie 4 (Livraison 2d)
   ╚═══════════════════════════════════════════════════════════════════════════
   Panneau fixe à droite, centré verticalement, qui présente l'empreinte
   carbone éditoriale (Hero Fraunces + équivalences + stats compactes).
   Collapse en mini-pill via #rse-panel-collapse / #rse-mini-pill.

   Largeurs paramétrables :
     --rse-panel-w       : 240px (déployé)
     --rse-panel-w-mini  :  56px (replié)

   Le contenu principal (#app-content > main + composer-wrap) reçoit un
   padding-right dynamique selon l'état du panneau (cf. body.has-rse-panel).
   Masqué automatiquement sous 1100px (responsive section 14).
   ─────────────────────────────────────────────────────────────────────────── */

:root {
  --rse-panel-w:        240px;
  --rse-panel-w-mini:    56px;
  --rse-panel-margin:    12px;
}

/* v2.8 : padding-right SUPPRIMÉ.
   Raison : le panneau RSE est en position:fixed, donc il ne prend pas de
   place dans le flux normal. Le padding-right créait un espace vide inutile
   entre le scrollbar du thread et le panneau RSE.
   Solution : thread + composer (max-width 1100px) centrés sur toute la
   largeur. Le panneau RSE flotte à droite SANS toucher au layout.
   Si le thread devait dépasser sous le panneau RSE en très grande fenêtre,
   le panneau a un fond opaque qui couvre proprement.
   ─────────────────────────────────────────────────────────────────────── */
/* body.has-rse-panel #app-content { (anciennement padding-right ici) } */

/* ─── Panneau déployé ─── */
.rse-panel {
  position: fixed;
  top: 50%;
  right: var(--rse-panel-margin);
  transform: translateY(-50%);
  width: var(--rse-panel-w);
  max-height: calc(100vh - var(--header-h, 56px) - 64px);
  overflow-y: auto;
  background: var(--c-bg-elevated);
  border: 1px solid var(--c-line);
  border-radius: var(--radius-md);
  padding: var(--sp-4) var(--sp-4) var(--sp-3);
  z-index: var(--z-sticky, 30);
  transition: opacity 0.25s ease, transform 0.25s ease;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  box-shadow: var(--shadow-sm);
}

body.rse-collapsed .rse-panel {
  opacity: 0;
  pointer-events: none;
  transform: translateY(-50%) scale(0.94);
}

/* En-tête : titre + bouton collapse */
.rse-panel__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--c-line);
  flex-shrink: 0;
}
.rse-panel__title {
  font-family: var(--f-display);
  font-style: italic;
  font-weight: 500;
  font-size: var(--fs-md);
  color: var(--c-fg);
  letter-spacing: -0.01em;
}
.rse-panel__collapse-btn {
  width: 24px;
  height: 24px;
  background: transparent;
  border: 0;
  color: var(--c-fg-subtle);
  cursor: pointer;
  border-radius: var(--radius-sm);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background var(--d-fast), color var(--d-fast);
}
.rse-panel__collapse-btn:hover {
  background: var(--c-bg-hover);
  color: var(--c-fg);
}

/* Bloc Hero : grand chiffre éditorial */
.rse-hero {
  padding: var(--sp-1) 0 var(--sp-2);
}
.rse-hero__num {
  font-family: var(--f-display);
  font-weight: 500;
  font-size: 52px;
  line-height: 1;
  color: var(--c-eco);
  letter-spacing: -0.03em;
}
.rse-hero__num em {
  font-style: italic;
  display: inline-block;
  transition: transform 0.3s ease;
}

/* Animation "pulse rouge" lors d'un incrément */
.rse-hero__num em.is-pulsing {
  animation: rse-pulse 0.6s ease;
}
@keyframes rse-pulse {
  0%   { color: var(--c-eco); transform: scale(1); }
  30%  { color: var(--c-accent); transform: scale(1.08); }
  100% { color: var(--c-eco); transform: scale(1); }
}

.rse-hero__unit {
  font-family: var(--f-sans);
  font-size: 13px;
  color: var(--c-fg-muted);
  margin-left: 6px;
  display: inline-block;
  vertical-align: 12px;
  font-weight: 400;
}
.rse-hero__label {
  font-family: var(--f-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--c-fg-subtle);
  margin-top: 4px;
}

/* Liste des équivalences concrètes */
.rse-equiv-list {
  margin: 0;
  padding: var(--sp-3) 0 0;
  border-top: 1px dashed var(--c-line);
  list-style: none;
  flex-shrink: 0;
}
.rse-equiv-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 6px 0;
  font-size: 12.5px;
  color: var(--c-fg-muted);
  line-height: 1.4;
}
.rse-equiv-item__icon {
  width: 28px;
  height: 28px;
  background: color-mix(in srgb, var(--c-eco) 12%, transparent);
  color: var(--c-eco);
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.rse-equiv-item__icon .icon {
  width: 14px;
  height: 14px;
}
.rse-equiv-item__text strong {
  color: var(--c-fg);
  font-weight: 500;
}

/* Stats footer (Conversation · Aujourd'hui · Coûts) */
.rse-panel__stats {
  margin-top: auto;
  padding-top: var(--sp-3);
  border-top: 1px solid var(--c-line);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 12px;
  flex-shrink: 0;
}
.rse-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.rse-stat__label {
  font-family: var(--f-mono);
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--c-fg-subtle);
}
.rse-stat__value {
  font-family: var(--f-mono);
  font-size: 12px;
  color: var(--c-fg);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rse-stat__value .ph {
  color: var(--c-fg-subtle);
  font-style: italic;
  font-weight: 400;
}

/* ─── v2.18 : Bloc stats Option C — Hiérarchie premium ──────────────────────
   Remplace les anciens .rse-stat dans le panneau (toujours conservés pour
   compatibilité éventuelle). Style aérien aligné avec le hero CO2. */
.rse-panel__stats--c {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
  padding-top: var(--sp-3);
  margin-top: var(--sp-3);
  border-top: 1px solid var(--c-line);
}
.rse-stats-c__header {
  font-family: var(--f-mono);
  font-size: 9px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--c-fg-subtle);
  text-align: center;
  margin-bottom: 4px;
}
.rse-stat-c {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 0 4px;
  gap: 12px;
}
.rse-stat-c__main {
  display: flex;
  align-items: baseline;
  gap: 4px;
}
.rse-stat-c__value {
  font-family: var(--f-serif);
  font-style: italic;
  font-weight: 400;
  font-size: 26px;
  color: var(--c-fg);
  line-height: 1;
}
.rse-stat-c__unit {
  font-family: var(--f-mono);
  font-size: 10px;
  color: var(--c-fg-muted);
}
.rse-stat-c__label {
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--c-fg-subtle);
  text-align: right;
}
.rse-stats-c__divider {
  border-top: 1px dashed var(--c-line);
  margin: 4px 0;
}
.rse-stat-c--accent .rse-stat-c__value {
  color: var(--c-accent);
  font-weight: 500;
}
.rse-stat-c--accent .rse-stat-c__value .ph {
  color: var(--c-accent);
  font-style: italic;
  font-weight: 400;
}

/* ─── v2.18 : Mode "bottom sheet" mobile pour le panneau RSE ────────────────
   Activé via classe .is-open-mobile sur #rse-panel (posée par le bouton 🌿
   du header en mobile). Override la règle display:none du breakpoint 1100px. */
@media (max-width: 1100px) {
  .rse-panel.is-open-mobile {
    display: flex !important;
    flex-direction: column;
    position: fixed !important;
    left: 0 !important;
    right: 0 !important;
    top: auto !important;
    bottom: env(safe-area-inset-bottom, 0) !important;
    transform: none !important;
    width: 100% !important;
    max-width: 100% !important;
    max-height: calc(85dvh - env(safe-area-inset-bottom, 0px));
    padding-bottom: calc(var(--sp-4) + env(safe-area-inset-bottom, 0px));
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    border-bottom: 0;
    border-left: 0;
    border-right: 0;
    overflow-y: auto;
    z-index: var(--z-modal);
    animation: rse-sheet-in 0.25s ease;
  }
  @keyframes rse-sheet-in {
    from { opacity: 0; transform: translateY(100%) !important; }
    to   { opacity: 1; transform: none !important; }
  }
  /* Backdrop sombre derrière le sheet */
  .rse-sheet-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(15, 8, 9, 0.45);
    z-index: calc(var(--z-modal) - 1);
    animation: backdrop-in 0.2s ease;
  }
  @keyframes backdrop-in {
    from { opacity: 0; }
    to   { opacity: 1; }
  }
  /* Sur mobile, masquer le bouton collapse du panneau (sans intérêt en sheet) */
  .rse-panel.is-open-mobile .rse-panel__collapse-btn {
    display: none;
  }
}

/* ─── Mini-pill (état replié) ─── */
.rse-mini-pill {
  position: fixed;
  top: 50%;
  right: var(--rse-panel-margin);
  transform: translateY(-50%);
  width: var(--rse-panel-w-mini);
  background: var(--c-bg-elevated);
  border: 1px solid var(--c-line);
  border-radius: 30px;
  padding: 14px 6px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  cursor: pointer;
  z-index: var(--z-sticky, 30);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease, background var(--d-fast);
}
body.rse-collapsed .rse-mini-pill {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(-50%) scale(1);
}
.rse-mini-pill:hover {
  background: var(--c-bg-hover);
}
.rse-mini-pill__num {
  font-family: var(--f-display);
  font-weight: 500;
  font-style: italic;
  font-size: 22px;
  line-height: 1;
  color: var(--c-eco);
}
.rse-mini-pill__num em {
  font-style: italic;
}
.rse-mini-pill__num em.is-pulsing {
  animation: rse-pulse 0.6s ease;
}
.rse-mini-pill__unit {
  font-family: var(--f-mono);
  font-size: 8.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--c-fg-subtle);
  white-space: nowrap;
}
.rse-mini-pill__arrow {
  margin-top: 2px;
  color: var(--c-fg-subtle);
}
.rse-mini-pill__arrow .icon {
  width: 14px;
  height: 14px;
}


/* ─────────────────────────────────────────────────────────────────────────
   Mode ICÔNE PROGRESSIF (v2.12)
   ─────────────────────────────────────────────────────────────────────────
   Quand la fenêtre se réduit, on cache progressivement les labels textuels
   pour garder TOUS les boutons accessibles :
     - ≤ 1024px : labels entry-btn cachés → mode icône pour les 6 modes
     - ≤  640px : label du modèle aussi caché → mode mini intégral
   Le bouton envoyer reste TOUJOURS visible à droite (poussé par le spacer).
   ───────────────────────────────────────────────────────────────────────── */

/* v2.24 (2026-07-03) — ≤ 1400px : indicator réduit à 50px pour laisser
   plus de place au reste du composer.
   Note : à ≤1024px, l'indicator est TOTALEMENT masqué (règle plus bas) —
   ce média intermédiaire ne s'applique donc que pour 1024px < w ≤ 1400px. */
@media (max-width: 1400px) {
  .entry-btn__indicator {
    max-width: 50px;
  }
}

/* ≤ 1024px : labels des entry-btn cachés, icônes seules */
@media (max-width: 1024px) {
  .entry-btn__label {
    display: none;
  }
  .entry-btn {
    padding: 6px 8px;
    width: 32px;
    height: 32px;
    justify-content: center;
  }
  .entry-btn__indicator {
    display: none !important;
  }
}

/* ≤ 640px : label du modèle aussi caché */
@media (max-width: 640px) {
  #model-badge,
  .composer__model-hint {
    display: none;
  }
  .composer__model {
    width: 32px;
    height: 32px;
    padding: 0;
    justify-content: center;
    max-width: 32px;
  }
}


/* ╔═══════════════════════════════════════════════════════════════════════════
   ║ 14. RESPONSIVE
   ╚═══════════════════════════════════════════════════════════════════════════ */

/* Tablette ≤ 1024px */
@media (max-width: 1024px) {
  .tools-panel {
    width: min(var(--tools-w), 90vw);
  }
}

/* Tablette / petit laptop ≤ 1100px — masquer le panneau RSE droit */
@media (max-width: 1100px) {
  .rse-panel,
  .rse-mini-pill {
    display: none !important;
  }
}

/* Mobile ≤ 640px */
@media (max-width: 640px) {

  /* Header : cacher le sous-titre, garder l'essentiel */
  .brand__sep,
  .brand__sub { display: none; }

  .user-chip__info { display: none; }
  .user-chip { padding: 4px; }

  /* Sidebar : prend toute la largeur en mobile */
  .sidebar { width: 100%; }

  /* Composer : padding réduit */
  .composer-wrap { padding: var(--sp-2) var(--sp-3); }

  /* v2.16 : En mobile, on remplace les 6 entry-btn par UN seul bouton
     "Outils" qui ouvre une popover de choix. Plus besoin d'optimiser les
     gaps/paddings extrêmement comme en v2.15.
     ─────────────────────────────────────────────────────────────────── */
  .composer__bar {
    gap: 6px;           /* gap normal (suffisant maintenant) */
    padding: var(--sp-2);
  }
  /* Cacher les 6 entry-btn en mobile (Conv, Image, Agent, Docs, Personal, MCP) */
  .composer__bar .entry-btn {
    display: none;
  }
  /* Cacher aussi le divider qui les précédait */
  .composer__bar .composer__divider:nth-of-type(2) {
    display: none;
  }
  /* Afficher le bouton Outils mobile */
  .mobile-mode-btn {
    display: inline-flex;
  }

  /* Empty state : 1 colonne au lieu de 2 */
  .shortcut-grid {
    grid-template-columns: 1fr;
    width: 100%;
    max-width: 400px;
  }

  /* v2.19 : Fix tronquage du greeting sur mobile.
     `.empty-state` est en flex column avec justify-content:center, ce qui
     centre le contenu verticalement. Quand le contenu est PLUS GRAND que la
     hauteur disponible (greeting + lede + 6 cards + composer fixed en bas),
     le centrage fait dépasser le haut → "Bonjour [prénom]" tronqué.
     Fix : flex-start + padding-top safe-area pour respecter la notch. */
  .empty-state {
    justify-content: flex-start;
    padding-top: calc(var(--sp-6) + env(safe-area-inset-top, 0px));
    padding-bottom: var(--sp-8);
  }

  .empty-state__greeting { font-size: 36px; }

  /* Composer model : masquer le hint */
  .composer__model-hint { display: none; }
  .composer__model { max-width: 180px; font-size: 12.5px; }

  /* Entry buttons : masquer les labels en mobile, garder seulement les icônes */
  .entry-btn__label { display: none; }
  .entry-btn { padding: 6px 8px; }
  .entry-btn__indicator { display: none !important; }

  /* Divider plus discret en mobile */
  .composer__divider { margin: 0 2px; }

  /* Popovers : bottom sheet plein écran en mobile (UX native)
     ─────────────────────────────────────────────────────────
     v2.13 : ajout env(safe-area-inset-bottom) pour respecter la barre de
     navigation Android (3 icônes du bas) ou la home indicator iOS. Sans ça,
     la popover était masquée par cette barre système sur ~48px.
     Padding-bottom assure que le contenu interne (boutons, bouton envoyer)
     reste cliquable au-dessus de la safe area. */
  .popover {
    position: fixed !important;
    left: 0 !important;
    right: 0 !important;
    top: auto !important;
    bottom: env(safe-area-inset-bottom, 0) !important;
    width: 100% !important;
    max-width: 100% !important;
    max-height: calc(70vh - env(safe-area-inset-bottom, 0px));
    max-height: calc(70dvh - env(safe-area-inset-bottom, 0px));  /* v2.15 : dvh */
    padding-bottom: env(safe-area-inset-bottom, 0);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    border-bottom: 0;
    border-left: 0;
    border-right: 0;
    transform-origin: bottom center !important;
  }
  @keyframes popover-in {
    from { opacity: 0; transform: translateY(100%); }
    to   { opacity: 1; transform: translateY(0); }
  }

  /* Tools panel : full width sur mobile */
  .tools-panel { width: 100%; }

  /* Cumul session : 1 ligne max compactée */
  .session-stats { font-size: 10px; gap: var(--sp-2); }
  .session-label { display: none; }

  /* Messages : moins de marge */
  .thread { padding: var(--sp-4) var(--sp-3); }
  #chat-history { gap: var(--sp-4); }

  /* Cacher le dropdown user-chevron en mobile */
  .user-chevron { display: none; }
}

/* Mobile très étroit ≤ 380px */
@media (max-width: 380px) {
  .app-header { padding: 0 var(--sp-3); gap: var(--sp-2); }
  .brand__name { font-size: var(--fs-base); }
}


/* ═══════════════════════════════════════════════════════════════════════════
   v2.27 (2026-07-07) — REFONTE AGENTS PERSONNELS (Session 1)
   ═══════════════════════════════════════════════════════════════════════════
   
   Consomme uniquement les variables CSS (design-tokens.css + theme-arkensai.css).
   
   ─────────────────────────────────────────────────────────────────────────── */

/* ── Popover Perso enrichi (items avec actions ✏️/🗑) ─────────────────────── */

.pa-popover-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  transition: background-color .12s ease, border-color .12s ease;
}

.pa-popover-item:hover {
  background: var(--c-bg-hover);
  border-color: var(--c-line);
}

.pa-popover-item.is-active {
  border-color: var(--c-accent);
  background: var(--c-accent-soft, var(--c-bg-hover));
}

.pa-popover-item__main {
  flex: 1 1 auto;
  min-width: 0;
  text-align: left;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--c-fg);
  font-family: inherit;
}

.pa-popover-item__name {
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1.3;
  color: var(--c-fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pa-popover-item__badge {
  font-size: var(--fs-xs);
  font-weight: 400;
  color: var(--c-fg-muted);
  margin-left: 4px;
}

.pa-popover-item__desc {
  font-size: var(--fs-xs);
  color: var(--c-fg-muted);
  line-height: 1.35;
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pa-popover-item__actions {
  display: flex;
  gap: 2px;
  flex-shrink: 0;
}

.pa-popover-item__act {
  padding: 4px 6px;
  border: none;
  background: transparent;
  border-radius: var(--radius-sm, 4px);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  color: var(--c-fg-muted);
  transition: background-color .12s ease, color .12s ease;
}

.pa-popover-item__act:hover {
  background: var(--c-bg-elevated);
  color: var(--c-fg);
}

.pa-act-delete:hover {
  color: var(--c-danger, #e15a5a);
}

/* ── Modale création/édition v1 (Variante B — 1 colonne verticale) ──────── */

.pa-modal-v1__overlay {
  position: fixed;
  inset: 0;
  /* v2.28 : backdrop renforcé pour meilleur contraste (était .55 → 72%) */
  background: rgba(0, 0, 0, .72);
  /* v2.28 : blur plus prononcé + support Safari */
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-4);
  animation: pa-fade-in .18s ease;
}

@keyframes pa-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.pa-modal-v1 {
  width: 100%;
  max-width: 560px;
  max-height: 90vh;
  /* v2.30 : fond blanc pur (clair) / bordeaux foncé (sombre) — vraie variable Arkensai */
  background: var(--c-bg-elevated);
  /* v2.30 : bordure d'accent rouge Arkensai (Option C François 08/07)
     Crée une séparation visuelle nette avec le backdrop, quel que soit le thème.
     - Thème clair : #A11D2A (rouge bordeaux profond)
     - Thème sombre : #E11D2E (rouge vif) */
  border: 2px solid var(--c-accent);
  border-radius: var(--radius-lg, 12px);
  /* v2.30 : shadow renforcée + halo d'accent subtil pour "détacher" la modale
     du backdrop grisé (halo rouge très léger 8% opacité) */
  box-shadow:
    0 30px 80px rgba(0, 0, 0, .45),
    0 0 0 4px var(--c-accent-soft, rgba(161, 29, 42, .08));
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: pa-scale-in .2s cubic-bezier(.16, 1, .3, 1);
}

@keyframes pa-scale-in {
  from { opacity: 0; transform: scale(.96); }
  to   { opacity: 1; transform: scale(1); }
}

.pa-modal-v1__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--c-line);
  flex-shrink: 0;
}

.pa-modal-v1__title {
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--c-fg);
  margin: 0;
}

.pa-modal-v1__close {
  background: transparent;
  border: none;
  color: var(--c-fg-muted);
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: var(--radius-sm);
  transition: background-color .12s ease, color .12s ease;
}

.pa-modal-v1__close:hover {
  background: var(--c-bg-hover);
  color: var(--c-fg);
}

.pa-modal-v1__body {
  padding: var(--sp-4) var(--sp-5);
  overflow-y: auto;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.pa-modal-v1__section {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.pa-modal-v1__label {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--c-fg);
  display: flex;
  align-items: center;
  gap: 4px;
}

.pa-modal-v1__label .req {
  color: var(--c-danger, #e15a5a);
}

.pa-modal-v1__label .opt {
  color: var(--c-fg-muted);
  font-weight: 400;
  font-size: var(--fs-xs);
}

.pa-modal-v1__input,
.pa-modal-v1__select,
.pa-modal-v1__textarea {
  width: 100%;
  padding: 8px 12px;
  background: var(--c-bg, var(--c-bg-elevated));
  border: 1px solid var(--c-line);
  border-radius: var(--radius-sm);
  color: var(--c-fg);
  font-family: inherit;
  font-size: var(--fs-sm);
  transition: border-color .12s ease, box-shadow .12s ease;
}

.pa-modal-v1__input:focus,
.pa-modal-v1__select:focus,
.pa-modal-v1__textarea:focus {
  outline: none;
  border-color: var(--c-accent);
  box-shadow: 0 0 0 3px var(--c-accent-soft, rgba(79, 138, 255, .15));
}

.pa-modal-v1__textarea {
  resize: vertical;
  min-height: 100px;
  font-family: var(--f-mono, monospace);
  line-height: 1.45;
}

.pa-modal-v1__hint {
  font-size: var(--fs-xs);
  color: var(--c-fg-muted);
  line-height: 1.35;
  margin-top: 2px;
}

.pa-modal-v1__status {
  min-height: 20px;
  font-size: var(--fs-xs);
  color: var(--c-fg-muted);
}

.pa-modal-v1__status.is-error {
  color: var(--c-danger, #e15a5a);
}

.pa-modal-v1__status.is-success {
  color: var(--c-success, #2de0a5);
}

.pa-modal-v1__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-2);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--c-line);
  margin-top: var(--sp-2);
}

/* ── Responsive mobile (bottom sheet style) ─────────────────────────────── */

@media (max-width: 640px) {
  .pa-modal-v1__overlay {
    align-items: flex-end;
    padding: 0;
  }

  .pa-modal-v1 {
    max-width: 100%;
    max-height: 95vh;
    border-radius: var(--radius-lg, 12px) var(--radius-lg, 12px) 0 0;
    animation: pa-slide-up .22s cubic-bezier(.16, 1, .3, 1);
  }

  @keyframes pa-slide-up {
    from { transform: translateY(100%); opacity: 0; }
    to   { transform: translateY(0); opacity: 1; }
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   v2.32 (2026-07-08) — CONNECTEURS MCP
   ═══════════════════════════════════════════════════════════════════════════
   
   Rendu items du popover-mcp-list (module mcp_connectors_v1.js).
   Vraies variables Arkensai uniquement.
   
   ─────────────────────────────────────────────────────────────────────────── */

.mcp-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  transition: background-color .12s ease, border-color .12s ease;
}

.mcp-item:hover {
  background: var(--c-bg-hover);
  border-color: var(--c-line);
}

.mcp-item.is-disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.mcp-item.is-disabled:hover {
  background: transparent;
  border-color: transparent;
}

.mcp-item__icon {
  width: 32px;
  height: 32px;
  min-width: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  line-height: 1;
  background: var(--c-bg);
  border: 1px solid var(--c-line);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}

.mcp-item.is-connected .mcp-item__icon {
  background: var(--c-accent-soft, var(--c-bg));
  border-color: var(--c-accent);
}

.mcp-item__main {
  flex: 1 1 auto;
  min-width: 0;
}

.mcp-item__name {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--c-fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.3;
}

.mcp-item__desc {
  font-size: var(--fs-xs);
  color: var(--c-fg-muted);
  line-height: 1.35;
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.mcp-item__status {
  flex-shrink: 0;
  font-size: var(--fs-xs);
  font-weight: 500;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--c-line);
  background: var(--c-bg);
  color: var(--c-fg-muted);
  white-space: nowrap;
}

.mcp-status--ok {
  color: var(--c-eco, #2d7a3e);
  border-color: var(--c-eco, #2d7a3e);
  background: var(--c-bg);
}

.mcp-status--off {
  color: var(--c-fg-muted);
  border-color: var(--c-line);
}

.mcp-status--disabled {
  color: var(--c-fg-subtle, var(--c-fg-muted));
  border-color: var(--c-line);
  background: var(--c-bg-muted);
}


/* ═══════════════════════════════════════════════════════════════════════════
   v2.33 (2026-07-08) — SPRINT MCP-2 : TOGGLE + BANDEAUX + BADGES
   ═══════════════════════════════════════════════════════════════════════════
   Vraies variables Arkensai uniquement.
   ─────────────────────────────────────────────────────────────────────────── */

/* Structure ligne principale (v2.33 : ajout d'un container ligne) ─────────── */

.mcp-item__row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
}

/* État actif — halo accent quand toggle ON ────────────────────────────────── */

.mcp-item.is-active {
  border: 1px solid var(--c-accent);
  background: var(--c-accent-soft, var(--c-bg-hover));
}

.mcp-item.is-active .mcp-item__icon {
  background: var(--c-accent-soft, var(--c-bg));
  border-color: var(--c-accent);
}

/* Badge "N tools" à côté du nom ──────────────────────────────────────────── */

.mcp-item__tool-count {
  display: inline-block;
  padding: 1px 6px;
  margin-left: 6px;
  background: var(--c-bg-muted);
  border: 1px solid var(--c-line);
  border-radius: 999px;
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--c-fg-muted);
  vertical-align: middle;
}

/* Ligne toggle en dessous de l'item ──────────────────────────────────────── */

.mcp-item__toggle-row {
  margin-top: var(--sp-2);
  padding-top: var(--sp-2);
  border-top: 1px dashed var(--c-line);
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.mcp-item__toggle-row.is-disabled .mcp-toggle {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Switch toggle ──────────────────────────────────────────────────────────── */

.mcp-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  cursor: pointer;
  user-select: none;
  font-size: var(--fs-xs);
}

.mcp-toggle__input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
  pointer-events: none;
}

.mcp-toggle__slider {
  position: relative;
  display: inline-block;
  width: 34px;
  height: 18px;
  background: var(--c-bg-muted);
  border: 1px solid var(--c-line);
  border-radius: 999px;
  transition: background-color .16s ease, border-color .16s ease;
  flex-shrink: 0;
}

.mcp-toggle__slider::after {
  content: '';
  position: absolute;
  top: 1px;
  left: 1px;
  width: 14px;
  height: 14px;
  background: var(--c-bg-elevated);
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(0,0,0,.15);
  transition: transform .18s cubic-bezier(.16, 1, .3, 1);
}

.mcp-toggle__input:checked ~ .mcp-toggle__slider {
  background: var(--c-accent);
  border-color: var(--c-accent);
}

.mcp-toggle__input:checked ~ .mcp-toggle__slider::after {
  transform: translateX(16px);
  background: var(--c-accent-fg, #FFFFFF);
}

.mcp-toggle__label {
  color: var(--c-fg-muted);
}

.mcp-toggle__input:checked ~ .mcp-toggle__label {
  color: var(--c-accent);
  font-weight: 500;
}

.mcp-toggle__input:disabled ~ .mcp-toggle__slider {
  cursor: not-allowed;
  opacity: 0.6;
}

/* Bandeaux (info globale OFF, warn modèle sans tools) ─────────────────────── */

.mcp-banner {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-2);
  border-radius: var(--radius-sm);
  border: 1px solid var(--c-line);
  background: var(--c-bg-muted);
  font-size: var(--fs-xs);
  line-height: 1.4;
}

.mcp-banner--info {
  border-color: var(--c-info, var(--c-line));
  background: var(--c-bg-muted);
  color: var(--c-fg);
}

.mcp-banner--warn {
  border-color: var(--c-warn, #C67A00);
  background: var(--c-bg-muted);
  color: var(--c-fg);
}

.mcp-banner__icon {
  font-size: 16px;
  line-height: 1.2;
  flex-shrink: 0;
}

.mcp-banner__text {
  flex: 1;
  color: var(--c-fg-muted);
}

/* Indicateur composer (compteur MCP) ─────────────────────────────────────── */
/* .entry-btn__indicator existe déjà. On l'utilise pour afficher le compteur.
   La classe .has-selection sur le bouton parent déclenche la couleur accent. */

#entry-mcp-indicator:empty {
  display: none;
}

#entry-mcp-btn.has-selection #entry-mcp-indicator {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  background: var(--c-accent);
  color: var(--c-accent-fg, #FFFFFF);
  border-radius: 999px;
  font-size: 10px;
  font-weight: 600;
  line-height: 1;
}


/* ═══════════════════════════════════════════════════════════════════════════
   v2.34 (2026-07-10) — UX FIXES POPOVER CONNECTEURS MCP
   ═══════════════════════════════════════════════════════════════════════════
   
   Overrides chirurgicaux pour corriger 3 bugs UX identifiés le 10/07/2026.
   Voir le changelog v2.34 en tête de fichier pour le diagnostic factuel
   complet de chaque bug (causes, valeurs mesurées, tokens choisis).
   
   Ces règles VIENNENT APRÈS les blocs v2.32/v2.33 dans le fichier et
   les surchargent par cascade. Pour rollback : supprimer ce bloc entier.
   
   ─────────────────────────────────────────────────────────────────────────── */


/* ─── Fix bug 1 : popover débordait ─────────────────────────────────────────
   .mcp-item était en flex row (default). Les 2 enfants .mcp-item__row
   (width:100%) et .mcp-item__toggle-row se retrouvaient côte à côte
   horizontalement, ce qui poussait le toggle-row hors du container.
   Fix : passer en flex column pour que .mcp-item__toggle-row soit
   effectivement EN DESSOUS (cohérent avec son border-top dashed).
   ─────────────────────────────────────────────────────────────────────── */

.mcp-item {
  flex-direction: column;
  align-items: stretch;
  /* gap remis à 0 car .mcp-item__toggle-row a déjà margin-top:var(--sp-2) */
  gap: 0;
}

/* Le border-top dashed du toggle-row prend maintenant tout son sens */
.mcp-item__toggle-row {
  /* Le contenu (toggle + label) reste aligné à droite */
  justify-content: flex-end;
}


/* ─── Fix bug 3 : toggle OFF invisible en mode sombre ───────────────────────
   .mcp-toggle__slider utilisait var(--c-bg-muted) comme background quand OFF.
   Sur les 2 thèmes, l'écart RGB avec le fond parent était < 10 points →
   invisible.
   Fix : passer à var(--c-line-strong) qui est fait pour ça (contraste
   affirmé, ~35-40 points d'écart). Comportement checked (ON) inchangé —
   la règle .mcp-toggle__input:checked ~ .mcp-toggle__slider vient APRÈS
   dans la cascade v2.33 donc la couleur accent l'emporte en état ON.
   
   IMPORTANT : ce fix override le background mais préserve la border et la
   transition existantes. Aucun impact sur le curseur (::after).
   ─────────────────────────────────────────────────────────────────────── */

.mcp-toggle__slider {
  background: var(--c-line-strong);
  border-color: var(--c-line-strong);
}


/* ─── Fix bug 2 : spinner animé pendant loadAll ─────────────────────────────
   Nouveau container de chargement engageant (au lieu du texte plat
   "Chargement…" de v2.0 JS). Utilisé par mcp_connectors v2.1 dans
   renderPopover() avant le fetch initial. Une fois le preload au boot
   en place (v2.1 aussi), ce spinner n'apparaîtra qu'en cas de cold
   start Cloud Run ou de cache expiré.
   ─────────────────────────────────────────────────────────────────────── */

.mcp-loading-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: var(--sp-6) var(--sp-4);
  color: var(--c-fg-muted);
  font-size: var(--fs-sm);
}

.mcp-spinner__icon {
  width: 24px;
  height: 24px;
  color: var(--c-accent);
  animation: mcp-spin 1s linear infinite;
}

@keyframes mcp-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}


/* ─── Fin bloc v2.34 UX FIXES ─────────────────────────────────────────── */
