/* ATTENTION — LE JETON D'ACCENT S'APPELLE `--brass`, PAS `--gold`.
   Vingt règles de ce fichier désignaient `var(--gold)`, qui n'est défini nulle
   part : ni dans tokens.css, ni ici. Une variable CSS inconnue rend la
   déclaration invalide, sans erreur et sans avertissement — les prix
   s'affichaient donc en blanc, les pastilles « +15 % de jetons » perdaient
   leur fond, et le bandeau des autres voies n'avait ni bordure ni teinte.
   Rien ne cassait : tout se contentait de disparaître. Corrigé le 21 août
   2026. Le seul accent de la maison est `--brass` (#C9B896). */

/* ===========================================================================
   L'ARÈNE
   ---------------------------------------------------------------------------
   Une délibération n'est pas une conversation : c'est une géométrie. Des voix
   distinctes occupent des positions distinctes, émettent vers un centre, et
   ce centre finit par produire autre chose que la somme de ce qu'il a reçu.

   Toute la mise en scène sert cette lecture. Rien n'est là pour l'effet.
   =========================================================================== */

/* --- Le champ ---------------------------------------------------------------
   Deux nappes de lumière très lentes, plus un grain fin. Le grain est ce qui
   empêche les dégradés de baguer sur un écran ordinaire, et ce qui donne à
   l'ensemble une matière plutôt qu'un vide numérique. */

.field {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(120vw 90vh at 15% -10%, rgba(155, 123, 240, .10), transparent 60%),
    radial-gradient(100vw 80vh at 90% 110%, rgba(79, 211, 232, .08), transparent 62%),
    var(--void);
}

.field::before {
  content: "";
  position: absolute;
  inset: -20%;
  background:
    radial-gradient(38vw 38vw at 50% 50%, rgba(232, 163, 61, .07), transparent 62%);
  animation: derive var(--t-vast) linear infinite alternate;
  animation-duration: 34s;
}

@keyframes derive {
  from { transform: translate3d(-8%, -4%, 0) scale(1); }
  to   { transform: translate3d(10%, 6%, 0) scale(1.18); }
}

/* Grain procédural : un SVG en data-URI, donc aucun fichier à charger. */
.field::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: .3;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}

/* --- Ossature ---------------------------------------------------------------- */

.shell {
  position: relative;
  z-index: 1;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  /* En paysage, l'encoche mange le bord gauche ou droit selon le sens de
     rotation. Ces deux lignes suffisent à ne jamais écrire dessous. */
  padding-left: var(--safe-l);
  padding-right: var(--safe-r);
}

/* L'EN-TÊTE TIENT SUR DEUX LIGNES.
   ---------------------------------------------------------------------------
   Tout était sur une seule : le logo, trois boutons réduits à un signe, le
   quota, l'état du service. Sur un téléphone, les trois signes finissaient
   pincés entre deux blocs plus larges, sans un mot pour dire ce qu'ils
   faisaient — et un glyphe sans mot ne s'explique qu'au survol, geste qui
   n'existe pas au doigt.

   Une ligne dit donc qui l'on est et si le service répond ; la suivante, ce
   qu'on peut faire de son compte. Les actions y gagnent la place de porter
   leur nom. */
.bar {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: calc(1.1rem + var(--safe-t)) var(--gut) 1.1rem;
}

/* La variante à deux lignes, et elle est nommée plutôt que déduite : la
   console et la page de reprise partagent cette même barre avec un seul
   rang. Basculer `.bar` en colonne les aurait empilées elles aussi — leur
   logo au-dessus de leur pastille d'état, sans que rien ne le demande. */
.bar--menu {
  flex-direction: column;
  align-items: stretch;
  gap: .6rem;
}

.bar__haut {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.bar__menu {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .45rem;
}

/* Les entrées du menu ne crient pas comme les pastilles d'état : pas de
   capitales, pas d'interlettrage étiré, et un corps de texte plus grand. Une
   pastille s'aperçoit du coin de l'œil, un menu se lit. */
.bar__menu .pulse--bouton {
  gap: .45rem;
  padding: .38rem .85rem;
  font-family: inherit;
  font-size: var(--t--1);
  letter-spacing: .01em;
  text-transform: none;
  color: var(--ink-soft);
}
.bar__menu .pulse--bouton:hover,
.bar__menu .pulse--bouton:focus-visible {
  border-color: var(--brass);
  color: var(--brass);
}

.menu__glyphe {
  font-size: 1.05em;
  line-height: 1;
  color: var(--brass);
}

/* Le nombre de délibérations gardées. Il ne se lit qu'en second : c'est le mot
   « Historique » qui porte l'action, le compte n'en est que la mesure. */
.menu__compte {
  font-family: var(--mono);
  font-size: var(--t--2);
  color: var(--ink-faint);
}
.menu__compte:empty { display: none; }

.mark {
  display: flex;
  align-items: center;   /* un graphique n'a pas de ligne de base */
  gap: .7rem;
  margin-inline-end: auto;
  text-decoration: none;
  color: var(--ink);
}
.mark__word {
  font-size: var(--t-1);
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.mark__tag {
  font-size: var(--t--2);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

/* Pastille d'état des fournisseurs : petite, mais c'est la première chose
   qu'on regarde quand plus rien ne répond. */
.pulse {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .32rem .8rem;
  border: 1px solid var(--edge);
  border-radius: var(--r-pill);
  background: var(--glass);
  font-size: var(--t--2);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.pulse__dot {
  /* Fonctionne aujourd'hui parce que le parent est flex, ce qui blockifie
     l'enfant. On ne s'appuie pas sur un effet de bord du contexte. */
  display: block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--voice-5);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--voice-5) 22%, transparent);
  animation: respire 2.6s var(--ease) infinite;
}
.pulse[data-down="true"] .pulse__dot {
  background: var(--danger);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 22%, transparent);
}
@keyframes respire { 50% { opacity: .35; transform: scale(.8); } }

/* --- Scène ------------------------------------------------------------------- */

.stage {
  flex: 1;
  width: min(100% - var(--gut) * 2, var(--wrap));
  margin-inline: auto;
  /* La barre d'accueil de l'iPhone flotte au-dessus du bas de page : sans
     cette réserve, le dernier bouton du fil se trouve juste dessous. */
  /* La barre de gestes des téléphones récents mord le bas de l'écran :
     deux rems s'y perdaient, et le dernier bouton se retrouvait dessous. */
  padding-bottom: calc(3.5rem + var(--safe-b));
  display: grid;
  gap: clamp(1.4rem, 4vw, 3rem);
  align-content: start;
}

/* Au repos, l'arène occupe tout ; en délibération elle cède la place au fil. */
.stage[data-phase="repos"]         { grid-template-columns: 1fr; }
.stage[data-phase="deliberation"],
.stage[data-phase="synthese"]      { grid-template-columns: 1fr; }

/* L'anneau et la question, réunis en une colonne.
   L'écart entre eux venait de la scène, qui les tenait pour deux éléments
   distincts ; il vient désormais d'ici, à l'identique. En dessous de 1060 px
   ce bloc n'est qu'un empilement ordinaire, et rien ne change à l'œil. */
.cote {
  display: grid;
  gap: clamp(1.4rem, 4vw, 3rem);
  align-content: start;
}

@media (min-width: 1060px) {
  /* LE FIL PREND TOUTE LA LARGEUR (29 août 2026).
     Il vivait dans une colonne de 58 %, l'anneau ancré à côté. C'était juste
     et cela tenait l'anneau immobile — mais une délibération est un texte
     long, et un texte long lu sur la moitié d'un écran large est un texte
     qu'on abandonne. L'anneau passe au-dessus, plus petit : il reste visible,
     il continue de montrer qui parle, et il ne prend plus la moitié de la
     place. Chacun garde son défilement : c'est ce qui comptait dans l'ancien
     dessin, et cela n'a pas changé. */
  .stage[data-phase="deliberation"],
  .stage[data-phase="synthese"] {
    grid-template-columns: 1fr;
    grid-template-areas: "cote" "fil";
    /* L'anneau prend ce qu'il lui faut, le fil prend tout le reste. */
    grid-template-rows: auto 1fr;
    align-content: stretch;
    align-items: stretch;

    /* La réserve du bas n'a plus à protéger que la barre d'accueil des
       téléphones — absente ici. Deux rems de vide sous le fil se voyaient. */
    padding-bottom: calc(1rem + var(--safe-b));

  }

  /* LA COLONNE ANCRÉE.
     Elle ne défile pas et ne se coupe pas. On aurait pu lui donner son propre
     défilement, mais ce serait la découper : les Voix sont posées en absolu
     autour de l'anneau et débordent volontairement sa boîte. Une zone de
     défilement les aurait rognées et aurait fait apparaître une barre
     horizontale sous le graphique.
     Elle tient donc en place parce que la page ne défile plus sous elle. */
  .stage[data-phase="deliberation"] .cote,
  .stage[data-phase="synthese"] .cote {
    grid-area: cote;
    min-height: 0;
    align-content: start;
  }


  /* Le fil occupe toute la hauteur et défile en son sein.
     « min-height: 0 » est la condition pour qu'un élément de grille étiré
     défile chez lui plutôt que pousser la grille vers le bas.
     « overscroll-behavior: contain » empêche la propagation : arrivé au bout
     du fil, la molette s'arrête là au lieu d'entraîner la page — et donc
     l'anneau — avec elle. C'est précisément ce qu'on nous demandait. */
  .stage[data-phase="deliberation"] .thread,
  .stage[data-phase="synthese"] .thread  {
    grid-area: fil;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-inline-end: .4rem;   /* le pouce de l'ascenseur ne mord pas le texte */
  }

  /* La coquille fait exactement l'écran : sans hauteur définie, « 1fr » n'a
     rien contre quoi se résoudre et la scène retrouverait la hauteur de son
     contenu.
     On ne lui met surtout pas de débordement caché : les Voix dépassent de
     l'anneau par construction, et tout recadrage les mangerait. Si un écran
     très bas ne suffisait pas, la page déborde et défile — au repos, où rien
     n'a besoin d'être ancré. */
  /* LA HAUTEUR FIXE NE VAUT QUE PENDANT LA DÉLIBÉRATION.

     Elle était posée sur `.shell` sans condition de phase. Au repos, sur un
     écran large, la coquille faisait donc exactement une fenêtre — hauteur
     FIXE, sans débordement défilable — et tout ce qui dépassait devenait
     inatteignable. On pouvait dérouler sans que rien ne vienne : le bas de
     page n'existait plus.

     Le commentaire ci-dessus le disait déjà : « au repos, rien n'a besoin
     d'être ancré ». La règle ne l'écoutait pas.

     `:has()` la restreint aux deux phases qui la réclament. Un navigateur qui
     ne connaît pas `:has()` ignore la règle entière — et retombe alors sur une
     page qui défile normalement, c'est-à-dire sur le comportement sûr. C'est
     la bonne façon de se tromper. */
  .shell:has(.stage[data-phase="deliberation"]),
  .shell:has(.stage[data-phase="synthese"]) { height: 100dvh; }

  .stage[data-phase="deliberation"],
  .stage[data-phase="synthese"] { min-height: 0; }
}

