/* L'aide destinée aux utilisateurs de l'application. Complète `pages.css`,
   qui porte déjà la palette et les fondations ; on n'écrit ici que ce qui
   change. Les deux feuilles sont ouvertes sans cookie : cette page s'adresse
   à des clients qui n'ont aucun compte sur ce serveur.

   ⚠️ Aucun script. Les onglets tiennent en CSS pure — `:target` plus un
   sélecteur de voisinage pour le panneau par défaut.

   ⚠️ **`:has()` porte tout ce qui vise une SECTION ; les onglets, eux, n'en
   dépendent pas.** Cette feuille l'a proscrit jusqu'au 16/09/2026 — « support
   inégal sur les téléphones qu'on ne choisit pas » — et ce refus a coûté tous
   les sommaires de la page, morts sans que rien ne le dise. Il est admis
   depuis, et ses règles s'écrivent à part : groupées avec celles de `:target`,
   un navigateur qui l'ignore jetterait le sélecteur entier et perdrait aussi
   les onglets, qui n'ont besoin de rien de tel.

   ⚠️ **Ce qu'un tel navigateur perd exactement, et c'est plus qu'avant** :
   tout lien qui désigne un titre à l'intérieur d'un panneau — les sommaires, et
   depuis le 16/09/2026 les liens de l'application, qui passaient jusque-là par
   des ancres-relais. Il garde les cinq onglets et arrive sur le panneau par
   défaut. C'est un repli assumé, pas un oubli : `:has()` est disponible partout
   depuis décembre 2023, loin en deçà du `minSdk 31` du produit, et le prix de
   l'autre voie est écrit plus bas — voir « Ce qui tenait ici : les
   ancres-relais ». Voir aussi « Le panneau qui CONTIENT la cible ». */

main { width: min(46rem, 100%); }
/* Le titre porte le logo à sa gauche. `flex` plutôt qu'une image dans le
   flux : le titre passe sur deux lignes en dessous de 380 px, et l'image
   resterait alors collée à la première. */
h1 { font-size: 1.4rem; margin: 0 0 .4rem;
     display: flex; align-items: center; gap: .6rem; }
/* ⚠️ `flex-shrink: 0` n'est pas décoratif : sans lui, un flex-item image se
   laisse écraser par le texte et le logo devient un ovale. */
h1 .logo { flex: 0 0 auto; width: 2.5rem; height: 2.5rem; border-radius: .55rem; }
h2 { font-size: 1.05rem; margin: 0 0 .8rem; }
h3 { font-size: .92rem; margin: 1.5rem 0 .4rem; color: var(--doux); }
/* ⚠️ Sans cette règle, un h4 prend le style par défaut du navigateur — donc
   PLUS GROS que le h3 qui le domine, et la hiérarchie se lit à l'envers. */
h4 { font-size: .92rem; margin: 1.1rem 0 .3rem; color: var(--texte); font-weight: 600; }
/* La barre collante recouvrirait ce qu'une ancre amène en haut : on lui réserve
   sa hauteur. ⚠️ Le panneau en a besoin autant que les titres — la cible de
   `/aide#cle-api` est l'article, pas son `h2`, et sans cette règle on arrivait
   sur un onglet dont le titre était caché derrière la barre. */
.panneau, h3[id] { scroll-margin-top: 4rem; }
p, li { line-height: 1.6; font-size: .93rem; }
ol, ul { padding-left: 1.2rem; }
li { margin: .35rem 0; }
code { font-family: ui-monospace, monospace; font-size: .85em;
       background: var(--fond); border: 1px solid var(--trait);
       border-radius: .3rem; padding: .1rem .3rem; overflow-wrap: anywhere; }
/* Une adresse écrite en toutes lettres dans un lien — le portail de
   Météo-France — élargissait la page à 491 px pour 360 : elle était cachée
   jusqu'à la 5.14.0.0, donc jamais mesurée. `anywhere` ne coupe que ce qui
   déborderait ; un lien court ne bouge pas. Trouvé par `essai_largeur.py`. */
p a, li a, td a { overflow-wrap: anywhere; }
/* `pages.css` rapetisse tous les liens à .85rem — bon pour un « retour » sous
   un formulaire, mauvais au fil d'un paragraphe, où le lien devenait plus petit
   que la phrase qui le porte. Ici ils reprennent la taille du texte. */
p a, li a, td a { color: var(--accent); font-size: inherit; }

table { border-collapse: collapse; width: 100%; font-size: .88rem; margin: .8rem 0; }
th, td { border: 1px solid var(--trait); padding: .5rem .6rem;
         text-align: left; vertical-align: top; }
th { background: var(--fond); font-weight: 600; }

