/* Feuille de style du runtime — **une seule**, pour tous les thèmes.
 *
 * Tout ce qui varie d'une marque à l'autre passe par les jetons `--f6-*`, servis par
 * `GET /api/v1/themes/{id}/theme.css`. C'est ce qui remplace les 27 feuilles de thème de
 * form6, dont plusieurs étaient des copies divergentes les unes des autres
 * (`theme_concerto`, `_2`, `_ia`, `_ia_v2`, `_ia_v2.old`, `_v2_a`, `_v2_b`).
 *
 * Les valeurs de repli ci-dessous ne sont pas un thème : elles rendent le runtime
 * présentable si aucun thème n'est chargé, ce qui arrive en développement et dans les
 * tests.
 *
 * **Et elles sont celles d'AI6, pas celles d'un client.** Elles ont porté le teal d'IMH
 * pendant tout le temps où IMH était le seul client, ce qui rendait un repli
 * *indétectable* : un déploiement Generali dont le thème ne charge pas s'affichait en
 * vert IMH — plausible, donc pris pour le rendu voulu. Le bleu AI6 dit ce qu'il est,
 * c'est-à-dire un parcours **non habillé**. Relevé sur « Preven6 Brand AI6 Technologies »
 * (Figma `6yMigBB33XH5sV9KrEE8pl`, section `12047:5364`). */

/* `border-box` partout dans le runtime. Sans lui, la marge intérieure s'ajoute à la
 * largeur : un élément à 100 % dépassait de sa colonne, et l'étape gagnait une barre de
 * défilement horizontale de quelques pixels — assez pour qu'on ne comprenne pas d'où elle
 * vient, jamais assez pour qu'on la cherche.
 *
 * Portée à l'hôte et à ses descendants, pas à la page : le runtime s'insère dans le site
 * d'un intégrateur, et n'a pas à lui imposer son modèle de boîte. */
f6-chatbot, f6-chatbot *, f6-chatbot *::before, f6-chatbot *::after,
.f6-preview, .f6-preview * {
  box-sizing: border-box;
}

/* `.f6-preview` reçoit les mêmes jetons que le runtime.
 *
 * C'est ce qui permet à l'aperçu de l'éditeur de montrer **ce que l'assuré verra**, en
 * lisant cette feuille-ci plutôt qu'une copie. L'éditeur affichait des boutons verts là
 * où le parcours rend des tuiles grises à icône : l'auteur réglait donc une apparence
 * qu'il n'a jamais vue, et découvrait la vraie à l'aperçu — quand il y pensait. */
f6-chatbot, .f6-preview {
  --f6-color-primary: #001dfc;
  --f6-color-primary-strong: #000f85;
  --f6-color-primary-subtle: #e6e9ff;
  --f6-color-text: #181c34;
  --f6-color-text-strong: #000f85;
  --f6-color-text-muted: #707070;
  --f6-color-surface: #ffffff;
  --f6-color-surface-sunken: #f5f7f9;
  --f6-color-surface-muted: #cccccc;
  --f6-color-border: #e6ebf0;
  --f6-color-error: #ff4d4f;
  --f6-color-on-primary: #ffffff;
  /* Le primaire **sur fond sombre** — cadres de visée, jauges et accents posés sur les
   * voiles sombres de la caméra. Un primaire foncé (marine, rouge sombre) y devient
   * illisible : chaque marque en fournit donc une **teinte claire** (jeton
   * `primary-on-dark`, comme `primary-subtle`). Ce repli neutre tient tant qu'aucun thème
   * n'est chargé. */
  --f6-color-primary-on-dark: #8f9bff;
  /* Le bleu **du repère cartographique** — le point « vous êtes ici » et le tracé du
   * trajet. Il ne suit **pas** la marque : c'est une convention de carte (le bleu Google),
   * lue comme « ma position » partout, et la reteindre à la couleur de la compagnie ferait
   * lire une position là où il y a une marque. Seul le **pin du logement** prend le
   * primaire ; le fond de carte reste neutre. Voir l'extension `trajet` (Lot 6). */
  --f6-color-map-you: #4285f4;
  --f6-font-title: system-ui, sans-serif;
  --f6-font-body: system-ui, sans-serif;
  --f6-font-size-h1: 24px;
  --f6-font-size-body: 16px;
  --f6-font-size-h2: 20px;
  --f6-font-size-small: 14px;
  --f6-space-1: 4px;
  --f6-space-2: 8px;
  --f6-space-4: 16px;
  --f6-space-6: 24px;
  --f6-space-8: 32px;
  --f6-radius-default: 5px;
  --f6-radius-pill: 999px;
  --f6-layout-max-width: 480px;

  display: block;
  font-family: var(--f6-font-body);
  font-size: var(--f6-font-size-body);
  color: var(--f6-color-text);
  background: var(--f6-color-surface);

  /* **Le plancher qui manquait, et il tenait toute la page.**
   *
   * La page hôte pose `display: flex` sur `<body>` : la coquille en est un élément flex, et
   * un élément flex a `min-width: auto` — c'est-à-dire la largeur de son **contenu** pour
   * plancher. Un texte long quelque part dedans ne débordait donc pas *dans* la coquille :
   * il l'élargissait, elle et tout ce qu'elle porte.
   *
   * Mesuré sur AI-1041, un nom d'assuré de 44 caractères dans le bandeau de dossier :
   * `f6-chatbot` passait à 418 px sur un écran de 390, et l'en-tête, le contenu et la barre
   * d'action se décalaient ensemble — 28 px de défilement horizontal sur toute la page.
   *
   * Aucun `min-width: 0` en aval ne pouvait rattraper ça : `.f6-shell`, `__top` et `__aside`
   * en portaient déjà un, sans effet. Une chaîne de flex ne rétrécit qu'aussi loin que son
   * maillon le plus rigide, et celui-là était le premier de tous.
   *
   * Ce n'est pas une correction de bandeau : n'importe quel contenu long — une adresse, un
   * libellé de garantie, une réponse d'assuré — aurait produit le même écran. */
  min-width: 0;
}

/* **Masqué au démarrage, le temps que le thème arrive.** Le runtime pose ses jetons neutres
 * (le repli dé-brandé ci-dessus) dès le premier octet ; sans ce voile, la coquille
 * s'afficherait en neutre puis se recolorerait à la marque — le clignotement signalé. Le
 * pilote retire `f6-booting` une fois le thème appliqué et la première étape peinte (ou au
 * bout du garde-fou).
 *
 * `opacity: 0`, **et pas `visibility: hidden`** : ce dernier fait mesurer **zéro** à ce qui
 * se monte dessous, et le calendrier `flatpickr`, monté pendant ce voile, se plaçait à des
 * dimensions nulles dont il ne se remettait pas une fois révélé. L'opacité laisse la mise en
 * page intacte — tout a ses dimensions, seul le rendu est transparent —, ce qui masque le
 * clignotement sans casser ce qui se mesure. `pointer-events: none` le temps du voile : rien
 * à cliquer sur un écran qu'on ne voit pas encore. */
f6-chatbot.f6-booting { opacity: 0; pointer-events: none; }

/* La coquille occupe **exactement** la hauteur disponible, et c'est ce qui garde les
 * actions au bas de l'écran. En `min-height`, un contenu plus long que l'écran poussait
 * la barre d'action vers le bas et laissait des champs *sous* elle : sur un écran de
 * téléphone, les dernières questions d'une étape devenaient invisibles, et le bouton
 * « Suivant » paraissait être la fin de l'étape alors qu'il en restait la moitié. */
.f6-shell {
  display: flex;
  flex-direction: column;
  height: 100%;
  max-width: var(--f6-layout-max-width);
  margin: 0 auto;
  overflow: hidden;
}

/* Le contenu défile, la barre d'action ne bouge pas. `min-height: 0` est obligatoire :
 * sans lui, un élément flex refuse de rétrécir sous la taille de son contenu, et le
 * défilement n'a jamais lieu. */
.f6-step {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: var(--f6-space-4);
}

.f6-transcript { flex: 0 1 auto; min-height: 0; }
.f6-actions { flex: 0 0 auto; }

/* En mode formulaire, le conteneur de défilement est **transparent** : `display:
 * contents` rend ses enfants directement enfants de la coquille, et la disposition est
 * exactement celle d'avant — une étape entière s'affiche d'un coup, il n'y a rien à
 * suivre. */
.f6-scroll { display: contents; }

/* En conversation, il devient le **seul** conteneur qui défile. Il y en avait deux,
 * empilés — la transcription et l'étape — chacun défilant dans son coin : amener une
 * bulle au bord de la transcription ne déplaçait donc pas la vue, et la question qui
 * venait d'apparaître restait sous la barre d'action. */
.f6-mode-chat .f6-scroll {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* --- L'en-tête **par-dessus le fil** ---------------------------------------
 *
 * L'en-tête était un frère du conteneur de défilement, donc au-dessus de lui dans la
 * colonne : rien ne passait jamais derrière, et le fil s'arrêtait net à son bord. Sorti du
 * flux, il le recouvre — les bulles montent **sous** le portrait et s'y dissolvent dans son
 * fondu (voir `.f6-chat-portrait`). C'est ce qui donne à la conversation sa profondeur : on
 * voit ce qui s'en va, au lieu de le voir disparaître d'un coup.
 *
 * **Le fil doit alors commencer plus bas**, d'exactement la hauteur de l'en-tête — et
 * aucune règle CSS ne peut la connaître : elle change avec le portrait (absent sans
 * assistante), avec le bouton de parole (offert ou non) et avec la caméra. Elle est donc
 * **mesurée** et publiée dans `--f6-header-height` (`chatbot.js`, `#watchHeaderHeight`). Le
 * repli, 150 px, est la hauteur nominale de `HeaderJulia` : il ne sert qu'au premier
 * rendu et aux navigateurs sans `ResizeObserver`.
 *
 * **Pas caméra allumée** : l'en-tête s'y replie en une ligne posée sur la vidéo, la scène
 * filmée occupe l'arrière-plan, et il n'y a plus de fil à faire passer dessous. */
.f6-mode-chat:not(.f6-camera-active) .f6-shell { position: relative; }
.f6-mode-chat:not(.f6-camera-active) .f6-header {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  /* Au-dessus du fil, sous la surcouche modale — un panneau qui attend une réponse coiffe
     tout, y compris le visage de celle qui l'a posée. */
  z-index: 5;
  pointer-events: none;
}
/* L'en-tête ne prend plus les clics **du vide qui l'entoure** : le portrait ne remplit pas
   toute sa largeur, et un bloc invisible en travers du fil empêcherait de toucher la bulle
   qui passe dessous. Ce qui se clique dedans les reprend, un par un. */
.f6-mode-chat:not(.f6-camera-active) .f6-chat-header,
.f6-mode-chat:not(.f6-camera-active) .f6-chat__avatar,
.f6-mode-chat:not(.f6-camera-active) .f6-brand-header { pointer-events: auto; }
.f6-mode-chat:not(.f6-camera-active) .f6-scroll {
  padding-top: var(--f6-header-height, 150px);
}
/* `flex: 0 0 auto` pour la transcription, `1 0 auto` pour l'étape : la conversation
 * garde sa hauteur, et c'est la zone de réponse qui absorbe la place restante. Les
 * pastilles se posent ainsi contre la barre d'action quand l'échange est court, sans
 * cesser de descendre quand il s'allonge. */
.f6-mode-chat .f6-scroll > .f6-transcript { flex: 0 0 auto; overflow: visible; }
.f6-mode-chat .f6-scroll > .f6-step { flex: 1 0 auto; overflow: visible; }
/* La réserve de défilement : sa hauteur est posée par le runtime, et vaut zéro la plupart
   du temps. `flex: 0 0 auto` pour qu'elle ne se laisse ni étirer ni comprimer — une
   réserve que la disposition rognerait ne réserverait rien. Hors conversation, elle
   n'existe pas : le mode formulaire ne cadre aucune question. */
.f6-mode-chat .f6-scroll > .f6-scroll__reserve { flex: 0 0 auto; }
.f6-scroll__reserve { height: 0; }
/* **Et elle disparaît caméra ouverte — `display: none`, pas une hauteur nulle.**
 *
 * Ce mode pose `justify-content: space-between` sur le conteneur (voir plus bas). Avec deux
 * enfants, il colle la transcription en haut et l'étape en bas, contre la barre d'action :
 * c'est ce qui met les pastilles sous le pouce et laisse le centre de l'écran à l'image.
 * Un **troisième** enfant, fût-il haut de zéro, change la répartition — l'étape devient
 * l'élément du milieu et se pose au centre, à 286 px de la barre, en plein dans le flux.
 *
 * Une hauteur nulle ne suffit donc pas : ce qui gêne ici n'est pas sa taille, c'est sa
 * présence dans le compte. */
f6-chatbot.f6-camera-active .f6-scroll__reserve { display: none; }

.f6-step__title {
  margin: 0 0 var(--f6-space-6);
  font-family: var(--f6-font-title);
  font-size: var(--f6-font-size-h1);
}

.f6-step__errors {
  margin-top: var(--f6-space-4);
  padding: var(--f6-space-2) var(--f6-space-4);
  border-left: 3px solid var(--f6-color-error);
  background: color-mix(in srgb, var(--f6-color-error) 8%, transparent);
  color: var(--f6-color-error);
}

.f6-errors { margin: 0; padding-left: var(--f6-space-4); }

/* --- Actions ------------------------------------------------------------ */

.f6-actions {
  display: flex;
  gap: var(--f6-space-2);
  align-items: center;
  padding: var(--f6-space-4);
  /* **La marge du système remplace la nôtre, elle ne s'y ajoute pas.** Sur un téléphone à
     encoche, `env(safe-area-inset-bottom)` vaut ~34 px ; posée en plus du rembourrage, elle
     donnait un vide sous la barre — l'« espace perdu en bas » relevé le 28/08. `max()`
     prend le plus grand des deux : le creux du système là où il existe, le nôtre ailleurs.
     Sur un écran sans encoche, `env()` vaut 0 et rien ne change. */
  padding-bottom: max(var(--f6-space-4), env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--f6-color-border);
  position: sticky;
  bottom: 0;
  background: var(--f6-color-surface);
}

/* **Le seuil mobile — et c'est l'espacement qui rend la hauteur, pas les polices.**
 *
 * Mesuré avant d'y toucher : le corps de texte est à 16 px, c'est-à-dire le `body-large` de
 * Material et un point sous le `Body` d'iOS. Le descendre mettrait la question posée à
 * l'assuré sous le corps de texte de toutes les applications qu'il utilise par ailleurs —
 * sur l'écran où il doit comprendre ce qui sera couvert. Ce qui coûtait la hauteur est
 * ailleurs : une échelle d'espacement de 16/24/32 pensée pour une page, pas pour un
 * téléphone tenu à une main.
 *
 * Les jetons, donc, et **seulement** les jetons : une règle qui coderait sa taille en dur
 * ferait régler la suivante à trois endroits.
 *
 * **Deux sélecteurs, et c'est ce qui fait que ce bloc s'applique.** Il ne s'appliquait pas.
 * La feuille de thème déclare les mêmes jetons — `--f6-space-4: 16px`, `--f6-font-size-h1:
 * 24px` — dans `[data-theme="<id>"]`, l'enveloppe que `catalog.py` pose à l'injection. Cela
 * fait **(0,1,0)** contre le **(0,0,1)** d'un `f6-chatbot` nu, sur le même élément (c'est
 * `chatbot.js` qui pose `data-theme` sur l'hôte lui-même), et la feuille est chargée après.
 * Une `@media` n'ajoute aucune spécificité, et la feuille de thème n'en contient aucune :
 * le thème gagnait à toutes les largeurs. Le seuil mobile était mort sur tout parcours
 * thémé, c'est-à-dire sur tous — 16/24/32 restaient 16/24/32 sous 480 px, et le `h1` à
 * 24 px, là où ce bloc croyait poser 12/16/24 et 20 px.
 *
 * `f6-chatbot[data-theme]` vaut (0,1,1) et passe devant ; le premier sélecteur de la liste
 * garde le repli non thémé (l'éditeur, un parcours sans marque). **Et non un `!important`** :
 * un thème a le droit de régler ses jetons, c'est sa raison d'être — ce qui doit passer
 * devant lui, c'est la *variante responsive*, qui est de la mise en page et vit donc ici.
 * Un thème qui voudrait vraiment imposer sa propre échelle mobile le peut encore : il lui
 * suffit d'une `@media` chez lui, qui gagnerait par l'ordre. */
@media (max-width: 480px) {
  f6-chatbot, f6-chatbot[data-theme] {
    --f6-space-4: 12px;
    --f6-space-6: 16px;
    --f6-space-8: 24px;
    /* **L'échelle descend d'un cran, et pas du même cran partout.**
     *
     * Ce bloc avait délibérément laissé le corps à 16 px — le `body-large` de Material, un
     * point sous le `Body` d'iOS — et pris la hauteur sur l'espacement seul. L'argument
     * tenait ; l'écran a changé depuis, il porte un en-tête, une bande de prise de vue et
     * une pilule à libellé.
     *
     * Les titres perdent 2 px, le corps aussi, et le petit texte **reste à son plancher**.
     *
     * L'échelle a bougé trois fois, et ce que cette histoire apprend vaut d'être gardé. Le
     * corps était à 16 px — le `body-large` de Material, un point sous le `Body` d'iOS —,
     * puis 15, et maintenant 14 : l'écran s'est chargé depuis (en-tête, portrait, bande de
     * prise de vue, barre d'action), et la place manque là où elle compte, sous la question.
     * Ce qu'on rend en corps de texte, on le gagne en lignes lues.
     *
     * **Le petit texte, lui, ne descend pas.** Un passage à 12 px a été essayé le 07/09 et
     * repris le jour même : le petit texte est le **détail d'une question**, celui qui cadre
     * la réponse attendue — le seul texte du parcours sur lequel on ne veut pas économiser.
     * 13 px est le plancher, il l'était déjà, et l'essai n'a fait que le confirmer.
     *
     * L'écart entre corps et détail se resserre donc à 1 px. C'est voulu : ce qui distingue
     * les deux à l'écran est la couleur et la place, pas la taille. */
    --f6-font-size-h1: 18px;
    --f6-font-size-h2: 16px;
    --f6-font-size-body: 14px;
    --f6-font-size-small: 13px;

    /* **Point 5 — le portrait de Julia, à la mesure d'un téléphone.**
     *
     * 85 px de boîte et 53 px d'image, quel que soit l'écran : ni l'une ni l'autre n'était
     * reprise ici. Le jeton existe désormais pour que les trois cotes — la boîte, l'aura et
     * l'image — se règlent d'un seul endroit ; elles étaient écrites trois fois et se
     * déréglaient séparément.
     *
     * **65 px et non 72, pour la même raison que le corps de texte descend** : le portrait
     * est en tête de conversation, donc il prend sa place sur celle de la première question.
     * Il doit rester reconnaissable — c'est l'interlocutrice —, pas occuper le haut de
     * l'écran. Sept pixels de boîte rendent une ligne au fil. */
    --f6-avatar-size: 65px;
  }
  /* La barre se resserre plus encore que le jeton : elle porte des commandes de 41 px, qui
     font déjà leur propre hauteur de touche, et c'est la seule bande fixe de l'écran. */
  .f6-actions {
    /* 12 px en littéral : `--f6-space-3` n'existe pas dans l'échelle (1/2/4/6/8) et
       retombait sur 0 ailleurs dans ce fichier — un jeton fantôme se propage. */
    padding: var(--f6-space-2) 12px;
    padding-bottom: max(var(--f6-space-2), env(safe-area-inset-bottom, 0px));
  }
}
/* `display` l'emporte sur la règle par défaut du navigateur pour `[hidden]` : sans cette
   ligne, poser `els.actions.hidden = true` (clôture réussie, plus rien à faire) ne cachait
   pas la barre — même piège que `.f6-voice-controls[hidden]` et `.f6-button--icon[hidden]`
   ci-dessous. Les boutons Précédent/Terminer restaient visibles et cliquables, avec des
   gestionnaires qui ne faisaient plus rien une fois le parcours terminé (AI-1011, O4). */
.f6-actions[hidden] { display: none; }

.f6-button {
  flex: 1;
  min-height: 44px; /* cible tactile : la déclaration se remplit au téléphone */
  padding: 0 var(--f6-space-4);
  border-radius: var(--f6-radius-default);
  border: 1px solid var(--f6-color-primary);
  background: var(--f6-color-surface);
  color: var(--f6-color-primary);
  font: inherit;
  cursor: pointer;
}

.f6-button--primary {
  background: var(--f6-color-primary);
  color: var(--f6-color-on-primary);
}

.f6-button--ghost { border-color: var(--f6-color-border); color: var(--f6-color-text-muted); }
.f6-button--icon { flex: 0 0 auto; min-width: 44px; }
.f6-button:disabled { opacity: .45; cursor: not-allowed; }

/* --- Mode conversationnel ---------------------------------------------- */

.f6-transcript {
  display: flex;
  flex-direction: column;
  gap: var(--f6-space-2);
  padding: var(--f6-space-4);
  overflow-y: auto;
}

/* **Un `display` d'auteur l'emporte sur le `[hidden]` du navigateur** — troisième fois
 * que le dépôt s'y fait prendre, après les commandes de voix et les boutons d'icône. Le
 * défaut ne s'était pas encore vu ici parce que `hidden` n'était posé que sur une
 * transcription **vide** : une boîte flex sans enfant ne se remarque pas. Depuis qu'une
 * étape formulaire la masque alors qu'elle est pleine, la règle ci-dessus la rouvrait,
 * et l'écran de confirmation restait empilé sous la conversation. */
.f6-transcript[hidden] { display: none; }

/* Les bulles, relevées au composant sur les maquettes.
 *
 * Le coin **carré du côté de l'interlocuteur** est ce qui donne à l'échange son sens de
 * lecture : Julia parle depuis la gauche, l'assuré répond depuis la droite. Quatre coins
 * arrondis rendraient les deux bulles interchangeables. */
.f6-chat__bubble {
  max-width: 88%;
  padding: 10px 15px;
  font-size: var(--f6-font-size-body);
  line-height: 1.3;
  filter: drop-shadow(0 0 5px rgba(0, 0, 0, .15));
}

.f6-chat__bubble--question {
  align-self: stretch;
  max-width: 100%;
  background: var(--f6-color-primary);
  color: var(--f6-color-on-primary);
  border-radius: 0 8px 8px 8px;
}

.f6-chat__bubble--answer {
  align-self: flex-end;
  background: var(--f6-color-surface-sunken);
  color: var(--f6-color-text-strong, var(--f6-color-text));
  border-radius: 8px 0 8px 8px;
}

/* La seconde ligne d'une question — la `description` du composant. La maquette s'en sert
 * pour cadrer la réponse attendue (« Répondez simplement “oui” ou “non” »), et c'est bien
 * une précision, pas une seconde question : elle se lit plus petite. */
/* **Le détail se replie.** Il fait souvent plus de lignes que la question qu'il précise —
   trois de plus sur la question photo du DDE —, et à 390 px les deux ensemble prenaient la
   moitié de l'écran, choix de réponse compris. On garde donc la question entière et l'on
   met le détail à un geste : c'est de la place rendue sans rien rapetisser. */
.f6-chat__bubble-pli { display: block; }
/* **La poignée est un bouton, et elle en a l'air.**
 *
 * Elle était « … » suivi d'un chevron : un signe qui ne dit pas ce qu'il ouvrirait. Elle
 * prend le style des autres commandes du parcours — une pilule discrète, un contour, une
 * hauteur de touche — et le mot « Plus de détails » à côté d'une icône. C'est ce qui a été
 * demandé le 31/08.
 *
 * Elle reste un `<summary>` : le pliage, le clavier et l'état annoncé aux lecteurs d'écran
 * viennent avec `<details>`, et rien n'est à tenir en JavaScript. La maquiller en bouton
 * est du ressort de cette feuille, pas du balisage. */
.f6-chat__bubble-plus {
  display: inline-flex;
  align-items: center;
  gap: var(--f6-space-1);
  margin-top: var(--f6-space-2);
  padding: 6px var(--f6-space-2);
  /* 32 px et non 44 : ce n'est pas une commande du parcours mais une commande *dans* une
     bulle, et une pilule de 44 px y ferait un second bouton principal. La cible reste
     confortable — le mot en fait la largeur. */
  min-height: 32px;
  font-size: var(--f6-font-size-small);
  color: var(--f6-color-text-strong, var(--f6-color-text));
  background: var(--f6-color-surface);
  border: 1px solid var(--f6-color-border);
  border-radius: var(--f6-radius-pill);
  cursor: pointer;
  /* Le marqueur natif est un triangle plein, différent d'un navigateur à l'autre. On le
     retire ; le chevron ci-dessous est le nôtre. */
  list-style: none;
}
.f6-chat__bubble-plus:hover { background: var(--f6-color-surface-sunken); }
/* **Caméra éteinte, il n'y a rien à replier.**
 *
 * Le repli n'achète de la place que sous la bande de capture : c'est elle qui prend le bas
 * de l'écran pendant que le détail de la question photo fait trois lignes de plus que la
 * question. Sans elle, la place ne manque pas — et un détail à un geste est un détail que
 * personne ne lit, alors que c'est lui qui cadre la réponse attendue.
 *
 * **C'est ici que ça se décide, et pas dans le JavaScript.** L'assuré ouvre et ferme la
 * caméra en cours de question ; un choix figé au moment du rendu serait faux la seconde
 * d'après. Ces deux règles suivent `f6-camera-active`, que l'hôte pose et retire.
 *
 * `display: block` sur le détail **contredit délibérément** la feuille du navigateur, qui
 * masque tout enfant d'un `<details>` fermé sauf son `<summary>`. C'est ce qui permet de
 * garder la sémantique du pliage — clavier, lecteurs d'écran — tout en montrant le contenu
 * là où le pliage n'a plus de raison d'être. */
f6-chatbot:not(.f6-camera-active) .f6-chat__bubble-plus { display: none; }
f6-chatbot:not(.f6-camera-active) .f6-chat__bubble-pli > .f6-chat__bubble-detail {
  display: block;
}
.f6-chat__bubble-plus::-webkit-details-marker { display: none; }
/* L'icône ne rétrécit pas quand le mot pousse : un « i » écrasé en ovale se lit comme un
   défaut d'affichage. */
.f6-chat__bubble-plus-icone { flex: 0 0 auto; }
/* Le chevron, tracé au trait plutôt qu'en caractère : une police peut ne pas l'avoir, et
   il se tourne alors que « ▾ » se remplacerait. */
.f6-chat__bubble-plus::after {
  content: "";
  width: 8px;
  height: 8px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 160ms ease;
}
.f6-chat__bubble-pli[open] .f6-chat__bubble-plus::after {
  transform: translateY(1px) rotate(-135deg);
}
/* **Déplié, le bouton se répond à lui-même.** « Réduire » ne le faisait pas : on ne réduit
   pas « Plus de détails », on en demande moins.
   
   Les deux mots sont dans le DOM et `[open]` choisit lequel s'affiche — attribut que
   `<details>` pose et retire tout seul. Un `content:` de pseudo-élément aurait fait le même
   effet en apparence, mais un texte qui n'existe que dans la feuille de style n'est ni
   traduisible, ni relu, ni annoncé de façon fiable par un lecteur d'écran. */
.f6-chat__bubble-plus-mot[data-pli="ouvert"] { display: none; }
.f6-chat__bubble-pli[open] .f6-chat__bubble-plus-mot[data-pli="ferme"] { display: none; }
.f6-chat__bubble-pli[open] .f6-chat__bubble-plus-mot[data-pli="ouvert"] { display: inline; }
@media (prefers-reduced-motion: reduce) {
  .f6-chat__bubble-plus::after { transition: none; }
}
/* Le détail, désormais lu d'un trait sur toutes les questions sauf la prise de vue. Il
   reste plus petit et légèrement en retrait : c'est une précision, pas une seconde
   question. */
.f6-chat__bubble-detail {
  display: block;
  margin-top: var(--f6-space-1);
  font-size: var(--f6-font-size-small);
  opacity: .9;
}

/* L'avatar et son aura — l'aura tourne doucement, ce qui signale « Julia écoute » sans
 * qu'aucun texte n'ait à le dire. Immobile si l'utilisateur a demandé moins d'animation. */
/* Le voile clair derrière l'en-tête et l'avatar : il décolle la conversation du haut de
 * l'écran sans y poser de trait. La maquette l'appelle « FondgrisBackgroundBlur ». */
.f6-chat-active .f6-transcript {
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--f6-color-border) 37%, transparent) 0,
    transparent 148px
  );
}