/* Une fois la délibération lancée, la question a fait son travail : elle
   se retire pour laisser la place au fil, sans disparaître tout à fait. */
.stage[data-phase="deliberation"] .ask__lead,
.stage[data-phase="synthese"]     .ask__lead,
.stage[data-phase="deliberation"] .ask__sub,
.stage[data-phase="synthese"]     .ask__sub { display: none; }

/* L'anneau se règle sur la largeur ET sur la hauteur disponibles.
   Sans le terme en dvh, un écran bas — un portable de 768 px — le laissait
   pousser le formulaire hors de l'écran ; la page redevenait défilante, et
   l'ancrage de la colonne se serait défait précisément là où il compte. */
.stage[data-phase="deliberation"] .ring,
.stage[data-phase="synthese"] .ring { width: min(100%, 420px, 46dvh); }

/* Au-dessus du fil et non plus à côté, l'anneau doit se faire plus petit :
   sinon il mange la hauteur que la lecture réclame. */
@media (min-width: 1060px) {
  .stage[data-phase="deliberation"] .ring,
  .stage[data-phase="synthese"] .ring { width: min(100%, 320px, 30dvh); }
}

/* --- L'anneau ----------------------------------------------------------------- */

.ring {
  position: relative;
  width: min(100%, 620px);
  margin-inline: auto;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  transition: transform var(--t-slow) var(--ease), opacity var(--t-slow) var(--ease);
}
.stage[data-phase="repos"] .ring { width: min(100%, 560px, 52dvh); }

.ring__svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }

/* Cercle de garde : la frontière de l'arène. */
.ring__orbit {
  fill: none;
  stroke: var(--edge);
  stroke-width: 1;
  stroke-dasharray: 2 7;
  opacity: .7;
  transform-origin: center;
  animation: rotation 120s linear infinite;
}
@keyframes rotation { to { transform: rotate(360deg); } }

/* Filaments : une voix qui rejoint le centre. Ils se dessinent, ils ne
   clignotent pas — l'argument met un temps à parvenir. */
.filament {
  fill: none;
  stroke-width: 1.4;
  stroke-linecap: round;
  opacity: 0;
  stroke-dasharray: var(--len, 300);
  stroke-dashoffset: var(--len, 300);
}
.filament[data-live="true"] {
  opacity: .85;
  animation: tirer 1.6s var(--ease) forwards;
}
.filament[data-done="true"] { opacity: .22; stroke-dashoffset: 0; }
@keyframes tirer { to { stroke-dashoffset: 0; } }

/* --- Un nœud = une voix -------------------------------------------------------- */

.node {
  position: absolute;
  width: 108px;
  /* Centrage sur le point d'ancrage. Une marge négative fixe supposerait
     une hauteur connue : le nom d'un agent peut passer sur deux lignes. */
  transform: translate(-50%, -50%);
  display: grid;
  justify-items: center;
  gap: .45rem;
  text-align: center;
  transition: transform var(--t-mid) var(--spring), opacity var(--t-mid) var(--ease);
}

.node__disc {
  position: relative;
  width: 56px; height: 56px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--voice) 38%, transparent);
  background: radial-gradient(circle at 34% 30%,
              color-mix(in srgb, var(--voice) 26%, transparent),
              color-mix(in srgb, var(--voice) 6%, transparent));
  color: var(--voice);
  font-size: 1.25rem;
  transition: box-shadow var(--t-mid) var(--ease), transform var(--t-mid) var(--spring);
}

.node__name {
  font-size: var(--t--2);
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-mute);
  transition: color var(--t-fast);
}

/* Halo pendant la prise de parole. C'est le seul moment où une voix
   domine visuellement — et il dure exactement le temps qu'elle parle. */
.node[data-state="parle"] .node__disc {
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--voice) 60%, transparent),
    0 0 34px color-mix(in srgb, var(--voice) 45%, transparent),
    0 0 90px color-mix(in srgb, var(--voice) 22%, transparent);
  animation: battement 1.5s var(--ease) infinite;
}
.node[data-state="parle"] .node__name { color: var(--voice); }
@keyframes battement { 50% { transform: scale(1.06); } }

.node[data-state="fini"] .node__disc {
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--voice) 30%, transparent),
              0 0 18px color-mix(in srgb, var(--voice) 16%, transparent);
}
.node[data-state="echec"] { opacity: .32; }
.node[data-state="echec"] .node__disc { border-style: dashed; }

/* Anneau de progression autour du disque : une voix qui a parlé trois fois
   se distingue d'une voix qui vient d'arriver. */
.node__count {
  position: absolute;
  inset: -7px;
  border-radius: 50%;
  border: 1px solid transparent;
  border-top-color: var(--voice);
  opacity: .5;
  transform: rotate(var(--turns, 0deg));
  transition: transform var(--t-slow) var(--ease);
}

/* --- Le cœur -------------------------------------------------------------------- */

.core {
  position: relative;
  width: 132px; height: 132px;
  display: grid; place-items: center;
}

.core__halo {
  position: absolute; inset: -40%;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--brass) 20%, transparent), transparent 62%);
  opacity: .35;
  transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
}

.core__glyph {
  position: relative;
  width: 100%; height: 100%;
  color: var(--brass);
}
.core__ring {
  fill: none;
  stroke: currentColor;
  stroke-width: 1;
  opacity: .5;
  transform-origin: center;
}
.core__ring--a { animation: rotation 40s linear infinite; }
.core__ring--b { animation: rotation 64s linear infinite reverse; }

.core__seed {
  fill: currentColor;
  opacity: .9;
  transform-origin: center;
  transition: transform var(--t-slow) var(--spring);
}

/* Cristallisation : au moment de la synthèse le cœur se referme sur
   lui-même puis irradie. C'est le seul geste spectaculaire de l'interface,
   et il n'arrive qu'une fois par délibération. */
.ring[data-core="synthese"] .core__halo { opacity: 1; transform: scale(1.35); }
.ring[data-core="synthese"] .core__seed { transform: scale(1.7); }
.ring[data-core="synthese"] .core__glyph { animation: irradier 2.4s var(--ease) forwards; }

@keyframes irradier {
  0%   { filter: drop-shadow(0 0 0 var(--brass)); }
  35%  { filter: drop-shadow(0 0 40px var(--brass)); }
  100% { filter: drop-shadow(0 0 16px color-mix(in srgb, var(--brass) 55%, transparent)); }
}

/* --- La question ------------------------------------------------------------------ */

.ask { width: min(100%, 860px); margin-inline: auto; }

.ask__lead {
  font-family: var(--serif);
  font-size: var(--t-4);
  line-height: 1.02;
  letter-spacing: -.035em;
  text-align: center;
  margin-bottom: 1.6rem;
}
.ask__lead em {
  font-style: italic;
  color: var(--brass);
}

.ask__sub {
  max-width: 46ch;
  margin: 0 auto 2.4rem;
  text-align: center;
  color: var(--ink-soft);
  font-size: var(--t-0);
}

.ask__field {
  position: relative;
  display: flex;
  align-items: flex-end;
  gap: .8rem;
  padding: .9rem 1rem .9rem 1.4rem;
  border: 1px solid var(--edge);
  border-radius: var(--r-xl);
  background: var(--glass);
  backdrop-filter: blur(18px);
  transition: border-color var(--t-mid) var(--ease), box-shadow var(--t-mid) var(--ease);
}
.ask__field:focus-within {
  border-color: color-mix(in srgb, var(--brass) 50%, transparent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--brass) 25%, transparent),
              0 20px 60px rgba(0, 0, 0, .5);
}

.ask__input {
  flex: 1;
  min-height: 30px;
  max-height: 220px;
  padding: .4rem 0;
  border: 0;
  background: transparent;
  resize: none;
  font-size: var(--t-1);
  line-height: 1.45;
  outline: none;
}
.ask__input::placeholder { color: var(--ink-faint); }

