/*
  SpeakDo — thème "docket terrain".
  Palette sombre pour la lisibilité en extérieur, accent teal (signalétique
  Dolibarr/confiance) plutôt que l'ambre d'origine. L'ambre reste utilisé
  comme couleur sémantique d'avertissement (mode dégradé). Le contexte actif
  (client, devis, intervention...) s'affiche comme un panneau hiérarchique
  unique plutôt qu'une rangée de chips, pour rester lisible même avec
  plusieurs niveaux de contexte actifs à la fois.
*/

:root {
  --bg: #12161b;
  --surface: #1b2129;
  --surface-2: #232a33;
  --border: #2b333e;
  --text: #eef1f5;
  --text-dim: #93a0af;
  /* Encre des surfaces CLAIRES (17/09/2026). La palette de cette application est sombre de bout
     en bout : --text et --text-dim sont calculés pour être posés sur --bg/--surface, et deviennent
     illisibles dès qu'ils atterrissent sur un fond clair. La carte de confirmation (.msg-proposal)
     est la SEULE surface claire de toute la PWA — c'est donc le seul endroit où le problème peut
     se produire, et la seule raison d'être de ces deux variables.
     Contrastes sur blanc : 18,2:1 et 6,4:1 (WCAG AA exige 4,5:1). */
  --on-light: #12161b;
  --on-light-dim: #55606d;
  /* Accents SpeakDo DÉCLINÉS pour la surface claire. Ce ne sont pas d'autres couleurs : la teinte
     et la saturation sont bit à bit celles de --success (H 149,6 / S 0,585) et de --danger
     (H 0 / S 0,828). Seule la LUMINOSITÉ descend, et juste assez — le vert passe de L 0,482 à
     0,300, le rouge de 0,635 à 0,439. L'identité visuelle est conservée ; ce qui change, c'est
     qu'on peut les lire.
     Elles se mesurent sur le fond RÉEL de chaque badge, pas sur le blanc de la carte : les badges
     de risque posent un voile de leur propre teinte à 15 % (#e0f6eb et #fde6e6), un fond plus
     sombre que le blanc, donc un contraste PLUS FAIBLE. Mesurer sur blanc aurait été optimiste.
     Contrastes : vert 5,38:1 sur blanc et 4,76:1 sur son voile ; rouge 5,68:1 et 4,77:1.
     --success et --danger restent inchangées pour toutes les surfaces sombres. */
  --success-on-light: #20794c;
  --danger-on-light: #cd1313;
  --accent: #22b8a3;
  --accent-ink: #042b25;
  --warning: #ff8a1e;
  --warning-ink: #1a0f00;
  --danger: #ef5555;
  --success: #33c37a;
  --radius: 14px;
  --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-data: ui-monospace, "SF Mono", "Roboto Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  -webkit-tap-highlight-color: transparent;
  overflow: hidden; /* aucun scroll de page : seule .messages défile, en-tête et composer restent fixes */
  width: 100%;
}

#app-root {
  height: 100vh; /* repli pour les navigateurs sans support de dvh ; la règle dvh suivante prend le dessus si supportée */
  height: 100dvh;
  height: var(--app-vh, 100dvh); /* resynchronisé en JS (app.js) via visualViewport quand le clavier virtuel s'ouvre */
  display: flex;
  flex-direction: column;
  overflow: hidden;
  width: 100%;
}