/* **`transcript: current` ne montre que la question courante.** L'historique de l'échange
 * reste masqué — un écran plus sobre, une question à la fois. C'est le parcours qui le
 * décide, à son manifeste, et non le lien qui l'ouvre : le réglage a d'abord vécu sur
 * l'URL (`?transcript`), où personne ne le relisait, si bien que deux assurés du même
 * parcours n'avaient pas le même écran selon le lien reçu. Le défaut reste `full` — tout
 * le fil, comme une messagerie.
 *
 * Les bulles ne sont pas retirées, seulement masquées : le DOM survit, donc le retour
 * arrière reste juste (même politique que le mode caméra, qui force la question courante
 * seule — là, le fil couvrirait la vidéo qu'on demande à l'assuré de cadrer). */
f6-chatbot.f6-mode-chat.f6-transcript-compact
  .f6-transcript .f6-chat__bubble:not(.f6-chat__bubble--current) {
  display: none;
}

/* --- Le portrait de Julia et son aura -------------------------------------
 *
 * `Aura Julia` de la maquette (`I7904:98234;6009:61676`) : **dix anneaux concentriques**
 * pleins, de 85 px à 52,749 px, soit un pas constant de 3,58 px de diamètre — 1,79 px en
 * rayon. Le motif était déjà obtenu par un `repeating-radial-gradient`, à un pas de 4 px
 * relevé à l'œil ; il est ici celui de la maquette. Dix `<img>` empilés seraient dix
 * nœuds et dix requêtes pour le même dessin.
 *
 * **Ce que l'aura dit, et ce qu'elle ne disait pas.** Elle tournait — douze secondes par
 * tour, sur un motif à symétrie de révolution, c'est-à-dire une animation qui ne se voit
 * pas et un calcul qui, lui, se paie. Elle est maintenant **muette au repos et vivante
 * quand Julia parle** : `--f6-level-out` (0 à 1) est posé sur `f6-chatbot` à chaque trame
 * d'analyse par l'extension `assistant-live`, et c'est le niveau réel de **sa** voix.
 *
 * **Sa voix, et pas n'importe laquelle.** La mesure de l'assuré (`--f6-level-in`) va au
 * halo du micro, sous le portrait. Les fondre en une seule ferait respirer le visage de
 * Julia pendant que c'est l'assuré qui parle — le contresens exact que ces animations sont
 * censées lever.
 *
 * Quatre états, et c'est le visage qui les porte :
 *   - **pas d'entretien** — l'aura est là, pâle et immobile : c'est le dessin de la
 *     maquette, et il ne prétend rien ;
 *   - **liaison ouverte, personne ne parle** — un anneau s'échappe lentement du portrait
 *     (`::after`), assez pour dire « la ligne est ouverte », trop lent pour distraire ;
 *   - **Julia parle** — l'aura respire à l'amplitude de sa voix ;
 *   - **l'assuré parle** — l'aura se **pose**, très légèrement resserrée : Julia écoute.
 *     C'est le seul état où l'immobilité veut dire quelque chose.
 * ------------------------------------------------------------------------ */
/* **Une seule cote, et deux qui en dérivent.** La boîte, l'aura et le portrait valaient
   85 / 85 / 53 px, écrits en trois endroits : trois nombres qu'il fallait penser ensemble
   et que rien n'obligeait à le rester. Le jeton les tient. Il vaut 85 px par défaut et
   descend à 72 px sous 480 px (voir le seuil mobile plus haut) — l'ensemble prenait un
   huitième de la hauteur d'un téléphone. */
.f6-chat__avatar {
  position: relative;
  align-self: center;
  display: grid;
  place-items: center;
  width: var(--f6-avatar-size, 85px);
  height: var(--f6-avatar-size, 85px);
}
.f6-chat__avatar::before {
  content: '';
  grid-area: 1 / 1;
  width: var(--f6-avatar-size, 85px);
  height: var(--f6-avatar-size, 85px);
  border-radius: 50%;
  background:
    repeating-radial-gradient(
      circle,
      color-mix(in srgb, var(--f6-color-primary) 70%, transparent) 0 .9px,
      transparent .9px 1.79px
    );
  /* L'amplitude **et** la présence suivent la voix de Julia. `90ms` : assez court pour que
     l'aura colle à la syllabe, assez long pour qu'elle ne clignote pas d'une trame à
     l'autre — une aura qui suit la trame brute vibre au lieu de respirer. */
  opacity: calc(.42 + var(--f6-level-out, 0) * .58);
  transform: scale(calc(1 + var(--f6-level-out, 0) * .07));
  transition: opacity 140ms ease-out, transform 140ms ease-out;
}
/* **L'assuré parle : Julia écoute.** L'aura se resserre d'un cheveu et s'assombrit à
   peine — un mouvement qu'on ne remarque pas en le regardant, mais qui rend le tour de
   parole lisible du coin de l'œil. C'est l'inverse exact de l'état précédent, et c'est
   pour cela qu'il tient en deux lignes. Aucune onde ici : c'est l'immobilité qui dit
   l'écoute, et le halo du micro, en bas, qui porte alors le mouvement. */
f6-chatbot[data-speaking="user"] .f6-chat__avatar::before {
  opacity: .5;
  transform: scale(.97);
}
/* L'anneau qui s'échappe : **seulement quand la liaison est ouverte, et que personne ne
   parle**. C'est le seul signe que l'entretien est en cours pendant un silence, et il ne
   coûte qu'un pseudo-élément — pas un second dessin d'aura. Il se retire dès que Julia
   prend la parole : les ondes, plus bas, disent alors la même chose en mieux, et deux
   pulsations de périodes différentes autour du même visage se lisent comme un défaut. */
.f6-chat__avatar::after {
  content: '';
  grid-area: 1 / 1;
  /* Le même jeton que la boîte et l'aura : l'anneau naît **au bord** du portrait et son
     départ est une échelle (`.62` dans `f6-aura-onde`), donc relative. Laissé à 85 px
     pendant que la boîte descend à 72, il aurait débordé du cadre au lieu de l'épouser. */
  width: var(--f6-avatar-size, 85px);
  height: var(--f6-avatar-size, 85px);
  border-radius: 50%;
  border: 1px solid var(--f6-color-primary);
  opacity: 0;
  pointer-events: none;
}
f6-chatbot[data-live]:not([data-speaking="assistant"]) .f6-chat__avatar::after {
  animation: f6-aura-onde 2.6s cubic-bezier(.22, .61, .36, 1) infinite;
}
@keyframes f6-aura-onde {
  0%   { transform: scale(.66); opacity: .5; }
  70%  { opacity: 0; }
  100% { transform: scale(1.12); opacity: 0; }
}

/* --- Les ondes sonores : **Julia parle** ----------------------------------
 *
 * Trois anneaux qui s'échappent du portrait, décalés d'un tiers de période. Ce que l'aura
 * seule ne pouvait pas rendre : elle *respire* — elle grossit et pâlit avec l'amplitude —,
 * et une respiration dit « ce visage est vivant », pas « un son sort d'ici ». Un son qui
 * sort se voit à ce qu'il **s'éloigne** : il faut un mouvement qui parte du centre et
 * traverse le bord, donc plusieurs anneaux en file, jamais un seul qui pulse sur place.
 *
 * Elles ne paraissent **que** quand Julia parle (`data-speaking="assistant"`, posé par
 * `_paintLevel` au-dessus du seuil de parole). Pendant un silence, l'anneau lent de
 * `::after` suffit ; quand c'est l'assuré qui parle, le visage se pose — l'écoute est
 * l'immobilité, et c'est le halo du micro, en bas, qui bouge alors.
 *
 * **L'amplitude passe par `--f6-level-out`**, la voix de Julia mesurée à chaque trame — la
 * même source que l'aura, jamais un second détecteur. Elle ne pilote pas l'animation
 * elle-même (une durée qui change à chaque trame saccade), mais **sa portée** : l'anneau va
 * plus loin sur une syllabe forte. C'est délibérément grossier — on ne lit pas un niveau
 * sonore sur un anneau, on voit seulement que ça parle.
 * ------------------------------------------------------------------------ */
.f6-chat__ondes {
  grid-area: 1 / 1;
  /* Derrière le portrait, avec l'aura : les anneaux naissent **sous** le visage et en
     sortent. Nés au-dessus, ils passeraient devant lui à chaque tour. */
  z-index: 0;
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.f6-chat__ondes i {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1.5px solid var(--f6-color-primary);
  opacity: 0;
}
f6-chatbot[data-speaking="assistant"] .f6-chat__ondes i {
  animation: f6-onde-sonore 1.8s cubic-bezier(.22, .61, .36, 1) infinite;
}
/* Décalés d'un tiers : trois anneaux en file, et non trois anneaux qui battent ensemble. */
f6-chatbot[data-speaking="assistant"] .f6-chat__ondes i:nth-child(2) { animation-delay: .6s; }
f6-chatbot[data-speaking="assistant"] .f6-chat__ondes i:nth-child(3) { animation-delay: 1.2s; }
@keyframes f6-onde-sonore {
  /* Il part **au ras du portrait** (53 px sur 85, soit .62) : une onde qui naîtrait au bord
     de l'aura ne viendrait de nulle part. */
  0%   { transform: scale(.62); opacity: 0; }
  15%  { opacity: .55; }
  100% { transform: scale(calc(1.25 + var(--f6-level-out, 0) * .35)); opacity: 0; }
}
/* **Sans liaison, le portrait se met en retrait.** Il reste parfaitement lisible — c'est
   toujours l'interlocutrice —, mais il cesse de se présenter comme actif : c'est ce qui
   rend le bouton « Parler à Julia » juste en dessous lisible comme une invitation, et non
   comme une commande redondante. */
f6-chatbot[data-assistant]:not([data-live]) .f6-chat__avatar::before { opacity: .3; }
f6-chatbot[data-assistant]:not([data-live]) .f6-chat__avatar img { filter: saturate(.7); }

/* La photo est **au-dessus** de l'aura, et le `z-index` est explicite : les trois occupent
 * la même cellule de grille, si bien que leur ordre de peinture dépendrait sinon de leur
 * ordre dans le DOM — et un `::before` est engendré *avant* le contenu. Une règle de
 * thème qui poserait une position sur l'aura suffirait à la faire passer devant, et le
 * portrait disparaîtrait sans qu'aucune erreur ne le signale. */
.f6-chat__avatar::before { z-index: 0; }
.f6-chat__avatar::after { z-index: 2; }
.f6-chat__avatar img {
  position: relative;
  z-index: 1;
  grid-area: 1 / 1;
  /* 52,749 px dans la maquette sur une aura de 85 : le portrait **est** le dixième anneau,
     il n'y a pas de blanc entre lui et l'aura. Le rapport (0,6235) compte donc plus que le
     nombre — le figer à 53 px pendant que l'aura rétrécit ferait apparaître le dixième
     anneau, c'est-à-dire un liseré clair autour du visage. `calc()` le tient à toutes les
     tailles : 53 px sur 85, 45 px sur 72. */
  width: calc(var(--f6-avatar-size, 85px) * 0.6235);
  height: calc(var(--f6-avatar-size, 85px) * 0.6235);
  border-radius: 50%;
  object-fit: cover;
  transition: filter 200ms ease;
}
@media (prefers-reduced-motion: reduce) {
  .f6-chat__avatar::before { transition: none; transform: none; }
  f6-chatbot[data-live]:not([data-speaking="assistant"]) .f6-chat__avatar::after { animation: none; }
  /* Les ondes s'arrêtent, mais ne disparaissent pas : un anneau posé dit encore « ça
     parle » à qui a demandé qu'on ne l'anime pas. */
  f6-chatbot[data-speaking="assistant"] .f6-chat__ondes i { animation: none; opacity: .35; }
  f6-chatbot[data-speaking="assistant"] .f6-chat__ondes i:nth-child(2) { transform: scale(1.12); }
  f6-chatbot[data-speaking="assistant"] .f6-chat__ondes i:nth-child(3) { transform: scale(1.24); }
}

/* --- Le bandeau de marque et de dossier ----------------------------------
 *
 * Structure ici, habillage dans le thème. Il apparaît sur **tous** les écrans et dans
 * les deux modes : c'est ce que montre la maquette, et c'est aussi ce qui permet à
 * l'assuré de vérifier d'un coup d'œil que le dossier ouvert est bien le sien. */
.f6-brand-header { flex: 0 0 auto; }
.f6-brand-header__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--f6-space-4);
  padding: var(--f6-space-2) var(--f6-space-4);
}
.f6-brand-header__logo { display: block; height: 28px; width: auto; }
.f6-brand-header__help { color: var(--f6-color-primary); font-size: var(--f6-font-size-small); }
/* Le bouton « Aide » d'un parcours porte la même classe que le lien statique du thème
 * qu'il remplace (`chatbot.js#renderBrandHeader`) — même place, même rôle. Un `<button>`
 * arrive avec son propre habillage de navigateur ; on ne retire que ça, la couleur et la
 * taille de police restant celles de la règle ci-dessus. */
button.f6-brand-header__help { border: 0; background: none; padding: 0; cursor: pointer; font: inherit; }
.f6-contract-banner__field { display: block; }
.f6-contract-banner__label::after { content: " : "; }

/* Le bandeau de dossier est un `<details>` : déplié en formulaire, replié en
 * conversation (voir `#bannerOpen`). Le résumé n'est donc visible que replié —
 * déplié, il ferait doublon avec la première ligne de la liste. */
.f6-contract-banner[open] > .f6-contract-banner__summary { display: none; }
.f6-contract-banner__summary { cursor: pointer; }
.f6-contract-banner__summary::-webkit-details-marker { display: none; }

/* --- `HeaderJulia` : la barre, puis le portrait ---------------------------
 *
 * Deux étages : la barre (logo · prénom · `⋮`), puis le portrait auréolé. C'est ce que fait
 * le composant de la maquette, qui mesure 152 px d'un tenant.
 *
 * **C'est la barre qui porte le fond blanc et l'ombre** (`headerJulia`, habillage dans le
 * thème) ; le portrait est posé sur la page, sans fond. Les deux étages ont porté chacun
 * les siens, et cela donnait un bloc blanc de 152 px découpé au ras du visage — là où la
 * maquette montre une barre ombrée, puis un portrait sur le fond de page.
 *
 * **Le portrait n'est plus `sticky`, et il ne perd rien.** L'en-tête est un frère de
 * `.f6-scroll` (voir le gabarit de `chatbot.js`), donc **hors** du conteneur qui défile :
 * rien ne passe jamais derrière lui, et l'adhérence des deux étages n'a jamais rien fait.
 * Elle coûtait en revanche un jeton (`--f6-chat-header-height`) posé sur le parent commun
 * pour que le second étage sache où s'arrêter sous le premier — un réglage à tenir à jour
 * pour un empilement qui n'existe pas. La barre garde le sien, inerte mais inoffensif ;
 * c'est le calage qui disparaît.
 * ------------------------------------------------------------------------ */
.f6-chat-header {
  position: sticky;
  top: 0;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--f6-space-4);
  padding: 10px 20px;
  background: var(--f6-color-surface);
}
.f6-chat-header__name {
  margin: 0;
  /* **Nunito, et non la fonte de titre.** « Julia » n'est pas un titre de page, c'est une
     identité dans une barre — la maquette l'écrit en `Nunito:Bold` 20 px, et l'en-tête de
     formulaire est tout en Nunito lui aussi. `--f6-font-title` (Roboto chez IMH) reste la
     fonte des titres d'étape, qui eux en sont. */
  font-family: var(--f6-font-body);
  font-weight: 700;
  font-size: var(--f6-font-size-h2, 20px);
  line-height: 1;
  color: var(--f6-color-primary);
}
.f6-chat-header__brand { display: inline-flex; align-items: center; height: 25px; }
.f6-chat-header__logo { display: block; height: 25px; width: auto; }
.f6-chat-header__menu { display: inline-flex; color: var(--f6-color-primary); }

/* Le second étage — le portrait, sous la barre.
 *
 * **Sans ombre, et sans fond plein : un fondu.** Il portait les deux, ce qui faisait de
 * l'en-tête un bloc blanc de 152 px découpé au ras du visage ; la maquette (`HeaderJulia`,
 * `7904:98234`) montre une barre blanche ombrée puis le portrait posé sur la page. L'ombre
 * remonte donc à la barre (habillage dans le thème), et le fond devient un dégradé qui
 * **s'efface vers le bas** : opaque contre la barre, transparent au bord inférieur.
 *
 * C'est ce dégradé qui rend l'en-tête en surimpression lisible. Le fil passe dessous (voir
 * plus haut) : sans lui, une bulle se glisserait entière derrière le visage et l'on ne
 * saurait plus ce qui est en haut du fil ; avec un fond plein, elle disparaîtrait d'un coup
 * contre une arête. Elle se dissout — on voit ce qui s'en va.
 *
 * Le portrait, lui, reste net : c'est une image posée au-dessus de ce fond. */
.f6-chat-portrait {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 10px 0 var(--f6-space-6);
  background: linear-gradient(
    to bottom,
    var(--f6-color-surface) 0%,
    var(--f6-color-surface) 55%,
    color-mix(in srgb, var(--f6-color-surface) 55%, transparent) 80%,
    transparent 100%
  );
}

/* Le menu de l'en-tête — le `⋮` qui existait et ne faisait rien.
 *
 * Il porte le guide des autorisations, atteignable **de partout** : `autorisations` est
 * douze étapes en arrière, et revenir en arrière dépile le journal. Consulter un état du
 * navigateur n'a pas à passer par le parcours. */
.f6-header-menu { position: relative; margin-left: auto; }
.f6-header-menu__button {
  width: 24px; height: 24px; padding: 0;
  background: none; border: 0; cursor: pointer;
  color: inherit;
}
.f6-header-menu__list {
  position: absolute; right: 0; top: 100%; z-index: 30;
  min-width: 12rem;
  padding: var(--f6-space-1);
  background: var(--f6-color-surface);
  border: 1px solid var(--f6-color-border);
  border-radius: var(--f6-radius-default);
  box-shadow: 0 8px 24px rgba(40, 60, 80, .25);
}
.f6-header-menu__list button {
  display: block; width: 100%;
  padding: var(--f6-space-2);
  background: none; border: 0; cursor: pointer;
  font: inherit; color: inherit; text-align: left;
}
.f6-header-menu__list button:hover { background: var(--f6-color-surface-sunken); }