.note { border-left: 3px solid var(--accent); background: var(--fond);
        padding: .7rem .9rem; border-radius: 0 .5rem .5rem 0; margin: 1rem 0; }
.note p { margin: 0; font-size: .88rem; }

/* --- La barre d'onglets ------------------------------------------------ */
/* L'ordre du HTML n'est pas celui de l'écran : la barre est écrite en dernier
   pour qu'un sélecteur `~` puisse l'atteindre depuis le panneau ciblé, et
   `order` la ramène en tête. Sans cela, aucun onglet ne pourrait s'allumer.

   Elle est **collante** : les panneaux font plusieurs écrans sur un téléphone,
   et une barre qui défile hors de vue laisse le lecteur sans aucun moyen de
   changer de sujet sans remonter. */
.onglets { display: flex; flex-direction: column; margin-top: 1.4rem; }
/* ⚠️ `nowrap` et non `wrap` : à quatre onglets, la barre se repliait sur deux
   lignes à 430 px de large, et sa seconde ligne — collante — recouvrait le titre
   qu'une ancre venait d'amener. Un défilement latéral vaut mieux qu'une barre
   qui grandit sous les pieds du lecteur. */
.barre { order: -1; position: sticky; top: 0; z-index: 2;
         display: flex; gap: .3rem; flex-wrap: nowrap; overflow-x: auto;
         scrollbar-width: none;
         background: var(--fond); border-bottom: 1px solid var(--trait);
         margin-bottom: 1.4rem; }
.barre::-webkit-scrollbar { display: none; }
.barre a { font-size: .88rem; font-weight: 600; color: var(--doux);
           text-decoration: none; padding: .65rem .7rem; white-space: nowrap;
           border-bottom: 2px solid transparent; margin-bottom: -1px; }
.barre a:hover { color: var(--texte); }
/* ── L'indice de défilement, au bord droit ──────────────────────────────────
   Demandé par Thierry le 27/08/2026, quand la barre en portait six : elle déborde
   dès cinq — « Télécommande » est déjà hors champ sur un S21 —, et rien
   ne disait qu'il en restait à droite — l'onglet allumé lui-même peut être hors
   champ quand on arrive depuis l'application.

   ⚠️ **Un triangle, et pas un simple fondu.** Le fondu a été essayé d'abord,
   et Thierry l'a jugé à l'écran : on voit « une sorte de fondu sur le e et le s
   de Réglages », ce qui ressemble à un défaut d'affichage tant qu'on ne sait
   pas ce que ça veut dire. Un signe qui demande d'être expliqué n'indique rien.
   Le fondu reste, mais derrière le triangle : il adoucit la rencontre du texte
   et du signe au lieu de la trancher.

   ⚠️ **`position: sticky` sur le pseudo-élément, jamais `mask-image` sur la
   barre.** Un masque aurait rendu la barre TRANSPARENTE à cet endroit : elle
   est collante, donc le contenu qui défile dessous serait apparu au travers.
   Ici tout est peint par-dessus un fond qui reste opaque.

   ⚠️ **Il s'efface en fin de course, et c'est `animation-timeline` qui le
   fait** — pas un script, que cette page s'interdit. Thierry l'a demandé après
   l'avoir vu rester au bout de la barre : un indice qui annonce une suite qui
   n'existe pas est pire que pas d'indice.

   ⚠️ **Et le support inégal n'est pas un obstacle ICI.** Un navigateur qui
   ignore `animation-timeline` laisse simplement le triangle affiché en
   permanence — l'état d'avant, gênant mais utilisable. C'est le même critère
   qui a fini par autoriser `:has()` en surcouche : *une dégradation douce se
   juge sur ce qu'elle laisse, jamais sur le taux de support.* ⚠️ Ce
   paragraphe s'en servait pour écarter `:has()` en bloc — à tort, et le prix
   en a été payé : la règle était bonne, c'est la conclusion qui était trop
   large. Ce qu'elle interdit est de bâtir SUR `:has()`, pas de s'en servir
   au-dessus de ce qui tient déjà. */
.barre::after { content: "▸"; color: var(--accent); font-size: 1rem;
                position: sticky; right: 0; flex: 0 0 1.9rem;
                display: flex; align-items: center; justify-content: flex-end;
                padding-right: .45rem; pointer-events: none;
                background: linear-gradient(to right, transparent, var(--fond) 55%); }

/* ⚠️ `scroll(nearest inline)` désigne LA BARRE elle-même : c'est le conteneur
   de défilement le plus proche du pseudo-élément. La plage part de 60 px avant
   la fin plutôt que d'un pourcentage — une barre courte et une barre longue
   doivent s'éteindre sur la même distance, pas sur la même fraction. */