button { font: inherit; }
input { font: inherit; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---------- Enrollment ---------- */

.enroll {
  min-height: 100vh; /* repli pour les navigateurs sans support de dvh */
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 20px;
  background:
    radial-gradient(circle at 20% -10%, rgba(34,184,163,.14), transparent 45%),
    var(--bg);
}

.enroll-card {
  width: 100%;
  max-width: 420px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 28px 24px;
}

.enroll-card h1 {
  font-size: 1.4rem;
  margin: 0 0 6px;
  letter-spacing: -0.01em;
}

.enroll-lede {
  color: var(--text-dim);
  font-size: 0.92rem;
  margin: 0 0 20px;
  line-height: 1.4;
}

.enroll-form { display: flex; flex-direction: column; gap: 14px; margin-top: 16px; }

.enroll-form label { display: flex; flex-direction: column; gap: 6px; font-size: 0.82rem; color: var(--text-dim); }

.enroll-form input {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 11px 12px;
  color: var(--text);
  font-family: var(--font-data);
  font-size: 0.95rem;
}

.enroll-error {
  color: var(--danger);
  font-size: 0.85rem;
  margin-top: 14px;
}

.btn {
  border: none;
  border-radius: 10px;
  padding: 12px 16px;
  font-weight: 600;
  font-size: 0.95rem;
  cursor: pointer;
}

.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-primary:disabled { opacity: .6; }
.btn-secondary { background: var(--surface-2); color: var(--text); border: 1px solid var(--border); width: 100%; }

/* ---------- Chat shell ---------- */

.chat {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  width: 100%;
}

/* Barre haute : UNE SEULE LIGNE, hauteur qui ne dépend pas du texte (chantier du 12/09/2026).
   Avant : le mode de travail était empilé sous « SpeakDo », ce qui donnait une deuxième ligne
   structurelle et une barre d'environ 71 px. Désormais la hauteur est fixée par le plus haut de
   ses enfants — les boutons d'icône, 40 px — plus 2 × 10 px de marge : 60 px, dans la cible de
   56-64 px. Aucun libellé ne peut la faire grandir : voir .chat-profile. */
.chat-header {
  /* DEUX NIVEAUX (16/09/2026) : marque et icônes sur la première ligne, mode de travail sur la
     seconde, pleine largeur. La hauteur se calcule et ne dépend d'aucun texte :
         2 + 4 (marge) + 40 (ligne 1) + 2 (gap) + 28 (puce) = 76 px.
     La ligne 1 est plafonnée par la cible tactile de 40 px des boutons d'icône : c'est elle, et
     non un choix esthétique, qui interdit de descendre plus bas. La puce garde ses 28 px — la
     rétrécir aurait rendu 4 px en dégradant une cible déjà inférieure à 40. */
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* 10 px horizontaux (et non 16 comme avant le 12/09/2026) : à 320 px, chaque pixel rendu par
     les marges est un pixel de plus pour le nom du mode, et aucun pour une zone morte. */
  padding: 2px 10px 4px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  /* Ancre le sélecteur de mode de travail (11/09/2026) sous le bouton de profil. Sans effet sur
     le menu utilisateur, qui reste ancré à son propre .user-menu-wrap déjà positionné. */
  position: relative;
}

/* Première ligne. `justify-content: space-between` pousse les icônes à droite, `min-width: 0`
   laisse la marque rétrécir avant elles. */
.chat-header-main { display: flex; align-items: center; justify-content: space-between; gap: 8px; }

/* min-width: 0 sur la marque ET flex: 1 1 auto : c'est ce couple qui fait que, quand la largeur
   manque, c'est la MARQUE qui rétrécit — jamais les zones tactiles des icônes à droite
   (mandat §5). Depuis le 16/09/2026 le mode n'est plus ici : il a sa propre ligne. */
.chat-brand { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1 1 auto; }

/* La marque textuelle s'efface sous 480 px (voir la requête média en fin de bloc) : le logo
   porte déjà l'identité, et « SpeakDo » ne vaut pas la largeur qu'il coûte au nom du mode sur un
   écran de 320 px. */
.chat-brand-name { font-size: 0.95rem; white-space: nowrap; flex-shrink: 0; }

.chat-logo {
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  background: var(--accent);
  color: var(--accent-ink);
  display: grid;
  place-items: center;
  font-weight: 700;
  font-size: 0.95rem;
}

.chat-user { font-size: 0.78rem; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Mode de travail actif, à la place du nom de l'ERP (11/09/2026), rendu en PUCE compacte le
   12/09/2026. Hauteur FIXE : le contenu ne peut pas faire grandir la barre haute, quelle que
   soit la longueur du nom. Le nom seul est tronqué (.chat-profile-name), jamais le chevron. */
.chat-profile {
  /* Ligne propre depuis le 16/09/2026 : la puce n'est plus en concurrence avec le logo et les
     icônes. À 320 px elle dispose désormais de 300 px au lieu de 106 — « Technicien informatique
     — parc matériel » (39 caractères) tient en entier.
     `max-width: 100%` + `align-self: flex-start` et NON `width: 100%` : la puce prend toute la
     largeur dont elle a besoin, jusqu'à la ligne entière, mais pas au-delà de son texte — un
     mode court (« Commercial ») garderait sinon une capsule vide sur les deux tiers de l'écran.
     Le parent étant une colonne en `align-items: stretch`, sans `align-self` l'étirement
     reviendrait par la bande. */
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  max-width: 100%;
  align-self: flex-start;
  height: 28px;
  margin: 0;
  padding: 0 8px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--accent);
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  cursor: pointer;
}
/* Seul le nom rétrécit et s'ellipse : le chevron reste entier, sans quoi le bouton perdrait son
   affordance avant de perdre une lettre. */
.chat-profile-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Deux libellés dans le bouton, un seul affiché (16/09/2026). Au-dessus de 360 px c'est le
   libellé COMPLET ; en dessous, où il serait ellipsé, le nom court publié par le serveur
   (short_label) reprend la main. La bascule est faite par la requête média, jamais par du
   JavaScript à l'écoute du redimensionnement : la largeur de l'écran n'est pas un état de
   l'application. Le title et l'aria-label du bouton portent de toute façon toujours le libellé
   complet, quelle que soit la largeur. */
.chat-profile-name-short { display: none; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 359px) {
  .chat-profile-name { display: none; }
  .chat-profile-name-short { display: block; }
}
.chat-profile-caret { flex-shrink: 0; font-size: 0.7rem; opacity: 0.75; }
.chat-profile:disabled {
  color: var(--text-dim);
  font-weight: 500;
  cursor: default;
  /* Mode verrouillé : plus une étiquette qu'un bouton — ni bordure, ni fond, pour ne pas
     promettre un menu qui ne s'ouvrira pas. */
  border-color: transparent;
  background: none;
  padding-left: 0;
}

.profile-selector {
  /* Ancré sous l'en-tête entier (`.chat-header` porte position: relative), donc sous la ligne du
     mode qui en est désormais le dernier enfant : le menu s'ouvre bien au contact du bouton. */
  position: absolute;
  top: 100%;
  left: 10px;
  margin-top: 2px;
  z-index: 30;
  min-width: 220px;
  max-width: calc(100vw - 24px);
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
}
.profile-selector-title {
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding: 2px 8px 6px;
}
.profile-selector-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 11px 10px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 0.9rem;
  text-align: left;
  cursor: pointer;
}
.profile-selector-item:active { background: var(--surface-2); }
.profile-selector-item-active { color: var(--accent); cursor: default; }
.profile-selector-badge {
  flex-shrink: 0;
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
}