/* --- `TabBarJulia` : la barre d'actions en conversation -------------------
 *
 * La maquette y met **trois disques** — retour à gauche, caméra au centre, pièce jointe à
 * droite — et rien d'autre : ni « Suivant » plein, ni libellé. Elle y arrive parce que la
 * conversation avance en répondant : on touche une pastille, et la question suivante
 * vient. Le seul écran où quelque chose se valide est la saisie libre, et la maquette y
 * pose « Envoyer ma réponse » **dans la question** (`37 / Chat - Autre cause`), pas dans
 * la barre.
 *
 * Ici, trois colonnes : `1fr auto 1fr`. Le centre est **vraiment** centré — pas centré
 * dans l'espace libre, ce qui le décalait dès que les deux côtés n'avaient pas la même
 * largeur (le défaut qui avait imposé un centrage en absolu en mode caméra). Une colonne
 * vide ne déplace rien.
 *
 * « Valider » prend la colonne de droite, **et seulement quand il sert**. Il est déjà
 * `disabled` tant que la réponse n'est pas valide (`chatbot.js`, `els.next.disabled`) —
 * donc inerte au clic : le cacher alors ne retire aucun geste possible, et rend à la barre
 * les trois zones de la maquette sur toutes les questions à pastilles, c'est-à-dire la
 * quasi-totalité du parcours. */
.f6-mode-chat .f6-actions {
  display: grid;
  /* Quatre colonnes **égales** : le retour, le bouton de parole, la caméra, la validation.
     Deux emplacements d'extension distincts se posent au milieu — la caméra et l'entretien
     — et ils ne peuvent pas partager une cellule sans se recouvrir, d'où deux colonnes et
     non une.

     **`repeat(4, 1fr)`, et chaque commande centrée dans son quart.** C'était
     `1fr minmax(0, auto) auto 1fr` : les deux colonnes du milieu se dimensionnaient sur
     leur contenu et ne se séparaient que par le `column-gap` — huit pixels — pendant que le
     retour et « Valider » s'écartaient aux deux bords. Le bouton de parole et la caméra se
     touchaient presque, et c'est ce qui a été relevé en réunion le 31/08 : « très proches,
     voire presque collés », avec une demande de boutons **équidistants**.

     **La grille reste, et ce n'est pas une préférence.** Le gabarit ne pose que
     « Précédent » et « Suivant » dans le pied (`chatbot.js`) ; le bouton de parole et la
     caméra y sont ajoutés par leurs extensions, dans l'ordre où elles s'enregistrent —
     caméra d'abord. L'ordre à l'écran (retour · parole · caméra · valider) n'est donc tenu
     que par les `grid-area` ci-dessous. Un `display: flex` avec `justify-content:
     space-evenly`, qui donnerait la même équidistance en deux mots, afficherait en réalité
     « Précédent · Valider · caméra · parole ».

     **Ce que `1fr` change pour la pilule.** La colonne du bouton de parole était en
     `minmax(0, auto)` pour une raison précise : `auto` seul dimensionne sur le contenu et
     l'y *enferme*, si bien que le jour où ce bouton est devenu une pilule à libellé
     (« Parler avec Julia »), quatre contenus indéboîtables sur 375 px débordaient dès que
     « Valider » paraissait. `1fr` la contraint de la même manière — il pose une largeur, pas
     un minimum de contenu —, donc la pilule rétrécit toujours sous la pression.

     **Ce qu'on perd, et c'est assumé.** La symétrie `1fr … 1fr` faisait qu'une colonne vide
     ne déplaçait rien : caméra allumée sur un parcours sans entretien, le déclencheur
     restait au milieu de l'écran, là où le pouce le cherche. Avec quatre colonnes égales,
     une colonne vide occupe quand même son quart et la caméra se pose au centre du
     troisième. Aucun parcours en recette n'est dans ce cas — le DDE IMH offre toujours le
     bouton de parole. Le jour où il y en aura un,
     `.f6-actions:not(:has(.f6-assistant-controls))` repasse en trois colonnes.

     Le `column-gap` ne fait plus qu'un plancher : des colonnes égales et des contenus
     centrés ne se disputent plus l'espace. C'est heureux, parce qu'il ne serait de toute
     façon pas maître ici — la couche produit du thème déclare `gap` sur le même sélecteur,
     plus spécifique et chargée après. */
  grid-template-columns: repeat(4, 1fr);
  column-gap: var(--f6-space-2);
  align-items: center;
  justify-items: center;
  border-top: none;
}
/* Le même piège que partout ailleurs dans cette feuille, et c'est sa **cinquième**
   occurrence : un `display` d'auteur l'emporte sur le `[hidden]` du navigateur, à
   spécificité égale. Sans cette ligne, `els.actions.hidden = true` (clôture réussie) ne
   cacherait plus la barre en conversation. */
.f6-mode-chat .f6-actions[hidden] { display: none; }
/* `justify-self` retiré des deux boutons de bord : ils se centrent désormais dans leur
   quart comme les deux autres (`justify-items: center` ci-dessus), et c'est ce qui rend les
   quatre écarts égaux. Collés aux bords, ils rouvraient l'asymétrie qu'on vient de fermer. */
.f6-mode-chat .f6-actions [data-action="back"] { grid-area: 1 / 1; }
/* **L'ordre de la maquette : retour · mode Julia · caméra · valider** (`TabBarJulia`,
   `8223:84265`). Le bouton de parole vient **avant** la caméra — parler à Julia est la
   commande première de l'écran, la caméra ne sert qu'aux prises de vue qu'elle demande. Il
   était l'inverse (caméra puis micro) ; c'est un simple échange de colonnes (recette, 3b). */
.f6-mode-chat .f6-actions > .f6-assistant-controls {
  grid-area: 1 / 2;
  /* Le conteneur de l'emplacement doit rétrécir avec sa colonne, sans quoi la pilule qu'il
     porte impose sa largeur naturelle et le `minmax(0, 1fr)` ne sert à rien. */
  min-width: 0;
  max-width: 100%;
}
.f6-mode-chat .f6-actions > .f6-camera-controls { grid-area: 1 / 3; }
.f6-mode-chat .f6-actions [data-action="next"] {
  grid-area: 1 / 4;
  /* **Il ne se plie pas sur deux lignes**, et c'est le prix des colonnes égales.
   *
   * Un quart de 390 px fait 91 px. « Terminé — 1 page » n'y tient pas : le libellé passait
   * à la ligne, le bouton montait à 62 px dans une barre qui en fait 44, et débordait de
   * 10 px au-dessus et au-dessous. Mesuré, pas supposé — `test_video_mode_e2e` l'a dit.
   *
   * `nowrap` le garde sur une ligne ; il déborde alors un peu de sa colonne, des deux
   * côtés puisqu'il y est centré, et va chercher le vide qui entoure les disques de 41 px
   * voisins. C'est ce vide-là qui rend la chose tenable : les autres commandes n'occupent
   * que la moitié de leur quart. Le rembourrage se resserre pour la même raison. */
  white-space: nowrap;
  padding: 0 var(--f6-space-2);
}
/* **« Valider » reste, désactivé, plutôt que de disparaître.**
 *
 * Il s'effaçait là où répondre suffit à avancer (`chatbot.auto_advance`) : il est de toute
 * façon `disabled` tant que la réponse n'est pas valide, donc inerte au clic, et le cacher
 * rendait à la barre les trois zones de la maquette. La recette du 28/08 a tranché
 * autrement, et sur un argument que la maquette ne pouvait pas voir : sur une conversation,
 * la validité change **à chaque frappe**. Le bouton apparaissait et disparaissait au rythme
 * de la saisie, et la barre entière se réorganisait sous le pouce à chaque fois. Une
 * commande qui bouge est une commande qu'on rate.
 *
 * Il garde donc sa place et son état se lit : le thème peint le `:disabled` en **gris**
 * (`--f6-color-surface-sunken`) et non en primaire pâli — un bouton teal translucide se lit
 * encore comme un bouton teal, et on clique dessus. Le léger retrait d'opacité s'ajoute à ce
 * gris ; il ne le remplace pas. */
.f6-mode-chat.f6-auto-advance .f6-actions [data-action="next"]:disabled { opacity: .7; }

/* En mode conversationnel, seule la question courante est affichée : le reste de l'étape
 * est déjà dans la transcription. */
.f6-mode-chat .f6-step { padding-top: 0; }
.f6-mode-bottom .f6-step__body {
  position: sticky;
  bottom: 60px;
  background: var(--f6-color-surface);
}

/* --- Récapitulatif ------------------------------------------------------ */

.f6-recap__group { margin-bottom: var(--f6-space-6); }
.f6-recap__title {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: var(--f6-font-size-body);
  border-bottom: 1px solid var(--f6-color-border);
  padding-bottom: var(--f6-space-1);
}
.f6-recap__list { margin: 0; }
/* Le libellé et la valeur se **partagent** la ligne, et passent l'un sous l'autre quand
   ils n'y tiennent pas. Sans le retour à la ligne, une adresse ou un texte libre poussait
   le récapitulatif hors de l'écran ; sans les bases souples, c'est le mot lui-même qui se
   coupait — « oui » s'affichait « o / ui ». */
.f6-recap__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0 var(--f6-space-4);
  padding: var(--f6-space-1) 0;
}
.f6-recap__label { flex: 1 1 55%; color: var(--f6-color-text-muted); min-width: 0; }
.f6-recap__value {
  flex: 1 1 35%;
  margin: 0; font-weight: 600; text-align: right;
  min-width: 0; overflow-wrap: break-word;
}
.f6-recap__edit {
  border: 0; background: none; color: var(--f6-color-primary);
  cursor: pointer; font: inherit;
}
/* **Les photos du récapitulatif se regardent.** Une bande de vignettes carrées sous la
 * phrase qui les compte : l'assuré relit sa déclaration, et « 4 photos (…-1.jpg, …-2.jpg) »
 * ne lui apprenait rien. Elles restent petites — c'est un récapitulatif, pas une galerie —
 * et le clic ouvre la pièce entière. */
.f6-recap__vignettes {
  display: flex; flex-wrap: wrap; gap: var(--f6-space-1);
  margin: var(--f6-space-1) 0 0; padding: 0; list-style: none;
}
.f6-recap__vignette { flex: 0 0 auto; }
.f6-recap__vignette img {
  display: block; width: 56px; height: 56px;
  object-fit: cover; border-radius: var(--f6-radius-default);
  background: var(--f6-color-surface-sunken);
}

.f6-recap__pending {
  padding: var(--f6-space-2) var(--f6-space-4);
  background: var(--f6-color-primary-subtle);
  border-radius: var(--f6-radius-default);
}

/* --- Emplacements d'extension ------------------------------------------ */

.f6-slot { display: flex; align-items: center; gap: var(--f6-space-2); }
/* **Un emplacement sans rien à montrer ne prend pas de place.**
 *
 * Le montage d'un emplacement existe dès que l'extension est chargée, et il survit à
 * l'extinction de ce qu'il porte : le bouton de parole est caché hors conversation, le
 * déclencheur et l'interrupteur de caméra hors prise de vue. Le `<div>` restait alors dans
 * la barre d'action, large de zéro — mais **compté comme un élément** : il y consommait une
 * gouttière de 24 px en formulaire, et sa colonne entière en conversation. C'est le
 * « espace vide à droite » de la recette : sur l'écran d'accueil, « Lancer le questionnaire »
 * s'arrêtait 40 px avant le bord droit quand il en avait 16 à gauche.
 *
 * `:not(:has(> :not([hidden])))` se lit « aucun enfant visible ». Un navigateur sans `:has`
 * ignore la règle et retrouve le comportement d'avant — un espace de trop, jamais un
 * contrôle perdu. */
.f6-actions > .f6-slot:not(:has(> :not([hidden]))) { display: none; }

.f6-status {
  padding: var(--f6-space-2) var(--f6-space-4);
  font-size: var(--f6-font-size-small);
  color: var(--f6-color-text-muted);
  text-align: center;
}
/* **En entretien vocal, le bandeau d'état s'efface : le bouton micro dit déjà que Julia
 * écoute** — le disque plein, sa coche et le halo (thème). Ce runtime est pensé pour un
 * téléphone, et « Julia vous écoute. » posé en permanence en bas mangeait une ligne utile
 * pour une information que le bouton porte déjà (recette, point 7). Le bandeau reste pour ce
 * qui n'a pas d'autre porteur — une liaison rompue, par exemple, qui survient précisément
 * **hors** de l'état `data-live`. */
f6-chatbot[data-live] .f6-status { display: none; }

.f6-done { padding: var(--f6-space-8) 0; text-align: center; }

/* --- Ajustements de form.io -------------------------------------------- *
 * form.io produit du balisage Bootstrap. On n'en reprend que ce qu'il faut pour que ses
 * champs adoptent les jetons du thème — sans quoi le formulaire aurait l'air d'un autre
 * produit que le reste de la page. */

f6-chatbot .formio-component { margin-bottom: var(--f6-space-4); }
f6-chatbot .form-control,
f6-chatbot input[type="text"],
f6-chatbot input[type="email"],
f6-chatbot input[type="tel"],
f6-chatbot input[type="number"],
f6-chatbot textarea,
f6-chatbot select {
  width: 100%;
  min-height: 44px;
  padding: var(--f6-space-2) var(--f6-space-4);
  border: 1px solid var(--f6-color-border);
  border-radius: var(--f6-radius-default);
  font: inherit;
  color: inherit;
  background: var(--f6-color-surface);
}

f6-chatbot .form-control:focus-visible,
f6-chatbot .f6-radio-cards__option:focus-visible {
  outline: 2px solid var(--f6-color-primary);
  outline-offset: 2px;
}

/* **L'unité d'un champ (« m² ») se pose à droite, pas dessous.** form.io range un
 * suffixe dans un `.input-group` Bootstrap ; comme on ne charge pas Bootstrap au runtime,
 * le `.input-group-text` — privé de la mise en ligne — retombait sous le champ, à la
 * ligne. On rend le groupe horizontal et l'on colle l'unité au bord droit du champ. */
f6-chatbot .input-group { display: flex; align-items: stretch; }
f6-chatbot .input-group-append,
f6-chatbot .input-group-prepend { display: flex; }
f6-chatbot .input-group > .form-control,
f6-chatbot .input-group > input {
  /* `width: 1%` + `flex: 1 1 auto` : l'unité prend sa largeur, le champ occupe le reste —
   * sans quoi le `width: 100%` du champ pousse le suffixe à la ligne suivante. */
  flex: 1 1 auto;
  width: 1%;
}
f6-chatbot .input-group > .form-control:not(:last-child),
f6-chatbot .input-group > input:not(:last-child) {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  border-right: 0;
}
f6-chatbot .input-group-text {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: var(--f6-space-2) var(--f6-space-4);
  border: 1px solid var(--f6-color-border);
  border-left: 0;
  border-top-right-radius: var(--f6-radius-default);
  border-bottom-right-radius: var(--f6-radius-default);
  color: var(--f6-color-text-muted);
  background: var(--f6-color-primary-subtle);
  white-space: nowrap;
}

/* --- Le calendrier d'un champ de date -------------------------------------
 *
 * form.io colle à droite du champ un `.input-group-text` portant `<i class="fa fa-calendar">`.
 * **Font Awesome n'est pas chargé au runtime** — l'éditeur l'embarque, la page de l'assuré
 * non —, si bien que ce `<i>` ne dessinait rien : le champ de date se terminait par une
 * case teintée et vide. Personne ne voyait qu'on pouvait ouvrir un calendrier.
 *
 * On lui donne l'icône de la maquette, **en masque** : la couleur vient du thème
 * (`--f6-color-primary`) et non d'un `fill` figé dans le tracé, si bien que la même règle
 * sert Generali sans y toucher. Le tracé, lui, est celui de la bibliothèque, recopié.
 *
 * Et la case cesse de se présenter comme un suffixe d'unité (« m² ») : fond blanc comme le
 * champ, rembourrage resserré — c'est le bord droit du champ, pas une étiquette accolée. */
f6-chatbot .input-group-text:has(> .fa-calendar) {
  padding-left: var(--f6-space-2);
  padding-right: var(--f6-space-2);
  background: var(--f6-color-surface);
}
f6-chatbot .input-group-text > .fa-calendar {
  display: block;
  width: 24px;
  height: 24px;
  background: var(--f6-color-primary);
  -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20fill='black'%20d='M19.75%209.61816C19.6715%209.64605%2019.5881%209.66406%2019.5%209.66406H5.5C5.41194%209.66406%205.3285%209.64605%205.25%209.61816V17.9141C5.25%2019.2241%206.27713%2020.25%207.5%2020.25H17.5C18.7229%2020.25%2019.75%2019.2241%2019.75%2017.9141V9.61816ZM14.4619%2012.5059C14.7507%2012.2089%2015.2255%2012.2025%2015.5225%2012.4912C15.8194%2012.78%2015.8268%2013.2548%2015.5381%2013.5518L12.0381%2017.1514C11.8969%2017.2966%2011.7026%2017.3789%2011.5%2017.3789C11.2974%2017.3789%2011.1031%2017.2966%2010.9619%2017.1514L9.46191%2015.6084C9.1734%2015.3114%209.18063%2014.8365%209.47754%2014.5479C9.77453%2014.2593%2010.2494%2014.2656%2010.5381%2014.5625L11.5%2015.5518L14.4619%2012.5059ZM19.75%207.62891C19.75%206.31888%2018.7229%205.29297%2017.5%205.29297H7.5C6.27713%205.29297%205.25%206.31888%205.25%207.62891V8.20996C5.32846%208.18211%205.41198%208.16406%205.5%208.16406H19.5C19.588%208.16406%2019.6715%208.18211%2019.75%208.20996V7.62891ZM21.25%2017.9141C21.25%2020.0124%2019.5908%2021.75%2017.5%2021.75H7.5C5.40916%2021.75%203.75%2020.0124%203.75%2017.9141V7.62891C3.75%205.85722%204.93282%204.34261%206.55957%203.91406V3C6.55957%202.58579%206.89536%202.25%207.30957%202.25C7.72376%202.25002%208.05957%202.5858%208.05957%203V3.79297H16.75V3C16.75%202.58579%2017.0858%202.25%2017.5%202.25C17.9142%202.25%2018.25%202.58579%2018.25%203V3.86914C19.9741%204.22583%2021.25%205.78878%2021.25%207.62891V17.9141Z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20fill='black'%20d='M19.75%209.61816C19.6715%209.64605%2019.5881%209.66406%2019.5%209.66406H5.5C5.41194%209.66406%205.3285%209.64605%205.25%209.61816V17.9141C5.25%2019.2241%206.27713%2020.25%207.5%2020.25H17.5C18.7229%2020.25%2019.75%2019.2241%2019.75%2017.9141V9.61816ZM14.4619%2012.5059C14.7507%2012.2089%2015.2255%2012.2025%2015.5225%2012.4912C15.8194%2012.78%2015.8268%2013.2548%2015.5381%2013.5518L12.0381%2017.1514C11.8969%2017.2966%2011.7026%2017.3789%2011.5%2017.3789C11.2974%2017.3789%2011.1031%2017.2966%2010.9619%2017.1514L9.46191%2015.6084C9.1734%2015.3114%209.18063%2014.8365%209.47754%2014.5479C9.77453%2014.2593%2010.2494%2014.2656%2010.5381%2014.5625L11.5%2015.5518L14.4619%2012.5059ZM19.75%207.62891C19.75%206.31888%2018.7229%205.29297%2017.5%205.29297H7.5C6.27713%205.29297%205.25%206.31888%205.25%207.62891V8.20996C5.32846%208.18211%205.41198%208.16406%205.5%208.16406H19.5C19.588%208.16406%2019.6715%208.18211%2019.75%208.20996V7.62891ZM21.25%2017.9141C21.25%2020.0124%2019.5908%2021.75%2017.5%2021.75H7.5C5.40916%2021.75%203.75%2020.0124%203.75%2017.9141V7.62891C3.75%205.85722%204.93282%204.34261%206.55957%203.91406V3C6.55957%202.58579%206.89536%202.25%207.30957%202.25C7.72376%202.25002%208.05957%202.5858%208.05957%203V3.79297H16.75V3C16.75%202.58579%2017.0858%202.25%2017.5%202.25C17.9142%202.25%2018.25%202.58579%2018.25%203V3.86914C19.9741%204.22583%2021.25%205.78878%2021.25%207.62891V17.9141Z'/%3E%3C/svg%3E") center / contain no-repeat;
}

f6-chatbot .col-form-label,
f6-chatbot label { display: block; margin-bottom: var(--f6-space-1); font-weight: 600; }

/* **Ce qui a déjà été dit dans une bulle ne se répète pas sous le champ.**
 *
 * Le libellé de la question est dans la bulle, et il y est **avant** que l'assuré ne
 * réponde : le reposer au-dessus de la saisie le ferait lire deux fois.
 *
 * Cette règle vivait dans `themes/imh/theme.css`, et c'était le mauvais endroit :
 * empêcher la conversation de se répéter n'est pas un choix de marque. Un parcours servi
 * par un autre thème répétait donc son libellé, et le défaut ne se voyait que chez lui.
 * Un thème garde le droit d'en déroger ; il n'a plus la charge de la poser.
 *
 * On ne masque que le libellé **du champ** (`col-form-label`, celui que form.io pose
 * au-dessus d'une saisie). Viser tout `label` de la zone emporterait le libellé de chaque
 * option d'un choix multiple, et la case ronde d'un consentement dont le titre est porté
 * par un `<label>` — des éléments qui ne font double emploi avec rien.
 *
 * La `description`, elle, ne se masque **pas ici** : elle n'est redondante que lorsqu'elle
 * a effectivement été dite, et un composant sans libellé ne produit aucune bulle. C'est
 * donc `presenters/step-chat.js` qui la masque, clé par clé, au moment où il la dit. */
.f6-mode-chat .f6-chat__live .col-form-label,
.f6-mode-chat .f6-chat__live .field-required { display: none; }
/* form.io ajoute des précisions **destinées aux lecteurs d'écran** dans un `sr-only` —
 * une classe de Bootstrap, que le runtime ne charge pas. Elles s'affichaient donc en
 * clair : « Montant estimé des dommages (€) , numeric only, » sous les yeux d'un assuré,
 * en anglais et en jargon.
 *
 * On les masque à l'œil sans les retirer de l'arbre d'accessibilité : elles sont utiles
 * là où elles étaient prévues. `display: none` les supprimerait pour tout le monde.
 * (Bootstrap 5 a renommé la classe : on couvre les deux.) */
f6-chatbot .sr-only,
f6-chatbot .visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Choix natifs (radio, cases à cocher) : form.io les rend au balisage Bootstrap, dont le
 * runtime n'a que les classes. Sans ces règles, l'option se colle à sa case, la cible
 * tactile fait la taille du petit rond, et l'écran mélange deux vocabulaires visuels —
 * des tuiles généreuses ici, des radios minuscules trois lignes plus bas. */
f6-chatbot .form-check,
f6-chatbot .form-radio .form-check { position: relative; }
f6-chatbot .form-check-label {
  display: flex;
  align-items: center;
  gap: var(--f6-space-2);
  min-height: 40px;         /* cible tactile : la déclaration se remplit au téléphone */
  font-weight: 400;
  cursor: pointer;
}
f6-chatbot .form-check-input {
  width: 20px; height: 20px;
  margin: 0;
  accent-color: var(--f6-color-primary);
  flex: 0 0 auto;
}