/* Le pendant gauche, demandé par Thierry le 27/08/2026 une fois le droit
   éprouvé sur son téléphone. Même signe, même fondu, sens inverse.

   ⚠️ **Marge négative ici, et surtout PAS sur le triangle droit.** Le gauche
   est invisible au repos, et sans elle il pousserait « Quel mode ? » vers la
   droite en permanence — un espace vide au bord d'une barre déjà trop étroite.
   Le droit, lui, a besoin de sa largeur réelle : c'est elle qui le pose sur du
   fond en fin de course.

   ⚠️ **-2,65 rem est une valeur MESURÉE, pas la largeur du pseudo-élément.**
   À -1,9 rem — sa largeur exacte — il restait 12 px de décalage, le `gap` de la
   barre et le rembourrage du premier lien s'y ajoutant. Le contrôle est la
   position du « Q » de « Quel mode ? », relevée avec et sans le pseudo-élément :
   x = 11 dans les deux cas.

   ⚠️ **Il est éteint par défaut, et le droit ne l'est pas.** Sans
   `animation-timeline`, aucune animation ne le rallume : on perd l'indice
   gauche, ce qui est honnête. L'allumer par défaut aurait affiché, sur ces
   navigateurs-là, une flèche vers la gauche alors qu'on est déjà tout à
   gauche — un indice faux est pire qu'un indice absent. */
.barre::before { content: "◂"; color: var(--accent); font-size: 1rem;
                 position: sticky; left: 0; flex: 0 0 1.9rem;
                 margin-right: -2.65rem; opacity: 0;
                 display: flex; align-items: center; justify-content: flex-start;
                 padding-left: .45rem; pointer-events: none;
                 background: linear-gradient(to left, transparent, var(--fond) 55%); }

@supports (animation-timeline: scroll()) {
  .barre::after { animation: effacer-indice linear both;
                  animation-timeline: scroll(nearest inline);
                  animation-range: calc(100% - 60px) calc(100% - 8px); }
  @keyframes effacer-indice { to { opacity: 0; } }
  /* Le miroir : il s'allume sur les 60 premiers pixels de la course. */
  .barre::before { animation: montrer-indice linear both;
                   animation-timeline: scroll(nearest inline);
                   animation-range: 8px 60px; }
  @keyframes montrer-indice { from { opacity: 0; } to { opacity: 1; } }
}

/* L'ordre à l'écran, indépendant de celui du HTML. */
#modes { order: 1; }
#cle-api { order: 2; }
#mode-pont { order: 3; }
#reglages { order: 4; }
#telecommande { order: 5; }

.panneau { display: none; }
/* Rien n'est ciblé : on montre le panneau par défaut. */
.defaut { display: block; }
/* Un panneau ciblé apparaît et fait disparaître le panneau par défaut — qui est
   écrit après lui, seul cas où `~` le rejoint. Cibler le panneau par défaut
   lui-même ne déclenche donc rien, et il reste affiché : c'est voulu. */
.panneau:target { display: block; }
.panneau:target ~ .defaut { display: none; }

/* ── Le mode pont se cache ─────────────────────────────────────────────────
   Depuis la 5.0.0.0 (28/09/2026), tout ce qui parle du mode pont porte la
   classe `pont` : le panneau entier, son onglet, la comparaison des deux
   modes, et chaque phrase isolée dans les autres panneaux. Rien de tout cela
   n'est affiché tant que `<html>` ne porte pas `pont-devoile` — c'est
   l'application qui la pose quand le conducteur a dit le code de sécurité, et
   le pont quand la page est demandée avec `?pont=1`. La classe `sans-pont`
   fait l'inverse : ce qu'on lit à la place, quand le pont est caché.

   ⚠️ `!important`, et c'est nécessaire : `.panneau:target` rend le panneau
   du pont visible dès qu'un lien le vise, et cette règle-ci doit l'emporter
   quel que soit le lien. Un `/aide#mode-pont` reçu par quelqu'un qui n'a pas
   le pont ne doit rien montrer — ni le panneau, ni une page vide : les deux
   lignes du dessous rendent alors le panneau par défaut, que `:target` aurait
   éteint. */
html:not(.pont-devoile) .pont { display: none !important; }
html.pont-devoile .sans-pont { display: none !important; }
/* LM Studio, dévoilé par le second code de sécurité (« W9GFO ») : caché tant
   que `<html>` ne porte pas `lmstudio-devoile`, que l'application pose seule.
   `sans-lmstudio` porte ce qu'on lit à la place — « xAI ou Groq ».
   ⚠️ La météo mesurée n'est plus cachée depuis la 5.14.0.0 (09/10/2026) :
   elle partageait ce mécanisme jusque-là. */