/* gap réduit de 10 à 4 px (12/09/2026) : à 320 px, ces 12 px rendus sont autant de largeur pour
   le nom du mode. Les zones tactiles, elles, restent à 40 px — c'est l'espace ENTRE elles qui
   diminue, jamais leur surface (mandat §3 et §5). */
.chat-header-right { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }

.conn-status { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; }

.conn-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.conn-dot.conn-online { background: var(--success); }
.conn-dot.conn-degraded { background: var(--warning); }
.conn-dot.conn-offline { background: var(--danger); }

/* Jauge de quota LLM (correctif du 24/07/2026) : pastille à 3 barres, distincte de conn-dot
   par la forme (barres rectangulaires vs. cercle) autant que par la couleur, pour rester
   lisible sans dépendre uniquement de la couleur (accessibilité). Jamais de chiffre ni de
   texte numérique associé : la couleur/le remplissage EST l'information. */
.quota-gauge { display: inline-flex; align-items: flex-end; gap: 2px; height: 10px; }
.quota-gauge-bar { width: 3px; border-radius: 1px; background: var(--border); }
.quota-gauge-bar-1 { height: 4px; }
.quota-gauge-bar-2 { height: 7px; }
.quota-gauge-bar-3 { height: 10px; }
/* large : les 3 barres pleines en vert. */
.quota-gauge[data-level="large"] .quota-gauge-bar { background: var(--success); }
/* limite : seules les 2 premières barres colorées (ambre) — remplissage partiel. */
.quota-gauge[data-level="limite"] .quota-gauge-bar-1,
.quota-gauge[data-level="limite"] .quota-gauge-bar-2 { background: var(--warning); }
/* epuise : une seule barre (la plus basse) en rouge — remplissage minimal, lecture "quasi vide". */
.quota-gauge[data-level="epuise"] .quota-gauge-bar-1 { background: var(--danger); }