f6-chatbot .formio-errors { color: var(--f6-color-error); font-size: var(--f6-font-size-small); }
f6-chatbot .field-required::after { content: " *"; color: var(--f6-color-error); }
/* Un libellé masqué n'a pas d'astérisque à porter : form.io rend malgré tout son
 * `<label class="field-required control-label--hidden">`, et le marqueur flottait seul
 * au-dessus du champ — à côté d'un libellé que personne ne voit. */
f6-chatbot .control-label--hidden::after { content: none; }

/* Le bouton d'envoi de form.io ferait doublon avec la barre d'actions du runtime. */
f6-chatbot .formio-component-submit { display: none; }

/* Repli des tuiles quand aucun thème n'est chargé (développement, tests). */
.f6-radio-cards {
  display: grid;
  grid-template-columns: repeat(var(--f6-cards-columns, 1), 1fr);
  gap: var(--f6-space-2);
}
/* **Liste longue repliée** : au-delà des premières, les tuiles marquées « extra » sont
 * masquées jusqu'au dépliant. Elles restent dans le DOM (form.io lit sa valeur du modèle),
 * mais hors de l'écran — chercher son cas dans trente lignes coûte plus que le décrire. */
.f6-radio-cards[data-collapsed] .f6-radio-cards__option--extra { display: none; }
/* **L'option que le filtre écarte.** Une règle à part de celle du repli, et non un
 * partage de la même : les deux se superposent — on filtre une liste repliée — et une
 * tuile trouvée au-delà de la cinquième doit s'afficher alors que `--extra` la désigne
 * encore. Fondre les deux aurait rendu invisible exactement ce que le filtre trouve. */
.f6-radio-cards .f6-radio-cards__option--filtre-hors { display: none; }
.f6-cards-toggle {
  margin-top: var(--f6-space-2);
  padding: var(--f6-space-1) 0;
  border: 0; background: none;
  color: var(--f6-color-primary-strong);
  font: inherit; font-size: var(--f6-font-size-small);
  text-decoration: underline; cursor: pointer;
}
.f6-cards-toggle:hover { text-decoration: none; }
.f6-radio-cards__option {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--f6-space-2); min-height: 84px; padding: var(--f6-space-4);
  background: var(--f6-color-surface-sunken); border: 1px solid transparent;
  border-radius: var(--f6-radius-default); cursor: pointer; font: inherit; color: inherit;
}
.f6-radio-cards__option[aria-checked="true"] {
  background: var(--f6-color-primary-subtle);
  border-color: var(--f6-color-primary);
}
.f6-radio-cards__icon { width: 28px; height: 28px; color: var(--f6-color-primary); }

/* La **structure** des variantes vit ici, leur habillage dans le thème : une autre
 * marque doit pouvoir redessiner la carte sans réapprendre où sont les morceaux.
 *
 * Ce qu'une option ne porte pas ne s'affiche pas — le rendu ne pose ni portrait, ni
 * étiquette, ni invite qu'on ne lui a pas donnés. Les tuiles ordinaires, qui n'en portent
 * aucun, sont donc exactement ce qu'elles étaient. */
.f6-radio-cards__option[data-variant="card"] { position: relative; }
.f6-radio-cards__badge {
  position: absolute; top: var(--f6-space-2); right: var(--f6-space-2);
  font-size: var(--f6-font-size-small);
}
.f6-radio-cards__portrait {
  width: 84px; height: 84px; border-radius: 50%; object-fit: cover;
}
.f6-radio-cards__heading { font-weight: 700; }
.f6-radio-cards__body { font-size: var(--f6-font-size-small); }
.f6-radio-cards__hint { display: inline-flex; align-items: center; gap: 4px; }
.f6-radio-cards__note { font-style: italic; font-weight: 700; }

/* L'échappatoire a le poids d'un lien — mais reste un `role="radio"` : un `<a>` sans
 * cible serait un lien qui ne mène nulle part, et un lecteur d'écran l'annoncerait
 * comme tel. */
.f6-radio-cards__option[data-variant="link"] {
  min-height: 0; padding: var(--f6-space-2); background: none; border: none;
  text-decoration: underline;
  /* Elle prend sa ligne **sous** la grille au lieu de se ranger à côté d'une vraie
   * réponse : à deux colonnes, une ignorance posée en face d'une réponse se lit comme
   * son alternative, ce qu'elle n'est pas. */
  grid-column: 1 / -1;
}

/* Le séparateur n'est pas une option : il est hors de la grille et sans surface. */
.f6-radio-cards__separator { text-align: center; }

.f6-progress-steps {
  display: flex; align-items: center; gap: var(--f6-space-2);
  padding: var(--f6-space-2) 0;
}
.f6-progress-steps__dot {
  width: 8px; height: 8px; border-radius: var(--f6-radius-pill);
  background: var(--f6-color-surface); border: 1px solid var(--f6-color-primary);
}
.f6-progress-steps__dot--done,
.f6-progress-steps__dot--current { background: var(--f6-color-primary); }
.f6-progress-steps__label {
  margin-left: auto; font-size: var(--f6-font-size-small);
  color: var(--f6-color-primary-strong);
}

/* --- Images d'étape ------------------------------------------------------
 *
 * Le rapport d'aspect est réservé avant chargement : sans lui, l'arrivée de l'image
 * pousse la question vers le bas au moment précis où l'on s'apprête à y répondre. */
.f6-image { margin: 0 0 var(--f6-space-4); }
.f6-image__img {
  display: block; width: 100%; height: auto;
  border-radius: var(--f6-radius-default);
  object-fit: cover; background: var(--f6-color-surface-sunken);
}
.f6-image__caption {
  margin-top: var(--f6-space-1);
  font-size: var(--f6-font-size-small);
  color: var(--f6-color-text-muted);
}
.f6-image--banner { margin-inline: calc(-1 * var(--f6-space-4)); }
.f6-image--banner .f6-image__img { border-radius: 0; }
.f6-image--background {
  position: absolute; inset: 0; z-index: 0; margin: 0; pointer-events: none;
}
.f6-image--background .f6-image__img { height: 100%; border-radius: 0; }

/* --- Contenu rédigé ------------------------------------------------------
 *
 * Les quelques classes que les blocs `content` d'un parcours peuvent employer. Elles sont
 * ici et non dans le thème parce qu'elles sont **structurelles** : une puce reste une
 * puce d'une marque à l'autre. Ce qui change — la couleur de la pastille, l'icône —
 * descend dans `theme.css`. */
.f6-bullets, .f6-checklist, .f6-contact { margin: 0 0 var(--f6-space-4); padding-left: var(--f6-space-6); }
.f6-bullets li, .f6-checklist li, .f6-contact li { margin-bottom: var(--f6-space-2); }
.f6-checklist { list-style: none; padding-left: 0; }
.f6-note { color: var(--f6-color-text-muted); }
.f6-note--clock { text-align: center; }
.f6-address {
  text-align: center;
  font-size: var(--f6-font-size-h2);
  font-weight: 600;
}

/* **Les lignes de l'écran de confirmation** — une étiquette, une valeur, et elles se lisent
 * ensemble. Structurelles, donc ici : ce qui change d'une marque à l'autre (la couleur de
 * l'étiquette, la graisse de la valeur) descend dans `theme.css`.
 *
 * `flex-wrap` plutôt qu'une grille à deux colonnes : une adresse sur deux lignes et une
 * étiquette longue ne tiennent pas côte à côte sur un téléphone, et une grille les
 * comprimerait au lieu de les empiler. La valeur garde `margin-left: auto` pour se ranger à
 * droite quand les deux tiennent sur la même ligne. */
.f6-infos__ligne {
  display: flex;
  flex-wrap: wrap;
  gap: var(--f6-space-1) var(--f6-space-4);
  align-items: baseline;
  margin: 0 0 var(--f6-space-3);
  padding-bottom: var(--f6-space-3);
  border-bottom: 1px solid var(--f6-color-border);
}
.f6-infos__label { color: var(--f6-color-text-muted); }
.f6-infos__valeur { margin-left: auto; font-weight: 600; text-align: right; }
/* Une précision de bas d'écran : ce que l'assuré n'a pas à corriger ici, et qui lui sera
 * demandé ensuite. Le même registre que `.f6-note`, sans son usage centré. */
.f6-aide { color: var(--f6-color-text-muted); font-size: var(--f6-font-size-small); }

/* --- Consentement --------------------------------------------------------
 *
 * Structure ici, habillage de marque dans le thème — panneau vert pâle et case ronde,
 * qui n'appartiennent qu'à IMH.
 *
 * Le texte engagé est **toujours dans le DOM**, replié ou non : `<details>` reste lisible
 * par un lecteur d'écran et se retrouve par la recherche de la page, ce qu'un texte
 * inséré au clic ne permet pas. */
.f6-consent { display: flex; flex-direction: column; gap: var(--f6-space-2); }
.f6-consent__head {
  display: flex; align-items: center; gap: var(--f6-space-2);
  margin: 0; font-weight: 600; cursor: pointer;
}
.f6-consent__box { width: 20px; height: 20px; flex: 0 0 auto; accent-color: var(--f6-color-primary); }
.f6-consent__title { font-size: var(--f6-font-size-small); }
.f6-consent__statement { margin: 0; }
.f6-consent__panel { font-style: italic; font-size: var(--f6-font-size-small); }
/* **Un dépliant se voit, et il se voit à droite.**
 *
 * Le résumé n'était qu'un mot souligné de couleur : rien ne disait qu'il ouvrait quelque
 * chose, et le texte des conditions restait donc fermé sans que personne sache qu'il y en
 * avait un. « Un titre, et à droite un chevron pour ouvrir le contenu » (Alain).
 *
 * Le chevron est tracé au trait plutôt qu'écrit en caractère — une police peut ne pas
 * l'avoir, et « ▾ » se remplacerait alors par un carré. Il tourne à l'ouverture, ce qui
 * dit l'état sans un mot de plus. Le marqueur natif est retiré : il est différent d'un
 * navigateur à l'autre, et il se pose à gauche. */
.f6-consent__why > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--f6-space-2);
  cursor: pointer; color: var(--f6-color-primary);
  font-size: var(--f6-font-size-small);
  list-style: none;
}
.f6-consent__why > summary::-webkit-details-marker { display: none; }
.f6-consent__why > summary::after {
  content: "";
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 160ms ease;
}
.f6-consent__why[open] > summary::after { transform: translateY(1px) rotate(-135deg); }
@media (prefers-reduced-motion: reduce) {
  .f6-consent__why > summary::after { transition: none; }
}
.f6-consent__why-text { margin-top: var(--f6-space-2); font-size: var(--f6-font-size-small); }
.f6-consent__link { display: block; margin-top: var(--f6-space-2); color: var(--f6-color-primary); }

/* --- Autorisations -------------------------------------------------------
 *
 * Un refus est un état dont on sort, pas une impasse : le bloc d'explication a donc le
 * même poids visuel que la demande elle-même, et non celui d'un message d'erreur. */
/* --- Mode vocal ----------------------------------------------------------
 *
 * L'activation se présente en **modale** (maquette 8223:84284) : carte blanche, titre centré
 * en primaire, deux boutons côte à côte au **contour** (Oui / Non). En ligne — sans hôte de
 * surcouche, l'aperçu de l'éditeur —, la même carte se rend telle quelle. */
.f6-voice-mode {
  padding: var(--f6-space-4);
  background: var(--f6-color-surface);
  border: 1px solid var(--f6-color-border);
  border-radius: var(--f6-radius-default);
}
/* Le titre, **centré et en primaire** — c'est la question de la maquette, pas un titre de
 * page : il porte le choix, il ne coiffe pas l'écran. */
.f6-voice-mode__titre {
  margin: 0 0 var(--f6-space-2);
  font-weight: 700;
  text-align: center;
  color: var(--f6-color-primary-strong);
}
.f6-voice-mode__detail {
  margin: 0 0 var(--f6-space-2);
  font-size: var(--f6-font-size-small);
  color: var(--f6-color-text-muted);
}
/* La ligne « vous gardez la main » — même poids que le détail, elle rassure, elle
 * n'alerte pas. Un peu d'air la sépare des boutons qui suivent. */
.f6-voice-mode__note {
  margin: 0 0 var(--f6-space-4);
  font-size: var(--f6-font-size-small);
  color: var(--f6-color-text-muted);
}
/* Les deux choix, **côte à côte et de même poids** (maquette 8223:84284) : Oui et Non
 * partagent la largeur, tous deux au contour (`.f6-button`, chacun `flex: 1`). La maquette
 * ne hiérarchise pas les deux — pas d'activation « mise en avant » et de refus effacé. */
.f6-voice-mode__actions {
  display: flex;
  gap: var(--f6-space-2);
}
/* Le bouton d'activation centre son **éventuelle** icône à gauche du libellé. L'icône est
 * configurable (`f6.icon`) et peut être vide : il ne reste alors que le libellé, centré. */
.f6-voice-mode__activer {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--f6-space-2);
}
.f6-voice-mode__icone { width: 20px; height: 20px; flex: 0 0 auto; }

.f6-permissions {
  padding: var(--f6-space-4);
  background: var(--f6-color-surface);
  border: 1px solid var(--f6-color-border);
  border-radius: var(--f6-radius-default);
}
.f6-permissions__title {
  margin: 0 0 var(--f6-space-4);
  font-family: var(--f6-font-title);
  font-size: var(--f6-font-size-h1);
  color: var(--f6-color-primary-strong);
}
.f6-permissions__list { list-style: none; margin: 0 0 var(--f6-space-4); padding: 0; }
/* **Une grille de deux lignes, et c'est elle qui rend l'écran immobile.**
 *
 *     [icône] [Caméra ............] [✓] [Autoriser]
 *     [     ] [Pour filmer les pièces touchées et laisser…]
 *
 * La description était dans le libellé, sur la même ligne que lui. Le libellé prend la place
 * laissée libre par le bouton et la coche : accorder une permission changeait sa largeur, la
 * description passait de trois lignes à deux (ou l'inverse), et la ligne gagnait ou perdait
 * ~19 px — sous le doigt de l'assuré, au moment où il vise la permission suivante.
 *
 * Sur sa propre ligne, elle va du libellé au bord droit (`2 / -1`) : **sa largeur ne dépend
 * plus du bouton**. Ce que la colonne du bouton rend, celle du libellé le reprend, et la
 * somme des trois est constante. Le bouton peut donc disparaître pour de bon — on avait
 * essayé de lui réserver sa place (`visibility: hidden`), ce qui tenait la hauteur mais
 * laissait un trou en forme de bouton à côté de la coche.
 *
 * La première ligne, elle, garde la hauteur d'une cible tactile : sans cela elle se
 * rétracterait à la hauteur du titre quand le bouton s'en va. */
.f6-permissions__item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  grid-template-rows: minmax(44px, auto) auto;
  align-items: center;
  column-gap: var(--f6-space-2);
  padding: var(--f6-space-2) 0;
  border-bottom: 1px solid var(--f6-color-border);
  /* Le guide d'aide se pose en surcouche sur sa ligne (`position: absolute`). */
  position: relative;
}
.f6-permissions__icon { grid-area: 1 / 1; }
.f6-permissions__label { grid-area: 1 / 2; }
.f6-permissions__mark { grid-area: 1 / 3; }
.f6-permissions__ask { grid-area: 1 / 4; }
/* La description et « Comment l'activer ? » sur la seconde ligne, du libellé au bord droit. */
.f6-permissions__hint,
.f6-permissions__why { grid-column: 2 / -1; }
.f6-permissions__hint {
  margin: 0;
  color: var(--f6-color-text-muted);
  font-size: var(--f6-font-size-small);
}
.f6-permissions__item:last-child { border-bottom: 0; }
.f6-permissions__icon { font-size: 20px; }
/* --- L'état de chaque ligne, tracé plutôt qu'écrit -------------------------
 *
 * Un mot d'état en bout de ligne — « accordée », « refusée » — ne se lit pas d'un coup
 * d'œil, et c'est pourtant tout ce qu'on regarde sur cet écran. La **structure** et les
 * **états** vivent ici ; leurs couleurs sont du thème.
 *
 * L'anneau d'attente et la coche tracée ne sont pas de l'ornement : ils distinguent
 * « la demande est partie » de « rien ne se passe », et « ça vient d'être accordé » de
 * « c'était déjà accordé ». C'était le seul retour immédiat qu'apportait le widget
 * d'origine. */
/* **La coche d'état occupe sa place, même vide.** Elle n'apparaît qu'une fois la permission
   accordée ou refusée ; jusque-là son élément existe et mesure zéro. Le libellé, qui prend
   toute la place laissée libre, s'en trouvait plus étroit d'un coup — sa description passait
   d'une ligne à deux, et la ligne grandissait de 19 px au moment de l'accord. C'est le même
   défaut que le bouton juste à côté, vu de l'autre bord : ce qui se réserve n'est pas la
   hauteur d'une ligne mais la **largeur** de ce qui la partage. */
.f6-permissions__mark {
  display: inline-flex;
  flex: none;
  justify-content: center;
  width: 22px;
}
.f6-permissions__item--unsupported { opacity: .55; }
.f6-permissions__why {
  display: block; margin-top: var(--f6-space-1); padding: 0;
  background: none; border: 0; font: inherit; font-size: var(--f6-font-size-small);
  color: inherit; text-decoration: underline; cursor: pointer;
}
/* `nowrap` : « Autoriser » tient sur une ligne. Coupé en deux sur un écran étroit, il
   portait la ligne à deux hauteurs de texte pour un mot. */
.f6-permissions__ask { flex: none; white-space: nowrap; }

.f6-permissions__spinner { animation: f6-permissions-spin 900ms linear infinite; }
@keyframes f6-permissions-spin { to { transform: rotate(360deg); } }

.f6-permissions__check path {
  stroke-dasharray: 32; stroke-dashoffset: 0;
  animation: f6-permissions-draw 320ms ease-out;
}
@keyframes f6-permissions-draw { from { stroke-dashoffset: 32; } to { stroke-dashoffset: 0; } }

/* Comme l'aura de Julia : ce qui bouge s'arrête quand on l'a demandé. */
@media (prefers-reduced-motion: reduce) {
  .f6-permissions__spinner { animation: none; }
  .f6-permissions__check path { animation: none; }
}

/* L'aide est une **surcouche sur sa ligne**, fermable : elle remplaçait tout le panneau,
 * si bien qu'on perdait de vue ce qui avait déjà été accordé. */
.f6-permissions__item { position: relative; }
.f6-permissions__help-overlay {
  position: absolute; inset: auto 0 auto 0; top: 100%; z-index: 2;
  padding-top: var(--f6-space-2);
}
.f6-permissions__help {
  padding: var(--f6-space-4);
  background: var(--f6-color-surface);
  border: 1px solid var(--f6-color-border);
  border-radius: var(--f6-radius-default);
  box-shadow: 0 8px 24px rgba(40, 60, 80, .25);
}
.f6-permissions__help h3 { margin: 0 0 var(--f6-space-2); font-size: 1rem; }
.f6-permissions__help-footer {
  display: flex; gap: var(--f6-space-2); flex-wrap: wrap;
}
.f6-permissions__steps { margin: 0 0 var(--f6-space-4); padding-left: var(--f6-space-6); }
.f6-permissions__steps li { margin-bottom: var(--f6-space-1); }
.f6-permissions__note {
  padding: var(--f6-space-2);
  background: var(--f6-color-surface-sunken);
  border-radius: var(--f6-radius-default);
  font-size: var(--f6-font-size-small);
}
.f6-permissions__actions { display: flex; gap: var(--f6-space-2); flex-wrap: wrap; }

/* Demandée par une extension : elle couvre l'écran, parce qu'il n'y a rien d'utile à
   faire tant qu'on n'a pas répondu. */
.f6-permissions-host:not(:empty) {
  position: fixed; inset: 0; z-index: 40;
  display: flex; align-items: center; justify-content: center;
  padding: var(--f6-space-4);
  background: rgba(40, 60, 80, .45);
}
.f6-permissions-host .f6-permissions {
  width: 100%; max-width: var(--f6-layout-max-width);
  box-shadow: 0 8px 32px rgba(40, 60, 80, .25);
}
/* La modale d'activation du mode vocal reprend le **même** hôte de surcouche que le guide
   des autorisations (maquette 8223:84284) : même fond, même centrage, même ombre. Une
   seconde surcouche aurait fini par diverger de celle-ci. */
.f6-permissions-host .f6-voice-mode,
/* La photo en grand aussi : c'est la troisième modale du parcours, et la troisième à passer
   par cet hôte-là. Elle a vécu un temps dans une surcouche à elle, montée par l'extension
   caméra ; elle est revenue au composant de prise de vue — les gestes qu'elle porte
   (reprendre, remplacer, supprimer) écrivent dans la **réponse**, et la réponse est à lui. */
.f6-permissions-host .f6-photo-vue,
/* Et l'enquête de satisfaction, la quatrième. Elle n'apporte donc **aucun voile à elle** :
   celui de cet hôte lui suffit, ce qui est aussi la réponse la plus simple à « quelle
   couleur pour le fond ? » — celle qui est déjà là, et qui n'est écrite qu'une fois. */
.f6-permissions-host .f6-satisfaction {
  width: 100%; max-width: var(--f6-layout-max-width);
  box-shadow: 0 8px 32px rgba(40, 60, 80, .25);
}

/* --- Contrôles vocaux ----------------------------------------------------
 *
 * Deux boutons distincts, et c'est délibéré : couper le son n'est pas la même chose que
 * fermer le micro. Les réunir sur un seul contrôle obligerait à choisir entre parler et
 * entendre. */
.f6-voice-controls { display: flex; gap: var(--f6-space-1); margin-left: auto; }
/* `display` l'emporte sur la règle par défaut du navigateur pour `[hidden]` : sans cette
   ligne, cacher les commandes vocales hors de l'entretien ne les cachait pas. Même piège
   que pour `.f6-button--icon[hidden]`, deux règles plus bas. */
.f6-voice-controls[hidden] { display: none; }
.f6-button--icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; padding: 0;
  font-size: 18px; line-height: 1;
  background: var(--f6-color-surface);
  border: 1px solid var(--f6-color-border);
  border-radius: var(--f6-radius-pill);
  cursor: pointer;
}
.f6-button--icon:hover { border-color: var(--f6-color-primary); }
/* `display` l'emporte sur la règle par défaut du navigateur pour `[hidden]` : sans cette
   ligne, poser `hidden` sur un bouton d'icône ne le cachait pas. Le bouton « prendre une
   photo » restait donc offert caméra éteinte. */
.f6-button--icon[hidden] { display: none; }
.f6-voice-sound[data-voice-enabled=false] { opacity: .55; }

/* Le micro ouvert doit se voir sans ambiguïté : on ne laisse personne parler à un micro
   fermé, ni croire fermé un micro ouvert. */
