/* ==========================================================================
 *  O.R.I.O.N — L'APPLICATION WEB
 * ==========================================================================
 *
 *  LE PRINCIPE DE CETTE FEUILLE
 *  ----------------------------
 *  Elle ne contient presque AUCUNE couleur en dur. Tout passe par les
 *  variables `--ciel-*` que le fond vivant publie soixante fois par seconde :
 *  l'accent, les surfaces, l'encre, les bordures. Quand le soleil se couche
 *  chez l'utilisateur, l'application se réchauffe toute seule — on n'a pas
 *  écrit deux thèmes, on en a écrit un, branché sur le ciel.
 *
 *  Les valeurs de repli (après la virgule dans chaque `var()`) ne sont pas
 *  décoratives : elles servent AVANT que le ciel ait publié sa première
 *  teinte, et dans le mode classique où il est éteint. Sans elles, la page
 *  clignote en blanc à l'ouverture.
 *
 *  LE MODE CLASSIQUE
 *  -----------------
 *  `:root[data-charte="classique"]` fige les mêmes variables sur le noir et le
 *  cyan de la charte d'origine, et le ciel s'arrête. Même feuille, mêmes
 *  sélecteurs — donc aucun risque qu'un mode dérive de l'autre.
 *
 *  AUCUNE DÉPENDANCE. Pas de framework, pas de préprocesseur.
 * ========================================================================== */

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

/*  `hidden` doit vraiment cacher.
 *
 *  La règle du navigateur est `[hidden] { display: none }`, mais elle vient de
 *  SA feuille de style, qui perd contre n'importe quelle règle d'auteur. Dès
 *  qu'on écrit `.accueil { display: flex }`, poser l'attribut `hidden` ne fait
 *  plus rien — l'élément reste à l'écran et on cherche le bug dans le
 *  JavaScript, qui lui fonctionnait très bien. */
[hidden] { display: none !important; }

:root {
  --pol: -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, Roboto,
         'Helvetica Neue', Arial, sans-serif;
  --mono: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas,
          'Liberation Mono', monospace;

  --r-s: 10px;
  --r-m: 16px;
  --r-l: 22px;
  --r-xl: 28px;

  --barre: 280px;          /* largeur du panneau latéral */
  --colonne: 780px;        /* largeur de lecture du fil */

  /*  Une seule courbe d'animation pour toute l'application. Un mouvement
   *  cohérent se remarque moins qu'un mouvement varié — et c'est le but :
   *  l'interface doit paraître vivante, pas agitée. */
  --elan: cubic-bezier(.22, .61, .36, 1);
  --elan-doux: cubic-bezier(.4, 0, .2, 1);
}