.icon { width: 1.15em; height: 1.15em; flex-shrink: 0; vertical-align: -0.2em; }

.btn-icon {
  background: transparent;
  border: none;
  color: var(--text-dim);
  font-size: 1.15rem;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.btn-icon:active { background: var(--surface-2); }
.btn-icon:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}
.btn-icon-active { color: var(--accent); background: rgba(34,184,163,.16); }
a.btn-icon { text-decoration: none; }

/* Sous 480 px, « SpeakDo » cède la place au nom du mode : le logo porte déjà l'identité, et
   c'est le mode qui conditionne ce que l'application accepte de faire (chantier du 12/09/2026).
   Au-dessus, les deux tiennent confortablement sur la même ligne. */
@media (max-width: 479px) {
  /* La marque textuelle s'efface encore sous 480 px : elle ne dispute plus sa largeur au mode
     (qui a sa propre ligne depuis le 16/09/2026), mais elle ne porte aucune information que le
     logo ne porte déjà — autant la rendre au reste de la ligne. */
  .chat-brand-name { display: none; }
}

/* ---------- Context bar : panneau hiérarchique du contexte actif ---------- */

.context-bar {
  padding: 10px 12px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.context-hint { font-size: 0.8rem; color: var(--text-dim); padding-left: 4px; }
.context-hint-btn {
  background: none;
  border: none;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  width: 100%;
}
.context-hint-btn:hover, .context-hint-btn:focus-visible { color: var(--text); }

/* ---------- Bandeau de quota LLM : "limite" non bloquant, "epuise" bloqué (jamais de chiffre, cf. quota-gauge ci-dessus) ---------- */

.quota-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 12px;
  font-size: 0.84rem;
  flex-shrink: 0;
}
/* Spécificité plus élevée que .quota-banner seul : sans cette règle, display:flex ci-dessus
   l'emporte sur le display:none par défaut du navigateur pour [hidden], et l'attribut
   hidden (posé/retiré en JS) n'a plus aucun effet visuel — bandeau bloqué visible en
   permanence, y compris vide (statut "ok", texte jamais rempli). */
.quota-banner[hidden] { display: none; }
.quota-banner-warning { background: rgba(255,138,30,.14); color: var(--warning); border-bottom: 1px solid rgba(255,138,30,.35); }
.quota-banner-exceeded { background: rgba(239,85,85,.16); color: var(--danger); border-bottom: 1px solid rgba(239,85,85,.35); }
.quota-banner-close {
  background: none;
  border: none;
  color: inherit;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: 2px 4px;
  flex-shrink: 0;
}
.quota-banner-recharge {
  background: rgba(255,255,255,.14);
  border: 1px solid currentColor;
  color: inherit;
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  padding: 6px 10px;
  border-radius: 8px;
  flex-shrink: 0;
  white-space: nowrap;
}
.quota-banner-recharge[hidden] { display: none; }

/* Second bandeau (spec page Paiement §5, 29/07/2026) : essai terminé, bascule sur crédits
   ponctuels, alertes préventives 70/90 %, rappel J-7/J-1 — toujours ambre (§5.1 : jamais rouge,
   ce sont des moments de décision ou d'information, pas des erreurs bloquantes). */
.info-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 12px;
  font-size: 0.84rem;
  flex-shrink: 0;
  background: rgba(255,138,30,.14);
  color: var(--warning);
  border-bottom: 1px solid rgba(255,138,30,.35);
}
.info-banner[hidden] { display: none; }
.info-banner-action {
  background: rgba(255,255,255,.14);
  border: 1px solid currentColor;
  color: inherit;
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  padding: 6px 10px;
  border-radius: 8px;
  flex-shrink: 0;
  white-space: nowrap;
}
.info-banner-action[hidden] { display: none; }
.info-banner-close {
  background: none;
  border: none;
  color: inherit;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: 2px 4px;
  flex-shrink: 0;
}
.info-banner-close[hidden] { display: none; }