.ask__go {
  flex: none;
  height: 46px;
  padding: 0 1.5rem;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--brass);
  color: var(--void);
  font-weight: 600;
  font-size: var(--t--1);
  letter-spacing: .08em;
  text-transform: uppercase;
  transition: transform var(--t-fast) var(--spring), opacity var(--t-fast);
}
.ask__go:hover:not(:disabled) { transform: translateY(-1px); }
.ask__go:disabled { opacity: .3; cursor: not-allowed; }

/* --- Réglages ------------------------------------------------------------------- */

.dials {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin-top: 1.1rem;
  justify-content: center;
}

.dial {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .42rem .9rem;
  border: 1px solid var(--edge);
  border-radius: var(--r-pill);
  background: transparent;
  font-size: var(--t--2);
  letter-spacing: .06em;
  color: var(--ink-mute);
  transition: border-color var(--t-fast), color var(--t-fast), background-color var(--t-fast);
}
.dial:hover { border-color: var(--edge-hi); color: var(--ink-soft); }
.dial[aria-pressed="true"] {
  border-color: color-mix(in srgb, var(--voice, var(--brass)) 55%, transparent);
  background: color-mix(in srgb, var(--voice, var(--brass)) 12%, transparent);
  color: var(--ink);
}
.dial__glyph { color: var(--voice, var(--brass)); font-size: .95rem; }

.dials__sep {
  width: 1px; height: 20px;
  background: var(--edge);
  margin-inline: .4rem;
}

/* --- Le fil --------------------------------------------------------------------- */

/* Le fil ne se plafonne plus lui-même.
   Il portait « max-height: calc(100dvh - 190px) » : 190 px censés représenter
   l'en-tête et les marges. Le compte était trop généreux, et le fil s'arrêtait
   plusieurs dizaines de pixels au-dessus du bas de l'écran — un vide que rien
   ne venait remplir et que rien ne justifiait.
   Sa hauteur lui vient désormais de la grille, qui la connaît. */
.thread {
  display: grid;
  gap: 1rem;
  align-content: start;
  scroll-behavior: smooth;
}

.round {
  display: flex;
  align-items: center;
  gap: .8rem;
  padding: .3rem 0;
  font-size: var(--t--2);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.round::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--edge), transparent);
}

/* Une contribution. La barre de gauche porte la couleur : c'est le seul
   endroit où l'on identifie la voix sans lire son nom. */
.say {
  position: relative;
  padding: 1.05rem 1.2rem 1.05rem 1.5rem;
  border: 1px solid var(--edge);
  border-radius: var(--r-md);
  background: var(--glass);
  animation: surgir var(--t-mid) var(--ease) both;
}
.say::before {
  content: "";
  position: absolute;
  inset: 1rem auto 1rem 0;
  width: 2px;
  border-radius: 2px;
  background: var(--voice);
  opacity: .8;
}
@keyframes surgir {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

.say__head {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin-bottom: .6rem;
}
.say__glyph { color: var(--voice); font-size: .95rem; }
.say__who {
  font-size: var(--t--2);
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--voice);
}
.say__by {
  margin-inline-start: auto;
  font-family: var(--mono);
  font-size: .68rem;
  color: var(--ink-faint);
}
.say__body { color: var(--ink-soft); font-size: var(--t-0); line-height: 1.68; }
.say__body p + p { margin-top: .8em; }

.say[data-echec="true"] { border-style: dashed; opacity: .6; }
.say[data-echec="true"] .say__body { color: var(--danger); font-size: var(--t--1); }

/* Intervention de l'utilisateur en cours de tour. */
.say--input { border-style: dashed; background: rgba(201,184,150,.06); }
.say__input {
  width: 100%;
  min-height: 4.2rem;
  padding: .7rem .9rem;
  border: 1px solid var(--edge);
  border-radius: var(--r-sm);
  background: var(--panel);
  color: var(--ink);
  font: inherit;
  font-size: var(--t-0);
  line-height: 1.55;
  resize: vertical;
}
.say__input:focus { outline: none; border-color: var(--brass); }
.say__input:disabled { opacity: .6; }
.say__foot {
  display: flex;
  gap: .6rem;
  margin-top: .7rem;
}
.say__go,
.say__skip {
  padding: .5rem .9rem;
  border: 1px solid var(--edge);
  border-radius: var(--r-sm);
  background: var(--panel);
  color: var(--ink-soft);
  font: inherit;
  font-size: var(--t--1);
  cursor: pointer;
}
.say__go { background: var(--brass); color: var(--bg); border-color: var(--brass); }
.say__go:hover, .say__skip:hover { filter: brightness(1.15); }
.say__go:disabled, .say__skip:disabled { opacity: .5; cursor: default; }

/* Bloc de reprise d'une délibération passée. */
.reprise {
  margin: 1.2rem 0;
  padding: .9rem 1.1rem;
  border: 1px dashed var(--edge);
  border-radius: var(--r-md);
  background: rgba(201,184,150,.06);
}
.reprise__label {
  display: block;
  font-size: var(--t--2);
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--brass);
  margin-bottom: .4rem;
}
.reprise__q {
  font-size: var(--t-0);
  color: var(--ink-soft);
  font-style: italic;
}

/* Attente : trois points qui respirent au rythme d'une phrase, pas d'une
   barre de chargement. */
.waiting { display: inline-flex; gap: .32rem; align-items: center; }
.waiting i {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--voice);
  animation: onde 1.3s var(--ease) infinite;
}
.waiting i:nth-child(2) { animation-delay: .18s; }
.waiting i:nth-child(3) { animation-delay: .36s; }
@keyframes onde { 0%, 70%, 100% { opacity: .25; transform: translateY(0); } 35% { opacity: 1; transform: translateY(-4px); } }

/* --- La réponse ------------------------------------------------------------------ */

.verdict {
  position: relative;
  padding: clamp(1.6rem, 4vw, 2.8rem);
  border: 1px solid color-mix(in srgb, var(--brass) 26%, transparent);
  border-radius: var(--r-lg);
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--brass) 6%, transparent), transparent 40%),
    var(--glass);
  animation: surgir var(--t-slow) var(--ease) both;
}

.verdict__tag {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  margin-bottom: 1.2rem;
  font-size: var(--t--2);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--brass);
}
.verdict__tag::before {
  content: "";
  width: 26px; height: 1px;
  background: var(--brass);
}

/* Le serif n'est pas une coquetterie : il signale que ce bloc n'est pas de
   la même nature que le reste. C'est la réponse, pas de la mécanique. */
.verdict__body {
  font-family: var(--serif);
  font-size: var(--t-1);
  line-height: 1.72;
  color: var(--ink);
  max-width: var(--read);
}
.verdict__body p + p { margin-top: 1em; }

.verdict__foot {
  display: flex;
  flex-wrap: wrap;
  gap: .8rem;
  align-items: center;
  margin-top: 1.8rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--edge);
  font-family: var(--mono);
  font-size: .7rem;
  color: var(--ink-faint);
}
/* Les actes tiennent ensemble à droite. L'ancienne règle posait `margin-inline-start:
   auto` sur chaque bouton : avec un seul c'était juste, avec trois ils se
   repoussaient l'un l'autre jusqu'à occuper toute la ligne. */
.verdict__actes {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-inline-start: auto;
}

.verdict__foot button {
  padding: .42rem 1rem;
  border: 1px solid var(--edge);
  border-radius: var(--r-pill);
  background: transparent;
  font-family: var(--sans);
  font-size: var(--t--2);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  transition: border-color var(--t-fast), color var(--t-fast);
}
.verdict__foot button:hover { border-color: var(--brass); color: var(--brass); }
.verdict__foot button:disabled { opacity: .45; cursor: default; }

/* L'export complet est l'acte principal : il porte le laiton, les autres non.
   Trois boutons de même poids ne disent pas lequel on attend. */
.verdict__foot button[data-fort="true"] {
  border-color: color-mix(in srgb, var(--brass) 55%, transparent);
  color: var(--brass);
}

/* ===========================================================================
   INSCRIPTION VÉRIFIÉE
   =========================================================================== */

.sheet__panel--etroit { max-width: 30rem; }

.reg { display: flex; flex-direction: column; }

.reg__mot {
  margin: 0 0 1.4rem;
  font-size: var(--t--1);
  line-height: 1.7;
  color: var(--ink-soft);
}

.reg__label {
  font-family: var(--sans);
  font-size: var(--t--2);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: .45rem;
}

.reg__champ {
  padding: .8rem 1rem;
  margin-bottom: 1.1rem;
  border: 1px solid var(--edge);
  border-radius: var(--r-sm, 10px);
  background: color-mix(in srgb, var(--void) 60%, transparent);
  font-family: var(--sans);
  font-size: var(--t-0);
  color: var(--ink);
  transition: border-color var(--t-fast);
}
.reg__champ:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--brass) 65%, transparent);
}
.reg__champ::placeholder { color: var(--ink-faint); }

/* Un code à six chiffres se relit caractère par caractère : chasse fixe et
   lettres espacées, pour qu'on voie tout de suite si on en a saisi cinq. */
.reg__champ--code {
  font-family: var(--mono);
  font-size: 1.35rem;
  letter-spacing: .5em;
  text-align: center;
  padding-inline-start: .5em;   /* compense l'espacement, qui pousse le texte à droite */
}

.reg__aide {
  margin: -.7rem 0 1.2rem;
  font-size: var(--t--2);
  color: var(--ink-faint);
}