.f6-voice[data-listening] {
  background: var(--f6-color-primary);
  border-color: var(--f6-color-primary);
  animation: f6-voice-pulse 1.4s ease-in-out infinite;
}
@keyframes f6-voice-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--f6-color-primary) 55%, transparent); }
  50% { box-shadow: 0 0 0 8px color-mix(in srgb, var(--f6-color-primary) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .f6-voice[data-listening] { animation: none; }
}

/* --- Caméra d'arrière-plan -----------------------------------------------
 *
 * La vidéo est **hors du flux** : elle s'installe sans décaler d'un pixel ce que l'assuré
 * est en train de lire. C'est ce qui permet de l'allumer au milieu d'une question. */
.f6-background {
  position: fixed; inset: 0; z-index: 0; overflow: hidden;
  pointer-events: none;
}
/* Le montage de la caméra **remplit** l'arrière-plan fixe. Sans cela il hérite du
 * `.f6-slot { display: flex; align-items: center }` des emplacements en ligne — une boîte
 * sans hauteur propre —, si bien que le `height: 100%` de la vidéo se résolvait contre une
 * hauteur `auto` et retombait sur la **taille intrinsèque du flux** : une webcam paysage
 * s'affichait large et courte, collée en haut, le voile couvrant seul le reste du cadre.
 * Positionné `inset: 0`, la vidéo a enfin une boîte pleine hauteur à couvrir, et
 * `object-fit: cover` la **centre** (son `object-position` par défaut, 50 % 50 %). */
.f6-camera {
  position: absolute; inset: 0; display: block;
}
.f6-camera__video {
  width: 100%; height: 100%; object-fit: cover;
}
/* Sans flou, le texte devient illisible dès que la scène est claire ou chargée. Le voile
   fait le reste : c'est lui qui garantit le contraste, quel que soit ce qui est filmé. */
.f6-camera__video[data-blur] { filter: blur(6px) saturate(.9); transform: scale(1.06); }
.f6-camera::after {
  content: ''; position: absolute; inset: 0;
  background: color-mix(in srgb, var(--f6-color-surface) 72%, transparent);
}

/* Tant que la caméra filme, la coquille flotte au-dessus d'elle. */
f6-chatbot.f6-camera-active { background: transparent; }
f6-chatbot.f6-camera-active .f6-shell { position: relative; z-index: 1; }
f6-chatbot.f6-camera-active .f6-step,
f6-chatbot.f6-camera-active .f6-photo-bar__zone,
f6-chatbot.f6-camera-active .f6-actions {
  background: color-mix(in srgb, var(--f6-color-surface) 88%, transparent);
  backdrop-filter: blur(2px);
}

.f6-camera-controls { display: flex; gap: var(--f6-space-1); align-items: center; }
/* **Le piège du `[hidden]`, sixième occurrence dans cette feuille.** L'interrupteur est
   caché par `element.hidden` là où l'étape ne déclare pas la caméra ; un `display` d'auteur
   — celui que le thème lui donne pour en faire un disque — l'emporte sur la règle du
   navigateur, à spécificité égale. Sans cette ligne, il suivait l'assuré sur tous les
   écrans suivants, jusqu'à s'afficher en face de « Lancer le questionnaire ». */
.f6-camera-toggle[hidden] { display: none; }
.f6-camera-button[data-filming=true] {
  border-color: var(--f6-color-error); color: var(--f6-color-error);
}

/* --- Contrôles caméra sur le flux — plus rien n'y flotte -------------------
 *
 * Il n'y a plus de surimpression sur le viseur. La marche/arrêt était descendue dans la
 * barre au lot 5 (c'est un geste, pas un réglage) ; « Changer de caméra » y est resté seul
 * jusqu'à la recette du 28/08, où il s'est révélé posé sur l'angle même que l'on incline
 * pour cadrer. Il rejoindra le menu « ⋮ », après les autorisations, et ne paraîtra que
 * caméra ouverte — voir `extensions/camera/index.js`, `_switch()`. */

/* **La barre de l'écran filmé, comme la maquette : retour · déclencheur · Valider/voix.**
 * Le déclencheur est le geste principal d'une prise de vue — il tient le **centre de
 * l'écran**, il ne se range pas dans un coin (aujourd'hui il partait à gauche, `order: -1`).
 *
 * Il est **centré en absolu**, et pas par les marges d'une ligne flex : les boutons qui
 * l'entourent n'ont pas la même largeur (un retour étroit à gauche, un « Valider » large à
 * droite), si bien qu'un `margin: auto` le centrait dans l'espace *libre* — donc décalé vers
 * la gauche. Sorti du flux, il se pose au milieu de l'écran quoi qu'il arrive ; le retour
 * prend la gauche (`margin-right: auto`), « Valider » et « Parler à Julia » suivent à
 * droite, et le disque flotte au-dessus du vide laissé au centre. */
/* **Les trois colonnes de la conversation valent aussi caméra allumée**, et le centrage en
 * absolu n'a plus lieu d'être : la grille `1fr auto 1fr` place le déclencheur au milieu de
 * la *barre*, pas au milieu de l'espace libre. C'est le même résultat, obtenu par la
 * disposition plutôt que contre elle — et sans les quatre règles d'ordre qu'il fallait pour
 * ranger quatre boutons dans une ligne flex.
 *
 * Le bouton de parole a quitté ce pied : il est sous le portrait, dans l'en-tête. Les
 * règles qui l'envoyaient à droite (`.f6-slot--footer:not(.f6-camera-controls)`) et qui
 * masquaient son libellé pour qu'il ne passe pas sous le déclencheur (AI-1004) sont donc
 * tombées avec lui. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-actions { position: relative; }

/* --- L'en-tête **caméra allumée** : une seule barre ------------------------
 *
 * Aucune règle ne visait l'en-tête tant que la caméra filmait — les 41 autres règles de
 * cette famille ne touchent que l'étape, la barre, le fil et le flux. Les deux étages de
 * `HeaderJulia` restaient donc posés en entier **sur la vidéo**, soit ~150 px pris à
 * l'image que l'assuré est précisément en train de montrer. C'était la surcharge signalée.
 *
 * La maquette y répond par une barre unique : portrait et prénom à gauche, logo au centre,
 * commandes à droite. On l'obtient sans toucher au DOM — l'en-tête devient une ligne, le
 * portrait passe devant, et les trois éléments de la barre se réordonnent :
 *
 *     [ (◉) 🎤 ] [ Julia ]        [ logo ]        [ ⋮ ]
 *
 * Le portrait garde son aura : c'est le seul endroit où l'on voit encore que Julia écoute,
 * une fois la conversation masquée derrière la scène filmée.
 * ------------------------------------------------------------------------ */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-header {
  display: flex;
  align-items: center;
  gap: var(--f6-space-2);
  padding-right: var(--f6-space-2);
  background: var(--f6-color-surface);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .15);
  /* **Positionné, sinon le fond blanc ne se voit pas.** L'arrière-plan de la caméra
     (`.f6-background`) est `position: fixed; z-index: 0` et vit **dans** la coquille : dans
     son contexte d'empilement, un élément positionné à `z-index: 0` se peint au-dessus de
     tout ce qui ne l'est pas. L'en-tête, laissé `static` ici (la barre et le portrait y
     perdent leur adhérence pour tenir sur une ligne), passait donc **sous la vidéo** — il
     portait bien son blanc, on ne le voyait jamais. La zone de réponse et la barre d'action
     s'en tirent sans le savoir : elles sont `position: relative` par ailleurs, et postérieures
     à la vidéo dans le document.

     C'est le seul élément de la coquille à qui la maquette demande d'être **opaque** sur la
     scène filmée : il porte l'identité et le menu, pas le contenu. Le reste laisse voir.

     **5 et non 2**, et c'est le menu `⋮` qui l'a dit. Un `z-index` crée un contexte
     d'empilement : le déroulé du menu, posé à `z-index: 30` *dans* l'en-tête, ne vaut plus 30
     que **parmi les enfants de l'en-tête** — au-dehors, il ne pèse que le poids de son
     parent. À 2, l'en-tête passait sous la bulle de question (positionnée elle aussi, et
     postérieure dans le document), et le menu ouvert se faisait recouvrir par elle. 5 est la
     valeur qu'il a déjà en conversation ordinaire, et elle dit la même chose : au-dessus du
     fil, sous les surcouches modales. */
  position: relative;
  z-index: 5;
}

/* --- L'écran de prise de vue, plein cadre (maquette B du 30/08) -------------
 *
 * **Le haut d'écran s'efface pendant qu'on cadre**, et rien d'autre ne bouge : « une vue
 * plus simple, qui à la limite coupe de l'interface habituelle » (relecture du 30/08/2026,
 * écran B retenu sur maquette). Ce qui part est exactement ce que l'assuré ne peut pas
 * utiliser dans ce geste-là — la marque, le lien d'aide, la référence de sinistre et le nom
 * de l'assistante — et ce qui reste est ce qui sert : la question, la carte « Cadrage », les
 * vues, « Je passe », le déclencheur, le retour, la voix.
 *
 * **Le juge est `photoWanted()`, comme pour tout le reste de cet écran.** La classe
 * `.f6-photo-guide` est posée par l'extension caméra exactement quand une prise de vue
 * attend (`camera/index.js`), et c'est elle qui allume déjà le déclencheur, la carte
 * « Cadrage » et la netteté du flux. S'y raccrocher plutôt qu'à `.f6-camera-active` est une
 * décision, pas une facilité : sous `camera-active` seul, la marque disparaîtrait pendant
 * **tout** l'entretien filmé, y compris sur les questions ordinaires — ce que personne n'a
 * demandé, et où la référence de sinistre a son utilité. L'écran se dénude pour le geste
 * photo, et se rhabille à la question suivante.
 *
 * **Ce qui dit qu'on filme reste, et il n'est plus ici.** L'interrupteur de caméra a
 * quitté le flux pour le disque central de la barre (`f6-camera-toggle`, `TabBarJulia`) :
 * c'est lui qui passe au primaire quand l'objectif est ouvert, et la barre, elle, ne
 * s'efface pas. Effacer l'en-tête ne masque donc plus l'état d'enregistrement.
 *
 * **Ce qui part est l'habillage, pas la bande.** La barre unique ci-dessus est opaque —
 * fond de surface, ombre portée — parce qu'elle porte l'identité par-dessus la scène
 * filmée. N'en retirer que le contenu laisserait sa coquille : un bandeau blanc vide, les
 * 150 px repris d'une main et rendus de l'autre. On retire donc **les deux** : l'identité
 * et le fond qui la portait.
 *
 * **Mais le `⋮` reste, et c'est un test de la branche UX qui l'a dit.** Un premier jet
 * masquait l'en-tête entier (`display: none`) : le menu des **permissions** — caméra et
 * micro — devenait alors injoignable précisément à l'écran où l'on demande une photo,
 * c'est-à-dire au moment où un objectif refusé se répare. L'arbitrage du 30/08 retirait la
 * marque, la référence et le nom de l'assistante ; il n'a jamais parlé de retirer la seule
 * commande qui reste.
 *
 * La bande perd donc son fond et son ombre, et garde son menu.
 *
 * **Elle garde aussi le doigt**, et c'est une tentation à laquelle il ne faut pas céder.
 * `pointer-events: none` sur la bande — « ce qu'on touche là, c'est la vidéo » — se paie
 * deux fois : la vidéo n'est cliquable à cet endroit sur aucun écran, et la propriété rend
 * la bande transparente à `elementFromPoint`, donc invisible à toute vérification qui porte
 * sur la **peinture** plutôt que sur les nombres. Un test de la branche UX s'en est trouvé
 * rouge en disant « le menu est recouvert » alors qu'il ne l'était pas. */
f6-chatbot.f6-camera-active.f6-mode-chat.f6-photo-guide .f6-header {
  background: none;
  box-shadow: none;
}
f6-chatbot.f6-camera-active.f6-mode-chat.f6-photo-guide .f6-brand-header__top,
f6-chatbot.f6-camera-active.f6-mode-chat.f6-photo-guide .f6-contract-banner,
f6-chatbot.f6-camera-active.f6-mode-chat.f6-photo-guide .f6-chat-header__brand,
f6-chatbot.f6-camera-active.f6-mode-chat.f6-photo-guide .f6-chat-header__name,
f6-chatbot.f6-camera-active.f6-mode-chat.f6-photo-guide .f6-chat-portrait {
  display: none;
}
/* **Et le `⋮` reste à droite.** Retirer le prénom et le logo vide la ligne : le menu, seul
   enfant qui subsiste, glissait au bord gauche — et son déroulé, aligné sur son bord droit,
   sortait de l'écran par la gauche (`x: -160` sur 390 px de large). Il n'était pas recouvert,
   il n'était nulle part. La ligne pousse donc ce qui lui reste à droite, où le menu se
   trouvait déjà quand la barre était pleine. */
f6-chatbot.f6-camera-active.f6-mode-chat.f6-photo-guide .f6-chat-header {
  justify-content: flex-end;
}


/* **`[hidden]` avec sa règle, la quatrième fois.** Le bouton est masqué par l'attribut dès
 * qu'une prise de vue n'a rien à valider (`#reflectNextVisibility`). `.f6-button` ne pose
 * pas de `display`, si bien que la règle du navigateur suffirait aujourd'hui — mais c'est
 * exactement ce que disaient les trois précédentes avant qu'un `display` d'auteur ne soit
 * ajouté au-dessus, et le bouton réapparaissait vide. On l'écrit. */
.f6-actions [data-action="next"][hidden] { display: none; }

/* **La validation reste dans la barre, et c'est la branche UX qui a raison ici.**
 *
 * Elle en avait été exilée — pleine largeur au-dessus de la barre — parce que le
 * déclencheur en tenait le centre en absolu et que les deux se superposaient. Le
 * déclencheur a depuis **sa propre bande** (`.f6-photo-bar`), précisément l'espace où
 * l'exil se réfugiait : la raison de l'exil est tombée avec, et le rétablir ferait
 * flotter une pastille au-dessus d'une barre qui a la place de l'accueillir.
 *
 * Ce que la relecture du 30/08 a changé n'était pas *où* ce bouton se pose, mais **s'il
 * se pose** : rien tant qu'aucune vue n'est versée, « Terminé — N pages » ensuite. Cette
 * moitié-là vit dans `#confirmLabel` / `#reflectNextVisibility` et dans la règle
 * `[hidden]` ci-dessus — elle ne demande aucune mise en page. */
/* La barre perd son ombre et son adhérence propres : c'est la ligne entière qui colle et
   qui porte l'ombre, maintenant. Le portrait, lui, n'a plus ni l'une ni l'autre à annuler
   depuis qu'il est posé sur la page sans fond (voir `.f6-chat-portrait`). */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-chat-header {
  position: static;
  box-shadow: none;
  background: none;
}
f6-chatbot.f6-camera-active.f6-mode-chat .f6-chat-header {
  flex: 1 1 auto;
  min-width: 0;
  gap: var(--f6-space-2);
  padding: 8px 0 8px var(--f6-space-2);
}
/* Prénom, logo, menu — dans cet ordre, comme la maquette. `order` ne réordonne que dans un
   même conteneur : le portrait, lui, est un frère de la barre, et c'est la ligne du dessus
   qui le place. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-chat-header__name { order: 0; }
f6-chatbot.f6-camera-active.f6-mode-chat .f6-chat-header__brand { order: 1; margin: 0 auto; }
f6-chatbot.f6-camera-active.f6-mode-chat .f6-chat-header__menu { order: 2; }

/* Le portrait passe devant la barre, en ligne, et se réduit — 85 px sur une scène filmée,
   c'est un visage qui entre en concurrence avec ce qu'on montre. 36 px suffisent à dire
   qui écoute. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-chat-portrait {
  order: -1;
  flex: 0 0 auto;
  flex-direction: row;
  align-items: center;
  gap: var(--f6-space-1);
  padding: 6px 0 6px var(--f6-space-4);
}
f6-chatbot.f6-camera-active.f6-mode-chat .f6-chat__avatar {
  width: 36px;
  height: 36px;
}
f6-chatbot.f6-camera-active.f6-mode-chat .f6-chat__avatar::before,
f6-chatbot.f6-camera-active.f6-mode-chat .f6-chat__avatar::after {
  width: 36px;
  height: 36px;
}
f6-chatbot.f6-camera-active.f6-mode-chat .f6-chat__avatar img { width: 24px; height: 24px; }
/* **La règle qui cachait le portrait est tombée.** Elle disait : « Il tient 85 px au centre
 * du haut, juste au-dessus du dernier message qu'il repoussait vers le milieu de l'image. »
 * C'était vrai quand le portrait vivait dans le fil ; il est dans l'en-tête depuis, et la
 * maquette en veut précisément un — petit — à cette place, puisque c'est là que se lit
 * encore l'état de l'entretien une fois la conversation masquée. */

/* **« Valider » est redescendu dans la barre**, et il y reste sur une prise de vue comme
 * ailleurs.
 *
 * Il en était sorti — posé en pleine largeur juste au-dessus — parce que le déclencheur
 * tenait le centre de cette même barre : trois zones (retour · déclencheur · voix) plus un
 * bouton large ne tiennent pas sur un écran étroit, et « Valider » se superposait au disque.
 * Le déclencheur a depuis sa **bande à lui** (`.f6-photo-bar`, recette du 28/08, point 1),
 * qui occupe précisément l'espace où « Valider » se réfugiait — les deux s'y recouvraient.
 *
 * La barre retrouve donc ses quatre commandes de conversation, celles qui tiennent déjà sur
 * 360 px, et l'espace au-dessus revient à la photo. */

/* --- Lot 6 : la mini-carte du trajet --------------------------------------
 *
 * Un repère en haut à droite, dans le créneau guide. Le fond est **neutre** (couleurs
 * cartographiques) ; le tracé et « vous êtes ici » gardent le **bleu de convention**
 * (`--f6-color-map-you`) ; **seul le pin du logement prend la marque** (`--f6-color-primary`).
 * Elle ne prend pas le geste — c'est un repère, pas une commande. */
.f6-trajet-host {
  position: fixed;
  top: calc(64px + env(safe-area-inset-top, 0px));
  right: var(--f6-space-4);
  z-index: 3;
  pointer-events: none;
}
.f6-trajet {
  margin: 0;
  width: 132px;
  padding: var(--f6-space-1);
  background: color-mix(in srgb, var(--f6-color-surface) 90%, transparent);
  border-radius: var(--f6-radius-default);
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0, .35));
}
.f6-trajet__carte {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--f6-radius-default);
}
/* Le fond de carte : neutre, jamais la marque. */
.f6-trajet__fond {
  fill: var(--f6-color-surface-sunken);
  stroke: var(--f6-color-border);
  stroke-width: 1;
}
.f6-trajet__rue { stroke: var(--f6-color-border); stroke-width: 2.5; fill: none; }
/* Le tracé et le point de position : bleu de convention, indépendant du thème. */
.f6-trajet__trace {
  stroke: var(--f6-color-map-you);
  stroke-width: 3;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.f6-trajet__vous {
  fill: var(--f6-color-map-you);
  stroke: var(--f6-color-surface);
  stroke-width: 1.5;
}
/* Le pin du logement : la **seule** part qui prend la couleur de la compagnie. */
.f6-trajet__pin path { fill: var(--f6-color-primary); }
.f6-trajet__pin circle { fill: var(--f6-color-surface); }
.f6-trajet__lib {
  margin-top: 2px;
  font-size: var(--f6-font-size-small);
  line-height: 1.2;
  text-align: center;
  color: var(--f6-color-text-muted);
}

/* --- Filmer en conversation ----------------------------------------------
 *
 * **La disposition change, la sémantique non.** Même étape, même formulaire, même
 * journal : seule la place des trois zones bouge. La question courante est épinglée en
 * haut, l'échange défile dessous, et les réponses se posent en bas — c'est-à-dire à portée
 * du pouce, sur un téléphone tenu à bout de bras pour filmer.
 *
 * **Et le voile s'en va.** Ailleurs il garantit le contraste quelle que soit la scène ;
 * ici il recouvre précisément ce que l'assuré est venu montrer, et une image qu'on
 * dépose à 72 % derrière une interface n'est plus une image, c'est un fond. Le contraste
 * revient donc **aux éléments eux-mêmes** : les bulles ont leur couleur, les pastilles
 * leur surface, et ce qui reste nu porte une ombre portée. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-camera::after { display: none; }
f6-chatbot.f6-camera-active.f6-mode-chat .f6-transcript { background: none; }
/* La bande de prise de vue suit la même règle que la zone de réponse et la barre : elle est
   posée sur la scène que l'assuré est en train de cadrer, et un voile blanc derrière le
   déclencheur cache précisément le bas de ce qu'il photographie. Ce qu'elle porte se défend
   seul — le déclencheur par sa double bordure, l'invite par son ombre portée. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-step,
f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo-bar__zone,
f6-chatbot.f6-camera-active.f6-mode-chat .f6-actions {
  background: transparent;
  backdrop-filter: none;
  border-top: none;
}

/* **Le centre reste vide, et c'est la contrainte qui commande tout le reste.** L'assuré
 * filme : ce qu'il montre est au milieu du cadre, et c'est précisément là qu'une interface
 * a spontanément tendance à s'installer. `space-between` pousse donc l'échange en haut et
 * les réponses en bas, et **rien** ne vient occuper l'espace entre les deux. La coquille ne
 * défile plus — sans quoi le dernier message quitterait le haut de l'écran dès qu'on
 * remonte le fil. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-scroll {
  overflow: hidden;
  justify-content: space-between;
}
/* **Une seule bulle à l'écran : la question en cours.** Le fil garde tout — c'est lui qui
 * rend le retour arrière juste, et il ne se vide jamais — mais filmer et relire sont deux
 * gestes, et le second se fait caméra éteinte. Un échange affiché, même borné, finit par
 * recouvrir la scène ; masqué, il la laisse entière. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-scroll > .f6-transcript {
  flex: 0 0 auto;
  min-height: 0;
  overflow: visible;
  justify-content: flex-start;
}
/* `!important` parce qu'un `display` d'auteur l'emporte sur le `[hidden]` du navigateur,
 * et que les bulles portent le leur. Quatrième occurrence du même piège dans ce fichier. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-transcript > * { display: none !important; }
/* **Deux bulles échappent au masque, et pas la même chose.** `--current` est la question
 * qu'on est en train de poser — ce à quoi l'assuré doit répondre pendant qu'il filme.
 * `--epilogue` est ce qui se dit **quand il n'y a plus rien à demander** : le mot de la fin
 * de l'entretien, et les sections de son bilan. Sans cette seconde marque, la clôture était
 * versée au fil et masquée, et l'écran gardait la dernière question — tuiles disparues —
 * sous les yeux de l'assuré : la même question une seconde fois, sans rien dessous
 * (parcours IMH, 31/08/2026). */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-transcript > .f6-chat__bubble--current,
f6-chatbot.f6-camera-active.f6-mode-chat .f6-transcript > .f6-chat__bubble--epilogue {
  display: block !important;
}
/* **La saisie libre porte son propre fond en mode caméra.** Le voile de contraste est
 * retiré pour laisser voir la scène ; un texte nu — le libellé « …décrivez en toutes
 * lettres » et l'avis — y devenait illisible, posé sur un mur clair ou un visage. Comme les
 * tuiles et les bulles, la description porte donc sa propre surface : le contraste revient à
 * l'élément, jamais à un voile qui recouvrirait l'image. (Plan `2026_08_23_tests1`, R4.) */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-libre {
  margin-top: var(--f6-space-2);
  padding: var(--f6-space-2) var(--f6-space-4);
  background: var(--f6-color-surface);
  border-radius: var(--f6-radius-default);
}
f6-chatbot.f6-camera-active.f6-mode-chat .f6-libre__label { color: var(--f6-color-text); }

/* **La zone de réponse s'adapte au contenu, elle n'est plus figée à la moitié de l'écran.**
 * Elle était `flex: 0 0 auto; max-height: 50%` : une question courte en haut (souvent une
 * seule bulle) et beaucoup de tuiles en bas donnaient un grand vide au milieu **et** un
 * défilement des tuiles bloqué à 50 % de la hauteur — alors qu'il restait de la place au-
 * dessus (recette mobile). `flex: 0 1 auto` + `min-height: 0` la laisse prendre **ce qui
 * reste** sous la question : tant que le total tient à l'écran, `space-between` garde le vide
 * au milieu et laisse voir la scène ; dès que les tuiles débordent, elle se contracte à
 * l'espace disponible et ne fait défiler *que* le trop-plein, au lieu de se couper à mi-
 * hauteur. `.f6-step__body` porte le même `overflow` (voir plus bas), c'est lui qui défile. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-scroll > .f6-step {
  flex: 0 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* Contre la barre d'action, sans blanc entre les deux : la marge basse du mode
   * formulaire décollait les pastilles du bord, ce qui les ramenait vers le centre —
   * c'est-à-dire dans l'image. Le pouce, lui, se pose en bas de l'écran. */
  padding-bottom: var(--f6-space-2);
}
/* **`overflow-y: auto` sur `.f6-step` seul ne suffisait pas.** Sans le poser aussi sur
 * `.f6-step__body` — le conteneur direct des tuiles —, celui-ci s'étirait pour montrer
 * tout son contenu au lieu de se laisser contraindre par le `max-height: 50%` du parent :
 * les tuiles en trop passaient sous la barre d'action, invisibles et hors d'atteinte
 * (pas de défilement possible, `.f6-scroll` étant `overflow: hidden` en mode caméra).
 * Une question à plus de trois ou quatre choix — « à quel titre êtes-vous assuré »,
 * cinq réponses — les cachait purement et simplement. Trouvé en test réel, à la main. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-scroll > .f6-step > .f6-step__body {
  overflow-y: auto;
}
/* **La réserve du « Valider » flottant est tombée avec lui.**
 *
 * Elle repoussait le contenu de la zone de réponse de 68 px, pour que « Je passe » ne se
 * fasse pas recouvrir par un « Valider » posé en absolu au-dessus de la barre. Ce bouton est
 * redescendu dans la barre (§ 13.1, quand le déclencheur a pris sa propre bande) : la réserve
 * ne protégeait plus rien et prenait 68 px à la réponse — sur une prise de vue à quatre vues,
 * les dernières pastilles passaient sous le bord, coupées (recette du 28/08). C'est la bande
 * de prise de vue qui occupe cet espace désormais, et elle est **dans le flux** : elle ne
 * recouvre rien, donc il n'y a rien à lui réserver. */