.context-panel-text {
  min-width: 0;
  overflow: hidden;
}
.context-panel-primary, .context-panel-secondary {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.context-panel {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: var(--surface-2);
  border-radius: 10px;
  padding: 10px 12px;
}

.context-panel-label {
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 2px;
}

.context-panel-primary { font-size: 1rem; font-weight: 700; color: var(--text); }
.context-panel-secondary { font-size: 0.82rem; color: var(--text-dim); margin-top: 2px; }

.context-panel-clear {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-dim);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}
.context-panel-clear:active { background: var(--surface); }

/* Raccourcis du contexte courant (appeler / écrire / itinéraire) — profil Commercial.
   flex-shrink: 0 pour qu'ils ne soient jamais compressés par un nom de client long : sur
   mobile, ce sont eux la raison d'être du bandeau. */
.context-panel-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  margin-left: auto;
}

/* ---------- Exemples dépendants du profil métier ---------- */

.profile-examples { display: flex; flex-direction: column; gap: 6px; padding: 4px 0 8px; }
.profile-examples-title {
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.profile-example-chip {
  text-align: left;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text);
  font: inherit;
  font-size: 0.85rem;
  padding: 7px 14px;
  cursor: pointer;
}
.profile-example-chip:active { background: var(--surface); }

/* ---------- Proposition « vous êtes chez… ? » (géolocalisation) ---------- */

.nearby-proposal {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px;
  margin: 6px 0;
}
.nearby-question { font-size: 0.95rem; color: var(--text); }
.nearby-choices { display: flex; flex-direction: column; gap: 6px; }
.nearby-choice {
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  font: inherit;
  font-size: 0.88rem;
  padding: 9px 12px;
  cursor: pointer;
}
.nearby-choice:disabled { opacity: 0.5; cursor: default; }
.nearby-choice-dismiss { color: var(--text-dim); }

/* ---------- Briefing client (thirdparty.brief) ---------- */

.brief { display: flex; flex-direction: column; gap: 10px; }
.brief-title { font-weight: 700; color: var(--text); }
.brief-section { display: flex; flex-direction: column; gap: 2px; }
.brief-section-label {
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}
.brief-line { font-size: 0.9rem; color: var(--text); }
.brief-line-meta { color: var(--text-dim); }
.brief-empty, .brief-unavailable { font-size: 0.85rem; color: var(--text-dim); }

/* ---------- Entity search ---------- */

.entity-search {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: 10px 12px;
  flex-shrink: 0;
}

#entity-search-input {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  color: var(--text);
}

.entity-search-results { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; max-height: 200px; overflow-y: auto; }

.entity-result {
  text-align: left;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 9px 10px;
  color: var(--text);
  cursor: pointer;
}
.entity-result span { color: var(--text-dim); font-size: 0.82rem; }
.entity-result-fallback { color: var(--accent); font-style: italic; }

/* ---------- Messages ---------- */