.reg__erreur {
  margin-bottom: 1rem;
  padding: .7rem .9rem;
  border: 1px solid color-mix(in srgb, var(--danger) 40%, transparent);
  border-radius: var(--r-sm, 10px);
  font-size: var(--t--1);
  line-height: 1.55;
  color: var(--danger);
}

/* Le même bouton, quand c'est un lien : un « a » reste en ligne et ne prend
   ni sa hauteur ni son centrage sans qu'on le lui dise. */
.reg__go--lien {
  display: inline-block;
  text-align: center;
  text-decoration: none;
}

.reg__go {
  padding: .85rem 1.4rem;
  border: 1px solid color-mix(in srgb, var(--brass) 55%, transparent);
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--brass) 10%, transparent);
  font-family: var(--sans);
  font-size: var(--t--1);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--brass);
  cursor: pointer;
  transition: background var(--t-fast), border-color var(--t-fast);
}
.reg__go:hover:not(:disabled) { background: color-mix(in srgb, var(--brass) 18%, transparent); }
.reg__go:disabled { opacity: .5; cursor: default; }

.reg__retour {
  margin-top: .9rem;
  padding: .5rem;
  border: 0;
  background: transparent;
  font-family: var(--sans);
  font-size: var(--t--2);
  color: var(--ink-faint);
  cursor: pointer;
}
.reg__retour:hover { color: var(--ink-soft); }

/* Un canal peut tomber sans l'autre : le champ dont le code n'est jamais
   parti est neutralisé plutôt que laissé à remplir en vain. */
.reg__champ:disabled { opacity: .35; cursor: not-allowed; }

/* --- Le poste reconnu ---------------------------------------------------------------

   Une main tendue, pas une alarme. Le laiton plutôt que le rouge : ce n'est
   pas un incident, c'est une bonne nouvelle — le compte est là.

   Placé AU-DESSUS du champ de question et non dans un coin : quelqu'un qui
   croit avoir tout perdu commence par regarder là où il allait écrire. */

.reprise {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .55rem 1rem;
  margin: 0 0 1.3rem;
  padding: .85rem 1.1rem;
  border: 1px solid color-mix(in srgb, var(--brass) 42%, transparent);
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--brass) 8%, transparent);
}

.reprise__mot {
  flex: 1 1 16rem;
  font-size: var(--t--1);
  color: var(--ink);
}

/* L'indice se lit d'un coup d'œil sans se recopier : c'est tout son objet. */
.reprise__indice {
  font-family: var(--mono, monospace);
  font-weight: 400;
  letter-spacing: .02em;
  color: var(--brass);
  white-space: nowrap;
}

.reprise__go,
.reprise__non {
  padding: .48rem 1.05rem;
  border-radius: var(--r-pill);
  font-family: var(--sans);
  font-size: var(--t--2);
  letter-spacing: .07em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color var(--t-fast), background var(--t-fast), color var(--t-fast);
}

.reprise__go {
  border: 1px solid color-mix(in srgb, var(--brass) 55%, transparent);
  background: transparent;
  color: var(--brass);
}
.reprise__go:hover,
.reprise__go:focus-visible {
  background: color-mix(in srgb, var(--brass) 14%, transparent);
}
.reprise__go:disabled { opacity: .45; cursor: progress; }

/* Le refus reste possible et lisible, sans peser autant que l'acceptation :
   sur un poste partagé, c'est la réponse honnête, et la cacher reviendrait à
   pousser un inconnu vers un compte qui n'est pas le sien. */
.reprise__non {
  border: 1px solid transparent;
  background: transparent;
  color: var(--ink-faint);
}
.reprise__non:hover,
.reprise__non:focus-visible {
  border-color: var(--edge);
  color: var(--ink-soft);
}

/* Pendant une délibération, la bannière n'a plus rien à dire. */
.stage[data-phase="deliberation"] .reprise,
.stage[data-phase="synthese"] .reprise { display: none; }

.reg__facultatif {
  color: var(--ink-faint);
  text-transform: none;
  letter-spacing: 0;
}

/* --- Divers ------------------------------------------------------------------------ */

.alert {
  /* Un souffle au-dessus, une respiration en dessous.
     Le bloc n'avait aucune marge : il se collait au curseur de lecture qui le
     précède, et au bord de ce qui le suit. Un message qui touche ses voisins
     se lit comme leur prolongement, alors qu'il les interrompt. */
  margin: .5rem 0 2.5rem;
  padding: .9rem 1.2rem;
  border: 1px solid color-mix(in srgb, var(--danger) 40%, transparent);
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--danger) 8%, transparent);
  color: var(--ink);
  font-size: var(--t--1);
}

/* Le même bloc sert aussi à annoncer une bonne nouvelle : seule la couleur
   change, et le bouton qui la suit. */
.alert[data-bon="true"] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin-top: 1.4rem;
  border-color: color-mix(in srgb, var(--brass) 45%, transparent);
  background: color-mix(in srgb, var(--brass) 8%, transparent);
}
.alert[data-bon="true"] button {
  margin-inline-start: auto;
  padding: .5rem 1.1rem;
  border: 1px solid color-mix(in srgb, var(--brass) 55%, transparent);
  border-radius: var(--r-pill);
  background: transparent;
  font-family: var(--sans);
  font-size: var(--t--2);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brass);
  cursor: pointer;
}

[hidden] { display: none !important; }

/* Les règles d'écran étroit et de pointeur grossier sont rassemblées en fin
   de fichier — voir « TÉLÉPHONES ». */

/* ===========================================================================
   LE DISQUE — une pièce, pas une image qui tourne
   ---------------------------------------------------------------------------
   Trois couches, et chacune a une raison d'être :

   · les deux faces, peintes bombées, écartées de la profondeur de la pièce ;
   · la tranche, faite de lamelles disposées en cylindre — c'est elle qui
     empêche le disque de disparaître quand il se présente de profil ;
   · le reflet, posé PAR-DESSUS et hors de la rotation. C'est la couche qui
     fait lire le volume : une lumière ne tourne pas avec l'objet qu'elle
     éclaire, et un bombé qui tourne avec sa pièce se lit à plat.
   =========================================================================== */

.coin {
  display: block;
  position: relative;
  flex: none;
  perspective: 260px;
  opacity: 0;
  transition: opacity var(--t-slow) var(--ease);
}
.coin[data-pret="true"] { opacity: 1; }

.coin__body {
  display: block;
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  /* Une légère inclinaison suffit à révéler la tranche pendant tout le tour.
     À plat, on ne verrait l'épaisseur qu'au passage du profil. */
  animation: coin-spin 5s linear infinite;
}

@keyframes coin-spin {
  from { transform: rotateX(-12deg) rotateY(0deg); }
  to   { transform: rotateX(-12deg) rotateY(360deg); }
}

.coin__face {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  backface-visibility: hidden;
}
.coin__face--avant   { transform: translateZ(calc(var(--d) / 2)); }
.coin__face--arriere { transform: rotateY(180deg) translateZ(calc(var(--d) / 2)); }

/* Une lamelle de tranche : haute comme l'épaisseur, large comme la corde
   entre deux lamelles voisines, poussée sur le rayon. */
.coin__rim {
  position: absolute;
  top: 50%; left: 50%;
  height: var(--d);
  margin-top: calc(var(--d) / -2);
  background: linear-gradient(90deg,
    #0a1024 0%, #1e2a56 22%, #4a5fae 48%, #26325f 74%, #0a1024 100%);
  transform: rotateY(var(--a)) translateZ(var(--r));
  backface-visibility: hidden;
}

/* Le reflet. Il ne tourne pas : il reste accroché en haut à gauche, comme
   une source de lumière fixe dans la pièce. */
.coin__gloss {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  background:
    radial-gradient(52% 46% at 30% 24%, rgba(255,255,255,.34), rgba(255,255,255,.07) 46%, transparent 68%),
    radial-gradient(70% 60% at 74% 82%, rgba(120,150,255,.16), transparent 62%);
  mix-blend-mode: screen;
}

@media (prefers-reduced-motion: reduce) {
  .coin__body { animation-duration: 30s; }
}

/* ===========================================================================
   LA QUESTION POSÉE — reléguée en tête de fil dès la soumission
   =========================================================================== */

.query {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding: 1rem 1.2rem;
  border: 1px solid var(--edge);
  border-inline-start: 2px solid var(--brass);
  border-radius: var(--r-md);
  background: linear-gradient(90deg, color-mix(in srgb, var(--brass) 7%, transparent), transparent 60%);
  animation: surgir var(--t-mid) var(--ease) both;
}
.query__label {
  flex: none;
  font-size: var(--t--2);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--brass);
  padding-top: .2rem;
}
.query__text {
  flex: 1;
  font-family: var(--serif);
  font-size: var(--t-1);
  line-height: 1.4;
  color: var(--ink);
  text-align: end;   /* demandé : la question se pose en haut à droite */
}


/* ===========================================================================
   LE SÉLECTEUR DE MODÈLE
   =========================================================================== */