/* Le dernier message, en haut et immobile.
 *
 * `order: -1` le sort de l'ordre chronologique — il est la **dernière** bulle du fil — et
 * `sticky` le retient quand l'échange défile dessous. C'est la seule bulle qui porte cette
 * marque, posée par le présentateur : « la dernière » ne se dit pas en CSS. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-chat__bubble--current,
f6-chatbot.f6-camera-active.f6-mode-chat .f6-chat__bubble--epilogue {
  order: -1;
  z-index: 2;
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0, .45));
}
/* **La bulle laisse la place à la carte « Cadrage ».** Celle-ci flotte en haut à droite
 * (132 px) quand une prise de vue attend ; sur un écran étroit, la bulle pleine largeur
 * passait dessous et son texte disparaissait derrière. On réserve sa colonne — et seulement
 * quand la carte est là (`f6-photo-guide`, posé par la caméra) : ailleurs, toute la largeur. */
f6-chatbot.f6-camera-active.f6-mode-chat.f6-photo-guide .f6-chat__bubble--current {
  margin-right: calc(132px + var(--f6-space-4) + var(--f6-space-2));
}
/* **Et la réponse, elle, garde toute la largeur.** La même colonne avait été réservée sur
 * `.f6-step__body` (AI-1004, campagne QA iOS) : les tuiles y passaient alors sous la carte.
 * Elles n'y passent plus — la bulle courante est devenue collante (`order: -1`, plus haut) et
 * la réponse a glissé sous elle. Mesuré aux quatre tailles de la recette (390×844, 375×667,
 * 390×660, 434×726) : la carte s'arrête entre 292 et 331 px du haut, la réponse commence
 * entre 348 et 544 px — **jamais de recouvrement**, sur aucune.
 *
 * La réservation, elle, s'appliquait quand même : 156 px retirés à une réponse qui n'en avait
 * pas besoin, soit 40 % de la largeur d'un téléphone. Sur une question de prise de vue, la
 * jauge de vues et « Je passe » se retrouvaient serrés dans une colonne de 202 px calée à
 * gauche — le décalage signalé à la recette du 28/08. Elle est retirée ; le test qui suit
 * garde la propriété dans les deux sens (pleine largeur **et** pas d'intersection avec la
 * carte), pour qu'un futur remaniement qui les rapprocherait le dise. */

/* --- L'accord avant d'ouvrir l'objectif -----------------------------------
 *
 * Il couvre l'écran parce qu'il **attend une réponse** : posée dans un coin, la question
 * se contourne sans y penser, et l'on se retrouve à filmer sans l'avoir voulu. Deux
 * réponses, et celle qui engage le moins vient en premier — le pouce ne doit pas trouver
 * « Activer » sous celle qu'il cherchait à éviter. */
.f6-camera-ask-host {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: var(--f6-space-4);
}
/* Vide, il ne doit rien intercepter : sans cela, un emplacement transparent posé sur tout
 * l'écran avalerait chaque clic du parcours. */
.f6-camera-ask-host:empty { display: none; }
/* **Plein non plus, sauf sur le panneau.** La fenêtre n'offre plus qu'un refus ; ce qui
 * accepte est le bouton caméra du pied, *sous* le voile. Sans cette ligne il serait visible
 * et inerte — le pire des deux : on montre une commande qui ne répond pas. Le panneau, lui,
 * reprend les clics pour son propre bouton. */
.f6-camera-ask-host { pointer-events: none; }
.f6-camera-ask { pointer-events: auto; }
.f6-camera-ask-host::before {
  content: '';
  position: fixed;
  inset: 0;
  background: rgba(20, 30, 40, .55);
}
.f6-camera-ask {
  position: relative;
  width: min(28rem, 100%);
  padding: var(--f6-space-4);
  background: var(--f6-color-surface);
  border-radius: var(--f6-radius-default);
  box-shadow: 0 12px 32px rgba(20, 30, 40, .35);
}
/* --- Le bouton caméra pendant la demande --------------------------------
 *
 * **Il passe au-dessus du voile, et il bat.** C'est lui qui accepte désormais : la fenêtre
 * explique et offre le refus, l'icône du pied ouvre l'objectif. L'assuré apprend ainsi le
 * geste qu'il **réutilisera** pour couper la caméra — le même bouton, comme le dit le
 * message. L'ancien « Activer la caméra » enseignait un geste qui ne resservait jamais.
 *
 * `z-index: 61` contre les 60 de la fenêtre, et `position: relative` pour que ce nombre
 * compte. La barre d'action est en `position: sticky` sans `z-index` propre : elle ne crée
 * donc pas de contexte d'empilement, et l'élévation porte jusqu'au sommet. C'est vérifié,
 * pas supposé — un `transform` ou une `opacity` sur un parent l'aurait enfermée.
 *
 * Le voile s'arrête à 55 % d'opacité : le bouton reste donc parfaitement lisible au-dessus,
 * et le reste de l'écran assombri désigne, par contraste, le seul endroit où appuyer. */
f6-chatbot[data-camera-ask] .f6-camera-controls {
  position: relative;
  /* **Le maximum entier, et c'est délibéré.** Le plus haut niveau du parcours est 61 ;
     n'importe quelle valeur au-dessus suffirait aujourd'hui. Mais ce bouton est le seul
     point cliquable d'un écran voilé : s'il passe dessous, l'assuré est bloqué sans
     comprendre pourquoi. Un thème, une extension ou un panneau ajouté demain ne doivent
     pas pouvoir le recouvrir par inadvertance — d'où le plafond, plutôt qu'un nombre
     qu'il faudrait penser à relever. */
  z-index: 2147483647;
}
/* **Il se peint aux couleurs du thème pendant qu'on l'attend.** À l'arrêt, le bouton est un
 * disque gris (`--f6-color-surface-muted`) : posé sur un écran assombri, il se lisait comme
 * une commande désactivée — l'inverse de ce qu'on demande. Il prend donc la couleur de
 * marque, celle qu'il aura une fois la caméra ouverte, et le pictogramme reste en blanc.
 *
 * C'est le même dessin que l'icône glissée dans la phrase : l'assuré cherche cette forme,
 * et il la trouve — en couleur, seule éclairée sur l'écran.
 *
 * **Le `:not([hidden])` n'est pas là pour l'état caché**, il est là pour la spécificité. Le
 * thème peint ce bouton avec `.f6-camera-toggle:not([hidden])`, soit (0,3,0) une fois
 * enveloppé dans `[data-theme="…"]`. Sans ce même `:not`, cette règle vaut (0,2,1) et perd :
 * le bouton restait gris sous le voile, c'est-à-dire exactement l'air d'une commande
 * désactivée. Mesuré, pas supposé — `rgb(204,204,204)` au lieu du teal de marque. */
f6-chatbot[data-camera-ask] .f6-camera-toggle:not([hidden]) {
  background: var(--f6-color-primary);
  color: var(--f6-color-on-primary);
}
f6-chatbot[data-camera-ask] .f6-camera-controls::before,
f6-chatbot[data-camera-ask] .f6-camera-controls::after,
f6-chatbot[data-camera-wanted] .f6-camera-controls::before,
f6-chatbot[data-camera-wanted] .f6-camera-controls::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 41px;
  height: 41px;
  border-radius: 50%;
  border: 2px solid var(--f6-color-primary);
  pointer-events: none;
  animation: f6-camera-onde 2s ease-out infinite;
}
/* Deux anneaux décalés d'une demi-période : un seul laisse un temps mort où le bouton
   redevient un bouton parmi d'autres. */
f6-chatbot[data-camera-ask] .f6-camera-controls::after,
f6-chatbot[data-camera-wanted] .f6-camera-controls::after { animation-delay: 1s; }

/* **L'onde survit à la fenêtre, l'élévation non.**
 *
 * Fenêtre fermée, la caméra reste souvent attendue — l'assuré a refusé, ou n'a pas encore
 * répondu et la prise de vue arrive quand même. Le battement continue alors de dire qu'il
 * peut ouvrir l'objectif à tout moment, sans qu'on lui repose la question.
 *
 * Mais **il ne monte plus au-dessus de tout** : plus de voile à franchir, et un bouton au
 * plafond de la pile recouvrirait ce qui vient ensuite. Il reprend sa place ordinaire ; ce
 * qui le signale est l'onde, pas la hauteur. */
f6-chatbot[data-camera-wanted] .f6-camera-controls { position: relative; }

/* **Une onde discrète, pas un phare.**
 *
 * Réglée en deux temps, et les deux essais comptent. `scale(2)` d'abord : sur un bouton de
 * 41 px, l'anneau doublait et balayait la moitié de la barre — le regard y revenait sans
 * cesse, y compris quand l'assuré lisait autre chose. `1.35` ensuite, et l'on ne la voyait
 * plus : un halo qui ne dépasse pas le bouton ne signale rien.
 *
 * `1.6` est le point d'équilibre — l'anneau s'écarte assez pour attirer l'œil sans sortir de
 * l'entourage du bouton. Une sollicitation se règle à l'œil, pas au raisonnement. */
@keyframes f6-camera-onde {
  0%   { transform: scale(1);   opacity: .7; }
  100% { transform: scale(1.6); opacity: 0; }
}

/* **Aucun mouvement pour qui n'en veut pas.** Le bouton reste élevé et lisible : on retire
 * l'onde, jamais la possibilité d'appuyer. */
@media (prefers-reduced-motion: reduce) {
  f6-chatbot[data-camera-ask] .f6-camera-controls::before,
  f6-chatbot[data-camera-ask] .f6-camera-controls::after,
  f6-chatbot[data-camera-wanted] .f6-camera-controls::before,
  f6-chatbot[data-camera-wanted] .f6-camera-controls::after { animation: none; opacity: 0; }
}

/* **L'icône dans la phrase, et c'est le même tracé que le bouton.**
 *
 * « Activez-la avec l'icône ci-dessous » demandait à l'assuré de faire le rapprochement
 * tout seul, entre quatre commandes. En posant le pictogramme *dans* le texte, il n'y a
 * plus rien à deviner : il cherche cette forme-là, et il la trouve en bas.
 *
 * `currentColor` : elle prend la couleur du texte qui l'entoure, donc celle du thème, et
 * se lit comme un mot de la phrase — pas comme une vignette collée dedans.
 * `vertical-align` la pose sur la ligne de base. */
.f6-camera-ask__icone {
  display: inline-block;
  width: 1.15em;
  height: 1.15em;
  vertical-align: -.22em;
  margin: 0 .1em;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20d='M12.1055%208.83333H9.35554M15.8753%2014.3867L20.5252%2016.6771C21.0072%2016.9705%2021.513%2016.7976%2021.5%2016.1856L21.4674%208.09104C21.4263%207.42667%2021.0342%207.24539%2020.4569%207.55242L15.8622%209.64057M5.25003%2018.5H13.6055C14.8482%2018.5%2015.8555%2017.5051%2015.8555%2016.2778L15.8753%2013.4275L15.8555%207.72222C15.8555%206.49492%2014.8482%205.5%2013.6055%205.5H5.25003C4.00739%205.5%203.00003%206.49492%203.00003%207.72222V16.2778C3.00003%2017.5051%204.00739%2018.5%205.25003%2018.5Z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20d='M12.1055%208.83333H9.35554M15.8753%2014.3867L20.5252%2016.6771C21.0072%2016.9705%2021.513%2016.7976%2021.5%2016.1856L21.4674%208.09104C21.4263%207.42667%2021.0342%207.24539%2020.4569%207.55242L15.8622%209.64057M5.25003%2018.5H13.6055C14.8482%2018.5%2015.8555%2017.5051%2015.8555%2016.2778L15.8753%2013.4275L15.8555%207.72222C15.8555%206.49492%2014.8482%205.5%2013.6055%205.5H5.25003C4.00739%205.5%203.00003%206.49492%203.00003%207.72222V16.2778C3.00003%2017.5051%204.00739%2018.5%205.25003%2018.5Z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.f6-camera-ask__message {
  margin: 0 0 var(--f6-space-4);
  font-size: var(--f6-font-size-body);
  line-height: 1.4;
}
.f6-camera-ask__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--f6-space-2);
  justify-content: flex-end;
}
/* **Les deux réponses portent leur style ici, et pas celui des boutons du parcours.** En
 * conversation, le thème fait de `f6-button--ghost` un cercle de 41 px sans libellé — la
 * flèche « Précédent », dont l'icône est universelle. Appliquée ici, elle donnait un rond
 * muet en face d'« Activer la caméra » : un choix qui n'en est pas un. Une question qui
 * attend une réponse doit montrer ses deux réponses, quel que soit le thème. */
.f6-camera-ask__refuse,
.f6-camera-ask__accept {
  flex: 0 1 auto;
  min-height: 44px;
  padding: var(--f6-space-2) var(--f6-space-4);
  border-radius: var(--f6-radius-pill, 999px);
  font: inherit;
  font-size: var(--f6-font-size-body);
  cursor: pointer;
}
.f6-camera-ask__refuse {
  background: transparent;
  border: 2px solid var(--f6-color-border);
  color: var(--f6-color-text-muted, var(--f6-color-text));
}
.f6-camera-ask__accept {
  background: var(--f6-color-primary);
  border: 2px solid var(--f6-color-primary);
  color: var(--f6-color-on-primary);
}

/* --- La bande de prise de vue --------------------------------------------
 *
 * Une ligne au-dessus de la barre d'action, et **rien que la photo** : ce qui est déjà pris
 * à gauche, le déclencheur au centre, l'import à droite. Le déclencheur vivait dans la barre
 * d'action, où il partageait 375 px avec le retour, le mode vocal, la caméra et
 * « Valider » — cinq commandes sur une ligne, dont un disque de 56 px qui écrasait les
 * autres (recette du 28/08, point 1).
 *
 * **Vide, elle n'occupe aucune place** : hors prise de vue, la barre d'action remonte au ras
 * du fil comme avant. C'est la même règle que la surcouche modale, et pour la même raison —
 * une zone réservée « au cas où » mange une ligne sur un téléphone, en permanence, pour un
 * contenu qui n'arrive qu'une fois sur dix écrans.
 * ------------------------------------------------------------------------ */
.f6-photo-bar { flex: 0 0 auto; }
.f6-photo-bar:empty,
.f6-photo-bar__zone[hidden] { display: none; }
.f6-photo-bar__zone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--f6-space-1);
  padding: var(--f6-space-2) 12px 0;
}
/* Trois colonnes, et le déclencheur **au milieu de l'écran** : les deux colonnes de bord
   sont égales, si bien que l'import à droite ne le décale pas — c'est la place qu'il occupe
   sur tous les appareils photo, et le pouce l'y cherche sans regarder. La colonne de gauche
   reste vide : elle n'est là que pour équilibrer celle de l'import. */
.f6-photo-bar__gestes {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  width: 100%;
  gap: var(--f6-space-2);
}
.f6-photo-bar__gestes .f6-shutter { grid-area: 1 / 2; }
/* **Le halo du déclencheur** — l'« effet de focus » demandé à la recette. Il ne mesure rien :
   il dit qu'on attend une photo *ici*, et il s'arrête dès qu'elle est prise (le déclencheur
   se cache alors, et le halo avec lui). Deux anneaux décalés, comme celui du micro : un seul
   bat, deux respirent. */