.messages {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 14px 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.msg {
  max-width: 84%;
  padding: 10px 13px;
  border-radius: 14px;
  font-size: 0.92rem;
  line-height: 1.4;
  word-wrap: break-word;
  overflow-wrap: break-word;
}

.msg img {
  max-width: 100%;
  height: auto;
  display: block;
}


.msg-user { align-self: flex-end; background: var(--accent); color: var(--accent-ink); border-bottom-right-radius: 4px; }
.msg-assistant.msg-text { align-self: flex-start; background: var(--surface); border: 1px solid var(--border); border-bottom-left-radius: 4px; }
.msg-status { align-self: flex-start; color: var(--text-dim); font-style: italic; background: transparent; padding: 2px 4px; }
.msg-error { align-self: flex-start; background: rgba(239,85,85,.12); border: 1px solid var(--danger); color: #ffb3b3; }
.msg-error-retry {
  display: block;
  margin-top: 8px;
  width: auto;
  padding: 6px 12px;
  font-size: 0.82rem;
  background: rgba(239,85,85,.18);
  border-color: var(--danger);
  color: #ffb3b3;
}

.msg-photo { align-self: flex-end; padding: 6px; background: var(--surface); border: 1px solid var(--border); }
.msg-photo img { max-width: 100%; border-radius: 10px; display: block; }

.msg-result { align-self: flex-start; background: var(--surface); border: 1px solid var(--border); }
.result-list { display: flex; flex-direction: column; gap: 6px; }
.result-item {
  text-align: left;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
  color: var(--text);
  cursor: pointer;
}
.result-item span { color: var(--text-dim); font-size: 0.82rem; }
.result-item-selected { border-color: var(--success); }
.result-truncation-note { font-size: 0.78rem; color: var(--text-dim); padding: 2px 4px; }

.result-item-row { display: flex; align-items: stretch; gap: 6px; }
.result-item-row .result-item { flex: 1; }

/* CARTE DE RÉSULTAT (16/09/2026) — informations en haut sur toute la largeur, actions dessous.
   Remplace `.result-item-row` pour les listes de recherche : celui-ci empile ses enfants
   HORIZONTALEMENT en `align-items: stretch`, si bien que chaque action devenait une colonne
   pleine hauteur de 40 px. À 320 px, quatre actions consommaient la moitié de la largeur — celle
   qui manquait au nom du tiers, qui repassait alors à la ligne trois fois. Les raccourcis
   entraient en concurrence avec l'information qu'ils servent.

   `.result-linked-object` (object.list_linked) portait DÉJÀ cette structure en DOM — un en-tête
   puis une barre d'actions — mais aucune règle CSS ne lui avait jamais été écrite : la carte
   héritait donc de `.result-item-row` et souffrait exactement du même défaut. Les deux partagent
   désormais la même règle plutôt que d'en avoir deux qui divergent. */
.result-card,
.result-item-row.result-linked-object {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
}
/* La zone d'information occupe toute la largeur : c'est le nom du tiers qui domine, pas ses
   raccourcis. `flex: 0 0 auto` et non `flex: 1` — en colonne, `flex: 1` étirerait la hauteur. */
.result-card > .result-item,
.result-item-row.result-linked-object > .result-item { flex: 0 0 auto; width: 100%; }

/* Barre d'actions : UNE SEULE LIGNE dans le cas nominal (voir le calcul sur les pastilles
   ci-dessous). `flex-wrap` reste là comme filet — si un jour une carte porte plus d'actions
   qu'un écran n'en tient, elles passent à la ligne plutôt que de sortir de l'écran — mais aucune
   largeur de smartphone visée ne le déclenche aujourd'hui. Jamais de défilement horizontal. */
.result-card-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }

/* Pastilles CARRÉES à icône seule, 40 × 40 px — la cible tactile, et rien de plus.
   Un premier essai (16/09/2026) accolait un libellé à chaque icône : à quatre actions, la barre
   passait à deux lignes sur smartphone, ce que le passage en carte avait précisément pour but
   d'éviter. Quatre pastilles tiennent ici sur 178 px (4 × 40 + 3 × 6 de gap), soit largement
   moins que le plus petit écran visé — sans jamais rien élargir pour remplir la ligne.
   `flex: 0 0 auto` : aucune pastille ne s'étire, quel que soit le nombre d'actions présentes. */
.result-card-actions .result-item-maps,
.result-card-actions .result-item-contact,
.result-card-actions .result-item-open-erp {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  min-width: 40px;
  padding: 0;
  margin: 0;
}
/* `.icon` est dimensionnée en `em` : dans une pastille carrée sans texte, la taille de police
   héritée n'a plus rien à voir avec ce que l'icône doit mesurer. Fixée ici, donc, en pixels —
   c'est le seul contenu visible de la pastille, il n'a pas à dépendre d'un `font-size`. */
.result-card-actions .icon { width: 18px; height: 18px; }
.result-item-maps {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-2);
  text-decoration: none;
  font-size: 1.05rem;
  color: var(--text);
}
.result-item-maps:hover { border-color: var(--accent); }
.result-item-contact {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-2);
  text-decoration: none;
  font-size: 1.05rem;
  vertical-align: middle;
  margin-left: 6px;
  color: var(--text);
}
.result-item-contact:hover { border-color: var(--accent); }
.result-item-open-erp {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
  padding: 0;
}
.result-item-open-erp:hover { border-color: var(--accent); }
.result-item-open-erp:disabled { opacity: 0.5; cursor: default; }