/* Sous chaque pastille de Voix, le modèle qui l'incarne. */
.dial { flex-direction: column; align-items: center; gap: .15rem; padding: .5rem 1rem; }
.dial__line { display: inline-flex; align-items: center; gap: .5rem; }
.dial__model {
  font-size: .66rem;
  letter-spacing: .04em;
  text-transform: none;
  color: var(--ink-faint);
  max-width: 15ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dial[aria-pressed="true"] .dial__model { color: color-mix(in srgb, var(--voice) 75%, var(--ink)); }

.sheet {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: var(--gut);
  background: rgba(3, 4, 9, .78);
  backdrop-filter: blur(10px);
  animation: fondu var(--t-mid) var(--ease) both;
}
@keyframes fondu { from { opacity: 0; } to { opacity: 1; } }

.sheet__panel {
  width: min(100%, 780px);
  max-height: 86dvh;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--edge-hi);
  border-radius: var(--r-lg);
  background: var(--plane);
  box-shadow: 0 40px 120px rgba(0, 0, 0, .7);
  overflow: hidden;
  animation: monter var(--t-mid) var(--ease) both;
}
@keyframes monter { from { transform: translateY(18px) scale(.985); } to { transform: none; } }

.sheet__head {
  display: flex;
  align-items: center;
  gap: .9rem;
  padding: 1.2rem 1.4rem;
  border-bottom: 1px solid var(--edge);
}
.sheet__glyph {
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--voice) 45%, transparent);
  background: color-mix(in srgb, var(--voice) 14%, transparent);
  color: var(--voice);
}
/* Le titre et sa légende sont deux choses, pas une phrase. Restés en ligne,
   ils se lisaient d'un trait — « Créditer votre compte Il vous reste 50 000
   jetons » — et la légende semblait la fin du titre. */
.sheet__title { display: block; font-size: var(--t-1); }
.sheet__role {
  display: block;
  margin-top: .18rem;
  font-size: var(--t--2);
  color: var(--ink-mute);
  line-height: 1.35;
}
.sheet__close {
  margin-inline-start: auto;
  width: 34px; height: 34px;
  border: 1px solid var(--edge);
  border-radius: 50%;
  background: transparent;
  color: var(--ink-soft);
  font-size: 1.1rem;
}
.sheet__close:hover { border-color: var(--edge-hi); color: var(--ink); }

.sheet__body { overflow-y: auto; padding: .8rem 1.4rem 1.4rem; }

.house { margin-top: 1.2rem; }
.house:first-child { margin-top: .4rem; }
.house__name {
  display: flex;
  align-items: center;
  gap: .55rem;
  margin-bottom: .55rem;
  font-size: var(--t--2);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.house__name b { color: var(--maison); font-weight: 500; font-size: 1rem; }

.models { display: grid; gap: .45rem; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); }

.model {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .62rem .9rem;
  border: 1px solid var(--edge);
  border-radius: var(--r-sm);
  background: transparent;
  text-align: start;
  transition: border-color var(--t-fast), background-color var(--t-fast);
}
.model:hover:not(:disabled) { border-color: var(--edge-hi); background: var(--glass); }
.model[aria-pressed="true"] {
  border-color: color-mix(in srgb, var(--voice) 60%, transparent);
  background: color-mix(in srgb, var(--voice) 12%, transparent);
}
.model:disabled { opacity: .3; cursor: not-allowed; }

.model__id { flex: 1; min-width: 0; }
.model__name { display: block; font-size: var(--t--1); color: var(--ink); }
.model__note { display: block; font-size: .66rem; color: var(--ink-faint); }

/* Point d'accès : plein pour un appel direct, creux via un intermédiaire. */
.model__path {
  flex: none;
  width: 7px; height: 7px;
  border-radius: 50%;
  border: 1px solid var(--ink-faint);
}
.model__path[data-direct="true"] { background: var(--voice-5); border-color: var(--voice-5); }

.sheet__foot {
  padding: .85rem 1.4rem;
  border-top: 1px solid var(--edge);
  font-size: .68rem;
  color: var(--ink-faint);
  display: flex;
  align-items: center;
  gap: 1.2rem;
}
.sheet__foot i { font-style: normal; color: var(--voice-5); }

/* ===========================================================================
   LE MULTIPLICATEUR DE TOURS
   =========================================================================== */

.rounds { display: inline-flex; align-items: center; gap: .3rem; }

.rounds__n {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border: 1px solid var(--edge);
  border-radius: var(--r-sm);
  background: transparent;
  font-size: var(--t--1);
  font-variant-numeric: tabular-nums;
  color: var(--ink-mute);
  transition: border-color var(--t-fast), color var(--t-fast), background-color var(--t-fast);
}
.rounds__n:hover { border-color: var(--edge-hi); color: var(--ink-soft); }
.rounds__n[aria-pressed="true"] {
  border-color: var(--brass);
  background: color-mix(in srgb, var(--brass) 16%, transparent);
  color: var(--ink);
}

/* Le multiplicateur : ×1 → ×10 → ×100. Les neuf chiffres deviennent
   des dizaines, puis des centaines. */
.rounds__mul {
  min-width: 46px; height: 30px;
  padding: 0 .55rem;
  margin-inline-start: .25rem;
  border: 1px solid var(--brass);
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--brass) 10%, transparent);
  color: var(--brass);
  font-size: var(--t--1);
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
  transition: transform var(--t-fast) var(--spring), background-color var(--t-fast);
}
.rounds__mul:hover { transform: translateY(-1px); background: color-mix(in srgb, var(--brass) 20%, transparent); }
.rounds__mul[data-mul="10"]  { border-color: var(--voice-1); color: var(--voice-1); background: color-mix(in srgb, var(--voice-1) 12%, transparent); }
.rounds__mul[data-mul="100"] { border-color: var(--voice-2); color: var(--voice-2); background: color-mix(in srgb, var(--voice-2) 12%, transparent); }

/* Avertissement de coût : au-delà de dix tours, on annonce la facture. */
.cost {
  width: 100%;
  margin-top: .7rem;
  text-align: center;
  font-size: var(--t--2);
  color: var(--voice-1);
}
.cost[data-lourd="true"] { color: var(--danger); }

/* Pastille de quota. Elle vire au rouge quand il ne reste rien — c'est le
   moment où l'utilisateur a besoin de comprendre, pas d'être surpris. */
#quota[data-vide="true"] {
  border-color: color-mix(in srgb, var(--danger) 45%, transparent);
  color: var(--danger);
}

/* ===========================================================================
   LECTURE VOCALE
   ---------------------------------------------------------------------------
   Le curseur ne règle pas un volume : il règle combien de temps on accepte
   de passer à écouter. À gauche, tout le texte ; à droite, l'essentiel.
   L'étiquette dit le résultat en clair, pas un pourcentage abstrait.
   =========================================================================== */

.voix {
  display: flex;
  align-items: center;
  gap: .8rem;
  flex-wrap: wrap;
  width: 100%;
  margin-top: .9rem;
  padding-top: .9rem;
  border-top: 1px solid var(--edge);
}

.voix__titre {
  font-size: var(--t--2);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

.voix__curseur {
  flex: 1;
  min-width: 150px;
  max-width: 320px;
  height: 3px;
  appearance: none;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--brass) var(--p, 0%), var(--edge) var(--p, 0%));
  outline: none;
}
.voix__curseur::-webkit-slider-thumb {
  appearance: none;
  width: 15px; height: 15px;
  border-radius: 50%;
  background: var(--brass);
  border: 2px solid var(--void);
  cursor: pointer;
}
.voix__curseur::-moz-range-thumb {
  width: 15px; height: 15px;
  border-radius: 50%;
  background: var(--brass);
  border: 2px solid var(--void);
  cursor: pointer;
}

.voix__etat {
  font-size: var(--t--2);
  color: var(--ink-soft);
  min-width: 17ch;
}
.voix__etat b { color: var(--brass); font-weight: 600; }

/* Bouton d'écoute sous une contribution — discret jusqu'au survol. */
.dire {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  margin-top: .7rem;
  padding: .35rem .85rem;
  border: 1px solid var(--edge);
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--ink-faint);
  font-size: var(--t--2);
  transition: border-color var(--t-fast), color var(--t-fast);
}
.dire:hover { border-color: var(--voice); color: var(--voice); }
.dire[data-actif="true"] {
  border-color: var(--voice);
  color: var(--voice);
  background: color-mix(in srgb, var(--voice) 12%, transparent);
}
.dire[disabled] { opacity: .4; cursor: progress; }

/* Trois barres qui montent pendant la lecture : on voit quelle voix parle. */
.dire__onde { display: inline-flex; align-items: flex-end; gap: 2px; height: 11px; }
.dire__onde i {
  width: 2px; height: 4px;
  background: currentColor;
  border-radius: 1px;
  animation: onde-voix .9s ease-in-out infinite;
}
.dire__onde i:nth-child(2) { animation-delay: .15s; }
.dire__onde i:nth-child(3) { animation-delay: .3s; }
@keyframes onde-voix { 0%,100% { height: 3px; } 50% { height: 11px; } }

.dire__gain { color: var(--voice-5); font-variant-numeric: tabular-nums; }
.dire__libelle { letter-spacing: .04em; }

/* ===========================================================================
   TÉLÉPHONES
   ---------------------------------------------------------------------------
   Deux axes, et ils ne se recouvrent pas :

   · la LARGEUR gouverne la composition — ce qui tient sur une ligne, ce qui
     se replie, ce qui doit rétrécir ;
   · le POINTEUR gouverne les prises — un doigt ne vise pas comme une souris,
     et une tablette a des doigts sur un écran large.

   Les traiter ensemble donnerait des boutons minuscules sur iPad et des
   pastilles énormes sur un portable à écran étroit.
   =========================================================================== */

/* --- Composition ------------------------------------------------------------ */