html:not(.lmstudio-devoile) .lmstudio { display: none !important; }
html.lmstudio-devoile .sans-lmstudio { display: none !important; }
html:not(.pont-devoile) #mode-pont:target ~ .defaut { display: block; }
html:not(.pont-devoile) #mode-pont:has(:target) ~ .defaut { display: block; }

/* Même logique pour l'onglet allumé : défaut, puis extinction dès qu'un
   panneau est ciblé, puis rallumage du bon. L'ordre compte. */
.barre a[href="#modes"] { color: var(--texte); border-bottom-color: var(--accent); }
.panneau:target ~ .barre a { color: var(--doux); border-bottom-color: transparent; }
/* ── Ce qui tenait ici : les ancres-relais ───────────────────────────────────
   ⚠️ **Elles ont été retirées le 16/09/2026, et leur histoire dit pourquoi une
   règle se relit le jour où sa contrainte tombe.** Huit `<span>` de hauteur
   nulle vivaient AVANT les panneaux, avec chacun un `order: -1` qui remontait
   sa section en tête du panneau : c'était, disait ce commentaire, « le seul
   moyen, sans `:has()` ni script, de viser une section depuis l'extérieur ».
   C'était vrai le 26/08/2026.

   Ce n'était plus vrai le 16/09/2026 au matin, quand `.panneau:has(:target)`
   est entré dans cette feuille — il ouvre le panneau qui CONTIENT la cible, et
   le navigateur y défile tout seul, sans rien déplacer. Le relais est resté
   douze heures de plus, et c'est Thierry qui l'a vu à l'écran : arrivé depuis
   l'application sur « Obtenir une clé OpenAI », le titre de l'onglet et le
   sommaire étaient passés 1 150 px plus bas. *Un contournement survit à ce
   qu'il contournait, et il a l'air d'une règle.*

   ⚠️ **Le coût ne se voyait pas non plus dans la feuille.** Chaque section
   visée portait DEUX ancres — le relais pour l'application, un doublon
   `id=…-titre` pour le sommaire, posé exprès pour ne pas déclencher le
   réordonnancement. Une seule ancre les remplace, et `h3[id]` porte déjà la
   marge collante. */


#modes:target ~ .barre a[href="#modes"],
#cle-api:target ~ .barre a[href="#cle-api"],
#mode-pont:target ~ .barre a[href="#mode-pont"],
#reglages:target ~ .barre a[href="#reglages"],
#telecommande:target ~ .barre a[href="#telecommande"] {
  color: var(--texte); border-bottom-color: var(--accent);
}

/* ── Le panneau qui CONTIENT la cible ────────────────────────────────────────
   ⚠️ **Sans ces quatre blocs, tout sommaire d'onglet est mort.** Les règles
   ci-dessus n'allument qu'un panneau **ciblé lui-même** ; or cliquer un lien de
   sommaire désigne un `h3` *à l'intérieur* du panneau, qui cesse alors d'être
   la cible — il disparaît, et le panneau par défaut reprend la place. Mesuré au
   banc Chrome le 16/09/2026 : les onze liens du sommaire de l'onglet
   « Réglages » rendaient `PANNEAU=modes`, et les trois autres onglets à
   sommaire faisaient de même. *Le défaut du 26/08/2026 encore, mais vu du
   dedans : il ne touchait plus un lien, il touchait chaque sommaire de la
   page.*

   `:has()` est ce qui manquait, et l'en-tête de cette feuille l'écartait au nom
   d'un « support inégal » qui n'a plus cours — la sélection est disponible
   partout depuis décembre 2023, bien au-delà du `minSdk 31` du produit.

   ⚠️ **Ces règles sont écrites À PART, et jamais fondues dans celles du
   dessus.** Un navigateur qui ignore `:has()` jette le sélecteur entier : les
   grouper ferait tomber avec elles le `:target` qui, lui, fonctionne partout.
   Séparées, un tel navigateur retrouve exactement le comportement d'avant —
   les onglets marchent, les sommaires non — au lieu de perdre les deux. */
.panneau:has(:target) { display: block; }
.panneau:has(:target) ~ .defaut { display: none; }
.panneau:has(:target) ~ .barre a { color: var(--doux); border-bottom-color: transparent; }
#modes:has(:target) ~ .barre a[href="#modes"],
#cle-api:has(:target) ~ .barre a[href="#cle-api"],
#mode-pont:has(:target) ~ .barre a[href="#mode-pont"],
#reglages:has(:target) ~ .barre a[href="#reglages"],
#telecommande:has(:target) ~ .barre a[href="#telecommande"] {
  color: var(--texte); border-bottom-color: var(--accent);
}