.result-raw { display: flex; flex-direction: column; gap: 10px; }
.result-raw-heading { font-weight: 600; font-size: 0.82rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.02em; margin-bottom: 4px; }
.result-raw-list { display: flex; flex-direction: column; gap: 4px; margin: 0; padding-left: 1.1em; }
.result-raw-list li { color: var(--text); }
.result-raw-line { color: var(--text); font-size: 0.9rem; }

.result-raw-maps {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-2);
  color: var(--text);
  text-decoration: none;
  font-size: 0.9rem;
}
.result-raw-maps:hover { border-color: var(--accent); }

.result-summary { display: flex; flex-direction: column; gap: 6px; }
.result-summary-title { font-weight: 600; color: var(--text); }
.result-summary-line { color: var(--text); font-size: 0.9rem; }
.result-summary-line a { color: var(--accent); text-decoration: none; }
.result-summary-line a:hover { text-decoration: underline; }

.result-summary-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px; }
.result-summary-actions .btn-secondary { width: auto; padding: 8px 14px; font-size: 0.85rem; }

.result-raw-disclosure { margin-top: 4px; }
.result-raw-disclosure summary { cursor: pointer; color: var(--text-dim); font-size: 0.82rem; }
.result-raw-disclosure .result-raw { margin-top: 8px; }

/* Carte de confirmation — LA seule surface claire de l'application.
   `color` y est la correction de fond du 17/09/2026 : la règle posait un fond blanc tout en
   gardant l'encre du thème sombre (--text, #eef1f5), soit un contraste de 1,13:1. Tout ce qui
   ne redéfinissait pas explicitement sa couleur était donc écrit en blanc sur blanc. Les rares
   éléments qui restaient lisibles l'étaient parce qu'ils portaient chacun un `color: black`
   rustine — et le jour où un élément a été ajouté sans cette rustine (.proposal-question,
   11/09/2026), il est devenu invisible.
   L'encre est désormais déclarée UNE fois, ici, et héritée : un élément ajouté demain à cette
   carte est lisible sans que personne ait à y penser. Verrouillé par
   bin/self-test-proposal-card-contrast.php. */
.msg-proposal {
  align-self: flex-start;
  /* Une seule déclaration de fond : la précédente (var(--surface)) était morte, écrasée par
     `white` deux lignes plus bas, et laissait croire que cette carte suivait le thème. */
  background: #fff;
  border: 1px solid var(--accent);
  min-width: 220px;
  color: var(--on-light);
}

.proposal-header { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.proposal-title { font-weight: 700; }

.proposal-risk-badge {
  font-size: 0.7rem;
  font-weight: 600;
  padding: 3px 9px;
  border-radius: 999px;
  white-space: nowrap;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
/* Le badge RÉVERSIBLE partage l'encre du badge de succès. Ce partage n'est pas introduit ici :
   il existait déjà (les deux règles pointaient var(--success)), et le décliner pour la surface
   claire le conserve tel quel plutôt que d'inventer une distinction que le code n'a jamais
   faite. Si « réversible » devait un jour cesser d'être peint comme un succès, c'est une
   décision de design — pas un effet de bord d'un correctif de contraste. */
.proposal-risk-reversible { background: rgba(51,195,122,.15); color: var(--success-on-light); }
.proposal-risk-irreversible { background: rgba(239,85,85,.15); color: var(--danger-on-light); }

.proposal-fields { margin: 0 0 10px; display: grid; grid-template-columns: auto 1fr; gap: 5px 10px; }
.proposal-fields dt { font-size: 0.78rem; }
.proposal-fields dd { margin: 0; font-size: 0.88rem; font-weight: 600; }

.proposal-actions { display: flex; gap: 8px; justify-content: flex-end; }
.proposal-actions .btn { padding: 8px 14px; font-size: 0.85rem; }
.proposal-actions .btn-secondary { width: auto; }

.proposal-badge { display: flex; align-items: center; gap: 5px; font-size: 0.82rem; font-weight: 600; }
.proposal-badge-confirmed { color: var(--success-on-light); }
.proposal-badge-cancelled { color: var(--on-light-dim); }

.proposal-writing-status { width: 100%; text-align: right; font-size: 0.8rem; color: var(--on-light-dim); font-style: italic; }

/* Carte de changement de mode de travail (11/09/2026) : une question, pas un récapitulatif
   d'écriture Dolibarr — cette action ne touche aucune donnée de l'ERP. */
.proposal-question { margin: 8px 0 0; font-size: 0.95rem; line-height: 1.4; }
.proposal-context-note { margin: 6px 0 0; font-size: 0.82rem; color: var(--on-light-dim); }

/* ---------- Composer ---------- */

.composer {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 10px 10px calc(10px + env(safe-area-inset-bottom));
  background: var(--surface);
  border-top: 1px solid var(--border);
  flex-shrink: 0;
  width: 100%;
  position: relative;
}

.attach-menu {
  position: absolute;
  bottom: 100%;
  left: 10px;
  margin-bottom: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  overflow: hidden;
  z-index: 10;
}

.attach-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 12px 20px;
  background: transparent;
  border: none;
  color: var(--text);
  text-align: left;
  cursor: pointer;
  font-size: 0.92rem;
  white-space: nowrap;
}

.attach-menu-item:hover {
  background: var(--surface-2);
}

/* Menu utilisateur de l'en-tête (correctif du 30/07/2026, demande explicite : en-tête trop
   chargé) — regroupe recharge/langue/déconnexion, même motif visuel que .attach-menu ci-dessus
   mais ancré en haut à droite du bouton (le menu s'ouvre vers le bas, pas vers le haut). */
.user-menu-wrap {
  position: relative;
}

.user-menu {
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: 8px;
  min-width: 220px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  overflow: hidden;
  z-index: 20;
}

.user-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 12px 16px;
  background: transparent;
  border: none;
  color: var(--text);
  text-align: left;
  cursor: pointer;
  font-size: 0.92rem;
  white-space: nowrap;
}