@media (max-width: 720px) {

  /* L'en-tête. « zai · xai · anthropic · gemini · openrouter » informe
     l'exploitant, pas la personne qui vient poser une question — et sur
     360 px il repoussait le quota hors de l'écran. On garde le point coloré,
     qui dit à lui seul si le service répond, et le texte ne revient que
     lorsqu'il annonce une panne : là, il faut le lire en entier.
     Le quota, lui, reste toujours : c'est ce qu'on vérifie avant de poser
     une question. */
  .bar { gap: .5rem; padding-inline: calc(var(--gut) * .8); }
  .bar__haut { gap: .5rem; }
  .pulse { padding: .3rem .6rem; }

  /* Le menu se resserre, mais garde ses mots : c'est tout l'intérêt de
     l'avoir sorti sur sa propre ligne. S'il ne tient pas, il passe à la
     ligne — mieux vaut deux rangs lisibles qu'un rang de signes muets. */
  .bar__menu { gap: .35rem; }
  .bar__menu .pulse--bouton { padding: .34rem .6rem; gap: .35rem; }
  #pulse:not([data-down="true"]) #pulseText { display: none; }
  #pulse:not([data-down="true"]) { padding: .34rem .5rem; }
  .mark { gap: .5rem; }

  /* L'anneau. Au repos il porte la promesse et mérite la place ; dès que la
     délibération commence, ce qu'on veut lire est en dessous. Un anneau plein
     écran obligerait à le franchir au doigt à chaque nouvelle contribution. */
  .stage[data-phase="repos"] .ring { width: min(100%, 380px); }
  .stage[data-phase="deliberation"] .ring,
  .stage[data-phase="synthese"] .ring { width: min(72%, 280px); }

  .node { width: 78px; gap: .3rem; }
  .node__disc { width: 44px; height: 44px; font-size: 1rem; }
  .node__name { font-size: .6rem; letter-spacing: .08em; }
  .core { width: 96px; height: 96px; }

  /* La saisie. Le bouton passe sous le champ : côte à côte, il ne restait
     que six caractères visibles de la question en cours de frappe. */
  .ask__field {
    flex-direction: column;
    align-items: stretch;
    gap: .6rem;
    padding: 1rem;
    /* Un flou de 18 px sur toute la largeur coûte cher à chaque image sur un
       Android d'entrée de gamme, et se voit à peine sur un fond aussi sombre. */
    backdrop-filter: blur(8px);
  }
  .ask__go { width: 100%; height: 48px; }

  /* Le champ tient trois lignes AU REPOS.
     Sa hauteur est ajustée par le script à chaque frappe, mais jamais au
     chargement : il s'ouvrait donc sur une seule ligne, et l'invite — qui en
     occupe trois sur 390 px — débordait sous le bouton. On voyait une phrase
     coupée en deux avant même d'avoir touché le clavier. */
  .ask__input { min-height: 3.4em; }

  /* LE BAS DE PAGE RESPIRE.
     Deux rems ne suffisaient pas sur un téléphone : la barre d'adresse de
     Safari et la barre de gestes d'Android flottent au-dessus du document,
     et « 100dvh » ne les compte que lorsqu'elles sont déployées. Le dernier
     réglage — le curseur de lecture — se retrouvait dessous, donc invisible,
     et la page paraissait coupée alors qu'elle était seulement masquée. */
  .stage { padding-bottom: calc(5rem + var(--safe-b)); }

  /* Le curseur de lecture est le dernier élément de la colonne : il lui faut
     sa propre séparation, sans quoi il se lit comme la suite des réglages. */
  .voix { margin-top: 1.3rem; padding-top: 1.3rem; }

  .ask__lead { font-size: var(--t-3); }
  .ask__sub { margin-bottom: 1.6rem; }

  /* Les réglages. Cinq Voix, neuf chiffres, un multiplicateur et deux modes :
     empilés en vrac, cela faisait deux écrans de pastilles avant la question.
     On les range en trois rangées lisibles, et les séparateurs verticaux —
     qui n'ont de sens que sur une seule ligne — disparaissent. */
  .dials { gap: .4rem .35rem; margin-top: .9rem; }
  .dials__sep { display: none; }
  .dial { padding: .45rem .7rem; }
  .dial__model { max-width: 11ch; font-size: .62rem; }

  .rounds { gap: .22rem; }
  .rounds__n { width: 28px; height: 28px; }

  /* Le fil défile avec la page : deux zones de défilement imbriquées sur un
     écran tactile, c'est une où le doigt se perd. */
  .thread { max-height: none; overflow: visible; gap: .8rem; }

  .query { flex-direction: column; gap: .5rem; }
  .query__text { text-align: start; font-size: var(--t-0); }

  .say { padding: .9rem 1rem; }
  .verdict { padding: 1.2rem 1.1rem; }

  /* Les actes sous la réponse passent pleine largeur et s'empilent : trois
     boutons serrés sur une ligne de 360 px se touchent l'un pour l'autre. */
  .verdict__foot { flex-direction: column; align-items: stretch; gap: .6rem; }
  .verdict__actes { margin-inline-start: 0; display: grid; gap: .5rem; }
  .verdict__foot button { width: 100%; }

  /* La lecture vocale : l'étiquette sous le curseur plutôt qu'à côté. */
  .voix { flex-wrap: wrap; }
  .voix__curseur { min-width: 0; flex: 1 1 100%; order: 3; }
  .voix__etat { min-width: 0; }

  /* Les panneaux deviennent des feuilles ancrées en bas — c'est là que le
     pouce arrive, et c'est le geste que les deux systèmes ont enseigné. */
  .sheet { place-items: end stretch; padding: 0; }
  .sheet__panel {
    width: 100%;
    max-height: 88dvh;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    border-bottom: 0;
    animation: monter-feuille var(--t-mid) var(--ease) both;
  }
  @keyframes monter-feuille { from { transform: translateY(100%); } to { transform: none; } }

  .sheet__head { padding: 1rem 1.1rem; }
  .sheet__body { padding: .8rem 1.1rem calc(1.4rem + var(--safe-b)); }
  .sheet__foot { padding: .8rem 1.1rem calc(.8rem + var(--safe-b)); }
  .models { grid-template-columns: 1fr; }

  .reg__champ { margin-bottom: .9rem; }
  .reg__mot { margin-bottom: 1.1rem; }
}

/* Très petits écrans — iPhone SE, Android d'entrée de gamme à 360 px. */
@media (max-width: 380px) {
  .node { width: 68px; }
  .node__disc { width: 40px; height: 40px; }
  .node__name { display: none; }   /* le glyphe et la couleur suffisent à identifier */
  .rounds__n { width: 26px; height: 26px; font-size: .78rem; }
  .dial__model { max-width: 9ch; }
}

/* --- Prises ------------------------------------------------------------------
   Une cible de 30 px se rate au doigt une fois sur trois ; les deux systèmes
   recommandent 44 px (Apple) et 48 dp (Android).

   ON AGRANDIT EN HAUTEUR, PAS EN LARGEUR. La tentation était de faire déborder
   la zone sensible de chaque bouton par un pseudo-élément — mais les neuf
   chiffres de tours sont espacés de 4 px : des zones de 44 px se seraient
   chevauchées, et chaque bouton aurait capté les appuis destinés à son voisin.
   On aurait remplacé une cible trop petite par une cible qui ment.

   Verticalement, rien ne se dispute la place : la hauteur peut grandir
   librement, et c'est ce qui manque le plus à un doigt.
   ---------------------------------------------------------------------------- */

@media (pointer: coarse) {

  .rounds__n { height: 44px; }
  .rounds__mul { min-height: 44px; }
  .dial { min-height: 46px; }
  .model { min-height: 48px; }
  .dire { min-height: 40px; padding-block: .5rem; }
  .sheet__close { width: 44px; height: 44px; }
  .verdict__foot button { min-height: 44px; }
  .reg__go { min-height: 50px; }
  .reg__retour { min-height: 44px; }
  .ask__go { min-height: 48px; }

  /* Le survol n'existe pas au doigt : il reste « collé » après l'appui et
     laisse une pastille allumée qui ne l'est plus. On le neutralise et on
     répond à la pression, qui est le seul retour honnête sur tactile. */
  .dial:hover, .model:hover, .dire:hover, .sheet__close:hover,
  .verdict__foot button:hover, .rounds__n:hover {
    border-color: var(--edge);
    color: inherit;
    background: transparent;
  }
  .dial:active, .model:active, .rounds__n:active, .dire:active,
  .verdict__foot button:active, .reg__go:active, .ask__go:active {
    transform: scale(.97);
    opacity: .85;
  }

  /* Le curseur de résumé : un rail de 3 px ne se saisit pas. La hauteur totale
     monte à 41 px, mais `content-box` maintient le trait fin — on agrandit ce
     qui se touche, pas ce qui se voit. */
  .voix__curseur { height: 5px; padding-block: 18px; background-clip: content-box; }
  .voix__curseur::-webkit-slider-thumb { width: 24px; height: 24px; }
  .voix__curseur::-moz-range-thumb { width: 24px; height: 24px; }

  /* iOS grossit la page dès qu'un champ de moins de 16 px reçoit le focus, et
     ne la redescend jamais tout à fait : la mise en page reste décalée pour le
     reste de la session. Seize pixels exactement, et le zoom n'a plus lieu. */
  .reg__champ, .ask__input { font-size: max(16px, var(--t-0)); }
  .reg__champ--code { font-size: 1.4rem; }
}

/* --- Paysage sur téléphone ---------------------------------------------------
   Peu de hauteur, beaucoup de largeur. L'anneau prendrait tout l'écran pour
   ne rien dire de plus : on le réduit, et le titre s'efface. */