/* --- Le sommaire de chaque onglet -------------------------------------- */
/* ⚠️ Il ne vise que des titres de **son propre** panneau, et c'est ce qui le
   rend possible sans JavaScript : ses liens ne sont cliquables que lorsque le
   panneau est affiché. Viser une section d'un autre onglet exigerait de
   l'ouvrir en même temps, ce que `:target` seul ne sait pas faire. */
.sommaire { display: grid; gap: .1rem .9rem;
            grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
            background: var(--carte); border: 1px solid var(--trait);
            border-radius: .6rem; padding: .8rem 1rem; margin: 0 0 1.4rem; }
.sommaire a { color: var(--doux); text-decoration: none;
              font-size: .88rem; padding: .28rem 0; }
.sommaire a:hover { color: var(--accent); }
/* L'entrée que le retour d'un bloc vient de désigner.

   ⚠️ **Une seule règle, là où l'arrivée par le sommaire en demande
   soixante-deux** : ici le lien EST la cible, donc il n'y a rien à corréler.
   C'est tout l'intérêt d'avoir fait viser au retour son entrée plutôt que le
   panneau — voir « Le retour au sommaire éteignait l'entrée », 17/09/2026.

   ⚠️ **`scroll-margin-top` est mesuré, pas choisi.** À 4 rem — la valeur du
   reste de la page — l'entrée arrivait juste sous la barre et le haut du
   sommaire était coupé : on revenait « au sommaire » sans le voir. À 26 rem,
   l'inverse : sommaire entier pour les entrées basses, et un vide au-dessus
   pour les hautes. 12 rem tenait les deux cas.

   ⚠️ **18 rem depuis le 17/09/2026, et c'est l'application qui l'a montré.**
   Thierry, lisant l'aide embarquée sur son S21 : « il n'y a pas assez de marge
   en haut pour "retour au sommaire". Il faudrait 3 lignes de marge
   supplémentaire. » Une entrée de sommaire occupe 2 rem — `.88rem` de texte,
   `.28rem` de marge haute et basse, `.1rem` de gouttière —, donc trois lignes
   valent 6 rem, et 12 + 6 = 18. *La valeur n'est pas arrondie au hasard : elle
   est la traduction du geste demandé.*

   ⚠️ **AUCUNE unité de viewport ici, et c'est une contrainte dure.** La règle
   s'est longtemps écrite `min(18rem, 40vh)`, le second terme bornant la marge à
   40 % de la hauteur pour protéger les écrans courts. Elle fonctionnait en
   ligne et **ne s'appliquait pas du tout dans l'application** : mesuré le
   17/09/2026 par le débogage de la WebView, `40vh` y rend `0px`, `50vw` aussi,
   et `@media (min-height: 1px)` y est FAUX — pendant que `innerHeight` vaut 813
   et que les media queries de largeur fonctionnent. Une valeur invalide fait
   tomber sa déclaration, pas la règle : la couleur s'appliquait, la marge non.

   ⚠️ **Le symptôme trompait sur la cause.** À l'écran, cela ressemblait à « la
   marge est trop petite » — c'est ainsi qu'elle a été signalée — et la régler de
   12 à 18 rem n'a rien changé, ni la première fois ni la seconde. *Une valeur
   jamais appliquée n'est pas une valeur trop petite, et deux réglages sans effet
   sont un signal, pas une malchance.*

   ⚠️ **18 rem tient seul les écrans courts**, et c'est mesuré : en paysage sur
   un téléphone — 412 px de haut — l'entrée se pose à 288 px, soit aux sept
   dixièmes du pli, donc à l'écran. Le garde-fou de `min()` ne servait que
   au-delà de ce que les écrans réels font. */
.sommaire a:target { color: var(--accent); scroll-margin-top: 18rem; }