.user-menu-item:hover {
  background: var(--surface-2);
}
a.user-menu-item { text-decoration: none; }

/* Sélecteur de langue en liste déroulante (demande explicite du 30/07/2026) : hérite du
   positionnement/padding de .user-menu-item (label porte les deux classes), seul le <select>
   lui-même a besoin d'un style dédié pour s'harmoniser avec le thème sombre plutôt que le
   rendu par défaut du navigateur. */
.user-menu-lang-select {
  flex: 1;
  background: transparent;
  border: none;
  color: var(--text);
  font-size: 0.92rem;
  cursor: pointer;
}
.user-menu-lang-select:focus {
  outline: 1px solid var(--accent);
}

#text-input {
  flex: 1;
  min-width: 0;
  max-width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 10px 16px;
  color: var(--text);
}

.btn-send { color: var(--accent); }
.btn-mic-active { color: var(--danger); }

.mic-overlay {
  position: fixed;
  inset: 0;
  background: rgba(18,22,27,.92);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  z-index: 20;
}

.mic-overlay[hidden] {
  display: none;
}

.mic-pulse {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--danger);
  animation: pulse 1.2s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.25); opacity: .6; }
}

.mic-overlay p { color: var(--text); }
.mic-overlay button {
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 10px 18px;
  border-radius: 10px;
}

@media (prefers-reduced-motion: reduce) {
  .mic-pulse { animation: none; }
}

/* ---------- Informations techniques (demandé le 31/07/2026, support à distance) ---------- */
.tech-info-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
  padding: 16px;
}
.tech-info-panel {
  background: var(--surface, #1a1f27);
  border-radius: 12px;
  padding: 20px;
  max-width: 420px;
  width: 100%;
  max-height: 80vh;
  overflow-y: auto;
}
.tech-info-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
  font-size: 1rem;
}
/* Titres de section (10/09/2026) : la modale regroupe profil / application / connexion. */
.tech-info-section-title {
  color: var(--text-dim);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 14px 0 6px;
}
.tech-info-sections > .tech-info-section-title:first-child { margin-top: 0; }
.tech-info-fields {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 12px;
  row-gap: 8px;
  margin: 0;
}
.tech-info-fields dt { color: var(--text-dim); font-size: 0.85rem; white-space: nowrap; }
.tech-info-fields dd {
  margin: 0;
  font-size: 0.85rem;
  word-break: break-all;
  text-align: right;
}
.tech-info-copy-btn { width: 100%; margin-top: 16px; display: flex; align-items: center; justify-content: center; gap: 8px; }