@media (max-height: 520px) and (orientation: landscape) {
  .ask__lead, .ask__sub { display: none; }
  .stage[data-phase="repos"] .ring { width: min(46%, 260px); }
  .sheet__panel { max-height: 94dvh; }
}

/* ===========================================================================
   L'HISTORIQUE
   ---------------------------------------------------------------------------
   Une question posée à Cogency est souvent celle qu'on n'ose poser à personne.
   La liste doit donc se lire vite et se refermer vite : la date, la question,
   les premiers mots de la réponse. Rien de plus à l'écran que ce qu'il faut
   pour reconnaître ce qu'on cherche.
   =========================================================================== */

.pulse--bouton {
  cursor: pointer;
  font-family: var(--mono);
  transition: border-color var(--t-fast), color var(--t-fast);
}
.pulse--bouton:hover { border-color: var(--brass); color: var(--brass); }

.histo {
  padding: 1rem 0;
  border-bottom: 1px solid var(--edge);
}
.histo:last-child { border-bottom: 0; }

.histo__tete {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .8rem;
  margin-bottom: .5rem;
  font-family: var(--mono);
  font-size: .68rem;
  color: var(--ink-faint);
}
.histo__date { color: var(--ink-mute); }
.histo__meta { margin-inline-start: auto; }

.histo__q {
  font-family: var(--serif);
  font-size: var(--t-0);
  line-height: 1.45;
  color: var(--ink);
  margin-bottom: .4rem;
}

/* Trois lignes d'extrait : assez pour reconnaître une réponse, pas assez
   pour la relire ici — c'est le rôle du fil. */
.histo__extrait {
  font-size: var(--t--1);
  line-height: 1.55;
  color: var(--ink-mute);
  margin-bottom: .7rem;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.histo__actes { display: flex; flex-wrap: wrap; gap: .4rem; }

.histo__actes .mini {
  padding: .35rem .8rem;
  border: 1px solid var(--edge);
  border-radius: var(--r-pill);
  background: transparent;
  font-family: var(--sans);
  font-size: var(--t--2);
  letter-spacing: .04em;
  color: var(--ink-mute);
  transition: border-color var(--t-fast), color var(--t-fast);
}
.histo__actes .mini:hover { border-color: var(--brass); color: var(--brass); }

@media (pointer: coarse) {
  .histo__actes .mini { min-height: 42px; padding-inline: 1rem; }
  .histo__actes .mini:hover { border-color: var(--edge); color: var(--ink-mute); }
  .histo__actes .mini:active { transform: scale(.97); }
}

@media (max-width: 720px) {
  .histo__meta { margin-inline-start: 0; width: 100%; }
  .histo__actes { display: grid; gap: .45rem; }
}

/* --- Les offres de jetons ------------------------------------------------------

   Quatre cartes, lisibles d'un coup d'œil : ce qu'on paie à droite, ce qu'on
   reçoit dessous. Le prix et la quantité sont sur la même ligne visuelle parce
   que c'est le rapport entre les deux qu'on compare, jamais l'un des deux
   seul. */

.offre {
  display: grid;
  gap: .3rem;
  width: 100%;
  text-align: start;
  padding: 1rem 1.1rem;
  border: 1px solid var(--edge);
  border-radius: 14px;
  background: color-mix(in srgb, var(--ink) 3%, transparent);
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition: border-color var(--t-mid) var(--ease), background var(--t-mid) var(--ease);
}
.offre + .offre { margin-top: .7rem; }
.offre:hover,
.offre:focus-visible {
  border-color: var(--brass);
  background: color-mix(in srgb, var(--brass) 7%, transparent);
}
.offre[data-etat="attente"] { opacity: .5; cursor: progress; }
.offre:disabled { cursor: default; }

.offre__haut {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}
.offre__nom    { font-size: var(--t-1); letter-spacing: .01em; }
.offre__prix   { font-size: var(--t-1); color: var(--brass); white-space: nowrap; }
.offre__jetons { font-size: var(--t--1); color: var(--ink-soft); }
.offre__tenue  { font-size: var(--t--2); color: var(--ink-faint); }
.offre__prime {
  justify-self: start;
  margin-top: .25rem;
  padding: .12rem .5rem;
  border-radius: 999px;
  font-size: var(--t--2);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brass);
  background: color-mix(in srgb, var(--brass) 12%, transparent);
}

/* Ce que tout palier payant donne. La liste est la même partout — c'est le
   volume qui distingue les paliers, pas les fonctions — et elle se lit donc
   comme un rappel, en retrait, jamais comme un argument de vente. */
.offre__traits {
  list-style: none;
  margin: .4rem 0 0;
  padding: 0;
  display: grid;
  gap: .16rem;
}
.offre__traits li {
  font-size: var(--t--2);
  color: var(--ink-mute);
}
.offre__traits li::before {
  content: '·';
  color: var(--brass);
  margin-inline-end: .45rem;
}

/* Le renvoi du code par SMS : un bouton qui se lit comme un lien. Il n'est pas
   l'action principale de l'écran — celle-ci reste « Vérifier » — mais il doit
   se voir de qui attend un code qui ne vient pas. */
.reg__relance {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--brass);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  text-align: start;
}
.reg__relance:hover { color: var(--ink); }
.reg__relance:disabled { color: var(--ink-mute); text-decoration: none; cursor: default; }

/* L'INVITATION À INSTALLER L'APPLICATION.
   Une bande sous l'en-tête, pas un panneau qui barre la route : elle propose
   un confort, pas une condition. Elle ne paraît qu'une fois — « Plus tard »
   la referme pour de bon. */
.appli {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .7rem 1rem;
  margin: 0 var(--gut) .9rem;
  padding: .75rem .95rem;
  border: 1px solid color-mix(in srgb, var(--brass) 40%, var(--edge));
  border-radius: 12px;
  background: color-mix(in srgb, var(--brass) 7%, transparent);
}
.appli__glyphe { color: var(--brass); font-size: 1.1rem; line-height: 1; }
.appli__mot {
  flex: 1 1 14rem;
  font-size: var(--t--1);
  line-height: 1.4;
  color: var(--ink-soft);
}
.appli__mot strong { color: var(--ink); font-weight: 500; }
.appli__actions {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-inline-start: auto;
}
.appli__go {
  padding: .36rem .95rem;
  border: 1px solid var(--brass);
  border-radius: var(--r-pill);
  color: var(--brass);
  text-decoration: none;
  font-size: var(--t--2);
  letter-spacing: .04em;
  white-space: nowrap;
  transition: background var(--t-fast);
}
.appli__go:hover,
.appli__go:focus-visible { background: color-mix(in srgb, var(--brass) 14%, transparent); }
.appli__non {
  padding: .36rem .6rem;
  border: 0;
  background: transparent;
  color: var(--ink-mute);
  font: inherit;
  font-size: var(--t--2);
  cursor: pointer;
}
.appli__non:hover { color: var(--ink-soft); }

/* LE BANDEAU DES AUTRES VOIES.
   Il passe devant les prix, une fois, et se referme sur « J'ai compris ». Il
   emprunte l'or de la maison plutôt que le gris des mentions : ce n'est pas
   une note de bas de page, c'est une offre — celle qui s'adresse à qui, sans
   elle, repartirait sans rien acheter. */
.splash {
  display: grid;
  gap: .4rem;
  margin-bottom: 1.1rem;
  padding: .95rem 1.05rem;
  border: 1px solid color-mix(in srgb, var(--brass) 45%, var(--edge));
  border-radius: 14px;
  background: color-mix(in srgb, var(--brass) 8%, transparent);
}
.splash__titre {
  margin: 0;
  font-size: var(--t--2);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brass);
}
.splash__l {
  margin: 0;
  font-size: var(--t--1);
  line-height: 1.45;
  color: var(--ink-soft);
}
.splash__l--contact { color: var(--ink-mute); }
.splash__go {
  justify-self: start;
  margin-top: .35rem;
  padding: .36rem .95rem;
  border: 1px solid var(--brass);
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--brass);
  font: inherit;
  font-size: var(--t--2);
  letter-spacing: .04em;
  cursor: pointer;
  transition: background var(--t-fast);
}
.splash__go:hover,
.splash__go:focus-visible { background: color-mix(in srgb, var(--brass) 14%, transparent); }

/* Les chemins qui ne s'achètent pas d'un clic : le devis institutionnel, le
   paiement par agent, la candidature d'agent. Des phrases, pas des cartes —
   posées en retrait sous la grille, séparées d'elle par un trait. */
.offre__aparte {
  margin-top: 1rem;
  padding-top: .9rem;
  border-top: 1px solid var(--edge);
  display: grid;
  gap: .55rem;
}
.offre__aparte-l {
  margin: 0;
  font-size: var(--t--2);
  color: var(--ink-faint);
  line-height: 1.5;
}
.offre__aparte-l strong { color: var(--ink-soft); font-weight: 500; }

/* L'adresse vaut pour les trois lignes au-dessus : elle se détache d'elles. */
.offre__aparte-l--contact { color: var(--ink-mute); }

/* La pastille de quota devient un bouton : elle doit s'annoncer comme tel. */
.pulse[role="button"] { cursor: pointer; }
.pulse[role="button"]:hover { color: var(--brass); }

/* La consigne des vingt-quatre heures. Encadrée sans être alarmante : ce n'est
   pas une erreur, c'est une manœuvre à faire avant de continuer. */