.f6-shutter { position: relative; }
.f6-shutter::before,
.f6-shutter::after {
  content: '';
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  border: 2px solid var(--f6-color-primary);
  opacity: 0;
  pointer-events: none;
  animation: f6-shutter-focus 2.4s cubic-bezier(.22, .61, .36, 1) infinite;
}
.f6-shutter::after { animation-delay: 1.2s; }
.f6-shutter[data-busy="true"]::before,
.f6-shutter[data-busy="true"]::after { animation: none; opacity: 0; }
@keyframes f6-shutter-focus {
  0%   { transform: scale(.92); opacity: .7; }
  70%  { opacity: 0; }
  100% { transform: scale(1.45); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .f6-shutter::before, .f6-shutter::after { animation: none; opacity: .35; transform: none; }
}
/* L'import : un disque de 41 px, de la famille de la barre du bas — même hauteur, même
   rayon, même gris au repos. Le libellé reste dans le bouton, lu par les lecteurs d'écran :
   « Importer » ne tient pas à côté du déclencheur sans repousser celui-ci hors du centre. */
.f6-photo-bar__import {
  grid-area: 1 / 3;
  justify-self: end;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 41px;
  height: 41px;
  border-radius: 50%;
  background: var(--f6-color-surface-muted);
  color: var(--f6-color-on-primary, #fff);
  cursor: pointer;
}
.f6-photo-bar__import:focus-within {
  outline: 2px solid var(--f6-color-primary);
  outline-offset: 2px;
}
.f6-photo-bar__import-icone { width: 22px; height: 22px; }
.f6-photo-bar__import span {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
.f6-photo-bar__import input { position: absolute; width: 1px; height: 1px; opacity: 0; }

/* --- La photo en grand, et ce qu'on en fait -------------------------------
 *
 * L'assuré déclenchait, et rien ne lui montrait ce qui venait d'être versé : il poursuivait
 * l'entretien sans savoir si la photo était nette, cadrée, ou même la bonne pièce. La
 * vignette posée contre l'intitulé de sa vue le lui dit d'un coup d'œil ; celle-ci la lui
 * montre en grand et lui rend la main — reprendre, importer autre chose, ou supprimer.
 *
 * **Pas d'hôte à elle** : elle se pose dans la surcouche partagée
 * (`.f6-permissions-host`, plus haut), celle du guide des autorisations et de l'activation
 * vocale — un seul mécanisme de modale, un seul fond, un seul empilement. Elle en a eu un,
 * du temps où l'extension caméra la montait ; deux surcouches finissent toujours par
 * diverger sur le fond, le centrage ou l'ordre d'empilement.
 * ------------------------------------------------------------------------ */
.f6-photo-vue {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--f6-space-3, 12px);
  width: min(30rem, 100%);
  max-height: 100%;
  padding: var(--f6-space-4);
  background: var(--f6-color-surface);
  border-radius: var(--f6-radius-default);
  box-shadow: 0 12px 32px rgba(20, 30, 40, .35);
  overflow-y: auto;
}
.f6-photo-vue__titre {
  margin: 0;
  font-weight: 600;
  color: var(--f6-color-primary);
}
.f6-photo-vue__image {
  display: block;
  max-width: 100%;
  /* Assez grande pour juger la netteté, assez basse pour que les gestes restent visibles
     sans défiler : c'est là que se décide « je la garde ou je la refais ». */
  max-height: 52vh;
  border-radius: var(--f6-radius-default);
  object-fit: contain;
}
.f6-photo-vue__sans-image {
  margin: 0;
  font-size: var(--f6-font-size-small);
  color: var(--f6-color-text-muted);
  text-align: center;
}
.f6-photo-vue__gestes {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--f6-space-2);
  width: 100%;
}
.f6-photo-vue__geste {
  flex: 1 1 auto;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--f6-space-2) var(--f6-space-4);
  border: 2px solid var(--f6-color-primary);
  border-radius: var(--f6-radius-pill, 999px);
  background: transparent;
  color: var(--f6-color-primary);
  font: inherit;
  cursor: pointer;
}
.f6-photo-vue__geste input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.f6-photo-vue__geste--retirer {
  border-color: var(--f6-color-error, #c0392b);
  color: var(--f6-color-error, #c0392b);
}
.f6-photo-vue__fermer {
  padding: var(--f6-space-2);
  border: 0;
  background: none;
  color: var(--f6-color-text-muted);
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}

/* --- Le déclencheur ------------------------------------------------------
 *
 * Un disque blanc cerné de noir puis de blanc, **et un appareil photo dessiné dedans**.
 *
 * La double bordure n'est pas décorative : elle est ce qui rend le bouton visible **sur
 * n'importe quelle scène** — le trait noir le détache d'un mur clair, l'anneau blanc d'une
 * pièce sombre. Elle reste.
 *
 * Le disque **nu**, lui, n'a pas tenu la revue : « on ne comprend pas bien son rôle »
 * (Olivier, 28/08). Le raisonnement d'origine — c'est le dessin qu'ont tous les appareils
 * photo, donc il se reconnaît sans mot — vaut dans une application *photo*, où tout l'écran
 * annonce qu'on photographie. Ici il est posé au milieu d'un parcours de déclaration, sous
 * une conversation, à côté d'un bouton de caméra et d'un « Valider » : le contexte ne fait
 * plus la moitié du travail, et un cercle blanc redevient un cercle blanc. L'icône de la
 * bibliothèque (`assets_figma/icons/icon-camera-24.svg`) le dit en un coup d'œil.
 *
 * 56 px de diamètre : au-dessous des 44 px de la cible tactile recommandée, on le manque
 * en tenant l'appareil d'une main. */
.f6-shutter {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  padding: 0;
  border-radius: 50%;
  background: #fff;
  border: 3px solid #000;
  box-shadow: 0 0 0 3px #fff, 0 2px 8px rgba(0, 0, 0, .35);
  cursor: pointer;
  transition: transform .08s ease-out;
}
/* En masque, comme le calendrier du champ de date : la couleur vient du thème, jamais d'un
   `fill` figé dans le tracé — la même règle sert une autre marque sans y toucher. */
.f6-shutter__icone {
  display: block;
  width: 26px;
  height: 26px;
  background: var(--f6-color-primary);
  -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20fill='black'%20d='M7.2%206.12V7.12C7.55567%207.12%207.88457%206.93109%208.06378%206.62387L7.2%206.12ZM8.88%203.24V2.24C8.52433%202.24%208.19543%202.42891%208.01622%202.73613L8.88%203.24ZM15.12%203.24L15.9838%202.73613C15.8046%202.42891%2015.4757%202.24%2015.12%202.24V3.24ZM16.8%206.12L15.9362%206.62387C16.1154%206.93109%2016.4443%207.12%2016.8%207.12V6.12ZM2.4%2018.36H3.4V8.52H2.4H1.4V18.36H2.4ZM4.8%206.12V7.12H7.2V6.12V5.12H4.8V6.12ZM7.2%206.12L8.06378%206.62387L9.74378%203.74387L8.88%203.24L8.01622%202.73613L6.33622%205.61613L7.2%206.12ZM8.88%203.24V4.24H15.12V3.24V2.24H8.88V3.24ZM15.12%203.24L14.2562%203.74387L15.9362%206.62387L16.8%206.12L17.6638%205.61613L15.9838%202.73613L15.12%203.24ZM16.8%206.12V7.12H19.2V6.12V5.12H16.8V6.12ZM21.6%208.52H20.6V18.36H21.6H22.6V8.52H21.6ZM21.6%2018.36H20.6C20.6%2019.1332%2019.9732%2019.76%2019.2%2019.76V20.76V21.76C21.0778%2021.76%2022.6%2020.2378%2022.6%2018.36H21.6ZM19.2%206.12V7.12C19.9732%207.12%2020.6%207.7468%2020.6%208.52H21.6H22.6C22.6%206.64223%2021.0778%205.12%2019.2%205.12V6.12ZM2.4%208.52H3.4C3.4%207.7468%204.0268%207.12%204.8%207.12V6.12V5.12C2.92223%205.12%201.4%206.64223%201.4%208.52H2.4ZM4.8%2020.76V19.76C4.0268%2019.76%203.4%2019.1332%203.4%2018.36H2.4H1.4C1.4%2020.2378%202.92223%2021.76%204.8%2021.76V20.76ZM15.6%2012.84H14.6C14.6%2014.2759%2013.4359%2015.44%2012%2015.44V16.44V17.44C14.5405%2017.44%2016.6%2015.3805%2016.6%2012.84H15.6ZM12%2016.44V15.44C10.5641%2015.44%209.4%2014.2759%209.4%2012.84H8.4H7.4C7.4%2015.3805%209.45949%2017.44%2012%2017.44V16.44ZM8.4%2012.84H9.4C9.4%2011.4041%2010.5641%2010.24%2012%2010.24V9.24V8.24C9.45949%208.24%207.4%2010.2995%207.4%2012.84H8.4ZM12%209.24V10.24C13.4359%2010.24%2014.6%2011.4041%2014.6%2012.84H15.6H16.6C16.6%2010.2995%2014.5405%208.24%2012%208.24V9.24ZM19.2%2020.76V19.76H4.8V20.76V21.76H19.2V20.76Z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20fill='black'%20d='M7.2%206.12V7.12C7.55567%207.12%207.88457%206.93109%208.06378%206.62387L7.2%206.12ZM8.88%203.24V2.24C8.52433%202.24%208.19543%202.42891%208.01622%202.73613L8.88%203.24ZM15.12%203.24L15.9838%202.73613C15.8046%202.42891%2015.4757%202.24%2015.12%202.24V3.24ZM16.8%206.12L15.9362%206.62387C16.1154%206.93109%2016.4443%207.12%2016.8%207.12V6.12ZM2.4%2018.36H3.4V8.52H2.4H1.4V18.36H2.4ZM4.8%206.12V7.12H7.2V6.12V5.12H4.8V6.12ZM7.2%206.12L8.06378%206.62387L9.74378%203.74387L8.88%203.24L8.01622%202.73613L6.33622%205.61613L7.2%206.12ZM8.88%203.24V4.24H15.12V3.24V2.24H8.88V3.24ZM15.12%203.24L14.2562%203.74387L15.9362%206.62387L16.8%206.12L17.6638%205.61613L15.9838%202.73613L15.12%203.24ZM16.8%206.12V7.12H19.2V6.12V5.12H16.8V6.12ZM21.6%208.52H20.6V18.36H21.6H22.6V8.52H21.6ZM21.6%2018.36H20.6C20.6%2019.1332%2019.9732%2019.76%2019.2%2019.76V20.76V21.76C21.0778%2021.76%2022.6%2020.2378%2022.6%2018.36H21.6ZM19.2%206.12V7.12C19.9732%207.12%2020.6%207.7468%2020.6%208.52H21.6H22.6C22.6%206.64223%2021.0778%205.12%2019.2%205.12V6.12ZM2.4%208.52H3.4C3.4%207.7468%204.0268%207.12%204.8%207.12V6.12V5.12C2.92223%205.12%201.4%206.64223%201.4%208.52H2.4ZM4.8%2020.76V19.76C4.0268%2019.76%203.4%2019.1332%203.4%2018.36H2.4H1.4C1.4%2020.2378%202.92223%2021.76%204.8%2021.76V20.76ZM15.6%2012.84H14.6C14.6%2014.2759%2013.4359%2015.44%2012%2015.44V16.44V17.44C14.5405%2017.44%2016.6%2015.3805%2016.6%2012.84H15.6ZM12%2016.44V15.44C10.5641%2015.44%209.4%2014.2759%209.4%2012.84H8.4H7.4C7.4%2015.3805%209.45949%2017.44%2012%2017.44V16.44ZM8.4%2012.84H9.4C9.4%2011.4041%2010.5641%2010.24%2012%2010.24V9.24V8.24C9.45949%208.24%207.4%2010.2995%207.4%2012.84H8.4ZM12%209.24V10.24C13.4359%2010.24%2014.6%2011.4041%2014.6%2012.84H15.6H16.6C16.6%2010.2995%2014.5405%208.24%2012%208.24V9.24ZM19.2%2020.76V19.76H4.8V20.76V21.76H19.2V20.76Z'/%3E%3C/svg%3E") center / contain no-repeat;
  pointer-events: none;
}
/* Pendant le versement, l'icône s'efface avec le reste : le disque creusé dit « en cours ». */
.f6-shutter[data-busy=true] .f6-shutter__icone { opacity: .5; }
.f6-shutter:active { transform: scale(.92); }
/* Pendant le versement : le disque se creuse, ce qui dit « en cours » sans mot ni glyphe.
 * Le bouton est déjà `disabled`, donc le geste ne se répète pas — c'est l'attente qu'on
 * montre, pas une interdiction. */
.f6-shutter[data-busy=true] { background: var(--f6-color-surface-sunken); opacity: .7; }
.f6-shutter:disabled { cursor: progress; }
.f6-shutter[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
  .f6-shutter { transition: none; }
  .f6-shutter:active { transform: none; }
}

/* --- Prise de vue guidée -------------------------------------------------
 *
 * Une vignette par vue attendue, et non un champ de fichiers. « Depuis le coin opposé » se
 * lit deux fois avant d'être compris ; un plan de pièce avec son angle marqué se voit. Un
 * assuré qui photographie mal ne recommence pas — il envoie ce qu'il a envoyé. */

.f6-photo__prises {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--f6-space-2);
}

.f6-prise {
  /* **Deux colonnes, deux rangées**, et non trois colonnes. Sur 390 px, une troisième
   * colonne qui porte « Photographier » en `nowrap` ne peut pas rétrécir : elle
   * chevauchait le cadrage de la vignette, qui passait derrière un bouton sans fond. Le
   * geste descend donc sous le texte, aligné à droite, et l'illustration garde sa colonne. */
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "visuel mots" "visuel geste";
  align-items: center;
  gap: var(--f6-space-2) var(--f6-space-4);
  padding: var(--f6-space-4);
  border: 1px solid var(--f6-color-border);
  border-radius: var(--f6-radius-default);
}
.f6-prise__visuel { grid-area: visuel; }
.f6-prise__mots { grid-area: mots; }
.f6-prise__geste { grid-area: geste; }

/* Une vue déjà prise se marque, elle ne s'estompe pas : c'est celle qu'on peut vouloir
 * reprendre, et un contenu grisé se lit « indisponible ». */
.f6-prise--posee { border-color: var(--f6-color-primary); }

.f6-prise__visuel {
  display: grid;
  place-items: center;
  width: 56px; height: 56px;
  color: var(--f6-color-primary);
  background: var(--f6-color-surface-sunken);
  border-radius: var(--f6-radius-default);
}
.f6-prise__art { width: 36px; height: 36px; }

.f6-prise__mots { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.f6-prise__lib { font-weight: 600; }
.f6-prise__aide { font-size: var(--f6-font-size-small); color: var(--f6-color-text-muted); }
.f6-prise__fait {
  font-size: var(--f6-font-size-small);
  color: var(--f6-color-primary);
  overflow-wrap: anywhere;
}

.f6-prise__geste {
  display: flex;
  flex-wrap: wrap;
  gap: var(--f6-space-2);
  align-items: center;
  justify-content: flex-end;
}

/* Le déclencheur est un `<label>` qui enveloppe l'entrée : c'est le seul montage qui ouvre
 * l'appareil photo **depuis le geste de l'utilisateur** sur mobile. Un bouton qui appelle
 * `input.click()` par programme est refusé par certains navigateurs, en silence. */
.f6-prise__bouton {
  display: inline-block;
  /* Un fond, et pas seulement une bordure : posé sur du transparent, il laissait lire le
     texte au travers dès qu'un chevauchement survenait — ce qui masque le défaut au lieu
     de le montrer. */
  background: var(--f6-color-surface, #fff);
  padding: var(--f6-space-1) var(--f6-space-4);
  border: 1px solid var(--f6-color-primary);
  border-radius: var(--f6-radius-pill);
  color: var(--f6-color-primary);
  font-size: var(--f6-font-size-small);
  font-weight: 600;
  cursor: pointer;
  text-align: center;
  white-space: nowrap;
}
.f6-prise__bouton input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.f6-prise__bouton:focus-within { outline: 2px solid var(--f6-color-primary); outline-offset: 2px; }

.f6-prise__retirer,
.f6-photo__passer {
  border: 0; background: none; padding: 0;
  color: var(--f6-color-text-muted);
  font: inherit; font-size: var(--f6-font-size-small);
  text-decoration: underline; cursor: pointer;
}
/* `--f6-space-3` n'existe pas (l'échelle est 1/2/4/6/8) : la valeur retombait sur 0 et
 * « Je passe » collait à la progression. Même piège que le `right: var(--f6-space-3)` du
 * guide — un jeton absent ne prévient pas, il s'efface. */
.f6-photo__passer { margin-top: var(--f6-space-4); }
.f6-photo__trouble { margin-top: var(--f6-space-2); color: var(--f6-color-error); }

/* Ce que la vue met en avant — le coin d'où viser, la trace à cadrer — respire doucement.
 * Le mouvement dit « regardez ici » sans qu'aucun texte ait à le dire, et il est en CSS
 * sur un SVG statique : `<animate>` obligerait à élargir la liste blanche des deux côtés
 * (`svg-allowlist.js` et `store/icons.py`) pour ce que trois lignes disent aussi bien. */
@keyframes f6-prise-hint {
  0%, 100% { opacity: .35; }
  50% { opacity: 1; }
}
.f6-prise__hint { animation: f6-prise-hint 2.4s ease-in-out infinite; }

@media (prefers-reduced-motion: reduce) {
  .f6-prise__hint { animation: none; opacity: .8; }
}

/* --- Le gabarit unifié : viser et suivre, sur l'écran filmé ---------------
 *
 * Maquette « SYSTÈME DE PRISE UNIFIÉ » (décision D4) : plein écran vidéo, une **carte
 * « Cadrage »** en haut à droite, une **jauge de pastilles** en bas, le déclencheur central,
 * « Je passe ». La vignette porte déjà, en formulaire, son illustration et son intitulé :
 * les répéter n'apprendrait rien, et un guide inline volerait la place des réponses. Le
 * **guide** et la **jauge** n'existent donc que pour le viseur — l'écran filmé où l'assuré
 * tient son téléphone à bout de bras. Par défaut ils ne s'affichent pas ; c'est
 * `f6-camera-active` qui les révèle, comme cette classe commande toute la disposition filmée.
 *
 * **La carte « Cadrage ».** Un voile sombre (comme les autres surimpressions de la caméra),
 * un titre, l'illustration de la vue courante dans un **cadre en pointillés** — « ce que voit
 * la photo » —, et l'intitulé dessous. Elle flotte **en haut à droite**, là où l'assuré la
 * voit sans quitter des yeux ce qu'il cadre, et **jamais au centre** (que
 * `test_le_centre_de_l_ecran_reste_libre` défend). Le cadre et l'illustration prennent la
 * teinte claire du primaire (`--f6-color-primary-on-dark`, P-1) — le primaire foncé d'une
 * marque y disparaîtrait —, le titre et l'intitulé un blanc neutre, lisible sur le voile.
 * `pointer-events: none` : un guide se regarde, il ne vole pas un clic à la scène. */
.f6-photo__guide,
.f6-photo__jauge { display: none; }

f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo__guide {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--f6-space-1);
  position: fixed;
  top: 22%;
  right: var(--f6-space-4);
  z-index: 3;
  width: 132px;
  padding: var(--f6-space-2);
  background: rgba(20, 30, 40, .66);
  border-radius: var(--f6-radius-default);
  backdrop-filter: blur(2px);
  text-align: center;
  pointer-events: none;
}
f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo__guide-titre {
  font-size: var(--f6-font-size-small);
  font-weight: 600;
  color: #fff;
  opacity: .82;
}
/* Le cadre en pointillés : le champ de la photo, tenu par la structure et non par l'icône,
 * pour se lire quel que soit le SVG de prise déposé au thème (qui n'est pas encore finalisé). */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo__guide-cadre {
  padding: var(--f6-space-2);
  border: 1.5px dashed var(--f6-color-primary-on-dark);
  border-radius: var(--f6-radius-default);
  color: var(--f6-color-primary-on-dark);
}
f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo__guide-svg { width: 44px; height: 44px; }
f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo__guide-lib {
  font-size: var(--f6-font-size-small);
  font-weight: 700;
  line-height: 1.2;
  color: #fff;
}

/* La jauge se pose **en bas**, sous les vignettes (masquées), contre la barre d'action :
 * une **pastille par vue**, cochée quand versée, la vue courante mise en avant (pastille
 * pleine, primaire). Les pastilles sont des voiles sombres — comme la carte —, le texte
 * blanc pour le « à prendre », la teinte claire du primaire pour le « pris ». Elles
 * s'enroulent (`flex-wrap`) : quatre coins tiennent sur deux lignes sans déborder. */
/* **Elle défile quand elle dépasse, et cela se voit.** Une prise de vue par pièce, avec sa
   vignette de 44 px : à cinq ou six, sur un écran de 390 px déjà occupé par la question et
   la bande de capture, la liste sortait de l'écran par le bas — muette. Une liste tronquée
   sans indice de défilement est une liste amputée : on ne cherche pas ce qu'on ne soupçonne
   pas. Le voile en dégradé au bas de la zone dit qu'il y a une suite. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo__jauge {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: var(--f6-space-2);
  margin: 0;
  padding: 0;
  list-style: none;
  max-height: 34vh;
  overflow-y: auto;
  /* Le doigt garde son élan dans la liste sans emporter la page derrière. */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  /* Le dernier rang s'estompe : c'est l'indice, et il ne coûte aucune hauteur — une barre
     de défilement, elle, ne se voit pas sur mobile tant qu'on n'a pas commencé à glisser. */
  mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent 100%);
}
f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo__pas {
  display: flex;
  align-items: center;
  gap: var(--f6-space-2);
  /* La photo touche presque le bord de la pastille — elle en est le sujet, pas un ornement
     posé à côté du texte. Le coin s'adoucit au lieu d'être une pilule : une pilule autour
     d'une image de 44 px lui taillerait les angles. */
  padding: 4px var(--f6-space-3, 12px) 4px 4px;
  border-radius: 10px;
  background: rgba(20, 30, 40, .72);
  color: #fff;
  font-size: var(--f6-font-size-small);
  font-weight: 600;
}
/* Sans photo, la pastille reste ce qu'elle était : une pilule de progression, qui n'a rien à
   montrer et n'a donc pas à prendre la place d'une vignette. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo__pas:not(:has(.f6-photo__pas-vue)) {
  padding: var(--f6-space-1) var(--f6-space-2);
  border-radius: var(--f6-radius-pill, 999px);
}
f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo__pas--faite {
  color: var(--f6-color-primary-on-dark);
}
f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo__pas--courante {
  background: var(--f6-color-primary);
  color: #fff;
}

/* **La photo, contre l'intitulé de sa vue.**
 *
 * La jauge disait seulement *laquelle* des vues était prise, par une coche : l'assuré savait
 * qu'il avait photographié « le premier angle », pas **ce qu'il avait photographié**. Il
 * poursuivait sans jamais revoir ses prises (recette du 28/08). La vignette est là, contre
 * le libellé qu'elle illustre, et elle ouvre la photo en grand.
 *
 * **44 px et rectangulaire**, et c'est une correction de la première version. Elle y était
 * ronde et de la taille d'une ligne de texte (26 px), pour se fondre dans la pastille : on ne
 * distinguait rien de la photo, seulement qu'il y en avait une (revue du 28/08, « les photos
 * ne sont pas suffisamment visibles »). Une vignette de pièce filmée n'a rien d'un avatar —
 * elle montre un cadrage, et un cadrage se lit dans un rectangle, à la taille d'une cible
 * tactile. Le liseré clair et l'ombre la détachent de la pastille sombre quelle que soit la
 * scène photographiée. */
.f6-photo__pas-vue {
  flex: 0 0 auto;
  display: block;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 2px solid var(--f6-color-primary-on-dark, #fff);
  border-radius: 6px;
  background: rgba(255, 255, 255, .15);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .45);
  color: inherit;
  font: inherit;
  cursor: pointer;
  overflow: hidden;
}
.f6-photo__pas-vue img { display: block; width: 100%; height: 100%; object-fit: cover; }
.f6-photo__pas-vue:focus-visible {
  outline: 2px solid var(--f6-color-primary-on-dark, #fff);
  outline-offset: 2px;
}
/* Hors caméra la jauge ne s'affiche pas (`.f6-photo__jauge { display: none }`) : les
   vignettes du composant portent alors la même information, avec leurs propres gestes. */

/* « Je passe » **sur le flux**. En formulaire c'est un lien discret, teinte sourde ; posé nu
 * sur la vidéo il y devenait illisible — sombre sur une scène claire — et se confondait avec
 * la progression juste au-dessus. Sur le flux il reprend donc la teinte claire et l'ombre
 * portée du guide et de la progression (le contraste revient à l'élément, pas à un voile), et
 * gagne une zone tactile franche : un bras tendu vise mal un lien souligné de 12 px. Il reste
 * **centré, sous la progression**, séparé d'elle — la sortie que défend « une cave sans réseau
 * est une réponse ». */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo__passer {
  display: inline-block;
  /* **Centré**, et c'est ce que la relecture du 30/08/2026 a demandé après avoir vu la
     première version : aligné à gauche, il pendait sous les pastilles de vues sans se
     rattacher à rien. Au centre, il se lit comme ce qu'il est — la seconde issue de
     l'écran, sous la première.

     Il ne se cogne pas à « Terminé — N » pour autant : celui-ci est sorti du flux
     (`position: absolute`, à droite, au-dessus de la barre), et un test de bout en bout
     mesure le non-recouvrement plutôt qu'un agencement — à 375 px les deux s'empilent, et
     figer une même ligne aurait cassé au premier libellé plus long. */
  margin: var(--f6-space-4) auto 0;
  align-self: center;
  /* **Une pastille, pas un lien.** Le texte était souligné, à la couleur de la marque, sur
     un flux vidéo : lisible sur un mur sombre, illisible sur un mur clair — la relecture du
     30/08/2026 l'a relevé sur deux captures d'un même parcours. L'ombre portée ne suffit
     pas, parce qu'elle dépend elle aussi de ce qu'on filme. Un fond opaque **à nous** rend
     le contraste indépendant de la scène, ce qui est la seule façon de le garantir.
     Il reste discret : le geste attendu est la photo, pas le passage. */
  padding: var(--f6-space-1) var(--f6-space-4);
  border-radius: 999px;
  background: rgba(20, 30, 40, .72);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .28);
  color: #fff;
  text-decoration: none;
  font-size: var(--f6-font-size-small);
}

/* La progression et « Je passe » se posent l'un sous l'autre, centrés : sans cet axe le
 * bloc s'alignait à gauche et les deux textes se chevauchaient au ras de la barre. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo {
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* **La bascule de rendu (3d).** En caméra, la liste de vignettes empilées cède la place :
 * le guide dit la vue courante, la progression ce qui est pris, et le déclencheur central
 * de la caméra (`.f6-shutter`) verse à la question — trois vignettes de plus recouvriraient
 * précisément la scène. « Je passe » demeure : une cave sans réseau reste une réponse
 * possible. La liste n'est pas retirée du DOM, seulement masquée — le retour au clavier la
 * rend intacte, comme le fil qui garde tout. */
f6-chatbot.f6-camera-active.f6-mode-chat .f6-photo__prises { display: none; }

/* --- Décrire au lieu de chercher ------------------------------------------
 *
 * Sur les listes longues, chercher son cas coûte plus que le décrire. Le champ vient
 * **sous** les tuiles et se dit — un champ nu, posé sans titre, est une fonction
 * introuvable, et le voisin l'a déjà payé sur sa recherche d'article. */

.f6-libre { margin-top: var(--f6-space-4); }
.f6-libre__label {
  display: block;
  margin-bottom: var(--f6-space-1);
  font-size: var(--f6-font-size-small);
  color: var(--f6-color-text-muted);
}
/* Le champ prend la place, le bouton « Proposer » reste à sa taille ; sur un écran étroit,
 * `flex-wrap` le laisse passer sous le champ plutôt que de l'écraser (placeholder rogné). */
.f6-libre__ligne { display: flex; gap: var(--f6-space-2); flex-wrap: wrap; }
.f6-libre__champ { flex: 1 1 10rem; min-width: 0; }
/* `--f6-space-3` n'existe pas (l'échelle est 1/2/4/6/8, § ligne ~1465) : ce bouton s'est
 * retrouvé sans le moindre remplissage horizontal, le texte « Proposer » débordant de son
 * propre contour. Repéré en testant sur mobile — même sweep que `.f6-prise`,
 * `.f6-prise__bouton`, `.f6-libre__proposition`, `.f6-libre__oui` et la carte de mode
 * (`themes/concerto-dde/theme.css`), qui portaient toutes le même jeton absent. */
.f6-libre__proposer {
  flex: 0 0 auto;
  padding: var(--f6-space-1) var(--f6-space-4);
  border: 1px solid var(--f6-color-border);
  border-radius: var(--f6-radius-pill);
  background: none; color: inherit; font: inherit; cursor: pointer;
}
.f6-libre__avis {
  margin-top: var(--f6-space-1);
  font-size: var(--f6-font-size-small);
  color: var(--f6-color-text-muted);
}

/* La proposition, et les deux seules suites possibles. Rien n'est répondu tant que
 * l'assuré n'a pas confirmé : une réponse déduite d'un texte n'est pas une réponse
 * déclarée. */