/* --- L'entrée du sommaire qui désigne la section en cours --------------- */
/*
   Demandé par Thierry le 17/09/2026 : « sur la politique de confidentialité,
   quand je clique sur "Votre voix" dans le sommaire, le lien est de couleur
   quand il a été sélectionné. Je veux ce comportement sur toutes les pages de
   l'aide où il y a un sommaire. »

   ⚠️ **Rien ne le faisait nulle part, pas même sur la page qui l'a inspiré.**
   Relevé au banc Chrome, clic de souris compris — couleur calculée du lien
   avant et après : `rgb(154, 160, 170)` les deux fois, la couleur de repos.
   Ce qui colore à l'écran vient donc du navigateur et non d'ici, et cela ne
   survit ni à un clic ailleurs, ni au navigateur d'à côté. La règle ci-dessous
   le rend VOULU : même comportement sur les douze pages, quel que soit le
   navigateur. *Un comportement qu'on n'a pas écrit n'est pas un comportement
   qu'on garde.*

   ⚠️ **Une ligne par ancre, et c'est inévitable.** En CSS, rien ne relie le
   `href` d'un lien à l'`id` d'un titre : `:has()` sait remonter jusqu'à
   l'ancêtre qui contient la cible, l'attribut sait désigner le lien, et la
   corrélation entre les deux s'écrit à la main. Les quatre langues d'une même
   page portant exactement les mêmes ancres, une seule liste les sert toutes —
   et une seule liste sert aussi les trois familles, un `href` n'existant que
   dans la page qui le porte.

   ⚠️ **Dégradation douce, comme les autres règles `:has()` de cette feuille** :
   un navigateur qui l'ignore ne colore rien, ce qui est exactement l'état
   d'avant. Rien de ce qui fonctionne aujourd'hui ne repose dessus.

   ⚠️ **Le mode d'échec est l'oubli, pas l'erreur** : une section ajoutée demain
   aura son lien et sa cible, passera `essai_ancres.py` et `essai_sommaires.py`,
   et n'aura pas sa ligne ici — elle serait la seule entrée muette d'un sommaire
   où toutes les autres répondent. Le cinquième contrôle d'`essai_ancres.py`
   compare cette liste aux sommaires des douze pages, **dans les deux sens** :
   il signale l'ancre oubliée comme la ligne devenue vestige.
*/
main:has(#abonnement-api:target) .sommaire a[href="#abonnement-api"],
main:has(#alarmes:target) .sommaire a[href="#alarmes"],
main:has(#appairer:target) .sommaire a[href="#appairer"],
main:has(#appeler-et-aller:target) .sommaire a[href="#appeler-et-aller"],
main:has(#appeler-un-contact:target) .sommaire a[href="#appeler-un-contact"],
main:has(#apprendre:target) .sommaire a[href="#apprendre"],
main:has(#assistant:target) .sommaire a[href="#assistant"],
main:has(#autres-reglages:target) .sommaire a[href="#autres-reglages"],
main:has(#bases:target) .sommaire a[href="#bases"],
main:has(#chemin-accessibilite:target) .sommaire a[href="#chemin-accessibilite"],
main:has(#choisir-modele:target) .sommaire a[href="#choisir-modele"],
main:has(#cle:target) .sommaire a[href="#cle"],
main:has(#cle-google:target) .sommaire a[href="#cle-google"],
main:has(#cle-groq:target) .sommaire a[href="#cle-groq"],
main:has(#cle-mistral:target) .sommaire a[href="#cle-mistral"],
main:has(#cle-openai:target) .sommaire a[href="#cle-openai"],
main:has(#cle-xai:target) .sommaire a[href="#cle-xai"],
main:has(#commutation:target) .sommaire a[href="#commutation"],
main:has(#api-a-la-voix:target) .sommaire a[href="#api-a-la-voix"],
main:has(#compte:target) .sommaire a[href="#compte"],
main:has(#consolidation:target) .sommaire a[href="#consolidation"],
main:has(#contacts:target) .sommaire a[href="#contacts"],
main:has(#copier:target) .sommaire a[href="#copier"],
main:has(#meteo:target) .sommaire a[href="#meteo"],
main:has(#couper-recherche:target) .sommaire a[href="#couper-recherche"],
main:has(#cout:target) .sommaire a[href="#cout"],
main:has(#crediter:target) .sommaire a[href="#crediter"],
main:has(#creer-cle:target) .sommaire a[href="#creer-cle"],
main:has(#depannage-bouton:target) .sommaire a[href="#depannage-bouton"],
main:has(#depannage-cle:target) .sommaire a[href="#depannage-cle"],
main:has(#donnees:target) .sommaire a[href="#donnees"],
main:has(#droits:target) .sommaire a[href="#droits"],
main:has(#editeur:target) .sommaire a[href="#editeur"],
main:has(#garanties:target) .sommaire a[href="#garanties"],
main:has(#hors-ue:target) .sommaire a[href="#hors-ue"],
main:has(#interdits:target) .sommaire a[href="#interdits"],
main:has(#jauge:target) .sommaire a[href="#jauge"],
main:has(#journal:target) .sommaire a[href="#journal"],
main:has(#langue-titre:target) .sommaire a[href="#langue-titre"],
main:has(#langues:target) .sommaire a[href="#langues"],
main:has(#limite:target) .sommaire a[href="#limite"],
main:has(#litiges:target) .sommaire a[href="#litiges"],
main:has(#marques:target) .sommaire a[href="#marques"],
main:has(#mineurs:target) .sommaire a[href="#mineurs"],
main:has(#modifications:target) .sommaire a[href="#modifications"],
main:has(#notifications:target) .sommaire a[href="#notifications"],
main:has(#objet:target) .sommaire a[href="#objet"],
main:has(#play:target) .sommaire a[href="#play"],
main:has(#pont:target) .sommaire a[href="#pont"],
main:has(#position:target) .sommaire a[href="#position"],
main:has(#prerequis:target) .sommaire a[href="#prerequis"],
main:has(#quelle-api:target) .sommaire a[href="#quelle-api"],
main:has(#reflexion:target) .sommaire a[href="#reflexion"],
main:has(#responsabilite:target) .sommaire a[href="#responsabilite"],
main:has(#reflexion-cout:target) .sommaire a[href="#reflexion-cout"],
main:has(#reflexion-modele:target) .sommaire a[href="#reflexion-modele"],
main:has(#reflexion-quand:target) .sommaire a[href="#reflexion-quand"],
main:has(#reponses:target) .sommaire a[href="#reponses"],
main:has(#responsable:target) .sommaire a[href="#responsable"],
main:has(#resume:target) .sommaire a[href="#resume"],
main:has(#retractation:target) .sommaire a[href="#retractation"],
main:has(#rien:target) .sommaire a[href="#rien"],
main:has(#saisir-cle:target) .sommaire a[href="#saisir-cle"],
main:has(#securite-cle:target) .sommaire a[href="#securite-cle"],
main:has(#serveur-local:target) .sommaire a[href="#serveur-local"],
main:has(#sms:target) .sommaire a[href="#sms"],
main:has(#suppression:target) .sommaire a[href="#suppression"],
main:has(#telephone:target) .sommaire a[href="#telephone"],
main:has(#texte:target) .sommaire a[href="#texte"],
main:has(#vendu:target) .sommaire a[href="#vendu"],
main:has(#verifier-bouton:target) .sommaire a[href="#verifier-bouton"],
main:has(#micro:target) .sommaire a[href="#micro"],
main:has(#voix:target) .sommaire a[href="#voix"],
main:has(#volant:target) .sommaire a[href="#volant"] {
  color: var(--accent); }

/* Le retour au sommaire, à la fin de chaque bloc qu'un sommaire désigne.
   Demandé par Thierry le 17/09/2026 : arrivé sur un bloc par le sommaire, on
   n'avait pour en repartir que le défilement — la remontée n'existait qu'une
   fois par onglet, tout en bas. ⚠️ **Il vise le PANNEAU dans `/aide`**, jamais
   un titre ni la barre : voir « "Revenir au sommaire" ramenait ailleurs ». Sur
   les deux pages juridiques, qui n'ont pas d'onglets, il vise le sommaire
   lui-même — d'où son `id`, posé ce jour-là. */
.remonter { margin-top: 2rem; text-align: right; }
.remonter a { color: var(--doux); text-decoration: none; font-size: .85rem; }
.remonter a:hover { color: var(--accent); }
/* ⚠️ Deux remontées se suivent en bas des pages juridiques — le sommaire, puis
   l'aide. Sans cette règle, les 2 rem de la seconde creusent un vide au milieu
   duquel on ne sait plus si la page est finie. */
.remonter + .remonter { margin-top: .25rem; }

/* Les commandes à recopier. ⚠️ `overflow-x` plutôt qu'un retour à la ligne :
   une commande coupée en deux se recopie de travers, et sur un téléphone
   c'est toute la page qui se mettrait à défiler latéralement. */
pre { background: var(--fond); border: 1px solid var(--trait);
      border-radius: .5rem; padding: .7rem .8rem; margin: .8rem 0;
      overflow-x: auto; }
pre code { background: none; border: none; padding: 0;
           font-size: .82rem; line-height: 1.6; white-space: pre;
           overflow-wrap: normal; }
/* Ce qu'il faut remplacer par sa propre valeur, en évidence. */
pre code em { color: var(--accent); font-style: normal; }

.mention { margin-top: 2.5rem; }

/* Sur un téléphone, un tableau à trois colonnes se retrouve à une poignée de
   caractères par ligne. Quelques dixièmes de rem gagnés sur la police et les
   marges suffisent à le rendre lisible sans le transformer en liste. */
@media (max-width: 30rem) {
  table { font-size: .82rem; }
  th, td { padding: .4rem .45rem; }
  /* ⚠️ **Et le tableau défile pour lui seul, plutôt que d'élargir la page.**
     C'est la règle écrite plus haut pour `pre` — « sur un téléphone c'est
     toute la page qui se mettrait à défiler latéralement » — qui n'avait
     jamais été appliquée ici. Le tableau des coûts fait 401 px ; sur un écran
     de 360, il portait le document à 417, et **la WebView de l'application
     réagit en dézoomant toute la page à 80 %**. Résultat : l'onglet « Mode
     API » s'affichait en caractères plus petits que les autres, sur le même
     fichier. Signalé par Thierry le 17/09/2026 — *« l'utilisateur doit avoir
     des pages d'aide uniformes en taille de caractères »*.

     ⚠️ **Le défilement plutôt qu'une police encore plus petite** : réduire de
     10 % suffirait en français et pas en allemand, dont les en-têtes sont plus
     longs. Une valeur qui tient dans une langue et pas dans une autre n'est
     pas un réglage, c'est un pari.

     ⚠️ **Et surtout pas `width: max-content`.** Essayé d'abord, mesuré
     aussitôt : il interdit aux cellules de replier leur texte, et le tableau
     comparatif des trois fournisseurs est passé de 345 à **2835 px** — le
     remède pire que le mal, sur le tableau d'à côté. La largeur reste donc
     celle du conteneur, et c'est le contenu qui défile à l'intérieur. */
  table { display: block; overflow-x: auto; }
  /* De quoi faire tenir les quatre onglets sur une ligne d'écran de téléphone. */
  .barre a { font-size: .84rem; padding: .6rem .5rem; }
}

/* --- Le pied de page commun, rendu par version.py ----------------------- */
/* Mentions légales et version, discrètes : on les consulte, on ne les lit pas.
   ⚠️ La page vocale a déjà un <footer>, celui des boutons — d'où la classe,
   qui ne vise que celui-ci. */
.pied { color:var(--doux); font-size:.72rem; line-height:1.5; text-align:center;
        margin-top:2.5rem; padding-top:1rem; border-top:1px solid var(--trait);
        display:block; }
.pied p { margin:.35rem 0; }

/* --- L'adresse de contact, absente du HTML ------------------------------ */
/* Demandé par Thierry le 07/09/2026 : l'adresse doit se lire à l'écran sans
   figurer en clair dans la source, que les moissonneurs d'adresses lisent.
   Elle est donc composée ICI, et le HTML ne porte qu'un `<span>` vide.

   ⚠️ **Deux morceaux et une arobase échappée**, de sorte qu'aucune arobase
   littérale n'apparaisse nulle part — ni dans la page, ni dans cette feuille.
   Une expression régulière qui cherche une adresse ne trouve rien dans l'une
   comme dans l'autre. ⚠️ Et le premier jet de ce commentaire portait
   l'exemple du motif, arobase comprise : il se serait fait ramasser par ce
   dont il parlait.

   ⚠️ **Pas de JavaScript, et ce n'est pas un choix de style** : cette page
   s'en interdit comme toute l'aide, et le CSP du vhost — `script-src 'self'`,
   les blocs inline autorisés par empreinte seulement — ne laisserait pas
   passer un script écrit ici. La voie CSS est la seule qui reste.

   ⚠️ **Le prix est réel et il faut le connaître** : un contenu généré ne se
   sélectionne pas à la souris et ne peut pas porter un lien `mailto:`. Le
   lecteur lit l'adresse et la recopie. C'est la contrepartie exacte de ce qui
   est demandé — une adresse cliquable est une adresse en clair.

   ⚠️ **Chaînes séparées plutôt qu'une seule** : en CSS, un échappement
   hexadécimal avale jusqu'à six chiffres, et « \0040tbnetsys » serait ambigu à
   la lecture. Les couper lève le doute sans rien coûter. */
.courriel { font-weight: 600; overflow-wrap: anywhere; }
.courriel::before { content: "contact"; }
.courriel::after  { content: "\0040" "tbnetsys" "\002E" "fr"; }

/* --- Le sélecteur de langue des deux pages publiques -------------------- */
/*
   Posé le 08/09/2026, avec les trois langues. Il est sous le titre, avant le
   chapeau : quelqu'un qui ouvre la page dans une langue qu'il ne lit pas doit
   trouver la sienne sans avoir à parcourir l'écran.

   ⚠️ Chaque langue est écrite DANS SA PROPRE LANGUE — « Français », « English »,
   « Español » — et jamais traduite. C'est la même règle que dans l'application :
   traduits, ces trois mots cesseraient de servir précisément au moment où ils
   servent.

   ⚠️ Des liens, pas un menu déroulant : la page n'a aucun JavaScript, et c'est
   ce qui la rend lisible partout. Le `?l=` emporte la langue, le fragment
   d'ancre survit.
*/
.langues { display: flex; flex-wrap: wrap; gap: .9rem;
           margin: -.4rem 0 1.2rem; font-size: .9rem; }
.langues a { color: var(--doux); text-decoration: none;
             border-bottom: 1px solid transparent; }
.langues a:hover { color: var(--accent); }
/* La langue courante ne se clique pas : elle se montre. Un lien qui ne mène
   nulle part fait douter du reste de la page. */
.langues span { color: var(--texte); font-weight: 600;
                border-bottom: 2px solid var(--accent); }