html, body {
  height: 100%;
  font-family: var(--pol);
  font-size: 15px;
  line-height: 1.55;
  color: var(--ciel-texte, #eef3f8);
  background: #05070c;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overscroll-behavior: none;
}

body { overflow: hidden; }

::selection { background: var(--ciel-accent-trait, rgba(110,231,255,.4)); color: #fff; }

/*  Les barres de défilement : discrètes, mais présentes. Une barre invisible
 *  cache l'information « il y a d'autres messages au-dessus ». */
* { scrollbar-width: thin; scrollbar-color: var(--ciel-bord, rgba(255,255,255,.18)) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--ciel-bord, rgba(255,255,255,.16));
  border-radius: 99px; border: 3px solid transparent; background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover { background: var(--ciel-bord-fort, rgba(255,255,255,.3)); background-clip: padding-box; }

/* =========================================================================
 *  LE VERRE
 * =========================================================================
 *  Quand le ciel est allumé, l'interface doit LE LAISSER VOIR. Des panneaux
 *  opaques posés devant un fond vivant le transforment en papier peint qu'on
 *  cesse de regarder au bout de dix minutes — et toute la valeur du dispositif
 *  disparaît avec.
 *
 *  L'opacité n'est donc écrite nulle part ici. `--ciel-verre` est CALCULÉ par
 *  le module du ciel : c'est la plus petite opacité qui tienne encore le
 *  rapport de contraste du texte, composée sur le ciel du moment. La nuit on
 *  voit les étoiles à travers les bulles ; à midi elles s'épaississent d'elles
 *  -mêmes. Voir `publierTeinte` dans ciel.js.
 *
 *  Le reste — le flou, le reflet du haut, l'ombre portée — ne sert pas à la
 *  lisibilité mais à la MATIÈRE : sans eux, un panneau translucide est un
 *  rectangle gris pâle, pas une plaque de verre.
 * ========================================================================= */
.verre {
  background: var(--ciel-verre, rgba(8, 11, 18, .72));
  backdrop-filter: blur(26px) saturate(1.4);
  -webkit-backdrop-filter: blur(26px) saturate(1.4);
  border: 1px solid var(--ciel-bord, rgba(255, 255, 255, .12));
  position: relative;
}

/*  LE REFLET DU HAUT — le détail qui fait « verre » plutôt que « calque ».
 *
 *  Une plaque de verre attrape la lumière sur son arête supérieure. Un seul
 *  trait clair, dégradé sur la largeur, et l'œil cesse de lire une
 *  transparence pour lire un objet. C'est dix lignes pour la moitié de
 *  l'effet. */
.verre::before {
  content: '';
  position: absolute; left: 12%; right: 12%; top: 0; height: 1px;
  background: linear-gradient(to right,
              transparent, var(--ciel-reflet, rgba(255,255,255,.28)), transparent);
  pointer-events: none;
  border-radius: inherit;
}

/* ----------------------------------------------------------------------- */
/*  LE CIEL — derrière tout, et jamais cliquable                            */
/* ----------------------------------------------------------------------- */
#ciel {
  position: fixed; inset: 0; z-index: 0;
  pointer-events: none;
  transition: opacity .6s var(--elan-doux);
}
:root[data-charte="classique"] #ciel { opacity: 0; }

/* ----------------------------------------------------------------------- */
/*  CHARPENTE                                                               */
/* ----------------------------------------------------------------------- */
/*  LE PANNEAU EST REPLIÉ PAR DÉFAUT.
 *
 *  Il occupait 280 px en permanence, sur tous les écrans, pour un historique
 *  qu'on consulte quelques secondes par jour. L'application s'ouvre donc
 *  maintenant sur ce qui sert : le champ de saisie, au centre. Le panneau se
 *  déplie d'un clic et se replie de même — il glisse par-dessus, il ne
 *  repousse rien, si bien que la conversation ne saute pas au passage. */
.app {
  position: relative; z-index: 1;
  display: block;
  height: 100%;
}

/* ======================= LE PANNEAU LATÉRAL ============================= */
.cote {
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 40;
  width: var(--barre);
  transform: translateX(-101%);
  display: flex; flex-direction: column;
  min-height: 0;
  background: var(--ciel-verre, rgba(8,11,18,.72));
  border-right: 1px solid var(--ciel-bord, rgba(255,255,255,.10));
  backdrop-filter: blur(28px) saturate(1.45);
  -webkit-backdrop-filter: blur(28px) saturate(1.45);
  transition: transform .34s var(--elan);
}

.cote-haut {
  display: flex; align-items: center; gap: 11px;
  padding: 18px 18px 14px;
}
/*  Le logo blanc prend la couleur du texte de l'interface : sous un ciel
 *  clair il fonce, la nuit il reste blanc — un seul dessin, teinté par le
 *  ciel (currentColor), avec une lueur à la couleur d'accent. */
.cote-haut .sceau { width: 30px; height: 30px; flex: none; overflow: visible;
  color: var(--ciel-texte, #eef3f8);
  filter: drop-shadow(0 0 5px var(--ciel-accent-doux, rgba(110, 231, 255, .35))); }
.cote-haut .nom {
  font-size: .80rem; font-weight: 650; letter-spacing: .22em;
  color: var(--ciel-texte, #eef3f8);
}

/*  Le bouton « nouvelle conversation » : c'est l'action principale de la
 *  barre, il doit se voir sans crier. */
.neuf {
  margin: 2px 14px 14px;
  display: flex; align-items: center; justify-content: center; gap: 9px;
  padding: 11px 14px;
  border: 1px solid var(--ciel-accent-trait, rgba(110,231,255,.4));
  border-radius: var(--r-m);
  background: var(--ciel-accent-doux, rgba(110,231,255,.12));
  color: var(--ciel-accent, #6ee7ff);
  font: inherit; font-weight: 600; font-size: .88rem;
  cursor: pointer;
  transition: background .22s var(--elan), transform .18s var(--elan),
              box-shadow .22s var(--elan);
}
.neuf:hover {
  background: var(--ciel-accent-trait, rgba(110,231,255,.26));
  transform: translateY(-1px);
  box-shadow: 0 8px 22px -12px var(--ciel-accent, #6ee7ff);
}
.neuf:active { transform: translateY(0) scale(.985); }
.neuf svg { width: 16px; height: 16px; }

/*  L'ATELIER, JUSTE EN DESSOUS.
 *
 *  Ouvrir une conversation et ouvrir l'atelier sont les deux façons de
 *  COMMENCER quelque chose : elles se ressemblent et vont ensemble. L'atelier
 *  était relégué au pied du tiroir, à côté des réglages, entre deux boutons
 *  de la taille d'une icône — on ne le trouvait qu'en le cherchant.
 *
 *  Il reste SECOND, en trait plutôt qu'en fond plein : c'est la porte qu'on
 *  pousse moins souvent, elle ne doit pas disputer l'accent à l'autre.
 *
 *  ------------------------------------------------------------------------
 *  POURQUOI CE BOUTON S'APPELLE `.btn-atelier` ET PLUS `.atelier`
 *  ------------------------------------------------------------------------
 *  Il s'appelait `.atelier`. Et `atelier.html` — qui charge cette même
 *  feuille — portait `<body class="atelier">`.
 *
 *  Le corps entier de la page de l'atelier était donc rendu COMME CE BOUTON :
 *  `display:flex`, `justify-content:center`, un padding, une bordure et une
 *  marge haute négative. Sur un écran de 1866 px, la page se rétractait à
 *  789 px au milieu du vide, et la colonne de code tombait à 169 px — une
 *  colonne d'éditeur plus étroite qu'une ligne de code.
 *
 *  Rien ne signalait la collision : les deux règles étaient correctes
 *  séparément, aucune console ne proteste, et le défaut ne se voit que sur la
 *  page qui n'a pas écrit la règle. C'est pourquoi le nom est maintenant
 *  PRÉFIXÉ : `.btn-` dit que c'est un bouton, et aucune page ne mettra jamais
 *  `btn-atelier` sur son `<body>`. */
.btn-atelier {
  margin: -6px 14px 14px;
  display: flex; align-items: center; justify-content: center; gap: 9px;
  padding: 10px 14px;
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.13));
  border-radius: var(--r-m);
  background: none;
  color: var(--ciel-texte-doux, rgba(238,243,248,.78));
  font: inherit; font-weight: 560; font-size: .86rem;
  cursor: pointer;
  transition: background .2s var(--elan), color .2s var(--elan),
              border-color .2s var(--elan);
}
.btn-atelier:hover {
  background: var(--ciel-accent-doux, rgba(255,255,255,.07));
  color: var(--ciel-texte, #eef3f8);
  border-color: var(--ciel-accent-trait, rgba(110,231,255,.32));
}
.btn-atelier svg { width: 16px; height: 16px; }

.cote-titre {
  padding: 6px 20px 8px;
  font-size: .68rem; font-weight: 620; letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ciel-texte-doux, rgba(238,243,248,.55));
}

.histoire { flex: 1; min-height: 0; overflow-y: auto; padding: 0 10px 12px; }

/*  LA LIGNE PORTE DEUX GESTES, DONC DEUX BOUTONS.
 *
 *  Elle ÉTAIT un bouton. Ouvrir la conversation et agir dessus sont pourtant
 *  deux choses distinctes, et un `<button>` dans un `<button>` n'est pas
 *  permis : le navigateur défait la structure en silence et les clics partent
 *  au mauvais endroit. La ligne est donc devenue un conteneur, et c'est le
 *  bouton d'ouverture qui prend toute la place restante. */
.fil-item {
  display: flex; align-items: center; gap: 2px;
  width: 100%;
  margin-bottom: 2px;
  border: 1px solid transparent; border-radius: var(--r-s);
  color: var(--ciel-texte-doux, rgba(238,243,248,.72));
  transition: background .18s var(--elan), color .18s var(--elan);
}
.fil-ouvrir {
  display: flex; align-items: center; gap: 10px;
  min-width: 0; flex: 1; text-align: left;
  padding: 9px 4px 9px 12px;
  border: 0; border-radius: var(--r-s);
  background: none; color: inherit;
  font: inherit; font-size: .875rem;
  cursor: pointer;
}
.fil-titre { min-width: 0; flex: 1;
             white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/*  L'ÉPINGLE SE VOIT.
 *
 *  Sans marque, une conversation qui reste obstinément en tête de liste
 *  passe pour un défaut de tri, et l'on cherche pourquoi elle ne bouge pas. */
.fil-epingle {
  flex: none; display: inline-flex; width: 12px; height: 12px;
  color: var(--ciel-accent, #6ee7ff); opacity: .75;
}
.fil-epingle svg { width: 100%; height: 100%; }

/*  LES TROIS POINTS.
 *
 *  Discrets au repos, francs au survol. Ils restent VISIBLES sur téléphone,
 *  où il n'y a pas de survol : une action qui n'apparaît qu'au passage de la
 *  souris n'existe pas sur un écran tactile. */
.fil-plus {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; margin-right: 5px;
  border: 0; border-radius: var(--r-s);
  background: none; color: var(--ciel-texte-doux, rgba(238,243,248,.42));
  cursor: pointer; opacity: 0;
  transition: opacity .16s var(--elan), background .16s var(--elan),
              color .16s var(--elan);
}
.fil-plus svg { width: 17px; height: 17px; }
.fil-item:hover .fil-plus,
.fil-item:focus-within .fil-plus,
.fil-plus[aria-expanded="true"] { opacity: 1; }
.fil-plus:hover {
  background: var(--ciel-accent-doux, rgba(255,255,255,.10));
  color: var(--ciel-texte, #eef3f8);
}
@media (hover: none) {
  .fil-plus { opacity: 1; }
}

/* --------------------------- LE MENU D'UNE CONVERSATION ----------------- */
/*  Posé sur le `body` en position fixe, et non dans la liste : dans un
 *  conteneur qui défile, un menu se fait couper par le bord dès qu'il
 *  s'ouvre sur la dernière ligne. */
.menu-conv {
  position: fixed; z-index: 80;
  min-width: 186px; padding: 5px;
  border-radius: var(--r-m);
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.13));
  background: var(--ciel-verre, rgba(10,14,22,.88));
  backdrop-filter: blur(26px) saturate(1.4);
  -webkit-backdrop-filter: blur(26px) saturate(1.4);
  box-shadow: 0 14px 38px rgba(0,0,0,.42);
  animation: surgir .14s var(--elan) both;
}
.menu-conv-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%; text-align: left;
  padding: 9px 11px;
  border: 0; border-radius: var(--r-s);
  background: none; color: var(--ciel-texte, #eef3f8);
  font: inherit; font-size: .85rem;
  cursor: pointer;
}
.menu-conv-item .ic {
  flex: none; display: inline-flex; width: 15px; height: 15px;
  color: var(--ciel-texte-doux, rgba(238,243,248,.55));
}
.menu-conv-item .ic svg { width: 100%; height: 100%; }
.menu-conv-item:hover { background: var(--ciel-accent-doux, rgba(255,255,255,.09)); }
/*  La suppression est définitive : elle se distingue AVANT le clic, pas
 *  après. C'est la seule ligne du menu qu'on ne peut pas défaire. */
.menu-conv-item.danger { color: #ff8b8b; }
.menu-conv-item.danger .ic { color: #ff8b8b; }
.menu-conv-item.danger:hover { background: rgba(255,107,107,.13); }

/*  LA BULLE : MÊME FORME, REMPLISSAGE DIFFÉRENT.
 *
 *  Pleine, il reste quelque chose à lire ; vide, on est à jour. Changer
 *  d'ICÔNE entre les deux états aurait fait croire à deux sortes d'objets —
 *  c'est la même conversation, seul son état change. */
.fil-ico {
  flex: none; display: inline-flex; width: 17px; height: 17px;
  color: var(--ciel-texte-doux, rgba(238,243,248,.4));
  transition: color .18s var(--elan);
}
.fil-ico svg { width: 100%; height: 100%; }
.fil-ico.pleine { color: var(--ciel-accent, #6ee7ff); }

.fil-item.non-lue { color: var(--ciel-texte, #eef3f8); }
.fil-item.non-lue .fil-titre { font-weight: 600; }
.fil-item:hover { background: var(--ciel-accent-doux, rgba(255,255,255,.07)); color: var(--ciel-texte, #eef3f8); }
.fil-item[aria-current="true"] {
  background: var(--ciel-accent-doux, rgba(110,231,255,.14));
  border-color: var(--ciel-accent-trait, rgba(110,231,255,.34));
  color: var(--ciel-texte, #fff);
}
.histoire .vide {
  padding: 16px 12px; font-size: .84rem;
  color: var(--ciel-texte-doux, rgba(238,243,248,.45));
}

.cote-bas {
  border-top: 1px solid var(--ciel-bord, rgba(255,255,255,.10));
  padding: 12px 14px;
  display: flex; flex-direction: column; gap: 10px;
}

/*  Les crédits mènent à leur propre page : c'est là qu'on va juste après
 *  avoir regardé le solde. */
.jauge {
  display: block; text-decoration: none; border-radius: var(--r-s);
  padding: 8px 10px; margin: -2px;
  font-size: .78rem; color: var(--ciel-texte-doux, rgba(238,243,248,.6));
  transition: background .18s var(--elan);
}
.jauge:hover { background: var(--ciel-accent-doux, rgba(255,255,255,.06)); }
.jauge-tete { display: block; }
.jauge b { color: var(--ciel-accent, #6ee7ff); font-weight: 640; font-variant-numeric: tabular-nums; }
.jauge-barre {
  margin-top: 6px; height: 4px; border-radius: 99px;
  background: var(--ciel-bord, rgba(255,255,255,.12)); overflow: hidden;
}
.jauge-barre i {
  display: block; height: 100%; border-radius: 99px;
  background: var(--ciel-accent, #6ee7ff);
  transition: width .6s var(--elan);
}

/* -------------------------- LE COMPTE, TOUT EN BAS ---------------------- */
/*  Le prénom et le forfait n'apparaissaient nulle part dans l'application :
 *  pour savoir sur quel plan on était — donc quels moteurs on avait — il
 *  fallait ouvrir les réglages. C'est pourtant la première chose qu'on
 *  cherche quand une réponse semble bridée. */
.compte {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; border-radius: var(--r-m);
  text-decoration: none; color: inherit;
  border: 1px solid transparent;
  transition: background .18s var(--elan), border-color .18s var(--elan);
}
.compte:hover {
  background: var(--ciel-accent-doux, rgba(255,255,255,.07));
  border-color: var(--ciel-bord, rgba(255,255,255,.12));
}

.pastille {
  flex: none; width: 32px; height: 32px; border-radius: 99px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--ciel-accent-doux, rgba(110,231,255,.16));
  color: var(--ciel-accent, #6ee7ff);
  font-size: .84rem; font-weight: 680;
}

.compte-txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.compte-txt b {
  font-size: .86rem; font-weight: 600; color: var(--ciel-texte, #eef3f8);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/*  Le forfait en petites capitales espacées : il se lit comme une étiquette,
 *  pas comme un second prénom. */
.compte-txt span {
  font-size: .68rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ciel-texte-doux, rgba(238,243,248,.52));
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.compte-fleche { width: 16px; height: 16px; flex: none;
                 color: var(--ciel-texte-doux, rgba(238,243,248,.42)); }
.compte:hover .compte-fleche { color: var(--ciel-accent, #6ee7ff); }

/* ============================ LA SCÈNE ================================== */
/*  LA SCÈNE PREND TOUTE LA HAUTEUR.
 *  Tant que le panneau occupait une colonne de grille, la hauteur venait de
 *  la grille. En passant le panneau en tiroir, `.app` est devenu un bloc
 *  ordinaire — et la scène s'est mise à ne faire que la hauteur de son
 *  contenu : la conversation tenait dans le tiers haut de l'écran, le reste
 *  était vide. */
.scene { display: flex; flex-direction: column; min-width: 0; height: 100%; }

/*  L'EN-TÊTE NE SE VOIT PLUS, ELLE SE LIT.
 *  Plus de fond, plus de bordure : un bandeau opaque en haut d'un écran
 *  qui a déjà un ciel coupe l'image en deux pour porter six mots. Le titre
 *  est centré, le bouton du tiroir reste à gauche, et c'est tout. */
.entete {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 22px 6px;
  background: none; border: 0;
  position: relative; z-index: 3;
}
/*  LE BOUTON DU TIROIR EST TOUJOURS LÀ.
 *  Le panneau des conversations est replié par défaut — l'écran de travail
 *  gagne 280 px, et on ne consulte pas son historique en écrivant. Il faut
 *  donc pouvoir le rappeler d'un geste, sur toutes les tailles d'écran. */
.entete .tiroir-btn { display: inline-flex; flex: none; }
.entete h1 {
  flex: 1; min-width: 0; text-align: center;
  font-size: .88rem; font-weight: 600; letter-spacing: .01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--ciel-texte-doux, rgba(238,243,248,.68));
}
/*  À droite, le bouton « nouvelle conversation » fait le contrepoids du
 *  tiroir : même taille, donc le titre reste centré sur l'écran. Sur
 *  l'écran d'accueil il n'a rien à faire — on y est déjà. */
.entete .rond-btn { width: 38px; height: 38px; }
.scene.vierge #btnNeufEntete { visibility: hidden; }


.meteo .pastille {
  width: 7px; height: 7px; border-radius: 99px;
  background: var(--ciel-accent, #6ee7ff);
  box-shadow: 0 0 10px var(--ciel-accent, #6ee7ff);
}

/* -------------------------------- LE FIL -------------------------------- */
.fil {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: 34px 22px 12px;
  scroll-behavior: smooth;
}
.fil-dedans {
  width: 100%; max-width: var(--colonne); margin: 0 auto;
  display: flex; flex-direction: column; gap: 22px;
}

/*  L'ACCUEIL — ce qu'on voit avant d'avoir écrit quoi que ce soit. */
.accueil {
  display: flex; flex-direction: column; align-items: center;
  text-align: center; padding: 6vh 0 3vh; gap: 16px;
}
/*  IL EST PLUS GROS, ET C'EST DÉLIBÉRÉ.
 *
 *  132 px, c'était la taille d'une icône : l'objet portait le nom du produit
 *  et se lisait comme une pastille décorative. Un trou noir a besoin de place
 *  pour qu'on voie son disque le traverser — c'est ce croisement qui fait
 *  l'image, et il disparaît en dessous de ~180 px.
 *
 *  `clamp` plutôt qu'une valeur fixe : sur un écran court, 216 px mangeraient
 *  la place du titre et du champ de saisie juste en dessous. */
.accueil .orbe { width: clamp(168px, 22vh, 216px); aspect-ratio: 1; height: auto; }
/*  L'accroche est posée à même le ciel, sans verre : par un midi clair,
 *  une ombre portée très douce la décolle du bleu sans la cercler. */
.accueil h2 {
  font-size: 1.75rem; font-weight: 640; letter-spacing: -.015em;
  color: var(--ciel-texte, #fff);
  text-shadow: 0 1px 18px rgba(0, 0, 0, .35), 0 1px 2px rgba(0, 0, 0, .25);
}
.accueil p {
  max-width: 460px; font-size: .98rem;
  color: var(--ciel-texte, rgba(238,243,248,.86));
  opacity: .82;
  text-shadow: 0 1px 12px rgba(0, 0, 0, .4);
}
.pistes { display: flex; flex-wrap: wrap; gap: 9px; justify-content: center; margin-top: 6px; }
.piste {
  padding: 9px 15px; border-radius: 99px;
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.13));
  background: var(--ciel-verre, rgba(8,11,18,.45));
  backdrop-filter: blur(20px) saturate(1.3);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
  color: var(--ciel-texte-doux, rgba(238,243,248,.8));
  font: inherit; font-size: .85rem; cursor: pointer;
  transition: transform .2s var(--elan), border-color .2s var(--elan),
              background .2s var(--elan), color .2s var(--elan);
}
.piste:hover {
  transform: translateY(-2px);
  border-color: var(--ciel-accent-trait, rgba(110,231,255,.45));
  background: var(--ciel-accent-doux, rgba(110,231,255,.12));
  color: var(--ciel-texte, #fff);
}

/* ------------------------------ LES BULLES ------------------------------ */
/*  PLUS SIMPLE, PLUS CALME.
 *
 *  La question était un bloc plein, couleur d'accent : sous un coucher de
 *  soleil, un rectangle orange vif qui attirait l'œil plus que la réponse.
 *  Elle devient du VERRE TEINTÉ — l'accent du ciel mêlé au verre — et se
 *  range à droite, discrète. La réponse garde son verre clair, sans ombre
 *  lourde : on lit le texte, pas la boîte. */
.tour { display: flex; flex-direction: column; gap: 8px; }
.tour.de-moi { align-items: flex-end; }

.bulle {
  position: relative;
  max-width: 100%;
  padding: 15px 19px;
  border-radius: 22px;
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.10));
  background: var(--ciel-verre, rgba(8,11,18,.62));
  backdrop-filter: blur(24px) saturate(1.45);
  -webkit-backdrop-filter: blur(24px) saturate(1.45);
  box-shadow: 0 22px 60px -42px rgba(0, 0, 0, .75);
  animation: surgir .42s var(--elan) both;
}
.bulle::before {
  content: '';
  position: absolute; left: 12%; right: 12%; top: 0; height: 1px;
  background: linear-gradient(to right,
              transparent, var(--ciel-reflet, rgba(255,255,255,.26)), transparent);
  pointer-events: none;
}
.tour.de-moi .bulle {
  max-width: min(78%, 580px);
  padding: 11px 17px;
  border-radius: 20px 20px 6px 20px;
  background: rgba(40, 60, 80, .55);
  background: color-mix(in srgb, var(--ciel-accent, #6ee7ff) 17%, var(--ciel-verre, rgba(8,11,18,.62)));
  border-color: color-mix(in srgb, var(--ciel-accent, #6ee7ff) 30%, transparent);
  color: var(--ciel-texte, #eef3f8);
  box-shadow: none;
}
.tour.de-lui .bulle { border-top-left-radius: 8px; }
/*  L'encart porte déjà son cadre : on ne l'enferme pas dans un second. */
.bulle.encart-hote {
  padding: 0; border: 0; background: none; box-shadow: none;
  backdrop-filter: none; -webkit-backdrop-filter: none;
}
.bulle.encart-hote::before { display: none; }

@keyframes surgir {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* --------------------- LE RENDU RICHE DES RÉPONSES ---------------------- */
.corps > * + * { margin-top: .82em; }
.corps h1, .corps h2, .corps h3 {
  line-height: 1.28; letter-spacing: -.012em;
  color: var(--ciel-accent, #6ee7ff);
}
.corps h1 { font-size: 1.42rem; font-weight: 680; }
.corps h2 { font-size: 1.16rem; font-weight: 660; }
.corps h3 { font-size: 1.00rem; font-weight: 640; color: var(--ciel-texte, #eef3f8); }
.corps h1 + *, .corps h2 + *, .corps h3 + * { margin-top: .42em; }

.corps strong { font-weight: 660; color: var(--ciel-texte, #fff); }
.corps em { font-style: italic; }
.corps a { color: var(--ciel-accent, #6ee7ff); text-underline-offset: 3px; }

.corps ul, .corps ol { padding-left: 1.35em; }
.corps li + li { margin-top: .3em; }
.corps li::marker { color: var(--ciel-accent, #6ee7ff); }

.corps blockquote {
  padding: 2px 0 2px 15px;
  border-left: 2px solid var(--ciel-accent-trait, rgba(110,231,255,.45));
  color: var(--ciel-texte-doux, rgba(238,243,248,.78));
  font-style: italic;
}

.corps hr {
  border: 0; height: 1px;
  background: var(--ciel-bord, rgba(255,255,255,.12));
  margin: 1.15em 0;
}

.corps code {
  font-family: var(--mono); font-size: .87em;
  padding: .14em .42em; border-radius: 6px;
  background: var(--ciel-accent-doux, rgba(110,231,255,.14));
  color: var(--ciel-accent, #6ee7ff);
}

/*  LES TABLEAUX débordent plus souvent qu'on ne croit : cours de bourse,
 *  comparatifs. Ils défilent dans leur propre boîte plutôt que d'élargir
 *  toute la page. */
.corps .table-hote { overflow-x: auto; border-radius: var(--r-s); }
.corps table { border-collapse: collapse; width: 100%; font-size: .9rem; }
.corps th, .corps td {
  padding: 8px 12px; text-align: left;
  border-bottom: 1px solid var(--ciel-bord, rgba(255,255,255,.10));
  white-space: nowrap;
}
.corps th {
  font-weight: 620; color: var(--ciel-accent, #6ee7ff);
  border-bottom-color: var(--ciel-accent-trait, rgba(110,231,255,.4));
}
.corps tbody tr:last-child td { border-bottom: 0; }

/*  Une colonne de chiffres s'aligne à DROITE, et en chasse fixe.
 *
 *  Alignés à gauche, « 9 » et « 1 240 » ne se comparent pas : il faut lire
 *  chaque nombre en entier. À droite, les unités sont les unes sous les
 *  autres et l'ordre de grandeur saute aux yeux. Les chiffres tabulaires
 *  finissent le travail : un « 1 » et un « 8 » occupent la même largeur, donc
 *  les colonnes restent droites d'une ligne à l'autre. */
.corps th.num, .corps td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}
/*  La ligne de total ne se lit pas comme les autres : elle les résume. */
.corps tbody tr.total td {
  font-weight: 640;
  color: var(--ciel-texte, #eef3f8);
  border-top: 1px solid var(--ciel-accent-trait, rgba(110,231,255,.4));
  background: var(--ciel-accent-doux, rgba(110,231,255,.07));
}

/* --------------------------- LES GRAPHIQUES ---------------------------- */
/*  Du SVG, sans bibliothèque, construit en nœuds par `graphique.js`. Les
 *  couleurs des séries sont posées en attribut — elles portent du SENS et ne
 *  doivent pas changer avec le thème — mais tout le décor (grille, axes,
 *  graduations) suit l'ambiance du ciel, comme le reste de l'interface. */
.orion-graphique {
  margin: 14px 0;
  padding: 14px 16px 10px;
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.12));
  border-radius: var(--r-m);
  background: var(--ciel-surface, rgba(4,6,11,.5));
}
.orion-graphique figcaption {
  font-size: .88rem; font-weight: 620; margin: 0 0 10px;
  color: var(--ciel-texte, #eef3f8);
}
/*  Hauteur fixe et largeur pleine : le viewBox fait 720×300 et
 *  `preserveAspectRatio="none"` l'étire en largeur. Sans hauteur explicite,
 *  un SVG sans ratio s'effondre à zéro pixel dans un conteneur souple — le
 *  graphique est là, dans le DOM, parfaitement dessiné, et invisible. */
.orion-graphique .g-svg { width: 100%; height: 300px; display: block; overflow: visible; }
.orion-graphique .g-grille line {
  stroke: var(--ciel-bord, rgba(255,255,255,.10)); stroke-width: 1;
}
.orion-graphique .g-grille line.g-zero {
  stroke: var(--ciel-bord-fort, rgba(255,255,255,.28)); stroke-width: 1.2;
}
.orion-graphique text {
  fill: var(--ciel-texte-doux, rgba(238,243,248,.62));
  font: 11px var(--pol);
}
.orion-graphique .g-axe { fill: var(--ciel-texte-doux, rgba(238,243,248,.5)); font-size: 10.5px; }
.orion-graphique .g-leg { font-size: 12px; fill: var(--ciel-texte, #eef3f8); }
.orion-graphique .g-centre { font-size: 15px; font-weight: 640; fill: var(--ciel-texte, #eef3f8); }
.orion-graphique .g-trou { fill: var(--ciel-surface, #0a0e15); }
.orion-graphique .g-barre, .orion-graphique .g-part, .orion-graphique .g-point {
  transition: opacity .14s var(--elan-doux);
}
.orion-graphique svg:hover .g-barre, .orion-graphique svg:hover .g-part { opacity: .72; }
.orion-graphique .g-barre:hover, .orion-graphique .g-part:hover,
.orion-graphique .g-point:hover { opacity: 1; }
.orion-graphique .g-legende {
  display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 10px;
  font-size: .8rem; color: var(--ciel-texte-doux, rgba(238,243,248,.72));
}
.orion-graphique .g-legende span { display: inline-flex; align-items: center; gap: 7px; }
.orion-graphique .g-legende i { width: 11px; height: 11px; border-radius: 3px; flex: none; }
.orion-graphique .g-note, .orion-graphique .g-vide {
  margin: 9px 0 0; font-size: .8rem; color: var(--ciel-texte-doux, rgba(238,243,248,.56));
}

/*  Sur un écran étroit, un graphique de trois cents pixels de haut mange tout
 *  l'écran et l'on ne voit plus le texte qui l'explique. */
@media (max-width: 620px) {
  .orion-graphique { padding: 11px 12px 8px; }
  .orion-graphique .g-svg { height: 220px; }
}

/* -------------------------- LES ZONES DE CODE --------------------------- */
/*  Le bloc de code n'est PAS un morceau de texte en police fixe : c'est un
 *  objet, avec son en-tête, son langage et son bouton de copie. On le traite
 *  comme tel parce qu'on ne le lit pas, on le prend. */
.zone {
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.12));
  border-radius: var(--r-m);
  overflow: hidden;
  background: rgba(4, 6, 11, .62);
}
.zone-tete {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px 8px 14px;
  border-bottom: 1px solid var(--ciel-bord, rgba(255,255,255,.10));
  background: rgba(255, 255, 255, .028);
}
.zone-langue {
  font-family: var(--mono); font-size: .72rem; letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ciel-texte-doux, rgba(238,243,248,.55));
}
.copier {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px; border-radius: 7px;
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.14));
  background: none; color: var(--ciel-texte-doux, rgba(238,243,248,.75));
  font: inherit; font-size: .76rem; cursor: pointer;
  transition: background .18s var(--elan), color .18s var(--elan),
              border-color .18s var(--elan);
}
.copier:hover {
  background: var(--ciel-accent-doux, rgba(110,231,255,.15));
  color: var(--ciel-accent, #6ee7ff);
  border-color: var(--ciel-accent-trait, rgba(110,231,255,.4));
}
.copier.fait { color: var(--ciel-accent, #6ee7ff); border-color: var(--ciel-accent-trait, rgba(110,231,255,.5)); }
.copier svg { width: 13px; height: 13px; }
.zone pre {
  margin: 0; padding: 14px; overflow-x: auto;
  font-family: var(--mono); font-size: .83rem; line-height: 1.62;
  color: #dbe6f2;
}

/*  Le <code> à l'intérieur d'un <pre> n'est PAS du code en ligne.
 *
 *  Sans cette remise à zéro, il hérite du fond et de la couleur de `.corps
 *  code` : chaque ligne du bloc se retrouve surlignée en cyan, comme si tout
 *  le programme était une suite de petites étiquettes. Ça se voit
 *  immédiatement sur une capture et pas du tout à la lecture du CSS. */
.zone pre code {
  background: none; padding: 0; border-radius: 0;
  color: inherit; font-family: inherit; font-size: inherit;
}
/*  Et dans une zone « à copier », le texte reste du texte : c'est un message
 *  à envoyer, pas un programme. */
.zone.texte pre code { font-family: var(--pol); }

/*  La zone de texte copiable : un paragraphe qu'on est censé reprendre tel
 *  quel — un message rédigé, une requête, une adresse. Elle se distingue du
 *  code par la police, mais garde le bouton. */
.zone.texte pre {
  font-family: var(--pol); font-size: .93rem; line-height: 1.6;
  white-space: pre-wrap; word-break: break-word;
  color: var(--ciel-texte, #eef3f8);
}

/* ------------------------ LA PENSÉE EN DIRECT --------------------------- */
/*  UNE LIGNE VIVANTE, PAS UN RAPPORT.
 *
 *  Une petite nébuleuse qui tourne, et ce qui se fait à l'instant, en texte
 *  qui miroite. Rien d'autre. Les étapes se déplient d'un clic ; la réponse
 *  arrivée, la ligne se replie en « 3 étapes » — ou disparaît. */
.pensee {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 2px 0 2px 4px;
  animation: surgir .3s var(--elan) both;
}
/*  LA NÉBULEUSE EN MINIATURE — la même famille que la grande : un cœur
 *  blanc, un voile bleu-vert, un voile rose, qui tournent l'un dans
 *  l'autre. Du CSS pur : aucune image, aucun canevas pour 18 pixels. */
.pensee .lueur {
  position: relative; flex: none;
  width: 18px; height: 18px; margin-top: 1px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 50% 50%, rgba(255,255,255,.95) 0 9%, transparent 24%),
    radial-gradient(circle at 36% 40%, rgba(120,225,255,.9), transparent 58%),
    radial-gradient(circle at 66% 64%, rgba(255,105,170,.85), transparent 62%),
    radial-gradient(circle at 50% 50%, rgba(150,95,255,.45), transparent 74%);
  box-shadow: 0 0 12px -2px rgba(255,120,190,.6), 0 0 18px -6px rgba(120,225,255,.7);
  animation: nebuleuse-mini 2.6s linear infinite, respire-mini 1.3s ease-in-out infinite alternate;
}
@keyframes nebuleuse-mini { to { rotate: 360deg; } }
@keyframes respire-mini { from { scale: .86; } to { scale: 1.08; } }

.pensee-texte { min-width: 0; flex: 1; }
.pensee-quoi {
  display: inline-flex; align-items: center; gap: 6px;
  border: 0; background: none; padding: 0; cursor: default;
  font: inherit; font-size: .85rem; text-align: left;
  color: var(--ciel-texte-doux, rgba(238,243,248,.66));
  /*  Le texte MIROITE pendant le travail : une lumière qui passe, lente. */
  background-image: linear-gradient(100deg,
      var(--ciel-texte-doux, rgba(238,243,248,.55)) 35%,
      var(--ciel-texte, #fff) 50%,
      var(--ciel-texte-doux, rgba(238,243,248,.55)) 65%);
  background-size: 250% 100%;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: miroiter 2.2s linear infinite;
}
@keyframes miroiter { from { background-position: 100% 0; } to { background-position: -150% 0; } }
.pensee-moteur { display: none; }

/*  Repliée : plus de miroitement, plus de rotation — c'est de l'historique. */
.pensee.fini .lueur {
  animation: none; scale: .62; opacity: .55;
  box-shadow: none;
}
.pensee.fini .pensee-quoi {
  animation: none; cursor: pointer;
  -webkit-text-fill-color: currentColor; background: none;
  font-size: .78rem;
  color: var(--ciel-texte-doux, rgba(238,243,248,.5));
}
.pensee.fini .pensee-quoi::after {
  content: ''; width: 6px; height: 6px; margin-left: 2px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  rotate: -45deg; transition: rotate .2s var(--elan);
}
.pensee.fini.deplie .pensee-quoi::after { rotate: 45deg; translate: 0 -2px; }
.pensee.fini .pensee-quoi:hover { color: var(--ciel-texte, #eef3f8); }
.pensee.arret .pensee-quoi { cursor: default; }
.pensee.arret .pensee-quoi::after { display: none; }

.etapes {
  display: flex; flex-direction: column; gap: 3px;
  margin-top: 7px; padding-left: 10px;
  border-left: 1px solid var(--ciel-bord, rgba(255,255,255,.09));
}
.etape {
  display: flex; align-items: center; gap: 8px;
  font-size: .79rem; color: var(--ciel-texte-doux, rgba(238,243,248,.58));
  animation: glisser .3s var(--elan) both;
}
@keyframes glisser { from { opacity: 0; transform: translateX(-6px); } to { opacity: 1; transform: none; } }

/*  L'ICÔNE DE L'ACTION, puis son ISSUE — collée au texte qu'elle qualifie. */
.etape .marque,
.etape .issue { flex: none; display: inline-flex; }
.etape .marque svg,
.etape .issue svg { width: 14px; height: 14px; display: block; }
.etape .marque { color: var(--ciel-texte-doux, rgba(238,243,248,.45)); }
.etape .quoi {
  min-width: 0; flex: 0 1 auto;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.etape .issue { color: var(--ciel-texte-doux, rgba(238,243,248,.35)); }
.etape.ok .issue { color: var(--ciel-accent, #6ee7ff); }
.etape.ok .marque { color: var(--ciel-texte-doux, rgba(238,243,248,.62)); }
.etape.ko .issue,
.etape.ko .marque { color: #ff7a7a; }
.etape.ko { color: #ffb0b0; }
.etape.denied .issue, .etape.denied .marque { color: #ffc98a; }

/* ------------------ SOUS LA RÉPONSE : COPIER · RÉGÉNÉRER · SOURCES ------- */
/*  Une rangée légère, toujours visible (un téléphone n'a pas de survol),
 *  qui ne prend de la couleur qu'au geste. Le résumé — moteur, coût,
 *  durée — se pose à droite, en petit : il se consulte, il ne se lit pas. */
.actions {
  display: flex; align-items: center; flex-wrap: wrap; gap: 2px;
  padding: 0 2px;
  animation: surgir .35s var(--elan) both;
}
.act {
  display: inline-flex; align-items: center; gap: 6px;
  height: 30px; padding: 0 10px;
  border-radius: 99px; border: 1px solid transparent;
  background: none; cursor: pointer;
  font: inherit; font-size: .78rem;
  color: var(--ciel-texte-doux, rgba(238,243,248,.62));
  transition: background .18s var(--elan), color .18s var(--elan),
              border-color .18s var(--elan), transform .15s var(--elan);
}
.act svg { width: 15px; height: 15px; flex: none; }
.act:hover, .act:focus-visible {
  color: var(--ciel-texte, #eef3f8);
  background: var(--ciel-accent-doux, rgba(110,231,255,.12));
  outline: none;
}
.act:active { transform: scale(.95); }
.act.fait { color: var(--ciel-accent, #6ee7ff); }
/*  « Écouter » pendant la lecture : l'accent, et une onde discrète. */
.act-ecouter.en-lecture { color: var(--ciel-accent, #6ee7ff); }
.act-ecouter.en-lecture svg { animation: act-ecoute 1.1s ease-in-out infinite; }
@keyframes act-ecoute { 50% { opacity: .45; } }
@media (prefers-reduced-motion: reduce) { .act-ecouter.en-lecture svg { animation: none; } }
.act-regen:hover svg { animation: tour-complet .6s var(--elan); }
@keyframes tour-complet { to { rotate: 360deg; } }

/*  « Régénérer » : sous la DERNIÈRE réponse seulement. Et jamais pendant
 *  qu'une réponse s'écrit. */
.fil-dedans > .tour:not(:last-child) .act-regen { display: none; }
body.en-cours .act-regen { opacity: .35; pointer-events: none; }

.act-sources {
  margin-left: 4px;
  border-color: var(--ciel-bord, rgba(255,255,255,.12));
  background: var(--ciel-verre, rgba(8,11,18,.45));
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  color: var(--ciel-texte, #eef3f8);
  padding: 0 11px 0 5px;
}
.act-sources[aria-expanded="true"] {
  border-color: var(--ciel-accent-trait, rgba(110,231,255,.45));
  background: var(--ciel-accent-doux, rgba(110,231,255,.14));
}
.act-sources b {
  font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--ciel-texte-doux, rgba(238,243,248,.6));
}
/*  Les initiales des sites, en petite pile qui se chevauche. */
.visages { display: inline-flex; }
.visages i, .pop-liste i {
  display: inline-flex; align-items: center; justify-content: center;
  font-style: normal; font-weight: 680; color: #fff;
  background: hsl(var(--teinte, 200) 52% 42%);
}
.visages i {
  width: 20px; height: 20px; border-radius: 50%;
  font-size: .62rem;
  border: 1.5px solid var(--ciel-surface, #0a0e15);
}
.visages i + i { margin-left: -7px; }
/*  L'ICÔNE DU SITE, quand elle arrive, recouvre l'initiale : posée sur un
 *  disque clair, comme dans un onglet — la plupart des icônes sont dessinées
 *  pour un fond blanc, et deviendraient illisibles sur la teinte sombre. */
.visages i, .pop-liste i { position: relative; overflow: hidden; }
.visages i img, .pop-liste i img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; padding: 14%; box-sizing: border-box;
  background: #fff; border-radius: inherit;
  opacity: 0; transition: opacity .25s ease;
}
.visages i.icone img, .pop-liste i.icone img { opacity: 1; }

.actions .meta {
  margin-left: auto; padding: 0 6px;
  font-size: .71rem; letter-spacing: .01em;
  font-variant-numeric: tabular-nums;
  color: var(--ciel-texte-doux, rgba(238,243,248,.45));
  opacity: .8;
}
@media (max-width: 560px) {
  .act-copier span, .act-regen span { display: none; }
  .act { padding: 0 9px; }
}

/* ---------------------- LA PETITE FENÊTRE DES SOURCES ------------------- */
.pop-sources {
  position: fixed; z-index: 70;
  max-height: min(62vh, 440px); overflow-y: auto;
  padding: 6px;
  border-radius: 18px;
  border: 1px solid var(--ciel-bord-fort, rgba(255,255,255,.18));
  /*  Presque opaque : elle se pose SUR du texte, qui ne doit pas transparaître
   *  entre ses lignes. La teinte reste celle du ciel. */
  background: rgba(12, 16, 24, .94);
  background: color-mix(in srgb, var(--ciel-surface, #0a0e15) 93%, transparent);
  backdrop-filter: blur(30px) saturate(1.6);
  -webkit-backdrop-filter: blur(30px) saturate(1.6);
  box-shadow: 0 30px 80px -28px rgba(0,0,0,.85);
  color: var(--ciel-texte, #eef3f8);
  opacity: 0; transform: translateY(6px) scale(.98); transform-origin: bottom left;
  transition: opacity .18s var(--elan), transform .22s var(--elan);
}
.pop-sources.ouvert { opacity: 1; transform: none; }
.pop-tete {
  display: flex; align-items: baseline; gap: 8px;
  padding: 8px 10px 6px;
  font-size: .8rem; color: var(--ciel-texte-doux, rgba(238,243,248,.55));
}
.pop-tete b { color: var(--ciel-texte, #eef3f8); font-weight: 640; font-size: .86rem; }
.pop-liste { list-style: none; margin: 0; padding: 0; }
.pop-liste a {
  display: grid; grid-template-columns: 30px 1fr 15px; align-items: center; gap: 11px;
  padding: 9px 10px; border-radius: 12px;
  color: inherit; text-decoration: none;
  transition: background .15s var(--elan);
}
.pop-liste a:hover, .pop-liste a:focus-visible {
  background: var(--ciel-accent-doux, rgba(110,231,255,.12)); outline: none;
}
.pop-liste i { width: 30px; height: 30px; border-radius: 9px; font-size: .8rem; }
.pop-liste span { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.pop-liste b {
  font-weight: 560; font-size: .85rem; line-height: 1.3;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.pop-liste small { font-size: .73rem; color: var(--ciel-texte-doux, rgba(238,243,248,.5)); }
.pop-liste svg { width: 15px; height: 15px; opacity: .45; }
.pop-liste a:hover svg { opacity: .9; color: var(--ciel-accent, #6ee7ff); }
/*  Au téléphone : une feuille posée en bas, pleine largeur, facile à viser. */
@media (max-width: 560px) {
  .pop-sources {
    left: 8px !important; right: 8px; width: auto !important;
    top: auto !important; bottom: calc(8px + env(safe-area-inset-bottom));
    border-radius: 22px; transform-origin: bottom center;
  }
}

/* ----------------------------- LE COMPOSEUR ----------------------------- */
.composeur-hote {
  padding: 10px 22px 20px;
  /*  PAS DE FONDU PEINT SOUS LE CHAMP.
   *  Il y avait ici un dégradé vers le « voile » des cartes, censé cacher la
   *  conversation sous le champ. Mais le fil ne passe PAS sous le champ : il
   *  s'arrête au-dessus (c'est un bloc à part, qui défile seul). Le dégradé
   *  ne cachait donc rien — il peignait seulement une bande plus claire que
   *  le ciel, bord net en haut, au niveau de la barre de message.
   *  Et on ne peut pas le remplacer par un masque sur le fil : un masque en
   *  fait une « racine d'arrière-plan », et le verre des bulles ne floute
   *  plus le ciel (les étoiles passent nettes à travers — vérifié).
   *  Le fil est coupé net par son propre bord, à 10 px au-dessus du champ :
   *  c'est la barre qui le borde, pas une bande. */
  background: none;
}
.composeur {
  width: 100%; max-width: var(--colonne); margin: 0 auto;
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.14));
  border-radius: var(--r-xl);
  background: var(--ciel-verre-haut, rgba(8,11,18,.7));
  backdrop-filter: blur(30px) saturate(1.5);
  -webkit-backdrop-filter: blur(30px) saturate(1.5);
  box-shadow: 0 20px 56px -30px rgba(0, 0, 0, .9);
  transition: border-color .25s var(--elan), box-shadow .25s var(--elan);
}
.composeur:focus-within {
  border-color: var(--ciel-accent-trait, rgba(110,231,255,.5));
  box-shadow: 0 0 0 4px var(--ciel-accent-doux, rgba(110,231,255,.12));
}

.pieces { display: none; gap: 8px; flex-wrap: wrap; padding: 12px 14px 0; }
.pieces.ouvert { display: flex; }
.piece {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 8px 6px 10px; border-radius: var(--r-s);
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.14));
  background: var(--ciel-accent-doux, rgba(110,231,255,.10));
  font-size: .8rem; color: var(--ciel-texte, #eef3f8);
  max-width: 260px;
}
.piece .nom { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.piece .oter {
  border: 0; background: none; cursor: pointer; padding: 2px;
  color: var(--ciel-texte-doux, rgba(238,243,248,.6)); font: inherit; line-height: 1;
}
.piece .oter:hover { color: #ff8a8a; }
.piece img { width: 26px; height: 26px; border-radius: 5px; object-fit: cover; flex: none; }

/*  LES GROS FICHIERS (vidéo, son, PDF) : un nom, un état (« Envoi 42 % »,
 *  « Je regarde… », puis le poids), et un fil de progression au pied de la
 *  pastille — qui disparaît une fois arrivé. */
.piece { position: relative; overflow: hidden; }
.piece .texte { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.piece .etat { font-size: .7rem; color: var(--ciel-texte-doux, rgba(238,243,248,.62)); font-variant-numeric: tabular-nums; }
.piece img.vignette-video { width: 40px; height: 26px; }
.piece .barre { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: transparent; }
.piece .barre i {
  display: block; height: 100%; width: 0;
  background: var(--ciel-accent, #6ee7ff);
  box-shadow: 0 0 8px var(--ciel-accent, #6ee7ff);
  transition: width .2s linear, opacity .4s;
}
.piece:not(.en-envoi) .barre i { opacity: 0; }

.composeur-rang { display: flex; align-items: flex-end; gap: 8px; padding: 8px 10px 8px 8px; }

.champ {
  flex: 1; min-width: 0;
  border: 0; outline: 0; resize: none;
  background: none; color: var(--ciel-texte, #eef3f8);
  font: inherit; font-size: .97rem; line-height: 1.5;
  padding: 10px 6px 10px 12px;
  max-height: 220px;
}
.champ::placeholder { color: var(--ciel-texte-doux, rgba(238,243,248,.42)); }

.rond-btn {
  flex: none;
  width: 40px; height: 40px; border-radius: 99px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.14));
  background: none; color: var(--ciel-texte-doux, rgba(238,243,248,.72));
  cursor: pointer;
  transition: background .2s var(--elan), color .2s var(--elan),
              border-color .2s var(--elan), transform .18s var(--elan);
}
.rond-btn:hover {
  background: var(--ciel-accent-doux, rgba(110,231,255,.14));
  color: var(--ciel-accent, #6ee7ff);
  border-color: var(--ciel-accent-trait, rgba(110,231,255,.4));
}
.rond-btn:active { transform: scale(.93); }
.rond-btn svg { width: 18px; height: 18px; }

.rond-btn.envoi {
  background: var(--ciel-accent, #6ee7ff);
  color: var(--ciel-encre, #05070c);
  border-color: transparent;
}
.rond-btn.envoi:hover { filter: brightness(1.1); transform: translateY(-1px); }
.rond-btn.envoi:disabled {
  opacity: .34; cursor: not-allowed; transform: none; filter: none;
}

.sous-champ {
  display: flex; align-items: center; gap: 10px;
  padding: 0 16px 10px;
  font-size: .74rem; color: var(--ciel-texte-doux, rgba(238,243,248,.45));
}
.sous-champ .pousse { margin-left: auto; }

/*  LA RANGÉE DISPARAÎT QUAND ELLE N'A RIEN À DIRE.
 *
 *  Elle portait une ligne d'astuce permanente — « Entrée pour envoyer » —
 *  qui a été retirée : on la lit une fois, on l'apprend, et elle occupe
 *  ensuite le bas de l'écran pour toujours. Ne reste que le coût de la
 *  demande, qui n'existe qu'après une réponse. Sans cette règle, il restait
 *  dix pixels de vide sous le champ en attendant qu'il ait quelque chose à
 *  afficher. */
.composeur-hote:has(#cout:empty) .sous-champ { display: none; }

/* =======================================================================
 *  LES PIÈCES JOINTES, DANS LE FIL
 * =======================================================================
 *
 *  On n'affichait que les NOMS — « photo_2026.png » — et, sans texte, la
 *  mention « (pièces jointes) ». On envoyait une image et on ne la voyait
 *  nulle part : impossible de vérifier qu'on avait joint la bonne, ni de se
 *  rappeler de quoi on parlait en remontant le fil.
 * ======================================================================= */
.jointes {
  display: flex; flex-wrap: wrap; gap: 8px;
  justify-content: flex-end;          /* du côté de celui qui parle */
  margin-bottom: 6px; max-width: 100%;
}
.jointes img {
  max-width: min(260px, 62vw); max-height: 260px;
  border-radius: var(--r-m, 16px); cursor: zoom-in;
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.14));
  object-fit: cover; display: block;
  transition: transform .18s var(--elan), border-color .18s var(--elan);
}
.jointes img:hover {
  transform: translateY(-2px);
  border-color: var(--ciel-accent-trait, rgba(110,231,255,.4));
}
/*  À plusieurs, des vignettes carrées : des images de proportions
 *  différentes côte à côte donnent un alignement en escalier. */
.jointes.multi img { width: 132px; height: 132px; }

.jointe-fichier {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 13px; border-radius: var(--r-m, 16px);
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.14));
  background: var(--ciel-verre, rgba(8,11,18,.5));
  font-size: .84rem; color: var(--ciel-texte, #eef3f8);
  max-width: 260px;
}
.jointe-fichier svg { width: 17px; height: 17px; flex: none; opacity: .7; }
.jointe-fichier.video img { width: 64px; height: 38px; border-radius: 7px; object-fit: cover; flex: none; }
.jointe-fichier b { font-weight: 560; overflow: hidden;
                    text-overflow: ellipsis; white-space: nowrap; }
.jointe-fichier i { font-style: normal; flex: none;
                    color: var(--ciel-texte-doux, rgba(238,243,248,.5)); }

/*  L'image en grand. Un simple voile : la fermer est le geste le plus
 *  probable, donc un clic n'importe où suffit. */
.loupe {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center; padding: 5vh 5vw;
  background: rgba(3, 5, 10, .88);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  cursor: zoom-out;
  animation: loupe-ouvre .18s var(--elan);
}
.loupe img {
  max-width: 100%; max-height: 100%;
  border-radius: var(--r-m, 16px);
  box-shadow: 0 30px 90px -30px rgba(0,0,0,.95);
}
@keyframes loupe-ouvre { from { opacity: 0 } to { opacity: 1 } }
@media (prefers-reduced-motion: reduce) { .loupe { animation: none } }

/* =======================================================================
 *  LE MODE VOCAL
 * =======================================================================
 *
 *  Quand on parle, la barre d'écriture n'a plus lieu d'être : elle prend
 *  toute la place et laisse croire qu'il faut taper. Elle s'efface au profit
 *  de trois boutons, dont un seul compte vraiment — couper le micro. Il est
 *  donc au centre, et deux fois plus gros que les deux autres.
 * ======================================================================= */
/*  LA BOÎTE DISPARAÎT.
 *
 *  Le composeur est un panneau de verre : une bordure, un fond, un flou, une
 *  ombre. Autour d'un champ de saisie, il délimite la zone où l'on écrit —
 *  c'est son rôle. Autour de trois boutons, il ne délimite rien : il reste un
 *  grand rectangle gris, vide aux trois quarts, qui prend la place de ce
 *  qu'on est venu regarder. Les boutons se posent donc directement sur le
 *  ciel.
 *
 *  Le voile du bas s'en va aussi : il existe pour que le texte qui défile ne
 *  passe pas derrière le champ. Sans champ, il ne cache plus rien et assombrit
 *  le bas de l'image pour rien. */
.composeur.vocal {
  border-color: transparent;
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
}
.composeur.vocal:focus-within { border-color: transparent; box-shadow: none; }

.composeur-vocal {
  display: flex; align-items: center; justify-content: center;
  gap: clamp(20px, 6vw, 38px);
  padding: 6px 10px 14px;
}

/* ------------------------- O.R.I.O.N au premier plan -------------------- */
/*  Il n'était qu'un petit point dans l'écran d'accueil, et il disparaissait
 *  dès la première réponse. En mode vocal, c'est LUI l'interface : il n'y a
 *  rien d'autre à regarder. */
.scene-vocale {
  display: flex; flex-direction: column; align-items: center;
  gap: 14px; padding: clamp(10px, 4vh, 34px) 0 4px;
}

.orbe-vocal {
  width: clamp(190px, 32vh, 300px);
  aspect-ratio: 1;
}

.etat-vocal {
  margin: 0; font-size: .92rem; letter-spacing: .01em;
  color: var(--ciel-texte-doux, rgba(238,243,248,.62));
  transition: color .25s var(--elan);
}
.etat-vocal.ecoute { color: var(--ciel-accent, #6ee7ff); }

/*  Un seul O.R.I.O.N à l'écran. L'accueil porte sa propre petite sphère et
 *  son « Bonjour » : gardés, ils en feraient deux, dont un minuscule juste
 *  au-dessus du grand. */
.scene.vocal .accueil { display: none; }

/*  Le fil s'efface sans disparaître. En mode vocal on écoute, on ne lit
 *  pas — mais effacer complètement la conversation ferait croire qu'elle est
 *  perdue. Assez pâle pour ne pas rivaliser avec l'orbe, assez présent pour
 *  qu'on voie qu'elle est toujours là. Elle revient entière d'un clic sur le
 *  crayon. */
.scene.vocal .fil {
  opacity: .3;
  transition: opacity .3s var(--elan);
}
.scene.vocal .fil:hover { opacity: .75; }

.micro-btn {
  position: relative; flex: none;
  width: 76px; height: 76px; border-radius: 99px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; cursor: pointer;
  background: var(--ciel-accent, #6ee7ff);
  color: var(--ciel-encre, #05070c);
  box-shadow: 0 10px 34px -10px var(--ciel-accent, #6ee7ff);
  transition: background .22s var(--elan), color .22s var(--elan),
              box-shadow .22s var(--elan), transform .18s var(--elan);
}
.micro-btn svg { width: 28px; height: 28px; position: relative; z-index: 1; }
.micro-btn:hover { filter: brightness(1.06); }
.micro-btn:active { transform: scale(.95); }

/*  Une seule des deux icônes est montrée : micro ouvert, ou micro barré.
 *  `aria-pressed` porte l'état — c'est lui que lit un lecteur d'écran, et
 *  c'est lui qui pilote l'affichage. Une seule source de vérité, donc pas
 *  d'icône qui finit par contredire l'état réel. */
.micro-btn .i-coupe { display: none; }
.micro-btn[aria-pressed="false"] {
  background: transparent;
  color: var(--ciel-texte-doux, rgba(238,243,248,.72));
  box-shadow: inset 0 0 0 1px var(--ciel-bord, rgba(255,255,255,.2));
}
.micro-btn[aria-pressed="false"] .i-micro { display: none; }
.micro-btn[aria-pressed="false"] .i-coupe { display: block; }

/*  L'onde ne pulse QUE quand le micro écoute vraiment. Une animation qui
 *  continue sur un micro coupé est un mensonge visuel : on se croit
 *  entendu. */
.micro-btn .onde {
  position: absolute; inset: 0; border-radius: 99px;
  border: 2px solid var(--ciel-accent, #6ee7ff);
  opacity: 0; pointer-events: none;
}
.micro-btn[aria-pressed="true"] .onde { animation: onde-micro 2s var(--elan) infinite; }
@keyframes onde-micro {
  0%   { transform: scale(1);    opacity: .5; }
  70%  { transform: scale(1.55); opacity: 0; }
  100% { transform: scale(1.55); opacity: 0; }
}

/*  Qui a demandé moins d'animation ne veut pas d'un cercle qui pulse en
 *  permanence sous ses yeux. L'état reste lisible sans elle : la couleur du
 *  bouton et l'icône le disent déjà. */
@media (prefers-reduced-motion: reduce) {
  .micro-btn[aria-pressed="true"] .onde { animation: none; opacity: .32; }
}

/*  Cette règle cachait la rangée en mode vocal, parce que la ligne d'astuce
 *  y parlait d'Entrée et de Maj+Entrée — hors sujet quand on ne tape pas.
 *  L'astuce n'existe plus, et le coût, lui, a autant de sens à la voix qu'à
 *  l'écrit : la rangée se cache désormais toute seule quand elle est vide,
 *  et s'affiche quand elle a un chiffre à donner. */

/* ----------------------------- LE TIROIR -------------------------------- */
/*  Réglages et questionnaires partagent la même boîte : un panneau qui monte
 *  du bas sur téléphone, qui se centre sur écran large. Un seul comportement
 *  à écrire, à tester et à corriger. */
.voile-modal {
  position: fixed; inset: 0; z-index: 40;
  background: rgba(3, 5, 9, .62);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  opacity: 0; pointer-events: none;
  transition: opacity .28s var(--elan);
}
.voile-modal.ouvert { opacity: 1; pointer-events: auto; }

.panneau {
  position: fixed; z-index: 41;
  left: 50%; top: 50%; transform: translate(-50%, -46%) scale(.97);
  width: min(560px, calc(100vw - 32px));
  max-height: min(80vh, 720px);
  display: flex; flex-direction: column;
  border: 1px solid var(--ciel-bord-fort, rgba(255,255,255,.16));
  border-radius: var(--r-xl);
  /*  Les panneaux modaux prennent le verre ÉPAIS : ils doivent se détacher du
   *  fil de discussion, pas seulement du ciel. */
  background: var(--ciel-verre-haut, #0b1119);
  backdrop-filter: blur(34px) saturate(1.5);
  -webkit-backdrop-filter: blur(34px) saturate(1.5);
  box-shadow: 0 40px 90px -30px rgba(0,0,0,.8);
  opacity: 0; pointer-events: none;
  transition: opacity .28s var(--elan), transform .28s var(--elan);
}
.panneau.ouvert { opacity: 1; pointer-events: auto; transform: translate(-50%, -50%) scale(1); }

.panneau-tete {
  display: flex; align-items: center; gap: 12px;
  padding: 18px 20px 14px;
  border-bottom: 1px solid var(--ciel-bord, rgba(255,255,255,.10));
}
.panneau-tete h2 { font-size: 1.02rem; font-weight: 640; }
.panneau-tete .fermer { margin-left: auto; }
.panneau-corps { padding: 16px 20px 20px; overflow-y: auto; }

.reglage {
  display: flex; align-items: center; gap: 14px;
  padding: 13px 0;
  border-bottom: 1px solid var(--ciel-bord, rgba(255,255,255,.07));
}
.reglage:last-child { border-bottom: 0; }
.reglage .txt { flex: 1; min-width: 0; }
.reglage .txt b { display: block; font-weight: 600; font-size: .92rem; }
.reglage .txt span {
  display: block; margin-top: 2px; font-size: .81rem;
  color: var(--ciel-texte-doux, rgba(238,243,248,.58));
}

/*  L'INTERRUPTEUR. Un vrai <input type=checkbox> dessous : il reste
 *  accessible au clavier et aux lecteurs d'écran, ce qu'un <div> cliquable
 *  ne serait jamais. */
.bascule { position: relative; flex: none; width: 44px; height: 25px; }
.bascule input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.bascule .piste-b {
  position: absolute; inset: 0; border-radius: 99px;
  background: var(--ciel-bord, rgba(255,255,255,.16));
  transition: background .24s var(--elan);
  pointer-events: none;
}
.bascule .bille {
  position: absolute; top: 3px; left: 3px;
  width: 19px; height: 19px; border-radius: 99px;
  background: #fff;
  transition: transform .26s var(--elan);
  pointer-events: none;
}
.bascule input:checked ~ .piste-b { background: var(--ciel-accent, #6ee7ff); }
.bascule input:checked ~ .bille { transform: translateX(19px); }
.bascule input:focus-visible ~ .piste-b { box-shadow: 0 0 0 3px var(--ciel-accent-doux, rgba(110,231,255,.4)); }

/* ------------------------- LE QUESTIONNAIRE ----------------------------- */
/*  O.R.I.O.N a le droit de s'arrêter au milieu d'une demande pour poser une
 *  question. C'est l'inverse du réflexe habituel — deviner et se tromper. */
.question { display: flex; flex-direction: column; gap: 12px; }
.question .intro { font-size: .95rem; }
.choix { display: flex; flex-direction: column; gap: 8px; }
.choix label {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 12px 14px; border-radius: var(--r-m);
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.12));
  background: var(--ciel-voile, rgba(255,255,255,.03));
  cursor: pointer;
  transition: border-color .2s var(--elan), background .2s var(--elan),
              transform .18s var(--elan);
}
.choix label:hover { transform: translateX(2px); border-color: var(--ciel-accent-trait, rgba(110,231,255,.4)); }
.choix input { margin-top: 3px; accent-color: var(--ciel-accent, #6ee7ff); width: 16px; height: 16px; }
.choix label:has(input:checked) {
  border-color: var(--ciel-accent, #6ee7ff);
  background: var(--ciel-accent-doux, rgba(110,231,255,.12));
}
.autre-champ {
  width: 100%; padding: 11px 14px; border-radius: var(--r-m);
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.14));
  background: rgba(0,0,0,.24); color: var(--ciel-texte, #eef3f8);
  font: inherit; font-size: .9rem;
}
.autre-champ:focus { outline: 0; border-color: var(--ciel-accent-trait, rgba(110,231,255,.5)); }

.btn-plein {
  padding: 11px 20px; border-radius: var(--r-m); border: 0;
  background: var(--ciel-accent, #6ee7ff); color: var(--ciel-encre, #05070c);
  font: inherit; font-weight: 640; font-size: .9rem; cursor: pointer;
  transition: transform .18s var(--elan), filter .18s var(--elan);
}
.btn-plein:hover { transform: translateY(-1px); filter: brightness(1.08); }
.btn-plein:active { transform: none; }

/* ------------------------- PENDANT L'ÉCRITURE --------------------------- */
/*  PLUS D'ANIMATION DE FIN.
 *
 *  Il y a eu des confettis, puis une vrille de la bulle. Les deux partaient
 *  de la même idée — marquer la fin d'une réponse — et avaient le même
 *  défaut : une réponse qui se termine n'est pas un événement. Ça arrive
 *  vingt fois par heure, et la fin se voit déjà sans rien ajouter.
 *
 *  Ce qui compte est PENDANT : la bulle grandit à mesure que le texte
 *  arrive. `content-visibility` et le confinement disent au navigateur que
 *  cette croissance ne peut pas déranger la mise en page autour — il
 *  recalcule alors la bulle seule au lieu de tout le fil, et l'écriture
 *  cesse de saccader sur les longues réponses. */
.bulle {
  contain: layout style;
}


/* ------------------------------- DIVERS --------------------------------- */
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

.avis {
  padding: 11px 15px; border-radius: var(--r-m);
  border: 1px solid rgba(255, 122, 122, .38);
  background: rgba(255, 90, 90, .10);
  color: #ffc0c0; font-size: .88rem;
}

/* ======================================================================== */
/*  LE TÉLÉPHONE — une mise en page distincte, pas un rétrécissement         */
/* ======================================================================== */
/*
 *  On ne se contente pas de réduire : la barre latérale devient un tiroir
 *  qui glisse par-dessus, le composeur gagne la zone sûre du bas, et la
 *  colonne de lecture prend toute la largeur. Une barre de 280 px compressée
 *  à 120 px ne serait utilisable ni d'un côté ni de l'autre.
 */
/*  LE TIROIR, SUR TOUTES LES TAILLES D'ÉCRAN.
 *  Ce n'était qu'une adaptation pour téléphone. C'est devenu le
 *  comportement normal : on ouvre l'historique quand on le cherche, et le
 *  reste du temps l'écran appartient à la conversation. */
.cote.ouvert { transform: none; box-shadow: 0 0 70px rgba(0,0,0,.6); }

.voile-cote {
  position: fixed; inset: 0; z-index: 35;
  background: rgba(3,5,9,.5);
  opacity: 0; pointer-events: none;
  transition: opacity .3s var(--elan);
}
.voile-cote.ouvert { opacity: 1; pointer-events: auto; }

/*  LE BOUTON RÉGLAGES NE QUITTE JAMAIS LE BAS DU PANNEAU.
 *  L'historique peut être long : sans cela, il fallait faire défiler pour
 *  atteindre ses propres réglages. */
.cote-bas { margin-top: auto; }
.cote-bas .ico-btn { text-decoration: none; }

@media (max-width: 900px) {
  .cote { width: min(84vw, 320px); }
  .entete { padding: 10px 14px 4px; }

  .fil { padding: 20px 14px 8px; }
  .fil-dedans { gap: 18px; }
  .tour.de-moi .bulle { max-width: 86%; }
  .bulle { padding: 12px 15px; border-radius: var(--r-m); }

  .accueil { padding: 3vh 0 2vh; }
  .accueil .orbe { width: clamp(132px, 30vw, 168px); height: auto; }
  .accueil h2 { font-size: 1.32rem; }
  .pistes { flex-direction: column; align-items: stretch; }
  .piste { text-align: left; }

  .composeur-hote {
    padding: 8px 12px calc(12px + env(safe-area-inset-bottom, 0px));
  }
  .composeur { border-radius: var(--r-l); }
  /*  16 px minimum : en dessous, iOS zoome sur le champ à la mise au point et
   *  l'utilisateur se retrouve avec une page décalée qu'il doit repincer. */
  .champ { font-size: 16px; padding: 10px 4px 10px 10px; }
  .sous-champ { display: none; }

  .panneau {
    top: auto; bottom: 0; left: 0; transform: translateY(100%);
    width: 100%; max-height: 86vh;
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    border-bottom: 0;
  }
  .panneau.ouvert { transform: none; }
  .panneau-corps { padding-bottom: calc(20px + env(safe-area-inset-bottom, 0px)); }
}

/*  La tablette : la barre reste, plus étroite. */
@media (min-width: 901px) and (max-width: 1180px) {
  :root { --barre: 240px; }
  .fil { padding: 26px 18px 10px; }
}

/* ======================================================================== */
/*  RESPECT DES PRÉFÉRENCES SYSTÈME                                         */
/* ======================================================================== */
/*  Quelqu'un qui a coupé les animations sur son appareil ne veut pas que la
 *  nôtre soit l'exception. Le ciel, lui, est géré dans son propre module. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ======================================================================== */
/*  LE MODE CLASSIQUE — noir, blanc, cyan. Rien d'autre.                     */
/* ======================================================================== */
/*
 *  Demandé explicitement : un utilisateur doit pouvoir revenir à la charte
 *  d'origine. On ne change pas de feuille ni de composants — on réécrit les
 *  MÊMES variables. C'est ce qui garantit qu'aucun des deux modes ne peut
 *  prendre du retard sur l'autre.
 */
:root[data-charte="classique"] {
  --ciel-zenith: #05070c;
  --ciel-horizon: #05070c;
  --ciel-lumiere: #6ee7ff;
  --ciel-surface: #0a0e15;
  --ciel-surface-haute: #10161f;
  --ciel-voile: rgba(10, 14, 21, .88);
  --ciel-accent: #6ee7ff;
  --ciel-accent-doux: rgba(110, 231, 255, .13);
  --ciel-accent-trait: rgba(110, 231, 255, .38);
  --ciel-encre: #04070c;
  --ciel-texte: #eaf1f7;
  --ciel-texte-doux: rgba(234, 241, 247, .62);
  --ciel-bord: rgba(255, 255, 255, .11);
  --ciel-bord-fort: rgba(255, 255, 255, .2);
  /*  Pas de verre en mode classique : sans ciel derrière, une transparence ne
   *  laisse voir que du noir. Autant assumer l'opaque, qui est la charte
   *  d'origine. */
  --ciel-verre: #0a0e15;
  --ciel-verre-haut: #10161f;
  --ciel-reflet: transparent;
}
:root[data-charte="classique"] body { background: #05070c; }

/* =======================================================================
 *  L'ÉCRAN D'OUVERTURE — l'accroche et le champ, ensemble
 * =======================================================================
 *
 *  Tant que la conversation est vide, l'accroche flottait en haut et le
 *  champ de saisie restait collé en bas : deux éléments seuls, séparés par
 *  un grand vide, alors qu'ils forment un seul geste — on lit son nom, on
 *  écrit. On les rassemble au centre.
 *
 *  Dès le premier message, tout reprend sa place : la conversation remonte,
 *  le champ redescend, et c'est la disposition normale d'un fil.
 */
.scene.vierge .fil { flex: 0 0 auto; margin-top: auto; }
.scene.vierge .fil-dedans { justify-content: center; }
.scene.vierge .composeur-hote { margin-bottom: auto; }
.scene.vierge .accueil { padding: 0 0 26px; }

/* ==========================================================================
 *  L'ENCART D'UN PROJET D'ATELIER
 * ==========================================================================
 *
 *  Il remplace une bascule d'écran automatique. Il doit donc porter à lui
 *  seul ce que la bascule apportait : quel projet, et comment y aller — sans
 *  quoi on perd le fil du travail en restant dans la conversation.
 *
 *  Il se range avec les bulles, pas contre elles : même largeur maximale,
 *  même arrondi de famille, l'accent seulement sur le bouton.
 * ========================================================================== */
.carte-atelier {
  display: flex; align-items: center; gap: 12px;
  margin: 10px 0 2px; padding: 12px 14px;
  border-radius: 16px;
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.10));
  background: var(--ciel-voile, rgba(255,255,255,.045));
  max-width: 100%;
}
.carte-atelier .ic {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 11px;
  background: var(--ciel-accent-doux, rgba(110,231,255,.12));
  color: var(--ciel-accent, #6ee7ff);
  font-size: 1.05rem; line-height: 1;
}
/*  `min-width: 0` : sans lui, un nom de projet long refuse de se couper et
 *  pousse le bouton hors de l'encart. */
.carte-atelier .txt {
  display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto;
}
.carte-atelier .txt b {
  color: var(--ciel-texte, #eef3f8);
  font-size: .92rem; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.carte-atelier .txt span {
  color: var(--ciel-texte-doux, rgba(238,243,248,.6));
  font-size: .78rem;
}
.carte-atelier .aller {
  flex: none;
  padding: 8px 14px; border-radius: 99px;
  border: 1px solid var(--ciel-accent-trait, rgba(110,231,255,.42));
  background: var(--ciel-accent-doux, rgba(110,231,255,.10));
  color: var(--ciel-texte, #eef3f8);
  font-size: .82rem; text-decoration: none; white-space: nowrap;
  transition: background .16s, border-color .16s;
}
.carte-atelier .aller:hover,
.carte-atelier .aller:focus-visible {
  background: var(--ciel-accent-trait, rgba(110,231,255,.24));
  border-color: var(--ciel-accent, #6ee7ff);
}
/*  Au téléphone, trois colonnes ne tiennent pas : le bouton passe dessous et
 *  prend toute la largeur, ce qui le rend aussi plus facile à viser. */
@media (max-width: 520px) {
  .carte-atelier { flex-wrap: wrap; }
  .carte-atelier .aller { width: 100%; text-align: center; }
}

/* ========================================================================= *
 *  LES ENCARTS — analyse de marché, étude de business
 * =========================================================================
 *  CE BLOC N'EXISTAIT PAS, ET C'EST TOUTE L'HISTOIRE.
 *
 *  `services/encart.js` produit depuis longtemps un encart très complet :
 *  verdict, chandeliers, niveaux, réserves, probabilité, espérance. Il pose
 *  des classes — `orion-encart`, `tete`, `grille`, `proba` — et pas une seule
 *  n'était définie nulle part dans les feuilles de style.
 *
 *  Résultat : le HTML arrivait dans la conversation et s'affichait en vrac.
 *  Des titres nus, des paires clé-valeur les unes sous les autres, un SVG
 *  perdu au milieu. Le moteur d'analyse le plus soigné du produit rendait
 *  quelque chose qui ressemblait à une page cassée — et rien ne le signalait,
 *  puisque le serveur, lui, faisait exactement son travail.
 *
 *  Les couleurs de sens (vert = objectif, rouge = stop) viennent en ligne,
 *  posées par le serveur : elles portent de l'information et ne doivent pas
 *  dépendre du thème. Tout le reste suit l'ambiance du ciel.
 * ========================================================================= */
.orion-encart {
  --acc: var(--ciel-accent, #6ee7ff);
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.12));
  border-left: 3px solid var(--acc);
  border-radius: var(--r-m);
  background: var(--ciel-surface, rgba(4,6,11,.55));
  padding: 16px 18px;
  margin: 4px 0;
  font-size: .9rem;
  line-height: 1.55;
}
.orion-encart .tete {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 14px; margin-bottom: 12px;
}
.orion-encart .eyebrow {
  display: block; font-size: .7rem; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ciel-texte-doux, rgba(238,243,248,.5));
}
.orion-encart h3 {
  margin: 3px 0 0; font-size: 1.05rem; font-weight: 640;
  color: var(--ciel-texte, #eef3f8);
}
.orion-encart h3 .prix { font-weight: 500; color: var(--ciel-texte-doux, rgba(238,243,248,.72)); }
.orion-encart .verdict {
  flex: none; align-self: center;
  padding: 5px 13px; border-radius: 99px;
  border: 1px solid var(--acc);
  color: var(--acc); background: color-mix(in srgb, var(--acc) 12%, transparent);
  font-size: .74rem; font-weight: 680; letter-spacing: .06em;
}

/*  Les paires clé-valeur. Un `space-between` avec un filet pointillé entre
 *  les deux : c'est ce qui permet de suivre la ligne des yeux jusqu'au
 *  chiffre sans se tromper de rangée. */
.orion-encart .l {
  display: flex; align-items: baseline; gap: 8px;
  padding: 3px 0;
}
.orion-encart .l > span {
  color: var(--ciel-texte-doux, rgba(238,243,248,.62));
  font-size: .84rem;
}
.orion-encart .l > span:first-child::after {
  content: ''; display: inline-block; width: 0;
}
.orion-encart .l > b {
  margin-left: auto; font-variant-numeric: tabular-nums;
  font-weight: 620; color: var(--ciel-texte, #eef3f8); white-space: nowrap;
}
.orion-encart .resume, .orion-encart .grille {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 0 24px;
  padding: 10px 0; margin: 0;
  border-top: 1px solid var(--ciel-bord, rgba(255,255,255,.09));
}
.orion-encart .graphe {
  margin: 12px -4px;
  border-radius: var(--r-s); overflow: hidden;
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.09));
}
.orion-encart .graphe svg { display: block; width: 100%; height: auto; }
.orion-encart .methode, .orion-encart .detail {
  margin: 8px 0 0; font-size: .79rem; line-height: 1.5;
  color: var(--ciel-texte-doux, rgba(238,243,248,.55));
}

/*  CE QUE ÇA FAIT EN ARGENT. Les deux issues côte à côte, à la même taille :
 *  leur symétrie EST le message. Un gain affiché gros à côté d'une perte
 *  écrite en petit serait une publicité, pas une analyse. */
.orion-encart .scenarios {
  margin-top: 12px; padding-top: 12px;
  border-top: 1px solid var(--ciel-bord, rgba(255,255,255,.09));
}
.orion-encart .scenarios > b { font-size: .86rem; color: var(--ciel-texte, #eef3f8); }
.orion-encart .duo { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 10px 0; }
.orion-encart .duo > div {
  padding: 11px 13px; border-radius: var(--r-s);
  border: 1px solid transparent;
}
.orion-encart .duo span { display: block; font-size: .76rem; opacity: .8; }
.orion-encart .duo b { display: block; margin-top: 3px; font-size: 1.15rem; font-variant-numeric: tabular-nums; }
.orion-encart .duo .gain { background: rgba(34,197,94,.12); border-color: rgba(34,197,94,.3); color: #22c55e; }
.orion-encart .duo .perte { background: rgba(239,68,68,.12); border-color: rgba(239,68,68,.3); color: #ef4444; }

.orion-encart .reserves {
  margin-top: 12px; padding: 11px 14px;
  border-radius: var(--r-s);
  background: rgba(234,179,8,.08); border: 1px solid rgba(234,179,8,.24);
}
.orion-encart .reserves b { font-size: .84rem; color: #eab308; }
.orion-encart .reserves ul { margin: 6px 0 0; padding-left: 18px; }
.orion-encart .reserves li { margin: 4px 0; font-size: .83rem; }

/*  La barre de probabilité : deux blocs qui se partagent la largeur. On voit
 *  la proportion avant de lire les pourcentages, ce qui est l'ordre naturel. */
.orion-encart .proba { margin-top: 13px; }
.orion-encart .barre {
  display: flex; height: 7px; border-radius: 99px; overflow: hidden;
  background: var(--ciel-bord, rgba(255,255,255,.1)); margin-bottom: 7px;
}
.orion-encart .barre i { display: block; height: 100%; }
.orion-encart .proba .l > span:last-child { margin-left: auto; }

.orion-encart .avert {
  margin-top: 14px; padding: 10px 13px;
  border-radius: var(--r-s);
  background: rgba(239,68,68,.07); border: 1px solid rgba(239,68,68,.2);
}
.orion-encart .avert b { font-size: .8rem; color: #ef4444; }
.orion-encart .avert p { margin: 4px 0 0; font-size: .78rem; line-height: 1.5;
  color: var(--ciel-texte-doux, rgba(238,243,248,.62)); }

/*  L'étude de business : pas de courbe, donc ce sont les sources qui portent
 *  la crédibilité — elles sont montrées, pas résumées. */
.orion-encart .verdict-texte { margin: 0 0 12px; font-size: .92rem; }
.orion-encart .colonne { margin-top: 10px; }
.orion-encart .colonne b { font-size: .84rem; }
.orion-encart .colonne.pour b { color: #22c55e; }
.orion-encart .colonne.contre b { color: #ef4444; }
.orion-encart .colonne ul, .orion-encart .sources ul { margin: 5px 0 0; padding-left: 18px; }
.orion-encart .colonne li, .orion-encart .sources li { margin: 3px 0; font-size: .85rem; }
.orion-encart .angles { margin-top: 13px; }
.orion-encart .angle-liste { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.orion-encart .angle {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: 99px; font-size: .76rem;
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.14));
  color: var(--ciel-texte-doux, rgba(238,243,248,.72));
}
.orion-encart .angle i { font-style: normal; opacity: .6; font-variant-numeric: tabular-nums; }
.orion-encart .angle.vide { opacity: .45; border-style: dashed; }

/*  LE VERDICT SE POSE. L'étude de marché s'affiche dès l'exploration, puis
 *  reçoit son verdict à la même place : le badge arrive d'un léger rebond,
 *  la phrase et les deux colonnes en fondu — l'œil voit ce qui a changé. */
.encart-hote.complete .orion-encart .verdict { animation: verdict-pose .5s var(--elan) both; }
.encart-hote.complete .orion-encart .verdict-texte,
.encart-hote.complete .orion-encart .colonne { animation: verdict-fondu .45s var(--elan) both; }
@keyframes verdict-pose { from { opacity: 0; transform: scale(.7); } }
@keyframes verdict-fondu { from { opacity: 0; transform: translateY(4px); } }
@media (prefers-reduced-motion: reduce) {
  .encart-hote.complete .orion-encart .verdict,
  .encart-hote.complete .orion-encart .verdict-texte,
  .encart-hote.complete .orion-encart .colonne { animation: none; }
}
.orion-encart .sources { margin-top: 13px; }
.orion-encart .sources b { font-size: .84rem; color: var(--ciel-texte, #eef3f8); }
.orion-encart .sources a { color: var(--ciel-accent, #6ee7ff); }
.orion-encart.erreur { border-left-color: #ef4444; }
.orion-encart.erreur > b { color: #ef4444; }

/*  Au téléphone, deux colonnes de chiffres deviennent illisibles : tout
 *  s'empile, et le verdict passe sous le titre au lieu de se serrer à côté. */
@media (max-width: 560px) {
  .orion-encart { padding: 13px 14px; font-size: .86rem; }
  .orion-encart .tete { flex-direction: column; gap: 9px; }
  .orion-encart .verdict { align-self: flex-start; }
  .orion-encart .duo { grid-template-columns: 1fr; }
}

/* =======================================================================
 *  INSTALLER L'APPLICATION — le bouton du tiroir et la marche à suivre
 * ======================================================================= */
.installer {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; margin: -2px;
  border: 0; border-radius: var(--r-s);
  background: none; cursor: pointer;
  font: inherit; font-size: .82rem; font-weight: 560; text-align: left;
  color: var(--ciel-texte-doux, rgba(238,243,248,.78));
  transition: background .18s var(--elan), color .18s var(--elan);
}
.installer svg { width: 18px; height: 18px; flex: none; color: var(--ciel-accent, #6ee7ff); }
.installer:hover, .installer:focus-visible {
  background: var(--ciel-accent-doux, rgba(255,255,255,.06));
  color: var(--ciel-texte, #eef3f8);
}
.etapes-installer { list-style: none; display: flex; flex-direction: column; gap: 14px; margin: 4px 0 16px; }
.etapes-installer li { display: flex; align-items: flex-start; gap: 12px; line-height: 1.5; }
.etapes-installer .num {
  flex: none; width: 26px; height: 26px; border-radius: 99px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: .8rem; font-weight: 700;
  background: var(--ciel-accent-doux, rgba(110,231,255,.13));
  color: var(--ciel-accent, #6ee7ff);
}
.etapes-installer .ico-partager {
  width: 18px; height: 18px; vertical-align: -3px; margin: 0 2px;
  color: var(--ciel-accent, #6ee7ff);
}
.aide-installer { font-size: .84rem; color: var(--ciel-texte-doux, rgba(238,243,248,.62)); }

/* =======================================================================
 *  LE TÉLÉPHONE
 * =======================================================================
 *
 *  L'APPLICATION INSTALLÉE PASSE SOUS LA BARRE D'ÉTAT. Ouverte depuis son
 *  icône, elle occupe tout l'écran (`viewport-fit=cover`, barre d'état
 *  translucide) : l'encoche et l'heure sont DANS la page. Chaque bord garde
 *  donc sa marge de sécurité — elle vaut zéro partout ailleurs.
 */
.entete { padding-top: calc(14px + env(safe-area-inset-top, 0px)); }
.cote-haut { padding-top: calc(18px + env(safe-area-inset-top, 0px)); }
.cote-bas { padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
.scene {
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
}
/*  La hauteur qui suit vraiment l'écran : sur téléphone, `100%` ne connaît
 *  pas les barres du navigateur qui apparaissent et disparaissent, et le
 *  champ de saisie finissait sous la barre d'adresse. */
@supports (height: 100dvh) {
  .app { height: 100dvh; }
}

@media (max-width: 760px) {
  .entete { padding: calc(8px + env(safe-area-inset-top, 0px)) 10px 2px; gap: 8px; }
  .entete .rond-btn { width: 40px; height: 40px; }

  /*  L'ÉCRAN VIDE, TENU D'UNE MAIN.
   *  Sur un grand écran, l'accroche et le champ se rassemblent au centre.
   *  Sur un téléphone, le centre est hors de portée du pouce : le champ
   *  reste EN BAS, là où le clavier va s'ouvrir, et l'accroche occupe le
   *  milieu de ce qui reste au-dessus. */
  .scene.vierge .fil { flex: 1 1 auto; margin-top: 0; display: flex; flex-direction: column; }
  .scene.vierge .fil-dedans { flex: 1 0 auto; justify-content: center; }
  .scene.vierge .composeur-hote { margin-bottom: 0; }
  .scene.vierge .accueil { padding: 0 0 4vh; }

  /*  Les réponses prennent la largeur : 14 px de marge suffisent quand
   *  chaque pixel de ligne compte. */
  .fil { padding: 14px 10px 8px; }
  .bulle { padding: 12px 14px; }
  .tour.de-moi .bulle { max-width: 88%; }
  .corps pre { font-size: .8rem; }

  .composeur-hote { padding: 6px 8px calc(8px + env(safe-area-inset-bottom, 0px)); }
  .composeur-rang .rond-btn { width: 40px; height: 40px; }

  /*  Le tiroir en verre ÉPAIS : sur un écran étroit il recouvre le champ de
   *  saisie, et un verre clair laissait voir le composeur à travers la
   *  ligne du compte — deux interfaces l'une sur l'autre. */
  .cote {
    background: rgba(8, 11, 18, .95);
    background: color-mix(in srgb, var(--ciel-surface, #0a0e15) 95%, transparent);
  }
}

/*  L'ATELIER N'EXISTE PAS SUR UN TÉLÉPHONE.
 *
 *  Une arborescence, un éditeur, une console côte à côte : sur six pouces,
 *  rien de tout cela ne se lit. Sur téléphone on n'en montre donc aucune
 *  porte — ni le bouton du tiroir, ni le lien des encarts de projet — et la
 *  page de l'atelier renvoie à la conversation (voir atelier.html).
 *
 *  « Téléphone » = écran tactile ET petit, dans un sens ou dans l'autre
 *  (couché, un téléphone fait moins de 500 px de haut). Une fenêtre étroite
 *  sur un ordinateur, elle, garde son atelier. La même requête est reprise
 *  mot pour mot dans app.js et atelier.html. */
@media (pointer: coarse) and (max-width: 760px), (pointer: coarse) and (max-height: 500px) {
  .btn-atelier { display: none !important; }
  .carte-atelier .aller { display: none !important; }
}

/* =======================================================================
 *  LES FORMULES — dessinées par le navigateur (MathML), voir js/maths.js
 * ======================================================================= */
.corps math {
  /*  La police mathématique du système : Cambria Math sous Windows, STIX
   *  sous macOS et iOS, la police « math » générique ailleurs. */
  font-family: 'STIX Two Math', 'Cambria Math', 'Latin Modern Math', 'Noto Sans Math', math;
  font-size: 1.08em;
  color: inherit;
}
/*  Une formule isolée : centrée, et qui défile de côté plutôt que de
 *  déborder de la bulle sur un téléphone. */
.corps .maths-bloc {
  margin: .55em 0;
  overflow-x: auto; overflow-y: hidden;
  padding: 4px 0;
  scrollbar-width: thin;
}
.corps .maths-bloc math { font-size: 1.16em; }
.corps li math, .corps p math:not([display="block"]) { vertical-align: -0.12em; }
/*  Dans une liste de calculs ou un tableau — un corrigé, typiquement —, les
 *  fractions gardent leur taille pleine : « 45/7 » en corps six se lit mal,
 *  et c'est précisément ce qu'on vient lire. */
.corps li > math, .corps td > math { math-style: normal; }
.corps math .gras { font-weight: 700; }
.corps math .encadre {
  border: 1px solid var(--ciel-accent-trait, rgba(110,231,255,.5));
  border-radius: 4px; padding: 2px 5px;
}
/*  Une formule que maths.js n'a pas su lire reste lisible, telle quelle. */
.corps .maths-brut { white-space: pre-wrap; }

/* =======================================================================
 *  LE MESSAGE VOCAL — maintenir le micro, parler, lâcher
 * =======================================================================
 *  Le geste des messageries : la barre d'enregistrement prend la place du
 *  champ, le micro grossit sous le doigt, un cadenas attend au-dessus
 *  (glisser vers le haut : mains libres), « Glisse pour annuler » à gauche.
 * ======================================================================= */
#btnVoix {
  /*  Le doigt qui glisse vers le haut ne doit pas faire défiler la page (le
   *  navigateur « volerait » le geste), ni ouvrir le menu d'un appui long. */
  touch-action: none;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
  position: relative; z-index: 3;
}
.composeur-rang { position: relative; }

#btnVoix.enregistre {
  background: #ff4d61;
  border-color: transparent;
  color: #fff;
  transform: scale(1.32);
  box-shadow: 0 0 0 7px rgba(255, 77, 97, .2), 0 10px 30px -8px rgba(255, 77, 97, .8);
  animation: micro-enregistre 1.6s var(--elan-doux) infinite;
}
@keyframes micro-enregistre {
  0%, 100% { box-shadow: 0 0 0 6px rgba(255, 77, 97, .22), 0 10px 30px -8px rgba(255, 77, 97, .8); }
  50%      { box-shadow: 0 0 0 13px rgba(255, 77, 97, .07), 0 10px 30px -8px rgba(255, 77, 97, .8); }
}

/*  Pendant l'enregistrement, le champ et les autres boutons s'effacent : il
 *  n'y a qu'une chose à faire — parler. */
.composeur-rang.note-en-cours > #btnJoindre,
.composeur-rang.note-en-cours > .champ,
.composeur-rang.note-en-cours > #btnEnvoi { visibility: hidden; }
.composeur-rang:has(.note-vocale[data-mode="verrouille"]) > #btnVoix { visibility: hidden; }

.note-vocale {
  position: absolute; z-index: 2;
  top: 8px; bottom: 8px; left: 8px;
  right: 106px;                       /* le micro reste visible sous le doigt */
  display: flex; align-items: center; gap: 10px;
  padding: 0 14px 0 16px;
  border-radius: 99px;
  background: var(--ciel-verre-haut, rgba(12, 16, 24, .92));
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.12));
  animation: note-entre .22s var(--elan) both;
  overflow: hidden;
}
.note-vocale[data-mode="verrouille"] { right: 10px; padding: 0 6px 0 6px; }
@keyframes note-entre { from { opacity: 0; transform: translateX(14px); } }
.note-vocale.nv-annule { animation: note-annule .26s var(--elan-doux) both; }
@keyframes note-annule { to { opacity: 0; transform: translateX(-40px) scale(.96); } }

.nv-point {
  flex: none; width: 10px; height: 10px; border-radius: 99px;
  background: #ff4d61;
  box-shadow: 0 0 10px rgba(255, 77, 97, .8);
  animation: nv-point 1.1s ease-in-out infinite;
}
@keyframes nv-point { 50% { opacity: .25; } }
.nv-temps {
  flex: none; min-width: 38px;
  font-variant-numeric: tabular-nums; font-size: .9rem;
  color: var(--ciel-texte, #eef3f8);
}
/*  L'onde vit : la plus récente à droite, les plus anciennes sortent par la
 *  gauche — elle remplit la barre quelle que soit sa largeur. */
.nv-onde {
  flex: 1; min-width: 40px; height: 26px;
  display: flex; align-items: center; justify-content: flex-end; gap: 2px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 18%);
  mask-image: linear-gradient(to right, transparent, #000 18%);
}
.nv-onde i {
  flex: 0 0 3px; height: 100%;
  border-radius: 2px;
  background: var(--ciel-accent, #6ee7ff);
  transform: scaleY(.12); transform-origin: center;
  transition: transform .09s linear;
}
.nv-glisse {
  flex: none;
  font-size: .8rem; white-space: nowrap;
  color: var(--ciel-texte-doux, rgba(238,243,248,.6));
  transform: translateX(var(--glisse, 0px));
  opacity: calc(1 + var(--glisse, 0px) / 120px);
}
.nv-fleche { display: inline-block; animation: nv-fleche 1.4s ease-in-out infinite; }
@keyframes nv-fleche { 50% { transform: translateX(-4px); } }

.nv-corbeille, .nv-envoi {
  display: none; flex: none;
  width: 38px; height: 38px; border-radius: 99px;
  align-items: center; justify-content: center;
  border: 0; cursor: pointer;
}
.nv-corbeille svg, .nv-envoi svg { width: 18px; height: 18px; }
.nv-corbeille { background: none; color: var(--ciel-texte-doux, rgba(238,243,248,.7)); }
.nv-corbeille:hover { color: #ff8a96; background: rgba(255, 77, 97, .12); }
.nv-envoi { background: var(--ciel-accent, #6ee7ff); color: var(--ciel-encre, #05070c); }
.nv-envoi:hover { filter: brightness(1.08); }
.note-vocale[data-mode="verrouille"] .nv-corbeille,
.note-vocale[data-mode="verrouille"] .nv-envoi { display: inline-flex; }
.note-vocale[data-mode="verrouille"] .nv-glisse { display: none; }

/*  Le cadenas, au-dessus du micro : il monte avec le doigt. */
.nv-verrou {
  position: absolute; z-index: 4;
  right: 58px; bottom: calc(100% + 4px);
  width: 40px; padding: 10px 0 8px;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  border-radius: 20px;
  background: var(--ciel-verre-haut, rgba(12, 16, 24, .94));
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.14));
  color: var(--ciel-texte-doux, rgba(238,243,248,.75));
  box-shadow: 0 12px 30px -14px rgba(0, 0, 0, .8);
  pointer-events: none;
  animation: nv-verrou-entre .25s var(--elan) both;
  transition: color .15s, border-color .15s;
}
@keyframes nv-verrou-entre { from { opacity: 0; transform: translateY(10px); } }
.nv-verrou svg { width: 18px; height: 18px; }
.nv-verrou .nv-chevron { width: 14px; height: 14px; animation: nv-chevron 1.2s ease-in-out infinite; }
@keyframes nv-chevron { 50% { transform: translateY(-3px); opacity: .5; } }
.nv-verrou.proche { color: var(--ciel-accent, #6ee7ff); border-color: var(--ciel-accent-trait, rgba(110,231,255,.5)); }
.nv-verrou.proche .nv-anse { transform: translateY(1.5px); }

/*  Une astuce passagère au-dessus du champ (« Trop court… »). */
.astuce-vocale {
  position: absolute; z-index: 5;
  left: 50%; bottom: calc(100% + 12px);
  transform: translate(-50%, 6px);
  max-width: calc(100% - 24px);
  padding: 8px 14px; border-radius: 99px;
  background: var(--ciel-verre-haut, rgba(12, 16, 24, .94));
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.14));
  font-size: .82rem; color: var(--ciel-texte, #eef3f8);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  opacity: 0; pointer-events: none;
  transition: opacity .2s var(--elan), transform .2s var(--elan);
}
.astuce-vocale.vu { opacity: 1; transform: translate(-50%, 0); }
.composeur { position: relative; }

/* ------------------------ La bulle d'un message vocal -------------------- */
.tour.de-moi .bulle.bulle-vocale {
  width: min(78vw, 320px);
  padding: 8px 12px 8px 8px;
}
.bv-lecteur { display: flex; align-items: center; gap: 10px; min-width: 0; }
/*  Le bouton de lecture : un rond plein, l'icône au milieu — le triangle
 *  est dessiné centré (voir ICONE_LIRE), aucune marge ne le repousse. */
.bv-jouer {
  flex: none; width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center; padding: 0;
  border: 0; cursor: pointer;
  background: var(--ciel-accent, #6ee7ff);
  color: var(--ciel-encre, #05070c);
  box-shadow: 0 2px 10px -4px color-mix(in srgb, var(--ciel-accent, #6ee7ff) 70%, transparent);
  transition: transform .15s var(--elan), opacity .2s, filter .2s;
}
.bv-jouer:hover:not(:disabled) { filter: brightness(1.08); }
.bv-jouer:active { transform: scale(.92); }
.bv-jouer:focus-visible { outline: 2px solid var(--ciel-texte, #eef3f8); outline-offset: 2px; }
.bv-jouer svg { width: 18px; height: 18px; display: block; grid-area: 1 / 1; }
.bv-jouer .i-pause { display: none; }
.bulle-vocale.joue .bv-jouer .i-lire { display: none; }
.bulle-vocale.joue .bv-jouer .i-pause { display: block; }
/*  Sans le son (enregistré sur un autre appareil) : le rond reste net, en
 *  contour, au lieu d'un bouton délavé qui a l'air cassé. */
.bv-jouer:disabled {
  cursor: default; box-shadow: none;
  background: transparent;
  color: var(--ciel-texte-doux, rgba(238,243,248,.55));
  border: 1.5px solid var(--ciel-bord, rgba(255,255,255,.22));
}

.bv-onde {
  flex: 1 1 auto; min-width: 0; height: 30px;
  display: flex; align-items: center; gap: 2px;
  overflow: hidden;
  cursor: pointer;
}
.bv-onde i {
  flex: 1 1 0; min-width: 1px; max-width: 4px;
  height: var(--h, 30%);
  border-radius: 2px;
  background: color-mix(in srgb, var(--ciel-texte, #eef3f8) 38%, transparent);
  transition: background .12s;
}
/*  Pendant qu'O.R.I.O.N comprend le vocal : l'onde respire, sans un mot. */
.bulle-vocale.en-envoi .bv-onde { animation: bv-attente 1.4s ease-in-out infinite; }
.bv-onde i.lu { background: var(--ciel-accent, #6ee7ff); }
.sans-son .bv-onde { cursor: default; }
.bv-temps {
  flex: none; min-width: 34px; text-align: right;
  font-size: .78rem; font-variant-numeric: tabular-nums;
  color: var(--ciel-texte-doux, rgba(238,243,248,.7));
}
.bv-vitesse {
  flex: none;
  padding: 2px 7px; border-radius: 99px;
  border: 1px solid var(--ciel-bord, rgba(255,255,255,.16));
  background: none; cursor: pointer;
  font: inherit; font-size: .7rem; font-weight: 600;
  color: var(--ciel-texte-doux, rgba(238,243,248,.72));
}
.bv-vitesse:hover { color: var(--ciel-accent, #6ee7ff); border-color: var(--ciel-accent-trait, rgba(110,231,255,.45)); }
.sans-son .bv-vitesse { display: none; }
/*  Un échec seulement : rien entendu, envoi raté. Jamais la transcription. */
.bv-etat {
  margin-top: 8px; padding-top: 7px;
  border-top: 1px solid var(--ciel-bord, rgba(255,255,255,.1));
  font-size: .82rem; line-height: 1.4;
}
@keyframes bv-attente { 50% { opacity: .45; } }
.bv-etat.erreur { color: #ffb3bb; }
.bv-reessayer {
  display: inline-block; margin-left: 8px;
  border: 0; background: none; padding: 0; cursor: pointer;
  font: inherit; color: var(--ciel-accent, #6ee7ff); text-decoration: underline;
}

/*  On lui coupe la parole d'un toucher sur la sphère. */
.scene-vocale { cursor: pointer; -webkit-tap-highlight-color: transparent; }

@media (max-width: 760px) {
  .note-vocale { right: 106px; gap: 8px; padding: 0 12px; }
  .nv-glisse { font-size: .76rem; }
}
@media (max-width: 380px) {
  .nv-glisse .nv-texte-long { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  #btnVoix.enregistre, .nv-point, .nv-fleche, .nv-verrou .nv-chevron, .bulle-vocale.en-envoi .bv-onde { animation: none; }
}
/*  Le micro s'ouvre : la barre est là, le point attend son rouge. */
.note-vocale.nv-prepa .nv-point { background: var(--ciel-texte-doux, rgba(238,243,248,.5)); box-shadow: none; animation: none; }