.f6-libre__proposition {
  margin-top: var(--f6-space-2);
  padding: var(--f6-space-4);
  border: 1px solid var(--f6-color-primary);
  border-radius: var(--f6-radius-default);
  display: flex; flex-wrap: wrap; gap: var(--f6-space-2); align-items: center;
}
.f6-libre__compris { flex: 1 1 100%; margin: 0; }
.f6-libre__oui {
  padding: var(--f6-space-1) var(--f6-space-4);
  border: 0; border-radius: var(--f6-radius-pill);
  background: var(--f6-color-primary); color: var(--f6-color-on-primary);
  font: inherit; font-weight: 600; cursor: pointer;
}
.f6-libre__non {
  border: 0; background: none; padding: 0;
  color: var(--f6-color-text-muted); font: inherit;
  text-decoration: underline; cursor: pointer;
}

/* --- « Je ne sais pas » ----------------------------------------------------
 *
 * Sur les questions qui n'ont pas d'options. **En formulaire**, un lien discret sous le
 * champ : c'est une sortie, pas un choix qu'on met sur le même plan que la réponse
 * attendue. Mais il se voit — sans lui, l'assuré n'a d'autre issue que d'inventer une
 * valeur pour avancer.
 *
 * **En conversation, c'est une pastille**, au-dessus de la barre de saisie, comme les
 * options d'une question à choix. Le lien souligné y était dans la barre, sous le champ,
 * et ne répondait pas : sur la question précédente, « Je ne sais pas » était une pastille
 * qu'on touche et qui enchaîne — deux gestes différents pour la même intention, à trois
 * questions d'intervalle (relecture du 01/09/2026). L'écart se lisait comme une panne.
 *
 * Le remontage se fait en `column-reverse` sur le composant, marqué par `.f6-nsp-hote` :
 * la classe est posée par le composant lui-même plutôt que devinée par `:has()`, dont
 * l'absence rendrait le bouton à sa place d'avant sans qu'aucune erreur ne le dise. */
.f6-nsp {
  display: inline-block;
  margin-top: var(--f6-space-1);
  border: 0; background: none; padding: 0;
  color: var(--f6-color-text-muted);
  font: inherit; font-size: var(--f6-font-size-small);
  text-decoration: underline; cursor: pointer;
}
.f6-nsp[aria-pressed="true"] {
  color: var(--f6-color-primary);
  font-weight: 600;
  text-decoration: none;
}
.f6-mode-chat .f6-chat__live .f6-nsp-hote {
  display: flex;
  flex-direction: column-reverse;
  gap: var(--f6-space-2);
}
.f6-mode-chat .f6-chat__live .f6-nsp {
  align-self: center;
  margin-top: 0;
  padding: var(--f6-space-2) var(--f6-space-4);
  border: 1px solid var(--f6-color-primary);
  border-radius: var(--f6-radius-pill);
  background: var(--f6-color-surface);
  color: var(--f6-color-text);
  font-size: inherit;
  text-decoration: none;
}
.f6-mode-chat .f6-chat__live .f6-nsp[aria-pressed="true"] {
  background: var(--f6-color-primary-subtle);
  font-weight: 600;
}
/* Décliné : le champ reste lisible mais cesse d'appeler une saisie. On ne le masque pas —
 * reprendre la main doit rester possible d'un clic dans le champ. */
.f6-nsp-decline .form-control,
.f6-nsp-decline input { opacity: .55; }

/* --------------------------------------------------------------------------
 * Le bouton de parole (assistant-live) — **dans la barre du bas, à côté de la caméra**.
 *
 * Sa place a bougé deux fois avant de se fixer. Il a d'abord partagé la ligne avec
 * « Précédent » et « Valider » — trois `flex: 1` à se répartir 375 px sur l'appareil de la
 * campagne QA, c'est-à-dire la commande la plus importante du parcours réduite au tiers
 * d'une ligne. Il a ensuite été essayé sous le portrait de Julia : plus lisible, mais
 * l'en-tête passait à ~190 px sur 667, et deux commandes de même nature — parler et filmer
 * — se retrouvaient aux deux bouts de l'écran. Il est à côté de la caméra : ce sont les
 * deux façons de montrer quelque chose à Julia, et elles se prennent du même pouce.
 *
 * **Le libellé est visible**, et c'est ce qui a changé en dernier. Il était dans le DOM mais
 * masqué à l'œil (`clip-path`), le bouton réduit à un disque de 41 px portant deux
 * pictogrammes de 15 px — un micro et un haut-parleur, collés. Personne ne lit deux dessins
 * de 15 px : le contrôle qui ouvre la conversation avec Julia était le seul de l'écran qu'il
 * fallait deviner. Une icône unique (une bulle de conversation) et « Parler avec Julia » en
 * toutes lettres remplacent les deux ; le bouton devient une pilule de **41 px de haut** —
 * la hauteur des disques qui l'encadrent, c'est elle qui tient l'équilibre de la barre, pas
 * l'égalité des largeurs.
 * ------------------------------------------------------------------------ */
/* `:not([hidden])` : un `display` d'auteur l'emporte sur le `[hidden]` du navigateur, et
 * le bouton est **caché hors entretien** (`button.hidden = …`). Sans cette garde, il
 * s'afficherait sur les écrans de formulaire — le piège déjà rencontré ailleurs dans cette
 * feuille (commandes de voix, boutons d'icône). */
.f6-assistant { display: none; }
.f6-assistant:not([hidden]) {
  /* Une grille de deux colonnes, et **le halo partage la cellule de l'icône** : c'est ce
     qui l'ancre au micro sans le positionner en absolu par rapport à un remplissage qu'un
     thème pourrait changer. */
  display: inline-grid;
  grid-template-columns: auto auto;
  align-items: center;
  gap: var(--f6-space-2, 8px);
  padding: 5px 14px 5px 11px;
  border: 1px solid var(--f6-color-primary);
  border-radius: var(--f6-radius-pill, 999px);
  background: var(--f6-color-surface);
  color: var(--f6-color-primary);
  font: inherit;
  font-size: var(--f6-font-size-small, 14px);
  line-height: 1.2;
  cursor: pointer;
  transition: background-color 180ms ease, color 180ms ease;
}
/* L'icône — **une seule**, et de la taille du halo qui l'entoure : les deux partagent la
   cellule `1 / 1`, si bien qu'un dessin plus étroit que l'anneau le décentrerait. */
.f6-assistant__icon {
  grid-area: 1 / 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
}
/* **Les deux dessins occupent la même case, et un seul se voit.** Les empiler plutôt que
   de les échanger en JavaScript garde le bouton stable : rien n'est reconstruit au moment
   où l'on bascule, donc rien ne clignote, et l'état tient dans un seul attribut. */
.f6-assistant__glyph {
  grid-area: 1 / 1;
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
}
.f6-assistant__glyph--voix { display: none; }
.f6-assistant[aria-pressed="true"] .f6-assistant__glyph--voix { display: block; }
.f6-assistant[aria-pressed="true"] .f6-assistant__glyph--muet { display: none; }

/* **Le libellé n'est plus à l'œil, et cette fois c'est voulu.**

   Il l'a été, du 28/08 au 29/08 : deux pictogrammes de 15 px collés ne se lisaient pas, et
   le mot les remplaçait. La maquette (`8217-82985`) tranche autrement — quatre pastilles
   rondes de même taille, aucun texte — et elle règle le défaut autrement : l'icône est un
   **haut-parleur**, qui dit « son » sans qu'on l'apprenne, là où une bulle de conversation
   disait seulement « on discute ».

   Il reste donc dans le DOM, pour les lecteurs d'écran et pour l'infobulle, mais il ne
   prend plus de place : c'est la largeur du libellé qui faisait déborder la barre, et
   « Revenir au te… » en était la trace. Ne pas le remettre à l'œil sans revenir sur la
   maquette. */
.f6-assistant__label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* **En entretien, le bouton se remplit.** Il cesse d'inviter — il rend compte : la liaison
   est ouverte, et ce qu'il propose désormais est d'en sortir. */
.f6-assistant[aria-pressed="true"]:not([hidden]) {
  background: var(--f6-color-primary-subtle, color-mix(in srgb, var(--f6-color-primary) 12%, transparent));
}
/* Une reconnexion n'est ni l'un ni l'autre : on ne promet pas une liaison qu'on est en
   train de rattraper. */
.f6-assistant[data-retrying]:not([hidden]) { opacity: .65; }

/* Le halo — **la vague autour du micro**.
 *
 * Deux anneaux qui s'échappent du pictogramme et s'effacent. Il ne mesure rien : sa seule
 * information est « le micro est ouvert », et c'est tout ce qu'un bouton a à dire. La
 * mesure, elle, est remontée sur l'aura de Julia — là où l'on regarde quand on parle.
 *
 * Les quatre barres qu'il remplace *mesuraient*, et c'était le défaut : le seul endroit de
 * l'écran où le niveau audio se lisait était en bas, à côté d'un libellé, pendant que le
 * visage tournait à vide. */
.f6-assistant__halo {
  grid-area: 1 / 1;
  position: relative;
  width: 20px;
  height: 20px;
  pointer-events: none;
}
.f6-assistant__halo i {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid currentColor;
  opacity: 0;
}
/* **Les deux voix**, et non plus le seul micro : l'onde bat quand Julia parle comme
   quand l'assuré parle (demande du 29/08). `data-voix` porte laquelle des deux ; il
   double `data-listening` plutôt que de l'élargir, parce que l'aura du portrait s'appuie
   sur ce dernier pour **ne pas** s'animer quand c'est l'assuré qui a la parole. */
.f6-assistant[data-listening] .f6-assistant__halo i,
.f6-assistant[data-voix] .f6-assistant__halo i {
  animation: f6-assistant-halo 1.8s cubic-bezier(.22, .61, .36, 1) infinite;
}
/* Le second part à mi-course : un seul anneau bat, deux respirent. */
.f6-assistant[data-listening] .f6-assistant__halo i:nth-child(2),
.f6-assistant[data-voix] .f6-assistant__halo i:nth-child(2) { animation-delay: .9s; }
/* L'anneau va **plus loin quand la voix porte plus**. C'est la seule mesure que garde le
   bouton, et elle est délibérément grossière : on ne lit pas un niveau sonore sur un halo
   de 20 px, on voit seulement qu'on est entendu — ce qui est exactement ce qu'un micro
   doit rendre. L'amplitude fine, elle, est sur l'aura de Julia. */
@keyframes f6-assistant-halo {
  0%   { transform: scale(.85); opacity: .55; }
  80%  { opacity: 0; }
  100% { transform: scale(calc(1.7 + var(--f6-level, 0) * .6)); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .f6-assistant[data-listening] .f6-assistant__halo i,
  .f6-assistant[data-voix] .f6-assistant__halo i { animation: none; opacity: .4; }
}

/* Qui parle porte le libellé. « Julia parle » n'existe pas comme état du bouton
   aujourd'hui (voir index.js) : l'onde et le libellé se contentent de dire « Revenir au
   texte » pendant tout l'appel, micro **et** voix de Julia confondus — une conversation
   est un tour à la fois, jamais les deux en même temps, donc la même onde suffit aux
   deux : elle suit le niveau de celui qui parle, quel qu'il soit. */

/* --- Aide (extension « assistance ») ------------------------------------
 *
 * Le déclencheur est `.f6-brand-header__help` (voir plus haut, et `chatbot.js
 * #renderBrandHeader`) — rien à styler ici pour un bouton, cette extension n'en monte
 * aucun elle-même.
 *
 * La popup/le chat, eux, empruntent le même scrim plein écran que le guide
 * d'autorisations (`.f6-permissions-host`) : ils couvrent l'écran le temps qu'on les lit,
 * et rien d'utile ne se fait derrière. */

.f6-assistance-popup,
.f6-assistance-chat {
  position: fixed; inset: 0; z-index: 40;
  display: flex; align-items: center; justify-content: center;
  padding: var(--f6-space-4);
  background: rgba(40, 60, 80, .45);
}

.f6-assistance-popup__card,
.f6-assistance-chat__card {
  width: 100%; max-width: var(--f6-layout-max-width);
  max-height: 80vh;
  display: flex; flex-direction: column;
  background: var(--f6-color-surface);
  border: 1px solid var(--f6-color-border);
  border-radius: var(--f6-radius-default);
  box-shadow: 0 8px 32px rgba(40, 60, 80, .25);
  overflow: hidden;
}

.f6-assistance-close {
  align-self: flex-end;
  border: 0; background: none; font-size: 1.5rem; line-height: 1; cursor: pointer;
  color: var(--f6-color-text-muted); padding: var(--f6-space-2) var(--f6-space-4);
}

.f6-assistance-popup__body {
  padding: 0 var(--f6-space-4) var(--f6-space-4);
  overflow-y: auto;
}

.f6-assistance-chat__header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 var(--f6-space-2) 0 var(--f6-space-4);
  border-bottom: 1px solid var(--f6-color-border);
  font-family: var(--f6-font-title);
  color: var(--f6-color-primary-strong);
}

.f6-assistance-chat__messages {
  flex: 1; min-height: 12rem; overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--f6-space-2);
  padding: var(--f6-space-4);
}

.f6-assistance-chat__msg {
  max-width: 80%;
  padding: var(--f6-space-2) var(--f6-space-4);
  border-radius: var(--f6-radius-default);
}
.f6-assistance-chat__msg--user {
  align-self: flex-end;
  background: var(--f6-color-primary);
  color: var(--f6-color-on-primary);
}
.f6-assistance-chat__msg--assistant {
  align-self: flex-start;
  background: var(--f6-color-primary-subtle);
}

.f6-assistance-chat__footer {
  display: flex; gap: var(--f6-space-2);
  padding: var(--f6-space-4);
  border-top: 1px solid var(--f6-color-border);
}
.f6-assistance-chat__footer input {
  flex: 1; min-height: 44px; padding: 0 var(--f6-space-4);
  border: 1px solid var(--f6-color-border); border-radius: var(--f6-radius-default);
  font: inherit;
}
/* `.f6-button` vient avec `flex: 1` — le bon défaut en bas de formulaire, où « Valider »
 * et « Je passe » se partagent la largeur, pas ici où le champ doit grandir seul et
 * « Envoyer » rester à sa taille de texte. */
.f6-assistance-chat__footer .f6-button { flex: 0 0 auto; }

/* --- Enquête de satisfaction ---------------------------------------------
 *
 * Une popup posée sur le parcours grisé (maquettes `6521:50244` et `6029:45073`) : titre en
 * couleur de marque, des questions notées sur une échelle étiquetée, un commentaire
 * facultatif, un bouton pleine largeur.
 *
 * **Aucune couleur en dur, pas une seule** — que des jetons. C'est ce qui fait qu'un
 * changement de marque emporte la popup avec lui, et c'est la demande, littéralement : le
 * contre-exemple est en V1, où `satisfactionSurvey` écrivait ses couleurs en `.css()`
 * inline et `numberChips` offrait trois sélecteurs de couleur en admin — une couleur figée
 * dans le parcours, qui survit au changement de thème.
 *
 * Ce qui est ici est la **structure** : disposition, tailles, états. Ce qui relève de la
 * fidélité à la maquette IMH est dans `themes/concerto-dde/theme.css`.
 * ------------------------------------------------------------------------ */

/* `display` l'emporte sur la règle par défaut du navigateur pour `[hidden]`. Sans cette
   ligne, le panneau resterait affiché **dans l'étape** pendant les quatre secondes d'attente
   — c'est-à-dire que la popup serait visible avant de s'ouvrir. Même piège que
   `.f6-voice-controls[hidden]` et `.f6-button--icon[hidden]`, deux fois déjà. */
.f6-satisfaction[hidden] { display: none; }

.f6-satisfaction {
  /* La croix se pose dans le coin du panneau : il lui faut un repère. */
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--f6-space-6);
  width: 100%;
  /* Trois questions notées et un commentaire dépassent la hauteur d'un téléphone : le
     panneau défile **en lui-même** plutôt que de pousser le bouton hors de l'écran. Un
     « Valider » qu'il faut chercher est un « Valider » sur lequel on n'appuie pas. */
  max-height: 100%;
  padding: var(--f6-space-6) var(--f6-space-4) var(--f6-space-4);
  background: var(--f6-color-surface);
  border-radius: var(--f6-radius-default);
  overflow-y: auto;
}

/* La croix : discrète, mais **de taille tactile**. C'est le seul geste de fermeture
   atteignable au doigt — `Échap` n'existe pas sur un téléphone —, et un point de 20 px dans
   un coin est un geste qu'on rate deux fois sur trois. */
.f6-satisfaction__fermer {
  position: absolute;
  top: var(--f6-space-1);
  right: var(--f6-space-1);
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--f6-color-text-muted);
  font-size: var(--f6-font-size-h2);
  line-height: 1;
  cursor: pointer;
}

.f6-satisfaction__titre {
  margin: 0;
  font-family: var(--f6-font-title);
  font-size: var(--f6-font-size-h2);
  font-weight: 700;
  text-align: center;
  color: var(--f6-color-primary);
}

/* Le titre reçoit le focus à l'ouverture (`tabindex="-1"`), parce qu'une modale qui laisse
   le focus derrière elle fait lire au lecteur d'écran une étape qu'on ne peut plus
   atteindre. Mais ce focus-là n'a pas été demandé au clavier : on garde l'anneau pour qui
   navigue au clavier (`:focus-visible`) et on l'efface pour les autres. */
.f6-satisfaction__titre:focus:not(:focus-visible) { outline: none; }

.f6-satisfaction__intro {
  margin: 0;
  font-size: var(--f6-font-size-small);
  color: var(--f6-color-text-muted);
}

.f6-satisfaction__question {
  display: flex;
  flex-direction: column;
  gap: var(--f6-space-2);
}

.f6-satisfaction__libelle {
  margin: 0;
  color: var(--f6-color-text);
}

/* Les crans se partagent la largeur à parts égales, quel qu'en soit le nombre : quatre dans
   les deux maquettes, mais c'est une donnée de la question et le CSS n'a pas à le savoir.
   `starRating` de la V1 en imposait cinq, ce qui rendait ces maquettes inexprimables. */
.f6-satisfaction__echelle {
  display: flex;
  align-items: flex-start;
}

.f6-satisfaction__cran {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--f6-space-1);
  /* 44 px de haut au minimum : c'est une cible tactile, sur un écran de téléphone. */
  min-height: 44px;
  padding: var(--f6-space-1);
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
  /* Éteint. **Pas `surface-sunken`** — ce jeton vaut le fond creusé de la page, donc un
     blanc cassé, et une étoile de cette couleur sur une carte blanche est invisible.
     `surface-muted` est le gris que la maquette montre. */
  color: var(--f6-color-surface-muted);
}

/* Allumé — par **rang**, donc toutes les étoiles jusqu'au cran choisi, comme une notation
   se lit. `aria-checked`, lui, ne vaut que pour le cran choisi : ce sont deux choses
   différentes, l'une visuelle et l'autre annoncée. */
.f6-satisfaction__cran--allume { color: var(--f6-color-primary); }

.f6-satisfaction__cran:focus-visible {
  outline: 2px solid var(--f6-color-primary);
  outline-offset: 2px;
}

.f6-satisfaction__astre {
  width: 32px;
  height: 32px;
  /* `currentColor` : l'étoile prend la couleur de son bouton, donc l'état d'allumage et la
     marque en une seule règle. Même mécanique que les icônes de tuiles, et même raison —
     c'est ce qui évite un second fichier par état. */
  fill: currentColor;
}

/* L'étiquette est **sous** l'étoile, et c'est elle qui porte le sens : « Décevant » et
   « Décevante » sont deux libellés de la même échelle, accordés au sujet de la question.
   Les coder ici obligerait à un composant par accord. */
.f6-satisfaction__cran-lib {
  font-size: var(--f6-font-size-small);
  color: var(--f6-color-text-muted);
  text-align: center;
}

/* Le commentaire : un bandeau plein posé sur le champ, tous deux dans la même boîte — c'est
   ce que montre `6521:50244`, et non un `<label>` flottant au-dessus. */
.f6-satisfaction__champ {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--f6-color-primary);
  border-radius: var(--f6-radius-default);
  /* Le bandeau est à fond plein jusqu'au bord : sans cela, ses angles carrés débordent du
     rayon de la boîte et l'on voit deux coins de couleur dépasser. */
  overflow: hidden;
}

.f6-satisfaction__bandeau {
  padding: var(--f6-space-2) var(--f6-space-4);
  background: var(--f6-color-primary);
  color: var(--f6-color-on-primary);
  font-weight: 600;
}

.f6-satisfaction__zone {
  /* La bordure est celle de la boîte : la redonner au champ en dessinerait deux. */
  border: 0;
  padding: var(--f6-space-2) var(--f6-space-4);
  background: var(--f6-color-surface);
  color: var(--f6-color-text);
  font: inherit;
  /* Verticalement seulement : élargi, le champ sortirait de la carte. */
  resize: vertical;
}

.f6-satisfaction__zone:focus { outline: none; }
/* L'anneau de focus se pose sur la **boîte**, puisque c'est elle qui porte la bordure —
   sinon le champ paraît ne jamais recevoir le focus. */
.f6-satisfaction__champ:focus-within {
  outline: 2px solid var(--f6-color-primary);
  outline-offset: 1px;
}

.f6-satisfaction__valider {
  width: 100%;
  min-height: 44px;
  padding: var(--f6-space-4);
  border: 0;
  border-radius: var(--f6-radius-default);
  background: var(--f6-color-primary);
  color: var(--f6-color-on-primary);
  font: inherit;
  font-size: var(--f6-font-size-h2);
  cursor: pointer;
}

/* Éteint tant qu'une question obligatoire attend sa réponse. Il **reste lisible** : un
   bouton effacé au point de disparaître se lit comme un bouton absent, et l'assuré cherche
   ailleurs ce qu'il a sous les yeux. */
.f6-satisfaction__valider:disabled {
  background: var(--f6-color-surface-muted);
  color: var(--f6-color-surface);
  cursor: not-allowed;
}

.f6-satisfaction__merci {
  margin: 0;
  text-align: center;
  color: var(--f6-color-text);
}

/* ── Deux primitives de révélation différée ─────────────────────────────────
 *
 * **Elles sont ici parce qu'un thème ne peut pas les déclarer.** Chaque `theme.css` est
 * servi enveloppé dans `[data-theme="<id>"] { … }` (voir la route des thèmes) : une règle
 * de style, donc. Or un `@keyframes` imbriqué dans une règle de style est **invalide** et
 * silencieusement ignoré — la feuille se charge, les couleurs s'appliquent, et seules les
 * animations manquent. Mesuré le 14/09/2026 sur l'écran de proposition Generali : le
 * loader restait affiché indéfiniment et le contenu ne s'ouvrait jamais, sans une seule
 * erreur en console.
 *
 * Un thème qui veut révéler ou replier un bloc après un délai emploie donc celles-ci, en
 * posant lui-même l'état initial et le `animation-delay`. Elles ne décident de rien : ce
 * sont deux fins d'animation, et c'est la feuille appelante qui dit quand.
 *
 * Pour la rotation, rien à ajouter : `f6-permissions-spin` est déjà une rotation de 360°
 * sans rien de propre aux permissions. */

@keyframes f6-replier {
  to {
    opacity: 0;
    height: 0;
    padding: 0;
    margin: 0;
    overflow: hidden;
  }
}

@keyframes f6-deplier {
  to {
    visibility: visible;
    opacity: 1;
    height: auto;
    overflow: visible;
  }
}