.reg__fenetre {
  margin: .9rem 0 .2rem;
  padding: .7rem .9rem;
  border: 1px solid color-mix(in srgb, var(--brass) 35%, transparent);
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--brass) 7%, transparent);
  font-size: var(--t--2);
  line-height: 1.55;
  color: var(--ink-soft);
}
.reg__lien {
  color: var(--brass);
  font-family: var(--mono);
  white-space: nowrap;
}

/* --- Les autres portes ---------------------------------------------------------

   Discret mais pas caché. Ce n'est pas une mention de pied de page : c'est une
   invitation, et elle doit être lisible par quelqu'un qui hésite encore à
   écrire dans le champ au-dessus.

   Le bandeau s'efface pendant la délibération — on ne propose pas une autre
   porte à quelqu'un qui vient d'entrer par celle-ci. */

.canaux {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .6rem;
  margin-top: 1.6rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--edge);
}
.stage[data-phase="deliberation"] .canaux,
.stage[data-phase="synthese"] .canaux { display: none; }

.canaux__mot {
  font-size: var(--t--2);
  letter-spacing: .04em;
  color: var(--ink-faint);
  margin-inline-end: .2rem;
}

.canal {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .42rem .85rem;
  border: 1px solid var(--edge);
  border-radius: var(--r-pill);
  background: transparent;
  font-family: var(--sans);
  font-size: var(--t--2);
  color: var(--ink-soft);
  cursor: pointer;
  transition: border-color var(--t-fast), color var(--t-fast), background var(--t-fast);
}
.canal:hover,
.canal:focus-visible {
  border-color: color-mix(in srgb, var(--brass) 55%, transparent);
  background: color-mix(in srgb, var(--brass) 7%, transparent);
  color: var(--ink);
}
/* Chaque service garde sa couleur au survol : c'est ce qui le rend
   reconnaissable avant même qu'on lise l'étiquette. */
.canal[data-canal="whatsapp"]:hover .canal__glyphe { fill: #25D366; }
.canal[data-canal="matrix"]:hover .canal__glyphe   { fill: #0DBD8B; }

.canal__glyphe {
  width: 17px;
  height: 17px;
  fill: currentColor;
  transition: fill var(--t-fast);
}

.canal__liste {
  margin: .9rem 0 0;
  padding-inline-start: 1.1rem;
  font-size: var(--t--1);
  color: var(--ink-soft);
  line-height: 1.7;
}
.canal__adresse {
  margin: 1.1rem 0 .9rem;
  font-family: var(--mono);
  font-size: var(--t-0);
  letter-spacing: .04em;
  color: var(--brass);
  word-break: break-all;
}
.canal__action {
  display: block;
  padding: .8rem 1rem;
  border-radius: var(--r-md);
  background: var(--brass);
  color: #1A1408;
  font-size: var(--t--1);
  letter-spacing: .08em;
  text-transform: uppercase;
  text-align: center;
  text-decoration: none;
}
.canal__action:hover { filter: brightness(1.08); }

/* --- Les modèles réservés ------------------------------------------------------

   Marqués, jamais grisés. Un bouton éteint ne dit pas ce qu'il faut faire pour
   l'allumer ; celui-ci s'ouvre sur l'explication et sur le catalogue. */

.model[data-reserve="true"] { opacity: .78; }
.model[data-reserve="true"]:hover { opacity: 1; border-color: var(--brass); }

.model__verrou {
  margin-inline-start: .38rem;
  font-size: .78em;
  color: var(--brass);
  vertical-align: baseline;
}

/* --- Le transfert d'appareil ---------------------------------------------------

   Le QR est servi en SVG par le serveur. On lui impose un fond clair : un code
   sombre sur fond sombre ne se lit par aucune caméra, et l'Arène est sombre. */

.transf__qr {
  display: grid;
  place-items: center;
  margin: 1rem auto .8rem;
  padding: .7rem;
  width: max-content;
  background: #fff;
  border-radius: 12px;
}
.transf__qr svg { display: block; width: 200px; height: 200px; }

.transf__code {
  text-align: center;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--t-2);
  letter-spacing: .28em;
  /* Le décalage compense l'interlettrage, qui pousse le texte vers la droite
     et le ferait paraître mal centré sous le QR. */
  text-indent: .28em;
  color: var(--brass);
  margin: 0 0 .6rem;
}
.transf__aide,
.transf__temps {
  text-align: center;
  font-size: var(--t--2);
  color: var(--ink-faint);
  margin: 0 0 .4rem;
}

/* =========================================================================
   LE SÉLECTEUR DE LANGUE, ET L'ÉCRITURE DE DROITE À GAUCHE
   =========================================================================

   Le `select` est posé transparent PAR-DESSUS le bouton : on voit le bouton
   dessiné comme ses voisins, on touche le sélecteur natif du système. Celui-ci
   sait afficher l'arabe et le chinois avec les bonnes polices, se pilote au
   clavier et se lit par les lecteurs d'écran — trois choses qu'un menu écrit
   à la main aurait fallu refaire, moins bien.
   ========================================================================= */
.pulse--langue { position: relative; }
.menu__langue {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: 0; cursor: pointer;
  font: inherit; border: 0; padding: 0;
  -webkit-appearance: none; appearance: none;
}
/* Le sélecteur est invisible : c'est le bouton qui doit montrer le focus,
   sinon la navigation au clavier traverse le menu sans rien allumer. */
.pulse--langue:focus-within {
  outline: 2px solid var(--brass, #C9B8F0);
  outline-offset: 2px;
}
/* Le menu déroulant, lui, se voit : il hérite du fond du système et non du
   nôtre, donc on force des couleurs lisibles dans les deux thèmes. */
.menu__langue option { color: #16121F; background: #FFFFFF; }

/* ---- L'arabe ------------------------------------------------------------
   Les propriétés logiques font l'essentiel du travail. Restent trois cas que
   la logique ne couvre pas : un glyphe directionnel, une police qui doit
   changer, et les nombres qui ne se retournent jamais. */
[dir="rtl"] body {
  font-family: "Noto Naskh Arabic", "Segoe UI", system-ui, sans-serif;
}
/* Les chiffres, les identifiants et les montants gardent leur sens de
   lecture : un TID ou un numéro Airtel retourné devient illisible. */
[dir="rtl"] .quota__n, [dir="rtl"] .offre__prix, [dir="rtl"] .reg__champ,
[dir="rtl"] input[type="email"], [dir="rtl"] input[type="tel"],
[dir="rtl"] .transf__code, [dir="rtl"] code {
  direction: ltr;
  text-align: start;
  unicode-bidi: isolate;
}
/* La flèche « revenir » pointe dans le sens de la lecture. */
[dir="rtl"] .reg__retour, [dir="rtl"] .tid__retour { transform: scaleX(-1); }
[dir="rtl"] .reg__retour > *, [dir="rtl"] .tid__retour > * { transform: scaleX(-1); }


/* =============================================================================
   AU REPOS, SUR GRAND ÉCRAN : L'ANNEAU D'UN CÔTÉ, LA PHRASE DE L'AUTRE
   -----------------------------------------------------------------------------
   Jusqu'ici tout était empilé et centré : l'anneau, puis l'accroche, puis le
   champ. Sur un écran large cela laissait deux colonnes de vide et poussait le
   champ de saisie vers le bas.

   L'anneau passe donc dans la première colonne, l'accroche dans la seconde, et
   tout ce qui se manipule — le champ, les réglages, la lecture — s'étend sous
   les deux. Ce qu'on regarde en haut, ce qu'on touche en bas.

   `display: contents` SUR `.ask` : ses enfants deviennent des cases de la
   grille de `.cote`. On évite ainsi de déplacer du balisage — la question et
   son formulaire restent une seule section pour qui lit le HTML — tout en les
   plaçant séparément. La boîte de `.ask` disparaît, ses contraintes de largeur
   avec elle ; c'est `.stage` qui borne déjà la page.

   LA PREMIÈRE COLONNE N'EST PAS « LA GAUCHE ». `grid-column: 1` suit le sens
   de lecture : à gauche en français, en anglais et en chinois, à DROITE en
   arabe, sans une ligne de plus. C'est la raison d'être des propriétés
   logiques, et la raison pour laquelle on n'écrit jamais `left` ici.
   ============================================================================= */
@media (min-width: 1060px) {
  .stage[data-phase="repos"] .cote {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: clamp(1.5rem, 4vw, 3.5rem);
    align-items: center;
  }

  .stage[data-phase="repos"] .ask { display: contents; }

  .stage[data-phase="repos"] .ring     { grid-column: 1; grid-row: 1; width: min(100%, 520px); }
  .stage[data-phase="repos"] .ask__mot { grid-column: 2; grid-row: 1; }

  /* Le texte cesse d'être centré : à côté d'un graphique, une colonne centrée
     flotte. Alignée sur le début de la ligne, elle a un bord commun avec lui. */
  .stage[data-phase="repos"] .ask__lead { text-align: start; margin-bottom: 1.2rem; }
  .stage[data-phase="repos"] .ask__sub  { text-align: start; margin-inline: 0; margin-bottom: 0; }

  /* Tout ce qui se manipule passe sous les deux colonnes. */
  .stage[data-phase="repos"] .reprise,
  .stage[data-phase="repos"] .ask__field,
  .stage[data-phase="repos"] .dials,
  .stage[data-phase="repos"] .voix,
  .stage[data-phase="repos"] .alert,
  .stage[data-phase="repos"] .canaux { grid-column: 1 / -1; }
}
