/* --- 1. Les sections respirent -----------------------------------------
   18 px aujourd'hui, contre 64 valides sur le parcours. Le meme jeton, pour
   que les deux pages aient le meme rythme : deux ecrans du meme produit qui
   respirent differemment se lisent comme deux produits.
   ------------------------------------------------------------------------ */
.admin-dashboard {
    display: flex;
    flex-direction: column; 
    gap: var(--espace-section);
}


/* --- 1 bis. LE CONTENEUR SEUL DECIDE DE L ESPACE ENTRE SES BLOCS ---------

   CE QUI NE MARCHAIT PAS, ET QUI SE MESURE. La regle ci-dessus fait de
   `.admin-dashboard` une colonne flex espacee par `gap`. Mais `lk.css` donne
   en plus `margin-bottom: 20px` a toute `.card`. Les deux s'ADDITIONNENT : un
   enfant direct qui porte `.card` se detache de 60 px, un enfant qui ne la
   porte pas de 40. Sur une meme page, l'espacement depend donc de la classe
   de l'enfant, et pas du rythme qu'on a choisi.

   MESURE DU 16/10/2026, marge basse des enfants directs de `.admin-dashboard` :
   `/partner`, `/admin`, `/partner/journey` -> tous a 0, l'espacement est juste ;
   `/partner/clients` -> 20, 20, 20, puis 0, 0 ;
   `/admin/users/1/materials` et `/partner/clients/{id}/materials` -> 20, 20, 20 ;
   `/partner/store` -> 20 puis 0, 0, 0 ;
   `/admin/settings` -> 0 puis 20, 20.

   Les pages qui tombaient juste sont EXACTEMENT celles dont les enfants
   n'etaient pas des cartes. C'est donc le `gap` qui a raison, et la marge qui
   est le reste d'une epoque ou ces blocs se posaient dans le flux.

   ON NE RETIRE PAS `margin-bottom` DE `.card`. La carte sert aussi hors de ce
   conteneur, posee dans le flux, ou sa marge est le seul espacement qu'elle
   ait. On la neutralise LA OU un `gap` la double, et nulle part ailleurs.

   HAUT ET BAS, parce que le defaut se presentait des deux cotes. Trois pages
   portaient en plus une `margin-top` sur un enfant direct, et elle doublait le
   `gap` exactement pareil : `/partner/journey` a 80 px, `/partner/clients` a 80
   puis 60. Ces trois declarations sont retirees a leur source le meme jour
   (`journey.css`, `base/pages/prat-clients.css`) : elles pesaient autant ou plus
   que cette regle, dans des feuilles chargees apres, donc les couvrir d'ici
   n'aurait pas marche. `margin-block` tient le cas general, le retrait tient
   les trois cas reels.

   LA CASCADE TIENT PAR L ORDRE, ET IL FAUT LE SAVOIR. `.admin-dashboard > *`
   et `.card` pesent le meme poids (0,1,0) : c'est la derniere ecrite qui
   gagne. Cette feuille est chargee APRES `lk.css` dans `layouts/app.blade.php`,
   et aucune des peaux chargees apres elle ne touche a la marge basse de
   `.card` (seul `base/profil-essai.css` le fait, pour `.grid-2 > .card`, un
   autre conteneur). Deplacer cette feuille avant `lk.css` reveillerait le
   defaut sans rien casser d'autre, donc sans bruit.
   ------------------------------------------------------------------------ */
.admin-dashboard > * {
    margin-block: 0;
}


/* --- 1 ter. UNE BOITE A MESSAGE VIDE NE PREND PAS DE PLACE ---------------

   `#ajax-message` attend le compte rendu d'une suppression en Ajax, sur les
   pages des programmes (`admin/materials/index` et `partner/materials/index`).
   Vide, elle mesure 0 px de haut. Mais elle reste un enfant du conteneur
   flex, et consomme donc un `gap` ENTIER : mesure du 16/10/2026, 40 px de vide
   entre l'entete et la barre d'actions, pour une boite sans contenu.

   `:empty` suit exactement l'etat de la boite : le script y ecrit par
   `innerHTML`, puis la vide par `innerHTML = ''` au bout de quatre secondes.
   Le message apparait donc a sa place, et l'espace se referme avec lui.
   ------------------------------------------------------------------------ */
#ajax-message:empty {
    display: none;
}

.admin-dashboard__hero {
    display: flex;
    justify-content: space-between;
    gap: 20px;
    align-items: flex-start;
}

.admin-dashboard__hero-main {
    min-width: 0;
}

.admin-dashboard__hero-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 18px;
    margin-top: 12px;
    font-size: 13px;
    line-height: 1.4;
    color: rgba(var(--white-rgb), 0.74);
}

.admin-dashboard__hero-stats span {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    white-space: nowrap;
}

.admin-dashboard__hero-stats strong {
    color: rgba(var(--white-rgb), 0.96);
    font-weight: 800;
}

/*
 * `admin-eyebrow` REJOINT LA REGLE PLUTOT QUE D'EN AVOIR UNE A ELLE.
 *
 * Quinze gabarits posaient ce surtitre sans qu'aucune feuille ne lui reponde :
 * quinze ecrans affichaient leur surtitre sans mise en forme. La tentation
 * serait d'ecrire une regle pour lui ; ce serait un QUATRIEME traitement de
 * surtitre, alors que le produit en compte deja trois et que le troisieme n'a
 * jamais ete decide. On le rattache donc au canonique.
 */
.admin-eyebrow,
.admin-dashboard__eyebrow {
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    opacity: 0.7;
    margin-bottom: 8px;
}

.admin-dashboard__title {
    margin: 0 0 10px;
}

.admin-dashboard__text {
    margin: 0;
    max-width: 760px;
    opacity: 0.9;
}

.admin-dashboard__hero-actions {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.admin-dashboard__stats {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 16px;
}

.admin-stat {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.admin-stat__label {
    font-size: 13px;
    opacity: 0.72;
}

.admin-stat__value {
    font-size: 32px;
    font-weight: 700;
    line-height: 1;
}

.admin-stat__note {
    font-size: 12px;
    opacity: 0.7;
}

.admin-dashboard__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 16px;
    align-items: stretch;
}

.admin-dashboard__card {
    display: flex;
    flex-direction: column;
    gap: 12px;
    text-decoration: none;
    color: inherit;
    transition: transform 0.18s ease, box-shadow 0.18s ease;
}

.admin-dashboard__card:hover {
    transform: translateY(-2px);
}

.admin-dashboard__card h2 {
    margin: 0;
    font-size: 22px;
}

.admin-dashboard__card p {
    margin: 0;
    opacity: 0.88;
    line-height: 1.5;
}

.admin-dashboard__card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.admin-dashboard__icon {
    font-size: 28px;
    line-height: 1;
}

.admin-dashboard__badge {
    display: inline-flex;
    align-items: center;
    padding: 6px 10px;
    border-radius: 999px;
    font-size: 12px;
    background: rgba(var(--green-state-rgb), 0.14);
    color: var(--green-mid);
}

.admin-dashboard__badge--muted {
    background: rgba(var(--white-rgb), 0.08);
    color: inherit;
    opacity: 0.75;
}

.admin-dashboard__link {
    margin-top: auto;
    font-weight: 600;
}

.admin-dashboard__link--muted {
    opacity: 0.7;
}

.admin-dashboard__card--muted {
    opacity: 0.92;
}

.admin-dashboard__section {
    display: grid;
    grid-template-columns: 0.985fr 2.015fr;
    gap: 16px;
}

.admin-quick-actions,
.admin-latest-users {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.admin-section__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.admin-messages {
    padding: 10px 38px 10px 12px;
    border: 1px solid rgba(var(--white-rgb), 0.10);
    border-radius: 12px;
    background: rgba(25, 146, 65, 0.2);
}

.admin-section__title {
    margin: 0;
    font-size: 20px;
}

.admin-section__text {
    margin: 0;
    opacity: 0.78;
    font-size: 14px;
}

.admin-users-panel__toolbar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.admin-users-panel__search-wrap {
    position: relative;
    min-width: 220px;
    flex: 1 1 260px;
    max-width: 360px;
}

/* `input.` et non `.` seule : une classe (0,1,0) ne bat pas
   `input[type="search"]` (0,1,1) de `lk.css:396`, qui impose
   `padding: 12px 14px`. La reserve de 38 px prevue a droite pour la croix
   d'effacement n'existait donc pas, et le texte tape courait jusqu'a 14 px du
   bord, sous le bouton. Trois ecrans d'administration. */
input.admin-users-panel__search {
    width: 100%;
    padding: 10px 38px 10px 12px;
    border: 1px solid rgba(var(--white-rgb), 0.10);
    border-radius: 12px;
    background: rgba(var(--white-rgb), 0.04);
    color: inherit;
    outline: none;
}

.admin-users-panel__search:focus {
    border-color: rgba(var(--white-rgb), 0.24);
    background: rgba(var(--white-rgb), 0.06);
}

.admin-users-panel__clear {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
    width: 24px;
    height: 24px;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: inherit;
    opacity: 0.65;
    cursor: pointer;
}

.admin-users-panel__clear:hover {
    opacity: 1;
    background: rgba(var(--white-rgb), 0.08);
}

.admin-users-panel__clear.is-hidden {
    display: none;
}

.admin-users-panel__list.is-loading {
    opacity: 0.55;
    pointer-events: none;
}

/* LE TABLEAU DES DOSSIERS DEFILE DANS SON CADRE, IL NE POUSSE PAS LA PAGE.

   `.profils-locaux__table` n'a aucun repli : ni etiquettes de colonnes, ni
   bascule en cartes. A 820 px il demande 751 px pour la place qu'on lui
   laisse, et c'est la PAGE qui partait de 36 px en travers -- releve sur
   `/partner/clients`.

   `overflow-x: auto` SEUL N AURAIT RIEN FAIT : la taille minimale automatique
   d'un enfant de flex ou de grille vaut la largeur de son contenu, donc le
   cadre grandit au lieu de faire defiler. C'est `min-width: 0` qui l'autorise
   a etre plus etroit que ce qu'il contient, et le couple des deux qui rend le
   defilement. Mesure apres : 36 px -> 0.

   LE DEFILEMENT PLUTOT QUE LE REPLI, et c'est le bon choix ici : sans
   etiquettes, replier ce tableau effacerait son entete sans rien pour le
   remplacer -- la meme regle que pour les tableaux des traitements. */
.admin-users-panel__list {
    min-width: 0;
    overflow-x: auto;
}

.admin-quick-actions__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
}

.admin-quick-action {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 14px;
    border-radius: 16px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(61, 104, 153, 0.5);
    text-decoration: none;
    color: inherit;
    transition: transform 0.18s ease, background 0.18s ease, border-color 0.18s ease;
}

.admin-quick-action:hover {
    transform: translateY(-2px);
    background: rgba(61, 104, 153, 0.8);
    border-color: rgba(var(--white-rgb), 0.14);
}

.admin-quick-action__title {
    font-weight: 600;
}

.admin-quick-action__text {
    font-size: 14px;
    opacity: 0.8;
    line-height: 1.4;
}

/* L ECART ENTRE DEUX LIGNES EST CELUI DES LISTES DE LA MAISON.

   L'Admin, le 23/10/2026 : « l'espacement entre les lignes de /users,
   /clients, et sur les previews des deux dashboard. Espacement a reprendre
   je pense, celui de /clients. »

   MESURE : /clients et /users ecartent leurs lignes de 5 px, le tableau de
   bord de 10. Les deux premiers ne le decident pas eux-memes -- ils lisent
   `--liste-ecart`, pose par le socle sur `border-spacing`. Ce `10px` ecrit a
   la main etait la seule valeur qui ne suivait personne.

   LA VARIABLE PLUTOT QUE SON RESULTAT : la liste du tableau de bord est un
   flex et non un tableau, donc elle ne peut pas heriter du `border-spacing`.
   Elle lit la meme variable, ce qui revient au meme et la fait suivre le jour
   ou l'ecart des listes changera. */
.admin-latest-users__list {
    display: flex;
    flex-direction: column;
    gap: var(--liste-ecart, 5px);
}

/*
 * LA MEME LIGNE POUR « Comptes » ET « Support ».
 *
 * C'etait un rectangle gris, sans rien qui dise de quoi il s'agit, quand
 * toutes les autres listes du produit portent un rail de couleur a gauche.
 * La ligne rejoint donc cette grammaire : chaque carte apporte SA teinte par
 * `--row-rgb` et rien d'autre — le type de compte pour l'une, l'attente
 * d'une reponse pour l'autre.
 *
 * Le repli est dans le `var()` : declare a part, il pesait plus lourd que la
 * teinte que la ligne veut poser.
 */
.admin-latest-user {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;

    /* Elle se plie quand le nom n'a plus la place. Le raisonnement et la
       mesure sont sur `.admin-latest-user__main`, qui porte le seuil. */
    flex-wrap: wrap;
    padding: 12px 14px;
    border-radius: 14px;
    box-sizing: border-box;
    border: 1px solid rgba(var(--row-rgb, var(--teinte-bleue)), 0.14);
    border-left: 4px solid rgba(var(--row-rgb, var(--teinte-bleue)), 0.76);
    background: rgba(var(--row-rgb, var(--teinte-bleue)), 0.07);
    background-clip: padding-box;
    transition: background .14s ease, border-color .14s ease;
}

.admin-latest-user:hover {
    background: rgba(var(--row-rgb, var(--teinte-bleue)), 0.12);
}

/* LA LIGNE SE PLIE QUAND LE NOM N A PLUS LA PLACE, ET ELLE DECIDE SEULE.
 *
 * La colonne d'actions -- pastille de role plus trois boutons -- mesure 231 px
 * et refuse de retrecir. Le nom prenait donc ce qui restait : 50 px a 390 px de
 * large, et zero pour l'un d'eux. `text-overflow: ellipsis` faisait son travail
 * et rendait « Chak… », ce qui ne designe personne.
 *
 * PAS DE SEUIL EN PIXELS D ECRAN, parce que le defaut ne depend pas de l'ecran
 * mais de la LARGEUR DE LA LIGNE : la meme carte tombe a 329 px quand la grille
 * du tableau de bord passe a deux colonnes, en plein 780 px. Un `flex-basis` de
 * 180 px fait passer les actions a la ligne des que le nom n'a plus de quoi se
 * lire, a n'importe quelle largeur et dans n'importe quelle grille.
 *
 * 180 px : le plus long nom du releve, « Pierre Praticien (Demo) », mesure
 * 177 px. Un nom plus long reste coupe, et c'est le role de l'ellipse.
 *
 * Mesure de 360 a 1280 px, onze noms : 7 coupes sur 11 a 390 px avant, 0 sur 11
 * a toutes les largeurs apres, sans un pixel de debordement de page. */
.admin-latest-user__main {
    min-width: 0;
    flex: 1 1 180px;
}

/* LE NOM A LA TAILLE DE CELUI DE /clients, qui est la reference.

   L'Admin, le 23/10/2026 : « aligne la taille de police du nom aussi dessus ».
   Mesure : `.partner-client-name` 15 px, `.admin-user-name` 13, celui-ci 14.
   Trois tailles pour la meme chose -- le nom de la personne qu'on regarde. */
.admin-latest-user__name {
    font-size: 15px;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* L APERCU DU DERNIER MESSAGE, sur une ligne et une seule.

   L'ADMIN, LE 15/10/2026 : « ajouter les memes infos que l'onglet de gauche aux
   onglets de /partner, apercu du dernier message, date et heure ». Meme forme
   que `.support-list__extrait` dans la messagerie : le texte entier reste dans
   le document, c'est l'affichage qui coupe, et le repli a trois points est
   celui du navigateur. */
.admin-latest-user__extrait {
    margin-top: 3px;
    font-size: 13px;
    line-height: 1.35;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.78));
}

/* La seconde ligne dit un fait, pas un nom de champ : elle se lit donc en
   retrait, sans reclamer l'attention du nom au-dessus. */
.admin-latest-user__meta {
    margin-top: 3px;
    font-size: 12.5px;
    /* Une opacite se multiplie a tout voile pose ensuite ; ce retrait-la est
       une encre, il s'ecrit comme une encre. 0,62 rendait 3,22 en clair. */
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
}

/* COMMENT JOINDRE CETTE PERSONNE : LA DEUXIEME COLONNE.

   L'Admin, le 23/10/2026, en voyant les contacts empiles sous le nom : « Dans
   une autre colonne dans le "vide", 2eme ». La ligne portait un large blanc
   entre l'identite et ses trois boutons ; les contacts l'occupent, et la ligne
   reprend sa hauteur au lieu de s'allonger de deux lignes.

   ELLE NE GRANDIT PAS, ET C EST LE NOM QUI Y GAGNE. Mesure du 23/10/2026 a
   831 px de ligne : un contact de la maison occupe 115 px utiles et la colonne
   en prenait 252, parce qu'elle grandissait avec la place libre. Le nom
   derriere n'en avait plus que 272 pour 305 demandes.

   UNE BASE FIXE PLUTOT QUE LE CONTENU, parce que c'est elle qui aligne les
   lignes entre elles. A `auto`, une adresse longue elargissait sa colonne et
   decalait les trois boutons de cette ligne-la : une liste dont les colonnes
   bougent d'une ligne a l'autre ne se parcourt plus. 200 px tient
   « marie-christine.vandenbroucke-delaunay@… » coupee a son debut lisible, et
   le `1` du milieu la laisse se resserrer quand la carte devient etroite.

   L ADRESSE PEUT COUPER, LE NUMERO JAMAIS. Une adresse coupee se reconnait
   encore a son debut ; un numero coupe au milieu ne se compose pas, et il est
   court. */
.admin-latest-user__contact {
    min-width: 0;
    flex: 0 1 170px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    font-size: 12.5px;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.7));
}

/* Elle garde sa largeur meme sans rien a montrer : une colonne qui disparait
   d'une ligne a l'autre decale les boutons et la liste cesse de s'aligner. */
.admin-latest-user__contact:empty {
    min-height: 1px;
}

/* L ADRESSE SE COUPE A LA LARGEUR DE SA COLONNE, ET IL A FALLU `max-width`.

   L'ADMIN, LE 23/10/2026, capture a l'appui : « decale vers la gauche pour ne
   pas mordre sur l'email ». Son adresse,
   « newhorizonsbyflorence@gmail.com », passait SOUS la pastille de role.

   `overflow` ET `text-overflow` NE SUFFISAIENT PAS. Dans une colonne flex, un
   enfant ne descend pas sous la largeur de son contenu : l'ellipse n'avait
   aucune largeur de reference a laquelle mordre, et l'adresse sortait de ses
   170 px au lieu d'y etre coupee. `min-width: 0` autorise le retrecissement,
   `max-width: 100%` lui donne la borne.

   ET C EST POURQUOI JE NE L AVAIS PAS VU : la base locale ne porte que des
   adresses de dix-huit a vingt-six caracteres, toutes plus courtes que la
   colonne. Mesure du 23/10 en posant celle de l'Admin, trente et un
   caracteres : 13 px de recouvrement. Un defaut qu'aucune donnee d'essai
   n'atteint ne se voit qu'en production. */
.admin-latest-user__mail {
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.admin-latest-user__tel {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* La pastille de role et les pastilles d'action sur une meme ligne d'axe.

   `align-items` sur le conteneur ne suffisait pas : la pastille porte son
   propre `align-self: flex-start`, pose pour qu'elle epouse son texte dans
   les cartes du parcours. C'est donc elle qu'il faut recentrer, ici et
   nulle part ailleurs. Mesure avant : dix pixels au-dessus. */
/* LA PASTILLE DE ROLE A UNE LARGEUR FIXE, ET C EST CE QUI ALIGNE LES BOUTONS.

   L'Admin, le 23/10/2026, capture a l'appui : « ca doit etre aligne ».

   Les quatre roles n'ont pas la meme longueur -- « Admin » 45 px, « Client »
   48, « Praticien » 62, « En formation » 80 -- et la rangee etant calee a
   droite, chaque largeur de mot decalait les trois boutons d'autant. Une
   colonne qui bouge d'une ligne a l'autre ne se parcourt plus du regard.

   `min-width` ET `border-box`, PAS UNE LARGEUR NUE. Premiere ecriture :
   `width: 78px` avec le remplissage lateral retire, pour que la largeur
   annoncee soit celle occupee. Le compte tombait juste et le rendu etait
   laid -- l'Admin : « corrige le visuel du role » -- parce qu'une pastille
   est un fond arrondi et que son texte ne doit pas en toucher les bords.

   104 px EST LA PLUS LARGE DES QUATRE, remplissage compris : « En formation »
   mesure 80 px de texte et 100 avec ses marges interieures. En `min-width`,
   chacune l'atteint sans qu'aucune ne la depasse, donc l'alignement tient
   sans rien couper -- et le jour ou un role plus long arrive, il s'affiche en
   entier et c'est l'alignement qui cede, pas le mot. */
/* ELLE PREND LA TEINTE DU ROLE, ET SON MOT SE CENTRE.

   L'Admin, le 23/10/2026 : « La couleur du role et centre pour la pastille ».

   LA TEINTE EST DEJA LA, ET ELLE N A PAS A ETRE RECHOISIE : la ligne porte
   `--row-rgb` dans son attribut de style, posee par le gabarit depuis le bleu
   du client, le violet du praticien et l'or de l'administration. La pastille
   la lit, donc elle suit la meme table -- et un role ajoute demain prendra sa
   couleur sans qu'on touche a cette feuille. Un compte en formation reste
   violet, comme le praticien : c'est ce que fait deja le rail de gauche.

   `justify-content` ET NON `text-align` : `.journey-pill` est un conteneur
   FLEX, et `text-align` n'y aligne rien. C'est pour cela que le mot restait
   colle a gauche dans une pastille deux fois plus large que lui, alors que la
   regle de centrage etait bien ecrite -- et appliquee. */
/* ELLE PREND LA LARGEUR DE SON MOT, COMME CELLE DE /users.

   L'Admin, le 23/10/2026 : « Les pastilles de role ont la meme taille,
   ajuster en fonction du role, comme /users ». La-bas, `.admin-user-type`
   mesure 53 px pour « Client », 69 pour « Praticien » et 103 pour
   « Administrateur » -- la largeur de son mot, rien de plus. Une largeur
   commune de 104 px les faisait toutes paraitre vides sauf la plus longue.

   ET LES BOUTONS RESTENT ALIGNES SANS ELLE : c'est ce qu'elle servait a
   tenir, et ce n'etait pas son role. L'alignement appartient a la rangee, pas
   a son premier element -- voir la largeur fixe posee juste en dessous. */
.admin-latest-user__actions > .journey-pill {
    flex: none;
    font-size: 12px;
    padding: 2px 10px;
    justify-content: center;
    color: rgb(var(--row-rgb, 148, 163, 184));
    background: rgba(var(--row-rgb, 148, 163, 184), 0.14);
    border-color: rgba(var(--row-rgb, 148, 163, 184), 0.38);
}

.admin-latest-user__actions {
    align-items: center;
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    justify-content: flex-end;

    /* ELLES NE PRENNENT PLUS QUE LEUR LARGEUR, ET RESTENT A DROITE.

       L'Admin, le 23/10/2026 : « Laisse plus de place pour le nom, reduit la
       3eme colonne ». Mesure a 831 px de ligne : les trois boutons et leurs
       ecarts font 154 px, et cette colonne en occupait 246 -- 92 px de vide
       pris au nom, parce qu'un `flex: 1 1 auto` la faisait grandir avec la
       place disponible. « Alexandra-Beatrice Montagne-Lafayette-Dubois » en
       demandait 305 et n'en recevait que 272.

       LE `margin-left: auto` REMPLACE LA CROISSANCE, et tient la raison pour
       laquelle elle existait : une fois passees a la ligne, les actions
       restaient collees au bord gauche sous le nom, parce que le
       `space-between` de la ligne n'a plus rien a espacer quand un seul
       element occupe la rangee. Une marge automatique les pousse a droite
       dans les deux cas, pliees ou non, sans leur faire reclamer un pixel de
       plus que leur contenu. */
    /* UNE LARGEUR FIXE, ET C EST ELLE QUI ALIGNE LES BOUTONS.

       La pastille a repris sa largeur naturelle le 23/10/2026, a la demande
       de l'Admin ; elle ne peut donc plus tenir l'alignement. La rangee s'en
       charge : largeur fixe, contenu cale a droite, les trois boutons etant
       les derniers, ils tombent au meme endroit quelle que soit la pastille.

       264 px EST CE QU ELLE DEMANDE AU PIRE : 103 px pour « Administrateur »,
       154 pour les trois boutons, 8 d'ecart entre les deux.

       ET CETTE LARGEUR N APPARTIENT QU AUX RANGEES QUI LA DEMANDENT.
       L'Admin, le 28/10/2026, sur les cartes Messagerie et Support des deux
       tableaux de bord : « le bouton peut etre au niveau de texte/data, pour
       gagner de l'espace ». Ces rangees-la n'ont qu'un bouton « Ouvrir »,
       large de 70 px ; en reclamer 264 ne laissait plus de quoi tenir a cote
       du nom dans une carte de tableau de bord, qui n'occupe qu'un tiers de
       la grille. Le bouton passait donc a la ligne et s'y retrouvait seul,
       une rangee entiere pour un mot.

       LE MARQUEUR EXISTAIT DEJA DANS LE BALISAGE : les listes de comptes et
       de clients portent `ligne-actions` -- ce sont elles qui ont une
       pastille de role et trois boutons a aligner -- et les messageries non.
       La largeur fixe les suit, au lieu de s'appliquer a tout le monde. */
    flex: 0 0 auto;
    margin-left: auto;
}

/* LES RANGEES A PASTILLE GARDENT LEUR COLONNE FIXE : c'est elle qui fait
   tomber leurs trois boutons au meme endroit d'une ligne a l'autre, quelle
   que soit la longueur du role. Voir le raisonnement juste au-dessus. */
.admin-latest-user__actions.ligne-actions {
    flex: 0 0 264px;
}

.admin-latest-user__actions .journey-pill {
    align-self: center;
}

.admin-empty {
    opacity: 0.7;
}

.admin-dashboard__card-stats {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    font-size: 13px;
    opacity: 0.82;
}

@media (max-width: 1180px) {
    .admin-dashboard__stats {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .admin-dashboard__section {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 980px) {
    .admin-dashboard__hero {
        flex-direction: column;
    }

    .admin-dashboard__hero-actions {
        justify-content: flex-start;
    }

    .admin-dashboard__hero-stats span {
        white-space: normal;
    }

    .admin-dashboard__stats,
    .admin-quick-actions__grid {
        grid-template-columns: 1fr;
    }

    .admin-dashboard__grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 640px) {
    .admin-dashboard__grid {
        grid-template-columns: 1fr;
    }
}

/* `margin-bottom` RETIRE : le bloc est un enfant direct de `.admin-dashboard`,
   dont le `gap` ecarte deja de 40 px. Les deux s'ajoutaient, et `/admin/email`
   etait la seule page du produit a 60 px la ou toutes les autres sont a 40.
   Voir « 1 bis » en tete de fichier. Mesure du 16/10/2026 : cette declaration,
   ecrite PLUS BAS que `.admin-dashboard > *` et du meme poids (0,1,0), gagnait
   par l'ordre. */
.admin-email-stats {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
}

.admin-email-stat {
    padding: 18px;
    min-height: 86px;
}

.admin-email-stat__label {
    font-size: 14px;
    opacity: 0.82;
    font-weight: 700;
}

.admin-email-stat__value {
    margin-top: 6px;
    font-size: 30px;
    line-height: 1;
    font-weight: 800;
}

@media (max-width: 1180px) {
    .admin-email-stats {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 640px) {
    .admin-email-stats {
        grid-template-columns: 1fr;
    }
}

.partner-dashboard__hero {
    align-items: flex-start;
}

.partner-dashboard__hero-main {
    min-width: 0;
}

.partner-dashboard__hero-actions {
    margin-left: auto;
    padding-top: 6px;
    align-items: flex-start;
}

.partner-dashboard__stages {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 16px;
    align-items: stretch;
}

.partner-dashboard__stages .admin-dashboard__card {
    min-width: 0;
}

.partner-dashboard__stages .admin-dashboard__icon {
    font-size: 24px;
}

.partner-dashboard__stages .admin-dashboard__card h2 {
    font-size: 18px;
    line-height: 1.2;
}

.partner-dashboard__stages .admin-dashboard__card p {
    font-size: 14px;
    line-height: 1.45;
}

.partner-dashboard__body {
    display: grid;
    grid-template-columns: 0.985fr 2.015fr;
    gap: 16px;
    align-items: start;
}

.partner-dashboard__sidebar {
    display: grid;
    gap: 16px;
}

.partner-dashboard-clients {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 18px;
}

/* Le lien d'invitation sur sa ligne, le titre et ses boutons sur la
   suivante : cote a cote, le lien n'avait plus la place de s'afficher en
   entier, et un lien tronque ne se verifie pas. */
.partner-dashboard-clients__head {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 18px;
}

.partner-dashboard-clients__head-main {
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

/* Le titre annonce la liste qui le suit : il vient donc apres le lien, et
   ne pousse pas les boutons vers le bas en s'elargissant. */
.partner-dashboard-clients__head-main .admin-section__title {
    margin: 0;
    margin-right: auto;
}

.partner-dashboard-clients__copy-link-btn {
    background: rgba(19, 172, 27, 0.788);
    border: 1px solid rgba(var(--white-rgb), 0.10);
    color: rgba(var(--white-rgb), 0.88);
    white-space: nowrap;
}

.partner-dashboard-clients__copy-link-btn:hover {
    background: rgba(23, 207, 32, 0.788);
    border-color: rgba(var(--white-rgb), 0.18);
    color: var(--white);
}

.partner-dashboard-clients-layout {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(340px, 1fr);
    gap: 16px;
    align-items: start;
}

.partner-dashboard-clients__list-pane {
    min-width: 0;
    display: grid;
    gap: 12px;
    max-height: 850px;
    overflow-y: auto;
    padding-right: 6px;
}


.partner-dashboard-clients__list-pane::-webkit-scrollbar,
.partner-client-card::-webkit-scrollbar,
.partner-client-expert__scroll::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

.partner-dashboard-clients__list-pane::-webkit-scrollbar-track,
.partner-client-card::-webkit-scrollbar-track,
.partner-client-expert__scroll::-webkit-scrollbar-track {
    background: transparent;
}

.partner-dashboard-clients__list-pane::-webkit-scrollbar-button,
.partner-client-card::-webkit-scrollbar-button,
.partner-client-expert__scroll::-webkit-scrollbar-button {
    display: none;
    width: 0;
    height: 0;
}

.partner-dashboard-clients__list-pane::-webkit-scrollbar-thumb,
.partner-client-card::-webkit-scrollbar-thumb,
.partner-client-expert__scroll::-webkit-scrollbar-thumb {
    background: linear-gradient(
        180deg,
        rgba(var(--white-rgb), 0.18),
        rgba(var(--white-rgb), 0.08)
    );
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: padding-box;
}

.partner-dashboard-clients__list-pane::-webkit-scrollbar-thumb:hover,
.partner-client-card::-webkit-scrollbar-thumb:hover,
.partner-client-expert__scroll::-webkit-scrollbar-thumb:hover {
    background: linear-gradient(
        180deg,
        rgba(var(--white-rgb), 0.28),
        rgba(var(--white-rgb), 0.14)
    );
    border: 2px solid transparent;
    background-clip: padding-box;
}

.partner-dashboard-clients .table-toolbar {
    margin: 0;
}

.partner-dashboard-clients #users-table-container {
    min-width: 0;
}

.partner-dashboard-clients #users-table-container.is-loading {
    opacity: 0.55;
    pointer-events: none;
}

.partner-dashboard-notifications-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
}

.partner-dashboard-notifications-row .partner-client-notifications {
    max-width: none;
}

/* -------------------------------------------------------------------------
   LA LIGNE-CARTE : une grammaire, trois listes
   -------------------------------------------------------------------------

   Trois ecrans posent la meme forme : une liste de personnes ou chaque ligne
   se lit comme une carte horizontale, avec un rail colore a gauche, un fond
   teinte et des bouts arrondis. Elle etait ecrite deux fois, une par ecran, et
   la troisieme copie allait suivre.

   ELLE VIT DONC ICI, en une seule fois. Chaque liste apporte SA COULEUR par
   `--row-rgb` et rien d'autre : l'etape du client, le violet du parcours, le
   type de compte. C'est la seule chose qui les distingue.

   LE REPLI EST DANS LE `var()`, PAS DANS UNE REGLE. Declare sur la ligne
   generique, il pesait `.liste-carte tbody tr.liste-carte__ligne`, soit plus
   lourd que le `.admin-partner-journey-row` qui voulait le remplacer : le
   suivi des parcours repassait au bleu sans que rien ne le signale. Un repli
   ecrit dans le `var()` ne se bat contre personne.

   `--row-solide` est la variante opaque du rail, pour la ligne choisie. A
   defaut, le rail choisi reprend la meme teinte, en plein.

   EN DESSOUS DE 640 PX, la carte passe de la CELLULE a la LIGNE : empilees,
   les cellules gardaient chacune un morceau du decor, le rail sur la
   premiere et l'arrondi de droite tout en bas.
   ------------------------------------------------------------------------- */

/* L'ECARTEMENT FAIT PARTIE DE LA GRAMMAIRE, pas de chaque liste.
   Deux des trois listes le declaraient chacune de leur cote ; la troisieme,
   celle des utilisateurs, ne l'avait pas et ses lignes restaient collees, ce
   qui les faisait lire comme un tableau la ou les deux autres lisent comme
   des cartes. C'est ce qui restait de la difference entre /users et
   /clients. */
.liste-carte {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0 10px;
}

.liste-carte tbody tr.liste-carte__ligne td {
    background: rgba(var(--row-rgb, var(--teinte-bleue)), 0.09);
    border-top: 1px solid rgba(var(--row-rgb, var(--teinte-bleue)), 0.14);
    border-bottom: 1px solid rgba(var(--row-rgb, var(--teinte-bleue)), 0.14);
}

.liste-carte tbody tr.liste-carte__ligne:hover td,
.liste-carte tbody tr.liste-carte__ligne.is-selected td {
    background: rgba(var(--row-rgb, var(--teinte-bleue)), 0.15);
}

.liste-carte tbody tr.liste-carte__ligne.is-selected td {
    border-top-color: rgba(var(--row-rgb, var(--teinte-bleue)), 0.34);
    border-bottom-color: rgba(var(--row-rgb, var(--teinte-bleue)), 0.34);
}

.liste-carte tbody tr.liste-carte__ligne td:first-child {
    border-left: 4px solid rgba(var(--row-rgb, var(--teinte-bleue)), 0.76);
    border-radius: 14px 0 0 14px;
}

.liste-carte tbody tr.liste-carte__ligne.is-selected td:first-child {
    border-left-color: var(--row-solide, rgb(var(--row-rgb, var(--teinte-bleue))));
}

.liste-carte tbody tr.liste-carte__ligne td:last-child {
    border-right: 1px solid rgba(var(--row-rgb, var(--teinte-bleue)), 0.14);
    border-radius: 0 14px 14px 0;
}

/* UNE LIGNE OUVERTE NE SE REFERME PAS SUR SON BAS, DES DEUX COTES.

   L'ADMIN, LE 04/11/2026 : « Le coin de la bordure reste apres ouverture
   d'une ligne », puis « des deux cotes ». Les coins avaient ete carres sur la
   CARTE, c'est-a-dire sous le seuil de repli, ou c'est la rangee entiere qui
   les porte. En mode TABLEAU, ils ne sont pas sur la rangee : ils sont sur la
   premiere et la derniere CELLULE, qui arrondissent chacune son bout. La
   correction ne les atteignait donc pas, et le volet restait pose sous un
   objet clos.

   Seuls les coins du BAS se carrent, et seulement le temps de l'ouverture. */
/* ET LE FOND SUIT LA BORDURE, PARCE QU IL EST SUR LA RANGEE.

   L'ADMIN, LE 04/11/2026 : « le fond ne suit pas la bordure ». Mesure sur la
   page reelle : les coins sont sur les CELLULES (14 px), la teinte de la
   rangee est sur le TR, et le TR n'avait aucun rayon. Un rectangle plein
   peint derriere quatre coins arrondis : la couleur debordait dans chaque
   coin, et carrer la bordure a l'ouverture n'a fait que rendre l'ecart
   visible.

   `border-collapse: separate` ici, donc le fond d'une rangee se decoupe bien
   sur son rayon ; la meme regle sur une table en `collapse` n'aurait rien
   fait. */
.liste-carte tbody tr.liste-carte__ligne {
    border-radius: 14px;
}

/* L ETAT OUVERT SE LIT SUR LA LIGNE, PAS SUR SA VOISINE.

   L'ADMIN, LE 04/11/2026 : « Ca reste apres avoir replie mais pas comme il
   faut », en pointant la regle de rayon de la rangee.

   MESURE DANS SON NAVIGATEUR, meme ligne, ouverte puis refermee : le volet
   n'a plus la classe `pc-suite--ouverte`, la RANGEE est bien revenue a
   `14px`, et ses deux cellules sont restees carrees du bas -- `14px 0 0 0` et
   `0 14px 0 0`. Les trois regles etaient ecrites en `:has(+ .pc-suite--
   ouverte)` : quand la classe part de la rangee SUIVANTE, le navigateur
   reevalue la regle qui vise la rangee elle-meme, pas celles qui visent ses
   cellules. Un fond carre restait donc aux deux coins du bas.

   UNE CLASSE POSEE PAR LE SCRIPT DU DEPLI, `pc-ligne-ouverte`, ne laisse
   pas ce doute : elle change sur l'element qu'on style, et tout ce qui
   descend de lui est reevalue avec elle. L'etape par `aria-expanded` n'a
   pas suffi -- meme asymetrie, la rangee suivait, ses cellules non. */
.liste-carte tbody tr.liste-carte__ligne.pc-ligne-ouverte {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
}

.liste-carte tbody tr.liste-carte__ligne.pc-ligne-ouverte td:first-child {
    border-bottom-left-radius: 0;
}

.liste-carte tbody tr.liste-carte__ligne.pc-ligne-ouverte td:last-child {
    border-bottom-right-radius: 0;
}

/*
 * 880 px : LA MEME BORNE QUE LA BASCULE ELLE-MEME.
 *
 * C'est ce bloc qui fait la CARTE : le cadre, le rembourrage, le rail de
 * couleur, le nom en tete et la date en pied. Il attendait 640 quand
 * `.responsive-table` empile des 880 (lk.css). Entre les deux, la ligne etait
 * demontee sans etre remontee : bandes pleine largeur, bordures de cellules
 * restees en place, et la date d'inscription en premier au lieu du nom.
 *
 * Les trois autres blocs de cette bascule ont deja ete ramenes a 880 ; celui-ci
 * etait le dernier.
 */
/* LE DESSIN DE CARTE DE LA FENETRE, POUR LES LISTES SANS CONTENEUR.
   -------------------------------------------------------------------------
   Celle des clients porte le sien dans `liste-clients.css`, decide par son
   cadre et non par la fenetre (04/11/2026). Les deux se superposaient sous
   880 px : meme carte, deux mises en page. Elle est donc exclue ici, et nulle
   part ailleurs -- les autres listes n'ont que ce repli.
   ------------------------------------------------------------------------- */
/* ET LA LISTE DES COMPTES SORT DE CES REPLIS DE FENETRE, le 06/11/2026 :
   elle a desormais son conteneur, comme celle des clients, et c'est lui qui
   decide du pli. Laissee ici, elle recevait deux dessins a la fois -- mesure :
   sa rangee restait en `flex` alors que sa propre regle demandait une grille,
   parce que cette feuille est chargee APRES le composant et gagnait a poids
   egal. */
@media (max-width: 880px) {
    .liste-carte:not(:has(.partner-client-row)):not(:has(.admin-user-row)) tbody tr.liste-carte__ligne {
        box-sizing: border-box;
        display: flex;
        flex-direction: column;
        padding: var(--espace-l);
        border: 1px solid rgba(var(--row-rgb, var(--teinte-bleue)), 0.14);
        border-left: 4px solid rgba(var(--row-rgb, var(--teinte-bleue)), 0.76);
        border-radius: var(--rayon-l);
        background: rgba(var(--row-rgb, var(--teinte-bleue)), 0.09);
    }

    .liste-carte:not(:has(.partner-client-row)):not(:has(.admin-user-row)) tbody tr.liste-carte__ligne.is-selected {
        border-color: rgba(var(--row-rgb, var(--teinte-bleue)), 0.34);
        border-left-color: var(--row-solide, rgb(var(--row-rgb, var(--teinte-bleue))));
        background: rgba(var(--row-rgb, var(--teinte-bleue)), 0.15);
    }

    /*
     * `td:first-child` ET `td:last-child` SONT NOMMES EXPRESSEMENT : ils
     * portent le rail et les arrondis, et leurs selecteurs pesent plus lourd
     * qu'un `td` seul. Sans les nommer, le rail restait accroche a la
     * premiere cellule DE LA SOURCE, que l'ordre visuel peut envoyer
     * ailleurs : un bout de rail arrondi flottait au milieu de la carte.
     */
    .liste-carte:not(:has(.partner-client-row)):not(:has(.admin-user-row)) tbody tr.liste-carte__ligne td,
    .liste-carte:not(:has(.partner-client-row)):not(:has(.admin-user-row)) tbody tr.liste-carte__ligne.is-selected td,
    .liste-carte:not(:has(.partner-client-row)):not(:has(.admin-user-row)) tbody tr.liste-carte__ligne:hover td,
    .liste-carte:not(:has(.partner-client-row)):not(:has(.admin-user-row)) tbody tr.liste-carte__ligne td:first-child,
    .liste-carte:not(:has(.partner-client-row)):not(:has(.admin-user-row)) tbody tr.liste-carte__ligne.is-selected td:first-child,
    .liste-carte:not(:has(.partner-client-row)):not(:has(.admin-user-row)) tbody tr.liste-carte__ligne td:last-child {
        border: none;
        border-radius: 0;
        background: none;
    }

    /*
     * LE TITRE EN TETE, LE PIED EN BAS.
     *
     * L'ordre des colonnes est celui d'un TABLEAU : on le lit colonne par
     * colonne, et la premiere sert souvent a trier. Une liste empilee se lit
     * carte par carte, et c'est le NOM qu'on cherche. Empilee telle quelle,
     * chaque carte s'ouvrait sur une date ou un identifiant.
     *
     * LES CELLULES SONT MARQUEES, PAS COMPTEES : la meme liste n'a pas
     * toujours le meme nombre de colonnes selon l'ecran qui l'affiche, et un
     * `nth-child` designait alors la mauvaise.
     */
    .liste-carte:not(:has(.partner-client-row)):not(:has(.admin-user-row)) tbody tr.liste-carte__ligne .cellule--titre {
        order: -1;
    }

    .liste-carte:not(:has(.partner-client-row)):not(:has(.admin-user-row)) tbody tr.liste-carte__ligne .cellule--titre .responsive-table__label {
        display: none;
    }

    .liste-carte:not(:has(.partner-client-row)):not(:has(.admin-user-row)) tbody tr.liste-carte__ligne .cellule--pied {
        order: 1;
        margin-bottom: 0;
        margin-top: var(--espace-s);
        padding-top: var(--espace-s);
        border-top: 1px solid rgba(var(--white-rgb), 0.08);
        opacity: .72;
        font-size: var(--taille-legende);
    }
}

.partner-clients-table th,
.partner-clients-table td {
    vertical-align: middle;
}

.partner-clients-table th {
    padding-bottom: 6px;
}

/* Le decor de la ligne vient de la grammaire commune (`liste-carte`) : ce
   tableau n'apporte que SA couleur, celle de l'etape ou en est le client. */
.partner-clients-table tbody tr.partner-client-row {
    --row-rgb: var(--journey-accent-rgb);
    --row-solide: var(--journey-accent-solid);
    cursor: pointer;
}

/* LA DATE D INSCRIPTION COMPTE, MAIS PAS AUTANT QUE LE RESTE.

   L'Admin, le 16/10/2026 : « pas de gras pour la date d'inscription, c'est
   important mais pas autant ». Elle portait un demi-gras et une encre a 94 %,
   c'est-a-dire le traitement d'une valeur qu'on cherche. Or on ne cherche pas
   une date d'inscription : on la trouve quand on y arrive. Le nom, lui, garde
   son gras.

   LE POIDS PART, L ENCRE DESCEND D UN CRAN : elle reste lisible, elle cesse
   d'etre le deuxieme element le plus voyant de la ligne. */
.partner-client-date {
    font-weight: 400;
    color: rgba(var(--white-rgb), 0.82);
    white-space: nowrap;
}

.partner-client-date__time {
    display: block;
    margin-top: 3px;
    font-size: 12px;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
    white-space: nowrap;
}

/*
 * LE NOM SE LIT, IL NE CRIE PAS.
 *
 * Il etait trace en 18 px de graisse 100, un filet : plus grand que tout ce
 * qui l'entoure et plus pale a la fois. Sur une liste, le nom est le point
 * d'ancrage — il doit se detacher par le POIDS, pas par la taille. 15 px en
 * 600, comme dans la liste des comptes, pour que les deux ecrans se
 * ressemblent.
 */
/*
 * LE NOM SE LIT, IL NE CRIE PAS.
 *
 * Il etait trace en 18 px de graisse 100, un filet : plus grand que tout
 * ce qui l entoure et plus pale a la fois. Sur une liste, le nom est le
 * point d ancrage, il doit se detacher par le POIDS et non par la taille.
 * 15 px en 600, comme dans la liste des comptes, pour que les deux ecrans
 * se ressemblent.
 *
 * La regle portait QUATRE declarations pour deux proprietes, chacune
 * annulant la precedente. C est ce qui m avait fait croire a un echec : ma
 * valeur etait bien la, ecrasee trois lignes plus bas.
 */
.partner-client-name {
    font-size: 15px;
    font-weight: 600;
    color: rgba(var(--white-rgb), 0.96);
}

.partner-clients-table tbody tr.partner-client-row .journey-pill--theme {
    background: rgba(var(--row-rgb, var(--teinte-bleue)), 0.18);
    border-color: rgba(var(--row-rgb, var(--teinte-bleue)), 0.34);
    color: rgba(var(--white-rgb), 0.94);
}

.partner-client-message-state {
    display: inline-flex;
    align-items: center;
    min-height: 26px;
    padding: 0 9px;
    border-radius: 999px;
    font-size: 12px;
    line-height: 1;
    font-weight: 800;
    white-space: nowrap;
}

.partner-client-message-state--new {
    color: var(--amber-soft);
    background: rgba(var(--amber-deep-rgb), 0.14);
    border: 1px solid rgba(var(--amber-deep-rgb), 0.28);
}

.partner-client-message-state--ok {
    color: var(--couleur-succes-doux);
    background: rgba(var(--share-bright-rgb), 0.12);
    border: 1px solid rgba(var(--share-bright-rgb), 0.22);
}

.partner-client-message-state--muted {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    background: rgba(var(--white-rgb), 0.06);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.partner-client-activity-state {
    display: inline-flex;
    align-items: center;
    min-height: 26px;
    padding: 0 9px;
    border-radius: 999px;
    font-size: 12px;
    line-height: 1;
    font-weight: 400;
    white-space: nowrap;
}

.partner-client-activity-state--recent {
    color: var(--couleur-succes-doux);
    background: rgba(var(--share-bright-rgb), 0.12);
    border: 1px solid rgba(var(--share-bright-rgb), 0.22);
}

.partner-client-activity-state--month {
    color: var(--blue-mist);
    background: rgba(var(--blue-rgb), 0.12);
    border: 1px solid rgba(var(--blue-rgb), 0.22);
}

.partner-client-activity-state--old {
    color: var(--amber-soft);
    background: rgba(var(--amber-deep-rgb), 0.12);
    border: 1px solid rgba(var(--amber-deep-rgb), 0.24);
}

.partner-client-activity-state--none {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    background: rgba(var(--white-rgb), 0.06);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.partner-client-activity-note {
    margin-top: 5px;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
    font-size: 12px;
    line-height: 1.25;
}

.journey-theme--courses-completed {
    --journey-accent-rgb: 34, 197, 94;
    --journey-accent-solid: var(--couleur-succes);
}

.partner-client-stage-note {
    margin-top: 5px;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
    font-size: 12px;
    line-height: 1.25;
    font-weight: 400;
}

.partner-client-stage-note__sub {
    margin-top: 3px;
    color: rgba(var(--white-rgb), 0.52);
    font-size: 12px;
    line-height: 1.25;
    font-weight: 400;
}

.partner-client-stage-note--completed .partner-client-stage-note__sub {
    color: rgba(var(--couleur-succes-doux-rgb), 0.72);
}

.partner-client-stage-note--completed {
    color: var(--couleur-succes-doux);
}

.partner-client-row--courses-completed td {
    background: rgba(var(--share-bright-rgb), 0.10);
    border-top-color: rgba(var(--share-bright-rgb), 0.18);
    border-bottom-color: rgba(var(--share-bright-rgb), 0.18);
}

.partner-client-row--courses-completed:hover td,
.partner-client-row--courses-completed.is-selected td {
    background: rgba(var(--share-bright-rgb), 0.16);
}

.ligne-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: nowrap;
}

/* LA BOITE DE LA PASTILLE : 46 x 42, et le repere pour son compteur.
   Le DESSIN de la pastille (rembourrage, rayon, taille de police, dessin du
   glyphe) vit dans `base/elements-retenus.css`, chargee apres celle-ci. Y
   redire la meme chose ici ne peignait rien et faisait croire le contraire :
   une taille de police de 17 px y a dormi des semaines pendant que la page
   en rendait 13. */
.ligne-action {
    position: relative;
    width: 46px;
    height: 42px;
    min-width: 46px;
    line-height: 1;
}
.ligne-action__compte {
    position: absolute;
    top: -7px;
    right: -7px;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    background: rgb(var(--amber-deep-rgb));
    color: var(--texte-fort);
    border: 1px solid rgba(var(--ink-900-rgb), 0.96);
    font-size: 11px;
    line-height: 1;
    font-weight: 900;
}

.partner-client-card {
    position: sticky;
    top: 18px;
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
    overflow-x: hidden;
    max-height: calc(100vh - 210px);
    overflow-y: auto;
    padding: 18px;
    border-radius: 18px;
    background: radial-gradient(circle at top right, rgba(var(--journey-accent-rgb), 0.14), transparent 38%),
        rgba(var(--slate-mid-rgb), 0.58);
    border: 1px solid rgba(var(--journey-accent-rgb), 0.24);
    box-shadow: 0 18px 44px rgba(var(--black-rgb), 0.18),
        inset 0 1px 0 rgba(var(--white-rgb), 0.06);
    backdrop-filter: blur(10px);
}

.partner-client-card__empty {
    color: rgba(var(--white-rgb), 0.68);
    line-height: 1.5;
}

.partner-client-card__content {
    display: grid;
    gap: 16px;
}

.partner-client-card__head {
    display: grid;
    gap: 10px;
}

.partner-client-card__eyebrow {
    /* 0,54 est calibre sur un sol sombre ; sur la carte claire il rend 3,76 a
       12 px (mesure, reproduite). Le jeton porte la bascule par theme. */
    color: rgba(var(--white-rgb), var(--voile-mention, 0.54));
    font-size: 12px;
    line-height: 1;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.partner-client-card__name {
    margin: 0;
    color: rgba(var(--white-rgb), 0.96);
    font-size: 23px;
    line-height: 1.2;
}

.partner-client-card__title-area {
    min-width: 0;
    display: grid;
    gap: 7px;
}

.partner-client-card__title-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    min-width: 0;
}

.partner-client-card__title-row .partner-client-card__name {
    flex: 1 1 auto;
    min-width: 0;
}

.partner-client-card__request-inline {
    flex: 0 0 auto;
    margin: 0;
}

.partner-client-card__request-mini-btn {
    appearance: none;
    min-height: 30px;
    padding: 0 10px;
    border-radius: 18px;

    display: inline-flex;
    align-items: center;
    justify-content: center;

    border: 1px solid rgba(var(--white-rgb), 0.10);

    /* LE MEME VERT QUE PARTOUT AILLEURS, ET C EST UNE CORRECTION DE CONTRASTE.
       `rgba(19, 172, 27, 0.788)` etait ecrit en dur, comme sur le bouton
       « Choisir » de l'ecran expert, et rendait 3,62 pour 4,5 exiges.
       `--share-fill-rgb` est le vert sur lequel le produit pose deja du blanc ;
       le survol reste plus clair, puisque le voile se pose sur une surface
       sombre. */
    background: rgba(var(--share-fill-rgb), 0.92);
    color: var(--white);

    font: inherit;
    font-size: 13px;
    line-height: 1;
    font-weight: 400;
    white-space: nowrap;

    cursor: pointer;
    transition:
        background .18s ease,
        border-color .18s ease,
        color .18s ease,
        transform .18s ease;
}

.partner-client-card__request-mini-btn:hover {
    background: rgb(var(--share-fill-rgb));
    border-color: rgba(var(--white-rgb), 0.18);
    color: var(--white);
    transform: translateY(-1px);
}

.partner-client-card__request-inline.is-disabled {
    opacity: 0.42;
}

.partner-client-card__request-inline.is-disabled .partner-client-card__request-mini-btn,
.partner-client-card__request-mini-btn:disabled {
    cursor: not-allowed;
    transform: none;
    opacity: 0.7;
    filter: grayscale(0.25);
}

@media (max-width: 460px) {
    .partner-client-card__request-inline,
    .partner-client-card__request-mini-btn {
        width: 100%;
    }
}

.partner-client-card__meta {
    display: grid;
    gap: 10px;
}

.partner-client-card__meta-item {
    display: grid;
    gap: 4px;
    padding: 12px;
    border-radius: 14px;
    background: rgba(var(--white-rgb), 0.04);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.partner-client-card__meta-item span {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.56));
    font-size: 12px;
    line-height: 1.3;
}

.partner-client-card__meta-item strong {
    color: rgba(var(--white-rgb), 0.92);
    font-size: 14px;
    line-height: 1.35;
}

.partner-client-card__courses {
    display: grid;
    gap: 10px;
    padding: 12px;
    border-radius: 16px;
    background: rgba(var(--white-rgb), 0.04);
    border: 1px solid rgba(var(--white-rgb), 0.075);
}

.partner-client-card__section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}

.partner-client-card__section-head span {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
    font-size: 12px;
    line-height: 1.3;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* `box-sizing` EXPLICITE : sans lui, la pastille est en `content-box` et les
   26 px de largeur minimale s'ajoutent aux 16 px de marge interne et au filet.
   Un compte a un chiffre occupait donc 44 px de large pour 26 de haut : une
   gelule couchee, avec son chiffre cale d'un cote, qui se lisait comme un
   interrupteur plutot que comme un nombre. */
.partner-client-card__section-head strong {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    min-width: 26px;
    height: 24px;
    padding: 0 8px;
    border-radius: 999px;
    background: rgba(var(--journey-accent-rgb), 0.18);
    border: 1px solid rgba(var(--journey-accent-rgb), 0.28);
    color: rgba(var(--white-rgb), 0.92);
    font-size: 12px;
    font-weight: 900;
}

.partner-client-card__courses-list {
    display: grid;
    gap: 8px;
}

.partner-client-card__course-item {
    display: grid;
    gap: 5px;
    padding: 10px;
    border-radius: 12px;
    background: rgba(var(--white-rgb), 0.04);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.partner-client-card__course-title {
    color: rgba(var(--white-rgb), 0.94);
    font-size: 14px;
    line-height: 1.3;
    font-weight: 800;
}

.partner-client-card__course-organ {
    color: rgba(var(--white-rgb), 0.72);
    font-size: 13px;
    line-height: 1.35;
}

.partner-client-card__course-meta,
.partner-client-card__courses-empty {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.56));
    font-size: 12px;
    line-height: 1.35;
}

.partner-client-card__advice-btn {
    width: 100%;
    justify-content: center;
}

.partner-client-card__actions {
    display: grid;
    gap: 10px;
}

.partner-client-card__actions .btn,
.partner-client-card__actions form {
    width: 100%;
    max-width: 100%;
    min-width: 0;
    box-sizing: border-box;
}

.partner-client-card__actions form .btn {
    width: 100%;
}

.partner-client-card__actions .btn {
    justify-content: center;
}

.partner-client-card__actions form {
    margin: 0;
}

.partner-client-card__actions form.is-disabled {
    opacity: 0.2;
    cursor: not-allowed;
}

.partner-client-card__actions form.is-disabled .btn,
.partner-client-card__actions form.is-disabled button {
    cursor: not-allowed;
}

.partner-client-card__hint {
    margin: -4px 0 0;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 13px;
    line-height: 1.45;
}

/* =========================================
   Partner dashboard: экспертная работа
   ========================================= */

.partner-client-card__expert-work {
    display: grid;
    gap: 12px;
    padding: 12px;
    border-radius: 16px;
    overflow: hidden;
    background: radial-gradient(circle at 100% 0%, rgba(var(--amber-bright-rgb), 0.18), transparent 38%),
        radial-gradient(circle at 0% 0%, rgba(var(--amber-deep-rgb), 0.10), transparent 42%),
        linear-gradient(180deg, rgba(92, 66, 18, 0.38), rgba(var(--slate-mid-rgb), 0.72));
    border: 1px solid rgba(var(--amber-bright-rgb), 0.24);
    box-shadow: 0 12px 28px rgba(var(--black-rgb), 0.16),
        0 0 0 1px rgba(var(--amber-bright-rgb), 0.06) inset,
        inset 0 1px 0 rgba(var(--white-rgb), 0.08);
}

.partner-client-card__expert-work .partner-client-card__section-head span {
    color: rgba(var(--amber-pale-rgb), 0.92);
}

.partner-client-card__expert-work .partner-client-card__section-head strong {
    background: rgba(var(--amber-bright-rgb), 0.16);
    border-color: rgba(var(--amber-bright-rgb), 0.32);
    color: rgba(254, 249, 195, 0.96);
}

.partner-client-expert {
    display: grid;
    gap: 12px;
    min-width: 0;
}

.partner-client-expert__top {
    display: grid;
    gap: 10px;
    min-width: 0;
}

.partner-client-expert__back {
    appearance: none;
    width: fit-content;
    min-height: 30px;
    padding: 0 10px;
    border-radius: 999px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.06);
    color: rgba(var(--white-rgb), 0.82);
    font: inherit;
    font-size: 12px;
    line-height: 1;
    font-weight: 400;
    cursor: pointer;
}

.partner-client-expert__back[hidden] {
    display: none;
}

.partner-client-expert__back:hover {
    background: rgba(var(--white-rgb), 0.09);
    color: var(--white);
}

.partner-client-expert__intro {
    display: grid;
    gap: 5px;
    min-width: 0;
}

.partner-client-expert__title {
    color: rgba(var(--white-rgb), 0.94);
    font-size: 15px;
    line-height: 1.25;
    font-weight: 400;
}

.partner-client-expert__text {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 12px;
    line-height: 1.4;
}

.partner-client-expert__scroll {
    min-width: 0;
    max-height: 360px;
    overflow-y: auto;
    overflow-x: hidden;
    padding-right: 6px;
}

.partner-client-expert__scroll::-webkit-scrollbar {
    width: 10px;
}

.partner-client-expert__scroll::-webkit-scrollbar-track {
    background: transparent;
}

.partner-client-expert__scroll::-webkit-scrollbar-thumb {
    background: linear-gradient(
        180deg,
        rgba(var(--white-rgb), 0.18),
        rgba(var(--white-rgb), 0.08)
    );
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: padding-box;
}

.partner-client-expert__scroll::-webkit-scrollbar-thumb:hover {
    background: linear-gradient(
        180deg,
        rgba(var(--white-rgb), 0.28),
        rgba(var(--white-rgb), 0.14)
    );
    border: 2px solid transparent;
    background-clip: padding-box;
}

.partner-client-expert__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 8px;
    min-width: 0;
}

.partner-client-expert__grid[hidden] {
    display: none;
}

.partner-client-expert__choice {
    appearance: none;
    width: 100%;
    min-width: 0;
    min-height: 40px;
    display: grid;
    gap: 4px;
    align-content: center;
    box-sizing: border-box;
    padding: 9px 10px;
    border-radius: 12px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    border-color: rgba(var(--amber-bright-rgb), 0.11);
    background: rgba(var(--slate-rgb), 0.32);
    color: inherit;
    text-align: left;
    cursor: pointer;
    transition:
        transform .18s ease,
        background .18s ease,
        border-color .18s ease,
        box-shadow .18s ease;
}

.partner-client-expert__choice:hover {
    background: rgba(var(--amber-deep-rgb), 0.13);
    border-color: rgba(var(--amber-bright-rgb), 0.28);
}

.partner-client-expert__choice.is-active {
    background:
        linear-gradient(135deg, rgba(180, 83, 9, 0.54), rgba(var(--amber-bright-rgb), 0.22));
    border-color: rgba(var(--amber-pale-rgb), 0.46);
    box-shadow:
        0 0 0 1px rgba(var(--amber-pale-rgb), 0.10) inset,
        0 10px 22px rgba(180, 83, 9, 0.18);
}

.partner-client-expert__choice-title {
    color: rgba(var(--white-rgb), 0.94);
    font-size: 15px;
    line-height: 1.25;
    font-weight: 400;
    white-space: normal;
    overflow-wrap: anywhere;
}

.partner-client-expert__choice-meta {
    color: rgba(var(--ink-300-rgb), 0.64);
    font-size: 11px;
    line-height: 1.25;
}

.partner-client-expert__footer {
    min-width: 0;
    padding-top: 10px;
    border-top: 1px solid rgba(var(--white-rgb), 0.08);
}

.partner-client-expert__open {
    width: 100%;
    max-width: 100%;
    min-width: 0;
    min-height: 42px;
    box-sizing: border-box;

    display: inline-flex;
    align-items: center;
    justify-content: center;

    border-radius: 12px;
    border: 1px solid rgba(255, 242, 178, 0.58);
    background: linear-gradient(135deg, #b7791f, var(--amber-bright) 58%, rgb(var(--portal-gold-clair-rgb)));

    color: #1f1603;
    text-align: center;
    text-decoration: none;
    font-size: 15px;
    line-height: 1.15;
    font-weight: 400;

    box-shadow: 0 12px 26px rgba(var(--amber-deep-rgb), 0.24),
        inset 0 1px 0 rgba(var(--white-rgb), 0.38);

    transition:
        transform .18s ease,
        background .18s ease,
        border-color .18s ease,
        box-shadow .18s ease;
}

.partner-client-expert__open:hover {
    color: var(--texte-fort);
    background:
        linear-gradient(135deg, #d49425, #fde047 58%, #fff7bd);
    border-color: rgba(255, 242, 178, 0.88);
    box-shadow: 0 14px 30px rgba(var(--amber-deep-rgb), 0.32),
        inset 0 1px 0 rgba(var(--white-rgb), 0.46);
}

.partner-client-expert__open.is-disabled {
    opacity: 0.46;
    cursor: not-allowed;
    pointer-events: none;
    filter: grayscale(0.22);
    transform: none;
    box-shadow: none;
}

body.has-partner-course-advice-modal {
    overflow: hidden;
}

.partner-course-advice-modal[hidden] {
    display: none;
}

.partner-course-advice-modal {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: grid;
    place-items: center;
    padding: 28px;
}

.partner-course-advice-modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(var(--black-rgb), 0.74);
    backdrop-filter: blur(8px);
}

.partner-course-advice-modal__dialog {
    position: relative;
    z-index: 1;
    width: min(980px, 100%);
    max-height: min(860px, calc(100vh - 56px));
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-radius: 18px;
    background:
        radial-gradient(circle at top right, rgba(111, 145, 255, 0.16), transparent 34%),
        rgba(var(--slate-mid-rgb), 0.96);
    border: 1px solid rgba(var(--white-rgb), 0.12);
    box-shadow: 0 28px 90px rgba(var(--black-rgb), 0.48),
        inset 0 1px 0 rgba(var(--white-rgb), 0.08);
}

.partner-course-advice-modal__head {
    flex: 0 0 auto;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 18px;
    padding: 20px 22px;
    border-bottom: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--slate-rgb), 0.28);
}

.partner-course-advice-modal__eyebrow {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
    font-size: 12px;
    line-height: 1.2;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.07em;
}

.partner-course-advice-modal__title {
    margin: 6px 0 0;
    color: rgba(var(--white-rgb), 0.98);
    font-size: 24px;
    line-height: 1.2;
}

.partner-course-advice-modal__client {
    margin-top: 5px;
    color: rgba(var(--white-rgb), 0.70);
    font-size: 14px;
    line-height: 1.35;
}

.partner-course-advice-modal__close {
    width: 40px;
    height: 40px;
    min-width: 40px;
    border: 1px solid rgba(var(--white-rgb), 0.10);
    border-radius: 14px;
    background: rgba(var(--white-rgb), 0.06);
    color: rgba(var(--white-rgb), 0.88);
    font-size: 28px;
    line-height: 1;
    cursor: pointer;
}

.partner-course-advice-modal__close:hover {
    background: rgba(var(--white-rgb), 0.11);
    color: var(--white);
}

.partner-course-advice-modal__body {
    min-height: 0;
    overflow-y: auto;
    padding: 18px 22px 22px;
}

.partner-course-advice-modal__body::-webkit-scrollbar {
    width: 10px;
}

.partner-course-advice-modal__body::-webkit-scrollbar-track {
    background: transparent;
}

.partner-course-advice-modal__body::-webkit-scrollbar-thumb {
    background: rgba(var(--white-rgb), 0.16);
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: padding-box;
}

.partner-course-advice-modal__loading,
.partner-course-advice-modal__empty,
.partner-course-advice-empty {
    padding: 16px;
    border-radius: 16px;
    background: rgba(var(--white-rgb), 0.04);
    border: 1px solid rgba(var(--white-rgb), 0.08);
    color: rgba(var(--white-rgb), 0.74);
    font-size: 14px;
    line-height: 1.5;
}

.partner-course-advice-modal .journey-course-advice {
    display: grid;
    gap: 16px;
    padding: 0;
    margin: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
}

.partner-course-advice-modal .journey-course-advice__title {
    margin: 0;
    color: rgba(var(--white-rgb), 0.96);
    font-size: 22px;
    line-height: 1.25;
}

.partner-course-advice-modal .journey-course-advice__intro {
    margin: 0;
    color: rgba(var(--white-rgb), 0.72);
    font-size: 14px;
    line-height: 1.55;
}

.partner-course-advice-modal .journey-course-advice__groups,
.partner-course-advice-modal .journey-course-advice-themes {
    display: grid;
    gap: 12px;
}

.partner-course-advice-modal .journey-course-advice-group,
.partner-course-advice-modal .journey-course-advice-theme {
    padding: 14px;
    border-radius: 18px;
    background: rgba(var(--white-rgb), 0.04);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.partner-course-advice-modal .journey-course-advice-group__title,
.partner-course-advice-modal .journey-course-advice-theme__title {
    margin: 0;
    color: rgba(var(--white-rgb), 0.94);
    font-size: 17px;
    line-height: 1.35;
}

.partner-course-advice-modal .journey-course-advice-group__meta,
.partner-course-advice-modal .journey-course-advice-theme__lead,
.partner-course-advice-modal .journey-course-advice-theme__period-label,
.partner-course-advice-modal .journey-course-advice-theme__list {
    color: rgba(var(--white-rgb), 0.72);
    font-size: 14px;
    line-height: 1.5;
}

.partner-course-advice-modal .journey-course-advice-theme__summary {
    cursor: pointer;
}

@media (max-width: 1180px) {
    .partner-dashboard-clients-layout {
        grid-template-columns: 1fr;
    }

    .partner-dashboard-clients__list-pane,
    .partner-client-card {
        max-height: none;
        overflow: visible;
    }

    .partner-client-card {
        position: static;
    }
}

@media (max-width: 780px) {
    .partner-dashboard-clients {
        padding: 14px;
    }

    .partner-dashboard-clients__head {
        flex-direction: column;
    }

    .partner-dashboard-clients__head .btn {
        width: 100%;
        justify-content: center;
    }

    .ligne-actions {
        flex-wrap: wrap;
    }
}

@media (max-width: 1280px) {
    .partner-dashboard__stages {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

@media (max-width: 980px) {
    .partner-dashboard__hero-actions {
        margin-left: 0;
        padding-top: 0;
    }
    .partner-dashboard__body {
        grid-template-columns: 1fr;
    }

    .partner-dashboard__stages {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 640px) {
    .partner-dashboard__copy-link-btn {
        width: 100%;
    }
    .partner-dashboard__ref-input-wrap {
        flex: 1 1 calc(100% - 62px);
        min-width: 0;
    }

    .partner-dashboard__icon-btn {
        width: 52px;
    }

    .partner-dashboard__stages {
        grid-template-columns: 1fr;
    }

    .partner-dashboard__icon-btn {
        width: 52px;
    }
}

.partner-stage-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 0 0 16px;
}

.partner-stage-filter {
    text-decoration: none;
    color: inherit;
    transition: transform 0.18s ease, opacity 0.18s ease;
}

/*
 * UN DEPLACEMENT SEUL N EST PAS UN RETOUR AU POINTEUR.
 *
 * Le filtre se contentait de monter d'un pixel. Mesure a l'ecart au fond, son
 * survol valait zero : la couleur ne bougeait pas d'un iota, et sous
 * `prefers-reduced-motion` il ne restait litteralement rien.
 *
 * L ANNEAU EST ECRIT EN `--white-rgb`, donc il s'inverse tout seul : blanc sur
 * le theme sombre, encre sur le theme clair. Une seule regle, deux themes, et
 * aucune chance qu'un jour l'un des deux soit oublie.
 */
.partner-stage-filter:hover {
    transform: translateY(-1px);
}

.partner-stage-filter:hover .journey-pill {
    box-shadow: 0 0 0 1px rgba(var(--white-rgb), 0.26);
}

@media (prefers-reduced-motion: reduce) {
    .partner-stage-filter:hover { transform: none; }
}

.partner-stage-filter.is-active .journey-pill {
    box-shadow: 0 0 0 2px rgba(var(--white-rgb), 0.08) inset;
}

/*
 * TOUTES LES PUCES DE FILTRE A LA MEME HAUTEUR.
 *
 * Deux styles cohabitaient dans la meme rangee : « Toutes les etapes » est un
 * `__clear` (32 px de haut, texte de 13), les autres sont des `journey-pill`
 * (22 px, texte herite de 15). Sur une ligne large, la difference passait ;
 * repliees sur trois lignes en telephone, les puces montaient et descendaient
 * d'une ligne a l'autre et la rangee ressemblait a un escalier.
 *
 * On aligne les pastilles d'etape sur la premiere, qui est la reference :
 * c'est elle qui porte l'etat « aucun filtre ». Les mesures sont copiees de
 * `__clear` a dessein, pour que les deux se corrigent ensemble.
 *
 * Cible restreinte aux filtres : `journey-pill` sert ailleurs a dire l'etape
 * d'un client, ou ces mesures n'ont rien a faire.
 */
.partner-stage-filters .journey-pill {
    min-height: 32px;
    padding: 0 12px;
    font-size: 13px;
    font-weight: 600;
    box-sizing: border-box;
}

/*
 * EN TELEPHONE, LA RANGEE DEFILE AU LIEU DE SE REPLIER.
 *
 * Repliees, les sept puces prenaient quatre lignes, soit 152 px : la liste
 * de clients commencait sous la ligne de flottaison, et l'ecran s'ouvrait
 * sur ses filtres plutot que sur son contenu. Une rangee qui defile tient
 * sur 32 px.
 *
 * LE BORD DROIT S'ESTOMPE, et c'est ce qui dit qu'il y a une suite. Coupee
 * net, une rangee ressemble a une rangee complete et personne ne pense a la
 * faire glisser. C'est un masque et non un degrade pose par-dessus : un
 * degrade aurait demande un element de plus, place en absolu au-dessus des
 * puces, donc a exclure des clics.
 */
@media (max-width: 640px) {
    /* ====================================================================
       LES FILTRES PASSENT A LA LIGNE, ILS NE GLISSENT PLUS
       ====================================================================
       CE QU IL Y AVAIT, ET POURQUOI C ETAIT DEFENDABLE. La rangee glissait
       horizontalement, barre cachee (`scrollbar-width: none` et son jumeau
       WebKit), avec un masque qui estompait le bord droit pour dire qu'il y
       avait une suite. L'argument tenait : sept puces a la ligne prennent trois
       rangees sur un telephone, et repoussent la liste d'autant.

       L'ADMIN, LE 16/10/2026 : « je ne veux pas de barre de scroll horizontale
       aussi ». C'est une decision, et elle vaut aussi pour un glissement dont
       la barre est cachee : une rangee qui glisse reste une rangee ou la
       moitie des filtres ne se voit pas, et le masque ne fait que le signaler.

       CE QUE CA COUTE, MESURE A 390 PX : la rangee passe de 32 px a trois
       lignes, et les 526 px qui vivaient hors du cadre reviennent dedans.
       Aucune barre, aucun filtre cache.

       LE MASQUE PART AVEC LE GLISSEMENT : il disait « il y a une suite », et
       il n'y en a plus. Laisse en place, il aurait estompe la derniere puce de
       chaque ligne sans rien signaler du tout.
       ==================================================================== */
    .partner-stage-filters {
        gap: 8px;
        flex-wrap: wrap;
        overflow-x: visible;
        min-width: 0;
        width: 100%;
        box-sizing: border-box;
    }

    .partner-stage-filters .partner-stage-filter {
        flex: 0 0 auto;
    }
}


.partner-stage-filter__clear {
    display: inline-flex;
    align-items: center;
    /* Sans cela, la bordure s'ajoute aux 32 px et cette puce mesure 34 quand
       les autres en font 32 : l'ecart de deux pixels se voit des que la
       rangee se replie. */
    box-sizing: border-box;
    min-height: 32px;
    padding: 0 12px;
    border-radius: 999px;
    text-decoration: none;
    font-size: 13px;
    font-weight: 600;
    background: rgba(var(--white-rgb), 0.08);
    border: 1px solid rgba(var(--white-rgb), 0.08);
    color: inherit;
}

.partner-stage-filter__clear:hover {
    background: rgba(var(--white-rgb), 0.12);
}

.partner-stage-filter__summary {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 0 0 16px;
}

.admin-settings-card {
    display: flex;
    flex-direction: column;
    gap: 18px;
}

.admin-settings-options {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
}

.admin-settings-option {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    padding: 16px;
    border-radius: 16px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.04);
    cursor: pointer;
    transition: background 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
}

.admin-settings-option:hover {
    transform: translateY(-1px);
    background: rgba(var(--white-rgb), 0.04);
    border-color: rgba(var(--white-rgb), 0.14);
}

.admin-settings-option.is-active {
    background: rgba(var(--green-state-rgb), 0.10);
    border-color: rgba(var(--green-state-rgb), 0.32);
}

.admin-settings-option input {
    margin-top: 4px;
}

.admin-settings-option__body {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.admin-settings-option__title {
    font-weight: 700;
}

.admin-settings-option__text {
    font-size: 14px;
    line-height: 1.5;
    opacity: 0.82;
}

.admin-settings-actions {
    display: flex;
    justify-content: flex-start;
    gap: 10px;
    flex-wrap: wrap;
}

@media (max-width: 780px) {
    .admin-settings-options {
        grid-template-columns: 1fr;
    }
}

.partner-client-notifications {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.partner-client-notifications__success {
    padding: 10px 12px;
    border-radius: 12px;
    background: rgba(var(--green-state-rgb), 0.12);
    border: 1px solid rgba(var(--green-state-rgb), 0.24);
    font-size: 13px;
    line-height: 1.4;
}

.partner-client-notifications__form {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.partner-client-notifications__list {
    display: grid;
    gap: 8px;
}

.partner-client-notifications__option {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    padding: 9px 10px;
    border-radius: 12px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.04);
    cursor: pointer;
}

.partner-client-notifications__option:hover {
    background: rgba(var(--white-rgb), 0.04);
    border-color: rgba(var(--white-rgb), 0.14);
}

.partner-client-notifications__option input {
    margin-top: 3px;
    accent-color: var(--green-mid);
}

.partner-client-notifications__option-body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/* LE TITRE DE L OPTION PREND L ENCRE PLEINE. Il l'heritait de sa carte, ou elle
   vaut 0,82 : sur la surface plus claire du bloc de notifications, cela rendait
   4,43 pour 4,5 exiges. C'est le libelle qu'on lit en premier dans ce bloc ; il
   n'a aucune raison d'etre le plus eteint des trois. */
.partner-client-notifications__option-title {
    font-size: 13px;
    font-weight: 700;
    line-height: 1.25;
    color: rgba(var(--white-rgb), var(--voile-12, 0.94));
}

/* UNE ENCRE, PAS UNE OPACITE. `opacity` eteint tout ce que l'element porte --
   un lien, une valeur, un signe -- et se multiplie a ce que la couleur avait
   deja de voile : le texte rendait 3,07 pour 4,5 exiges sur la carte de
   notifications (mesure `contraste.py`, les deux themes). Une couleur dit ce
   qu'on veut : le cran de mention du produit, avec le repli du sombre. */
.partner-client-notifications__option-text {
    font-size: 12px;
    line-height: 1.35;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.76));
}

.partner-client-notifications__actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

/* Meme raison, meme remede : 3,1 mesure a 0,68 d'opacite. */
.partner-client-notifications__hint {
    font-size: 12px;
    line-height: 1.35;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.76));
}

.admin-email-page-head {
    align-items: flex-start;
}

.admin-email-notice {
    padding: 14px;
    border-left: 4px solid #6d5dfc;
}

.admin-email-notice--error {
    border-left-color: var(--couleur-danger);
    color: var(--couleur-danger-doux);
}

.admin-email-layout {
    display: grid;
    grid-template-columns: 0.985fr 2.015fr;
    gap: 16px;
    align-items: start;
}

.admin-email-card {
    padding: 18px;
    min-width: 0;
}

.admin-email-card--log {
    position: sticky;
    top: 18px;
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 36px);
    overflow: hidden;
}

.admin-email-card--log .admin-section__head {
    flex: 0 0 auto;
    padding-bottom: 12px;
    margin-bottom: 12px;
    border-bottom: 1px solid rgba(var(--white-rgb), 0.08);
}

.admin-email-card--log .admin-email-feed {
    min-height: 0;
    overflow-y: auto;
    padding-right: 6px;
}

.admin-email-card--log .admin-email-feed::-webkit-scrollbar {
    width: 10px;
}

.admin-email-card--log .admin-email-feed::-webkit-scrollbar-track {
    background: transparent;
}

.admin-email-card--log .admin-email-feed::-webkit-scrollbar-thumb {
    background: linear-gradient(
        180deg,
        rgba(var(--white-rgb), 0.18),
        rgba(var(--white-rgb), 0.08)
    );
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: padding-box;
}

.admin-email-card--log .admin-email-feed::-webkit-scrollbar-thumb:hover {
    background: linear-gradient(
        180deg,
        rgba(var(--white-rgb), 0.28),
        rgba(var(--white-rgb), 0.14)
    );
    border: 2px solid transparent;
    background-clip: padding-box;
}

.admin-email-card__link {
    font-size: 13px;
    font-weight: 700;
    text-decoration: none;
    color: inherit;
    opacity: 0.78;
}

.admin-email-card__link:hover {
    opacity: 1;
}

.admin-email-feed {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.admin-email-feed-item {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px;
    border-radius: 14px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.04);
}

.admin-email-feed-item__top {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
}

.admin-email-feed-item__date {
    font-size: 12px;
    opacity: 0.68;
    white-space: nowrap;
}

.admin-email-feed-item__to {
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 13px;
    font-weight: 700;
    line-height: 1.3;
    word-break: break-word;
}

.admin-email-feed-item__to span {
    font-size: 12px;
    font-weight: 500;
    opacity: 0.68;
}

.admin-email-feed-item__template {
    font-size: 13px;
    line-height: 1.35;
    opacity: 0.78;
}

.admin-email-feed-item__error {
    padding: 8px 10px;
    border-radius: 10px;
    background: rgba(var(--red-rgb), 0.10);
    border: 1px solid rgba(var(--red-rgb), 0.18);
    color: var(--couleur-danger-doux);
    font-size: 12px;
    line-height: 1.35;
}

.admin-email-status {
    display: inline-flex;
    align-items: center;
    min-height: 24px;
    padding: 0 9px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 800;
    line-height: 1;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.08);
}

.admin-email-status--pending {
    background: rgba(var(--amber-deep-rgb), 0.12);
    border-color: rgba(var(--amber-deep-rgb), 0.26);
    color: var(--amber-soft);
}

.admin-email-status--processing {
    background: rgba(var(--blue-rgb), 0.12);
    border-color: rgba(var(--blue-rgb), 0.26);
    color: var(--blue-soft);
}

.admin-email-status--sent {
    background: rgba(var(--green-state-rgb), 0.12);
    border-color: rgba(var(--green-state-rgb), 0.26);
    color: var(--green-mid);
}

.admin-email-status--failed {
    background: rgba(var(--red-rgb), 0.12);
    border-color: rgba(var(--red-rgb), 0.26);
    color: var(--couleur-danger-doux);
}

.admin-email-status--cancelled {
    background: rgba(var(--white-rgb), 0.08);
    border-color: rgba(var(--white-rgb), 0.12);
    color: rgba(var(--white-rgb), 0.72);
}

.admin-email-templates-head {
    align-items: flex-start;
    margin-bottom: 16px;
}

.admin-email-template-groups {
    display: flex;
    flex-direction: column;
    gap: 18px;
}

.admin-email-template-group {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.admin-email-template-group__head {
    position: relative;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin: 0 0 2px;
    padding: 8px 14px 8px 16px;
    border-radius: 14px;
    background: rgba(var(--slate-rgb), 0.26);
    border: 1px solid rgba(var(--white-rgb), 0.08);
    color: rgba(var(--white-rgb), 0.96);
    box-shadow: inset 0 1px 0 rgba(var(--white-rgb), 0.04);
}

.admin-email-template-group__head::before {
    content: "";
    position: absolute;
    inset: 8px auto 8px 0;
    width: 4px;
    border-radius: 0 8px 8px 0;
    background: linear-gradient(180deg, rgba(var(--blue-light-rgb), 0.9), rgba(var(--blue-rgb), 0.55));
}

.admin-email-template-group__head h3 {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    padding-left: 2px;
    font-size: 20px;
    font-weight: 700;
    line-height: 1.25;
    color: rgba(var(--white-rgb), 0.96);
}

.admin-email-template-group__head span {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    height: 28px;
    padding: 0 9px;
    border-radius: 999px;
    background: rgba(var(--white-rgb), 0.08);
    border: 1px solid rgba(var(--white-rgb), 0.08);
    color: rgba(var(--white-rgb), 0.82);
    font-size: 12px;
    font-weight: 800;
    line-height: 1;
}

.admin-email-template-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.admin-email-template-item {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 14px;
    align-items: center;
    padding: 12px 14px;
    border-radius: 14px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.04);
}

.admin-email-template-item:hover {
    background: rgba(var(--white-rgb), 0.04);
    border-color: rgba(var(--white-rgb), 0.14);
}

.admin-email-template-item__main {
    min-width: 0;
}

.admin-email-template-item__name {
    font-size: 18px;
    font-weight: 400;
    line-height: 1.3;
}

.admin-email-template-item__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 6px;
    font-size: 12px;
    font-weight: 400;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
}

.admin-email-template-item__actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    flex-wrap: wrap;
}

.admin-email-template-item__actions form {
    margin: 0;
}

.admin-email-template-state {
    display: inline-flex;
    align-items: center;
    min-height: 30px;
    padding: 0 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 800;
    white-space: nowrap;
}

.admin-email-template-state.is-active {
    background: rgba(var(--green-state-rgb), 0.12);
    color: var(--green-mid);
}

.admin-email-template-state.is-disabled {
    background: rgba(var(--white-rgb), 0.08);
    color: rgba(var(--white-rgb), 0.68);
}

@media (max-width: 1180px) {
    .admin-email-layout {
        grid-template-columns: 1fr;
    }

    .admin-email-card--log {
        order: 2;
        position: static;
        max-height: 520px;
    }

    .admin-email-card--templates {
        order: 1;
    }
}

@media (max-width: 640px) {
    .admin-email-card--log {
        max-height: none;
        overflow: visible;
    }

    .admin-email-card--log .admin-email-feed {
        overflow: visible;
        padding-right: 0;
    }
}

@media (max-width: 780px) {
    .admin-email-template-item {
        grid-template-columns: 1fr;
    }

    .admin-email-template-item__actions {
        justify-content: flex-start;
    }
}

.admin-email-table-wrap {
    overflow: auto;
}

.admin-email-table {
    width: 100%;
    border-collapse: collapse;
    min-width: 860px;
}

.admin-email-table th,
.admin-email-table td {
    padding: 11px 10px;
    border-bottom: 1px solid rgba(var(--white-rgb), 0.08);
    text-align: left;
    vertical-align: top;
}

.admin-email-table th {
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.62;
}

.admin-email-table td {
    font-size: 13px;
    line-height: 1.4;
}

.admin-email-table__date {
    white-space: nowrap;
    opacity: 0.82;
}

.admin-email-table__error {
    color: var(--couleur-danger-doux);
    max-width: 340px;
}

.admin-email-pagination {
    margin-top: 16px;
}

.partner-dashboard-flash {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    border-radius: 18px;
    border: 1px solid rgba(var(--white-rgb), 0.12);
    box-shadow: 0 18px 46px rgba(var(--black-rgb), 0.24),
        inset 0 1px 0 rgba(var(--white-rgb), 0.10);
    backdrop-filter: blur(10px);
}

.partner-dashboard-flash--success {
    background: linear-gradient(135deg, rgba(var(--share-bright-rgb), 0.34), rgba(21, 128, 61, 0.52)),
        rgba(20, 83, 45, 0.74);
    border-color: rgba(var(--green-soft-rgb), 0.32);
}

.partner-dashboard-flash--error {
    background: linear-gradient(135deg, rgba(var(--red-rgb), 0.34), rgba(var(--red-mid-rgb), 0.56)),
        rgba(var(--red-deep-rgb), 0.78);
    border-color: rgba(var(--red-soft-rgb), 0.36);
}

.partner-dashboard-flash__icon {
    width: 32px;
    height: 32px;
    min-width: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    background: rgba(var(--white-rgb), 0.16);
    border: 1px solid rgba(var(--white-rgb), 0.16);
    font-weight: 900;
    line-height: 1;
}

.partner-dashboard-flash__text {
    font-size: 14px;
    line-height: 1.4;
    font-weight: 700;
    color: rgba(var(--white-rgb), 0.96);
}

.partner-pending-diagnostics.card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 14px;
    overflow: hidden;
    padding: 20px;
    border: 1px solid rgba(var(--amber-rgb), 0.42);
    background:
        radial-gradient(circle at 18% 0%, rgba(var(--gold-soft-rgb), 0.30), transparent 34%),
        linear-gradient(135deg, rgba(180, 83, 9, 0.86), rgba(120, 53, 15, 0.92)),
        rgba(120, 53, 15, 0.92);
    box-shadow: 0 20px 56px rgba(var(--black-rgb), 0.30),
        inset 0 1px 0 rgba(var(--white-rgb), 0.14);
}

.partner-pending-diagnostics::before {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 5px;
    background: linear-gradient(180deg, rgb(var(--amber-rgb)), var(--orange));
}

.partner-pending-diagnostics .admin-section__head {
    position: relative;
    z-index: 1;
}

.partner-pending-diagnostics .admin-section__title {
    color: rgba(var(--white-rgb), 0.98);
    text-shadow: 0 1px 2px rgba(var(--halo-texte-rgb, var(--black-rgb)), 0.28);
}

.partner-pending-diagnostics .admin-section__text {
    color: rgba(var(--white-rgb), 0.86);
    opacity: 1;
}

.partner-pending-diagnostics .admin-dashboard__badge {
    background: rgba(var(--white-rgb), 0.18);
    border: 1px solid rgba(var(--white-rgb), 0.18);
    color: #fff7ed;
}

/* ELLE SE DETACHE DE LA PHRASE QUI L'INTRODUIT.

   L'ADMIN, LE 18/10/2026 : « et au dessus ? du bloc client ». Meme defaut
   que la ligne de liaison plus bas, meme cause : le corps de carte est en
   `display: block`, donc sans `gap`, et aucun des trois blocs ne portait de
   marge. Mesure sur la page reelle : zero pixel entre la phrase et la liste.

   DOUZE PIXELS, ET PAS SEIZE : c'est l'ecart qu'une autre carte de cette
   page utilise deja entre un sous-titre et sa liste. La phrase introduit
   directement ce qui suit ; la ligne de liaison, elle, parle d'autre chose et
   prend l'ecart large.

   PAS DE `gap` SUR LE CORPS DE CARTE, qui aurait tout reglé d'un coup : les
   quatre autres corps de la page tiennent deja leurs ecarts par des marges
   propres a leurs enfants (16, 12 et 4 px, mesures), et un `gap` s'y serait
   AJOUTE au lieu de les remplacer. */
/* LA LISTE EST UN CONTENEUR MESURABLE.

   La ligne en attente vit dans une carte qui occupe tantot toute la page,
   tantot un tiers d'ecran : sa largeur ne se deduit pas de celle de la
   fenetre. Les replis ci-dessous se decident donc sur SA largeur a elle. */
.partner-pending-diagnostics__list {
    margin-top: var(--espace-m);
    position: relative;
    z-index: 1;
    display: grid;
    gap: 10px;
    container: ligne-attente / inline-size;
}

.partner-pending-diagnostic {
    /* TROIS PARTS SUR UNE RANGEE : qui c'est, ce qu'on a mesure, ce
       qu'on peut en faire. Chacune annonce la largeur sous laquelle
       elle prefere descendre, et c'est tout ce qui decide le repli --
       pas un palier de fenetre, pas une suite de retouches. */
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 18px;
    padding: 14px 16px;
    border-radius: 16px;
    border: 1px solid rgba(var(--white-rgb), 0.18);
    /*
     * LE FOND SUIT LE THEME, COMME LE FILET ET LE LISERE JUSTE AU-DESSUS.
     *
     * L ADMIN, LE 28/10/2026 : « Theme clair a ajuster. » Ce bloc portait un
     * brun sombre en dur a 34 pour cent : sur une carte creme, un pave gris
     * boueux qui se lit comme un element desactive. Le filet et le lisere de
     * ce meme bloc, eux, prenaient deja le jeton et basculaient bien : seul le
     * fond ne suivait pas.
     *
     * LE JETON EST CELUI QUI CONTRASTE : 255,255,255 en sombre et 17,24,39 en
     * clair, donc toujours la couleur OPPOSEE a la surface. Le lisere
     * interieur du haut dit deja que ce pave est pose SUR la carte ; le fond
     * le dit maintenant dans les deux themes.
     */
    background: rgba(var(--white-rgb), 0.05);
    box-shadow: inset 0 1px 0 rgba(var(--white-rgb), 0.08);
}

/* L IDENTITE A GAUCHE, LE DETAIL AU MILIEU, LES BOUTONS A DROITE.

   L'ADMIN, LE 04/11/2026 : « Et pourquoi le detail n'est pas entre l'identite
   et les boutons !!! ». Les pastilles etaient posees SOUS le nom, donc tout a
   gauche, pendant que la moitie droite de la ligne restait vide jusqu'aux
   boutons. Elles occupent maintenant cet entre-deux, sur leurs deux rangees.

   `flex: 1` sur le detail, pas sur l'identite : c'est le detail qui prend la
   place restante, l'identite garde la largeur de son nom. */
/* LE GROUPE INTERMEDIAIRE S EFFACE. Il tenait l'identite et les mesures dans
   un seul element de rangee : les deux se serraient l'une contre l'autre
   avant que la rangee ne songe a se replier. `display: contents` les rend a
   la rangee, chacune avec sa propre largeur de repli. */
.partner-pending-diagnostic__main {
    display: contents;
}

/* ET LE DETAIL DESCEND D UNE LIGNE PLUTOT QUE DE S ECRASER.

   Mesure du 04/11, carte du tableau de bord a 744 px : la rangee tenait de
   force, le nom se coupait a « Benjamin Hartma... » et l'intitule de la
   pastille se pliait sur quatre lignes. Une base de 320 px sur le detail le
   fait passer a la ligne avant d'en arriver la, et il y retrouve toute la
   largeur. */
/* RIEN NE S ETIRE POUR REMPLIR LA LIGNE.

   L'ADMIN, LE 04/11/2026 : « remplissage dynamique franchement c'est
   chiant ». Les mesures avaient le droit de grandir pour occuper la place
   restante : leur bloc changeait de largeur d'une ligne a l'autre et d'un
   ecran a l'autre, et l'oeil n'avait plus de point fixe.

   Chaque part prend donc la largeur de son contenu, et c'est le VIDE entre
   les mesures et les boutons qui varie, pas les parts. Le repli, lui, ne
   change pas : quand il n'y a plus la place, la part descend d'une ligne. */
.partner-pending-diagnostic .partner-pending-diagnostic__testing-time {
    flex: 0 1 auto;
    margin-top: 0;
}

.partner-pending-diagnostic__identite {
    flex: 0 1 auto;
    min-width: 0;
}

.partner-pending-diagnostic__name {
    font-weight: 800;
    color: rgba(var(--white-rgb), 0.98);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.partner-pending-diagnostic__meta {
    margin-top: 4px;
    font-size: 13px;
    color: rgba(var(--white-rgb), 0.76);
}

/* DEUX RANGEES PLUTOT QU UNE, POUR RENDRE DE LA LARGEUR.

   L'ADMIN, LE 04/11/2026 : « Temps de traitement au dessus du temps moyen et
   du nombre d'images, sur 2 lignes pour gagner de l'espace ».

   La reactivite jugee est la mesure qu'on lit en premier ; la duree moyenne et
   le nombre d'images l'expliquent. Elles descendent d'un cran et se serrent
   entre elles, au lieu d'allonger la rangee jusqu'aux boutons. */
.partner-pending-diagnostic__testing-time {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    margin-top: 8px;
    font-size: 13px;
    line-height: 1.35;
    color: rgba(var(--white-rgb), 0.82);
}

.partner-pending-diagnostic__time-reste {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 8px;
}

.partner-pending-diagnostic__testing-time span {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 5px 9px;
    border-radius: 999px;
    background: rgba(var(--white-rgb), 0.08);
    border: 1px solid rgba(var(--white-rgb), 0.10);
}

.partner-pending-diagnostic__testing-time em {
    margin-left: 4px;
    font-style: normal;
    font-size: 12px;
    font-weight: 800;
    opacity: 0.92;
}

.partner-pending-diagnostic__time-pill--normal {
    background: rgba(var(--share-bright-rgb), 0.14) !important;
    border-color: rgba(var(--share-bright-rgb), 0.30) !important;
}

.partner-pending-diagnostic__time-pill--fast,
.partner-pending-diagnostic__time-pill--slow {
    background: rgba(var(--red-rgb), 0.16) !important;
    border-color: rgba(var(--teinte-rouge), 0.34) !important;
}

.partner-pending-diagnostic__time-pill--unknown {
    background: rgba(var(--white-rgb), 0.08) !important;
    border-color: rgba(var(--white-rgb), 0.10) !important;
}

/*
 * LE CHIFFRE PREND L ENCRE DE LA PAGE.
 *
 * MESURE DU 28/10/2026, theme clair : CONTRASTE 2,5 sur les trois chiffres de
 * cette rangee -- « 34,4 », « 32 s » et « 4 ». Un creme en dur, #fff7ed, pose
 * sur une pastille claire : le chiffre, qui est la seule chose qu on vient
 * lire ici, etait le moins lisible de toute la rangee.
 *
 * L INSTRUMENT A MENTI DEUX FOIS AVANT DE DIRE CA, et ca vaut d etre note : il
 * lisait les composantes d un `color(srgb ...)`, qui vont de 0 a 1, comme si
 * elles allaient de 0 a 255 -- donc il voyait du noir partout, et rendait un
 * contraste de 1,18 la ou il est de 16. Et il traversait les fonds en
 * degrade, donc il comparait un texte
 * blanc au fond de la CARTE et pas a celui de son bouton. Calibre -- noir sur
 * blanc doit rendre 21 -- il ne rend plus que les trois vrais.
 */
.partner-pending-diagnostic__testing-time strong {
    color: rgba(var(--white-rgb), 0.98);
    font-weight: 900;
}

/* LES BOUTONS SE REPLIENT AU LIEU DE SE SERRER.

   L'ADMIN, LE 04/11/2026 : « Empile les boutons au besoin, ou fais passer a
   la ligne, rends ca bien ! ».

   Ils etaient en rangee a droite, autorises a passer a la ligne mais sans
   largeur de base : trois boutons dans 200 px se serraient jusqu'a couper
   leurs intitules au lieu de descendre. Chaque bouton demande donc sa
   largeur de texte (`flex: 0 1 auto` avec `white-space: nowrap`), et le
   groupe prend toute la ligne des qu'il ne tient plus a cote du reste --
   d'abord deux et un, puis empiles, chacun pleine largeur sous 360 px, la ou
   trois intitules francais ne tiennent plus cote a cote. */
.partner-pending-diagnostic__actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    justify-content: flex-end;

    /* A DROITE TANT QU ELLES TIENNENT. `margin-left: auto` les y pousse quand
       la rangee a du mou ; `flex-basis: auto` leur laisse la largeur de leurs
       trois intitules, ni plus ni moins. */
    flex: 0 1 auto;
    margin-left: auto;
}

/* LES TROIS ACTIONS SONT UNE FAMILLE, ET ELLES SE TIENNENT.

   Deux d'entre elles sont des formulaires, la troisieme est un bouton nu.
   `lk.css` met tous les boutons du produit en pleine largeur sous 640 px :
   le bouton nu s'etirait donc seul sur sa ligne pendant que les deux
   formulaires gardaient la largeur de leur texte. Mesure a 446 px de carte :
   359, 84, 100.

   La rangee reprend la decision de la coquille et l'applique aux trois : au
   repos chacune a la largeur de son intitule, sous 640 px elles s'empilent
   toutes les trois, pleine largeur. Un intitule, lui, ne se plie jamais en
   deux -- il descend avec son bouton. */
.partner-pending-diagnostic__actions .btn {
    white-space: nowrap;
}

/* QUAND ELLES ONT LEUR LIGNE, ELLES LA PRENNENT.

   L'ADMIN, LE 04/11/2026, capture d'une carte etroite : trois boutons
   empiles, cales a droite, et la moitie gauche de la carte vide sur trois
   rangs. « OPTIMISE ».

   Des que la carte n'a plus la largeur de tout mettre sur une ligne, les
   trois actions prennent la leur, en parts egales : un rang au lieu de trois,
   aucune zone morte. Elles ne s'empilent que si un tiers de carte ne suffit
   plus a un intitule -- 140 px, soit le plus long des trois. */
@container ligne-attente (max-width: 800px) {
    /* EN PARTS EGALES, ET C EST UNE GRILLE QUI LE GARANTIT. En rangee
       souple, le dernier bouton d'un rang incomplet s'etire tout seul :
       mesure a 426 px, deux boutons de 192 puis un de 393. Des colonnes de
       meme largeur, autant qu'il en tient a partir de 140 px -- le plus long
       des trois intitules -- et le rang incomplet garde la largeur des
       autres. */
    .partner-pending-diagnostic__actions {
        flex: 1 1 100%;
        margin-left: 0;
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    }

    .partner-pending-diagnostic__actions .btn {
        width: 100%;
    }
}


.partner-pending-diagnostic__actions form {
    margin: 0;
}

.partner-pending-diagnostic__actions .btn {
    min-height: 42px;
    border-radius: 12px;
}

.partner-pending-diagnostic__actions .btn-primary {
    background: #fff7ed;
    border-color: rgba(var(--white-rgb), 0.72);
    color: #7c2d12;
}

.partner-pending-diagnostic__actions .btn-primary:hover {
    background: #ffedd5;
    color: #7c2d12;
}

.partner-pending-diagnostic__actions .btn-secondary {
    background: rgba(var(--ink-900-rgb), 0.72);
    border-color: rgba(var(--white-rgb), 0.16);
    color: rgba(var(--white-rgb), 0.94);
}

.partner-pending-diagnostic__actions .btn-secondary:hover {
    background: rgba(var(--ink-900-rgb), 0.88);
}

/* LE PALIER QUI METTAIT LA RANGEE EN COLONNE EST PARTI.

   Il datait d'avant le repli par largeurs de base, et les deux mecaniques se
   contredisaient : en colonne, un `flex-basis` compte en HAUTEUR, si bien que
   les mesures occupaient 300 px de vide sous deux pastilles de 29. Mesure a
   500 px de fenetre, avant retrait : carte haute de 536 px pour 140 px de
   contenu.

   La rangee se replie d'elle-meme, ligne par ligne, et c'est la seule
   mecanique qui reste. */

.processing-layout {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(360px, 0.9fr);
    gap: 16px;
    align-items: start;
}

.processing-layout__main,
.processing-layout__side,
.processing-card,
.processing-stack {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.processing-card {
    padding: 18px;
}

.processing-muted {
    margin-top: 4px;
    font-size: 12px;
    line-height: 1.35;
    opacity: 0.68;
}

.processing-inline-form {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
}

/* `background-color:` ET NON `background:` : le raccourci remet
   `background-image` a `none`, et il effacait le chevron que la regle
   generale pose sur tout selecteur. Ces deux regles n'ont jamais voulu
   qu'une couleur.

   CE QUE CA DONNAIT : treize selecteurs SANS AUCUNE FLECHE sur la page des
   parcours de praticiens, un sur les parametres. Une regle qui cesse d'agir ne
   crie pas -- le champ s'ouvre toujours au clic, et rien ne dit qu'il est un
   selecteur. Releve le 13/11/2026 en les parcourant un par un. */
.processing-input {
    min-height: 42px;
    padding: 8px 10px;
    border: 1px solid rgba(var(--white-rgb), 0.10);
    border-radius: 12px;
    background-color: rgba(var(--white-rgb), 0.04);
    color: inherit;
    outline: none;
}

.processing-input:focus {
    border-color: rgba(var(--white-rgb), 0.24);
    background-color: rgba(var(--white-rgb), 0.06);
}

/* ET LA PLACE DU CHEVRON SE REPREND ICI, parce que le `padding` ci-dessus est
   un raccourci lui aussi : il ecrase le `padding-right` de la regle generale,
   qui ne pese qu'un element. Le texte serait passe SOUS la fleche.

   LES DEUX VARIABLES SONT CELLES DE LA REGLE GENERALE, posees par elle sur le
   selecteur : ecrire le nombre ici le ferait diverger au premier reglage.

   `select.` ET NON `.processing-input` SEUL : cette classe habille aussi des
   champs de saisie, qui n'ont pas de fleche et n'ont donc rien a reserver. */
select.processing-input {
    padding-right: calc(var(--fleche-ecart) * 2 + var(--fleche-largeur));
}

/*
 * LE MENU DEROULANT DE CES CHAMPS SUIT LE THEME.
 *
 * `color-scheme: dark` est bien pose a la racine, mais il ne suffit PAS quand
 * le champ porte un fond personnalise : le navigateur reprend alors la main et
 * dessine sa liste en clair. C'est le cas ici, `.processing-input` peint son
 * fond en `rgba(white, 0.04)`.
 *
 * Resultat vu a l'ecran, sur « Ouvrir l'essai aux nouveaux praticiens » : liste
 * blanche, option non retenue en gris pale sur blanc, illisible.
 *
 * Le remede est celui deja pose deux fois ailleurs dans cette feuille
 * (`.landing-presentation-field select`, `.admin-partner-journey-select`) : les
 * options portent leurs couleurs, EN OPAQUE. Un fond translucide ne
 * conviendrait pas non plus, le systeme le composerait sur du blanc.
 */
select.processing-input {
    color-scheme: dark;
}

select.processing-input option {
    background: var(--slate-mid);
    color: var(--ink-50);
}

select.processing-input option:checked {
    background: #4056c9;
    color: var(--white);
}

select.processing-input option:disabled {
    color: rgba(var(--white-rgb), 0.48);
}

.processing-input--small {
    width: 92px;
}

.processing-rule-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 12px;
    align-items: center;
    padding: 12px;
    border-radius: 14px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.04);
}

.processing-rule-row__controls {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* UNE ENCRE, PAS UNE OPACITE -- meme raison que le bloc de notifications.
   `opacity: 0.84` eteint le libelle ET la case qu'il porte, et se multiplie au
   voile que la couleur avait deja : 4,24 mesure pour 4,5 exiges sur la carte de
   traitement et sur les reglages. Le libelle d'un interrupteur est ce qu'on lit
   AVANT de basculer ; il prend l'encre pleine, et la case garde sa teinte. */
.processing-checkbox {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    color: rgba(var(--white-rgb), var(--voile-12, 0.94));
    white-space: nowrap;
}

.processing-checkbox input {
    accent-color: var(--green-mid);
}

.processing-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-size: 13px;
    font-weight: 700;
}

.processing-preset {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 12px;
    border-radius: 14px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.04);
}

.processing-preset__head {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    align-items: flex-start;
}

/* --- L'interrupteur se range en colonne ------------------------------------
   -------------------------------------------------------------------------
   `space-between` REPARTIT, IL N ALIGNE PAS. L'en-tete porte quatre enfants :
   le bloc de texte, la case cachee, l'interrupteur, le chevron. L'espace
   restant se distribuant EGALEMENT entre les intervalles, et le bloc de texte
   n'ayant pas de largeur fixe -- 284 px sur une ligne, 233 sur la suivante --,
   la moitie de cet ecart deplacait l'interrupteur. Releve a l'ecran : 856,
   831, 838, 831, puis 986 pixels. Cinq interrupteurs, cinq positions.

   POUR QU UNE COLONNE EXISTE, UN SEUL ENFANT DOIT ABSORBER LE JEU. Le bloc de
   texte pousse, l'interrupteur et le chevron gardent leur taille : l'un se
   range alors toujours a la meme distance de l'autre, quelle que soit la
   longueur du libelle.

   `min-width: 0` VA AVEC. Sans lui, un enfant de flex refuse de descendre sous
   la largeur de son contenu, et un libelle long repousserait l'interrupteur au
   lieu de se replier -- le defaut reviendrait par l'autre bout.
   ------------------------------------------------------------------------- */

.processing-preset__head > :first-child {
    flex: 1 1 auto;
    min-width: 0;
}

.processing-preset__head > .processing-checkbox,
.processing-preset__head > .processing-preset__chevron {
    flex: 0 0 auto;
}

/* --- 12. Les rangees de reglages se serrent sur leur contenu --------------
   -------------------------------------------------------------------------
   `.processing-preset__grid` pose DEUX COLONNES DE 565 px fixes, et elle sert
   neuf fois sur la page. Tant que les champs remplissaient leur colonne, ca ne
   se voyait pas. Des qu'on leur a rendu leur vraie largeur, le defaut est
   apparu : « Jours d'acces complet » occupe un sixieme de sa colonne et
   « Relances par jour » flotte au milieu de la page, a cinq cents pixels de son
   voisin.

   UNE COLONNE FIXE EST UN PARI SUR LE CONTENU. Elle suppose que tous les champs
   ont la meme importance et la meme taille, ce qui n'est vrai sur aucune de ces
   neuf rangees : on y trouve un nom de trente caracteres a cote d'un nombre a
   un chiffre.

   La rangee devient un FLUX : chaque champ prend sa largeur, ils se suivent
   avec un ecart constant, et passent a la ligne quand la place manque. Rien a
   declarer par cas, et une rangee de cinq champs courts tient desormais sur une
   ligne au lieu de deux.

   ALIGNES PAR LE HAUT, et j'ai essaye l'inverse d'abord. `flex-end` alignait
   les champs sur leur ligne de saisie, ce qui parait juste tant que les libelles
   font la meme hauteur. Des qu'une rangee melange « Jours d'acces complet » et
   « Ouvrir l'essai aux nouveaux praticiens », le second passe sur deux lignes,
   et le premier champ se retrouve pousse vers le bas, seul, sous son voisin.

   Par le haut, ce sont les LIBELLES qui s'alignent. Les champs peuvent alors se
   decaler entre eux, ce qui se lit comme deux colonnes de hauteurs differentes,
   et non comme un champ egare.
   ------------------------------------------------------------------------- */
.processing-preset__grid {
    display: flex;
    grid-template-columns: repeat(auto-fit, minmax(116px, 1fr));
    gap: 12px 28px;
    flex-wrap: wrap;
    align-items: flex-start;
}

/* Deux colonnes : a gauche ce qui est a soi, a droite le bareme commun.
   La colonne de gauche prend la largeur de son contenu, la droite le reste :
   c'est le bareme qui a des lignes a faire tenir. */
.processing-balance-card {
    display: grid;
    grid-template-columns: minmax(220px, auto) minmax(0, 1fr);
    align-items: start;
    gap: 14px 32px;
    padding: 18px;
}

.processing-balance-card__mine {
    display: flex;
    flex-direction: column;

    /* Le lien s'arrete a son intitule : dans une colonne, il s'etirait sur
       toute la largeur de la carte. */
    align-items: flex-start;
    gap: 10px;
}

.processing-balance-card__mine .admin-section__title {
    margin: 0;
}

@media (max-width: 860px) {
    .processing-balance-card {
        grid-template-columns: minmax(0, 1fr);
    }
}

.processing-balance-card__bar {
    height: 12px;
    border-radius: 999px;
    overflow: hidden;
    background: rgba(var(--white-rgb), 0.08);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.processing-balance-card__bar-fill {
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(90deg, rgba(var(--green-state-rgb),0.95), rgba(var(--green-mid-rgb),0.78));
}

.processing-balance-card__stats {
    display: flex;
    flex-wrap: wrap;
    gap: 10px 14px;
    font-size: 13px;
    opacity: 0.86;
}

/* Le bareme se consulte ligne par ligne : en phrase continue, il fallait
   relire pour retrouver quel prix allait avec quel traitement. */
.processing-balance-card__products-title {
    margin: 0 0 8px;
    font-size: 13px;
    font-weight: 500;
    opacity: 0.7;
}

/* Le prix est cale a droite de la LISTE, pas de la carte : sur 690 px, l'oeil
   perdait la ligne entre l'intitule et son cout. */
.processing-balance-card__tarifs {
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 13px;

    /* La liste se taille sur sa ligne la plus longue : cadrer sur la carte
       laissait 190 px de vide entre un intitule court et son cout. */
    width: max-content;
    max-width: 100%;
}

.processing-balance-card__tarifs li {
    display: flex;
    align-items: baseline;
    gap: 12px;
    padding: 5px 0;
    border-bottom: 1px solid rgba(var(--white-rgb), 0.06);
}

.processing-balance-card__tarifs li:last-child {
    border-bottom: none;
}

.processing-balance-card__tarifs span {
    opacity: 0.8;
}

/* Les points s'alignent a droite : c'est la colonne qu'on parcourt du regard
   quand on compare deux traitements. */
.processing-balance-card__tarifs strong {
    margin-left: auto;
    font-weight: 600;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

@media (max-width: 1180px) {
    .processing-layout {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 760px) {
    .processing-rule-row,
    .processing-preset__grid {
        grid-template-columns: 1fr;
    }

    .processing-inline-form {
        align-items: stretch;
    }

    .processing-inline-form .processing-input,
    .processing-inline-form .btn {
        width: 100%;
    }
}

/* =========================================
   Баллы и операции обработки
   ========================================= */

.processing-settings-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(320px, 0.65fr);
    gap: 16px;
    align-items: start;
}

.processing-card--operations {
    min-width: 0;
}

.processing-section-head {
    align-items: flex-start;
}

.processing-transactions-search {
    flex: 1 1 320px;
    justify-content: flex-end;
}

.processing-transactions-search .admin-users-panel__search-wrap {
    width: 100%;
    max-width: 420px;
}

.processing-page .admin-email-table-wrap {
    overflow-x: auto;
}

/*
 * CETTE FEUILLE DECRIVAIT UN TABLEAU A SEPT COLONNES QUI N'EXISTE PLUS.
 *
 * Le journal en a CINQ : deux ont ete fondues en une (« +100 -> 100 » se lit
 * comme une phrase) et la colonne d'action a ete retiree. Restaient sept
 * largeurs en `nth-child` -- donc deux qui ne designaient rien -- et un plancher
 * de 1180 px taille pour l'ancienne largeur : sur un ecran de portable, le
 * journal se mettait a defiler de cote pour tenir une place qu'il ne demande
 * plus. Cinq largeurs, et le plancher suit.
 */
.processing-page .processing-table--operations {
    width: 100%;
    min-width: 900px;
    table-layout: fixed;
}

/*
 * CALE EN HAUT, comme la table des soldes juste au-dessus et pour la meme
 * raison : la date et le praticien portent deux lignes, l'operation et le
 * mouvement une seule. Centrees, les uniques tombaient dans l'intervalle des
 * doubles -- 10,4 px entre la date et le mouvement, mesures au bas du
 * rectangle de texte a taille de police egale.
 *
 * Ce `middle` etait ecrit ici, en (0,3,1) : la regle generale de `lk.css`, qui
 * pese (0,1,1), ne pouvait pas l'atteindre. La table des soldes avait bascule,
 * pas celle-ci, et les deux se lisaient differemment sur le meme ecran.
 */
.processing-page .processing-table--operations th,
.processing-page .processing-table--operations td {
    padding: 11px 10px;
    overflow-wrap: anywhere;
    vertical-align: top;
}

/* Date, praticien, operation, mouvement, commentaire : cinq, et leur somme
   fait cent. Le commentaire prend le reste, c'est lui qui porte du texte. */
.processing-page .processing-table--operations th:nth-child(1),
.processing-page .processing-table--operations td:nth-child(1) {
    width: 12%;
}

.processing-page .processing-table--operations th:nth-child(2),
.processing-page .processing-table--operations td:nth-child(2) {
    width: 22%;
}

.processing-page .processing-table--operations th:nth-child(3),
.processing-page .processing-table--operations td:nth-child(3) {
    width: 15%;
}

.processing-page .processing-table--operations th:nth-child(4),
.processing-page .processing-table--operations td:nth-child(4) {
    width: 16%;
}

.processing-page .processing-table--operations th:nth-child(5),
.processing-page .processing-table--operations td:nth-child(5) {
    width: 35%;
}

/*
 * L EN-TETE COLLANT DU JOURNAL A ETE RETIRE, et ses regles restaient.
 *
 * `.processing-table-scroll` n'est posee sur aucun gabarit : huit regles, une
 * barre de defilement dessinee a la main et un commentaire de vingt lignes
 * expliquant pourquoi `border-collapse: collapse` et une entete collante ne
 * vont pas ensemble -- pour une entete qui n'existe plus. Une feuille qui
 * decrit ce qui n'est plus sert de piege : on la lit comme l'etat du produit.
 *
 * La justification est conservee la ou elle vaut encore, dans le gabarit
 * `admin/processing/index.blade.php`, qui dit pourquoi l'entete est partie.
 */

.processing-operation-partner {
    min-width: 0;
}

.processing-operation-partner strong {
    color: rgba(var(--white-rgb), 0.94);
    font-size: 14px;
    line-height: 1.3;
    font-weight: 400;
}

.processing-transaction-type {
    display: inline-flex;
    align-items: center;
    min-height: 28px;
    padding: 0 9px;
    border-radius: 999px;
    background: rgba(var(--blue-light-rgb), 0.12);
    border: 1px solid rgba(var(--blue-light-rgb), 0.22);
    color: var(--blue-mist);
    font-size: 12px;
    line-height: 1;
    font-weight: 400;
}

.processing-values-list {
    display: grid;
    gap: 7px;
}

.processing-values-list > div {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.processing-values-list span,
.processing-balance-state span {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
    font-size: 12px;
    line-height: 1.25;
}

.processing-values-list strong {
    font-size: 14px;
    line-height: 1;
    font-weight: 400;
    white-space: nowrap;
}

.processing-value--positive {
    color: var(--green-soft);
}

.processing-value--negative {
    color: var(--red-soft);
}

.processing-value--reserved {
    color: var(--amber-soft);
}

.processing-value--muted {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
}

/* Trois colonnes imposees dans une cellule de tableau etroite ne tenaient pas :
   138 px pour trois cases, moins les ecarts et les marges interieures, laissent
   26 px de texte, et « Reserve » comme « Disponible » se coupaient en plein
   milieu d'un mot. `auto-fit` avec un minimum reel garde les trois cases cote a
   cote quand la place existe, et les empile quand elle manque : un mot entier
   sur deux lignes se lit, un mot coupe en deux ne se lit pas. */
.processing-balance-state {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
    gap: 6px;
}

/* Le libelle ne se coupe plus au milieu : s'il manque vraiment la place, c'est
   la case qui passe a la ligne, pas le mot qui se brise. */
.processing-balance-state span {
    white-space: nowrap;
}

.processing-balance-state > div {
    display: grid;
    gap: 4px;
    padding: 8px;
    border-radius: 12px;
    background: rgba(var(--white-rgb), 0.04);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.processing-balance-state strong {
    color: rgba(var(--white-rgb), 0.92);
    font-size: 15px;
    line-height: 1;
    font-weight: 400;
}

.processing-balance-state__available {
    background: rgba(var(--share-bright-rgb), 0.08) !important;
    border-color: rgba(var(--share-bright-rgb), 0.18) !important;
}

.processing-balance-state__available strong {
    color: var(--couleur-succes-doux);
}

.processing-operation-description {
    color: rgba(var(--white-rgb), 0.82);
    line-height: 1.4;
}

.processing-transaction-adjustment {
    width: 100%;
    min-width: 0;
    max-width: 100%;
    box-sizing: border-box;
}

.processing-transaction-adjustment > summary {
    list-style: none;
}

.processing-transaction-adjustment > summary::-webkit-details-marker {
    display: none;
}

.processing-transaction-adjustment__toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;

    width: 100%;
    max-width: 100%;
    min-width: 0;
    min-height: 36px;
    box-sizing: border-box;

    padding: 0 10px;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
}

.processing-page .processing-table--operations td:last-child {
    overflow: hidden;
}

.processing-transaction-adjustment[open]
.processing-transaction-adjustment__toggle {
    margin-bottom: 9px;
}

.processing-transaction-adjustment__form {
    display: grid;
    gap: 8px;
}

.processing-transaction-adjustment__form .processing-field {
    gap: 4px;
    font-weight: 400;
}

.processing-transaction-adjustment__form .processing-input,
.processing-transaction-adjustment__form .btn {
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
}

.processing-transaction-adjustment__form .processing-input {
    min-height: 42px;
    padding: 7px 9px;
}

.processing-transaction-adjustment__form .btn {
    /* Ce bouton se pose au bout d'une ligne de saisie : il prend la hauteur du
       champ, pas celle des boutons compacts. Dans une ligne de formulaire,
       c'est le voisinage qui commande, pas la famille du composant. */
    min-height: 42px;
    justify-content: center;
}

.processing-page tr.is-hidden {
    display: none;
}

@media (max-width: 1180px) {
    .processing-settings-grid {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 780px) {
    .processing-section-head {
        flex-direction: column;
    }

    .processing-transactions-search {
        width: 100%;
        justify-content: stretch;
    }

    .processing-transactions-search .admin-users-panel__search-wrap {
        max-width: none;
    }

}

/* ===== Admin help articles ===== */

.admin-help-form-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.45fr) minmax(320px, 0.55fr);
    gap: 18px;
    align-items: start;
}

.admin-help-form-main,
.admin-help-form-side {
    padding: 18px;
}

.admin-help-form-side {
    position: sticky;
    top: 18px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.admin-help-field-hint {
    margin: -8px 0 16px;
    font-size: 13px;
    line-height: 1.45;
}

.admin-help-field-hint code {
    padding: 2px 6px;
    border-radius: 8px;
    background: rgba(var(--white-rgb), 0.06);
    color: var(--couleur-accent-doux);
}

.admin-help-body-field {
    min-height: 360px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
    line-height: 1.5;
}

.admin-help-checkbox {
    margin: 2px 0 0;
}

.admin-help-side-note {
    padding: 12px;
    border-radius: 14px;
    background: rgba(var(--blue-rgb), 0.10);
    border: 1px solid rgba(var(--blue-rgb), 0.22);
    color: rgba(var(--blue-mist-rgb), 0.86);
    font-size: 13px;
    line-height: 1.45;
}

/*
 * Les versions de la fiche dans les autres langues.
 *
 * Bloc a part sous le formulaire principal, et non une colonne : les textes
 * d'aide sont longs, et l'admin compare sa traduction au socle en lisant de
 * haut en bas.
 */
.admin-help-translations {
    margin-top: 18px;
    padding: 18px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.admin-help-translation {
    padding: 16px;
    border-radius: 14px;
    border: 1px solid rgba(var(--slate-light-rgb), 0.18);
    background: rgba(var(--slate-rgb), 0.28);
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.admin-help-translation__head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 4px;
}

.admin-help-translation .admin-help-body-field {
    min-height: 220px;
}

.admin-help-locale-pill {
    display: inline-block;
    margin-right: 6px;
    padding: 2px 8px;
    border-radius: 999px;
    border: 1px solid rgba(var(--blue-rgb), 0.28);
    background: rgba(var(--blue-rgb), 0.12);
    color: rgba(var(--blue-mist-rgb), 0.9);
    font-size: 12px;
    letter-spacing: 0.04em;
}

@media (max-width: 900px) {
    .admin-help-form-grid {
        grid-template-columns: 1fr;
    }

    .admin-help-form-side {
        position: static;
    }
}

/* ===== Admin help media ===== */

.admin-help-media-layout {
    display: grid;
    grid-template-columns: minmax(320px, 0.75fr) minmax(0, 1.45fr);
    gap: 18px;
    align-items: start;
}

.admin-help-media-upload,
.admin-help-media-list-card {
    padding: 18px;
}

.admin-help-media-upload {
    position: sticky;
    top: 18px;
}

.admin-help-media-list-head {
    margin-bottom: 14px;
}

.admin-help-media-filter {
    margin-bottom: 16px;
}

.admin-help-media-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 14px;
}

.admin-help-media-card {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-radius: 18px;
    background: rgba(var(--white-rgb), 0.04);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.admin-help-media-card__preview {
    position: relative;
    overflow: hidden;
    background: rgb(var(--black-rgb));
    aspect-ratio: 16 / 9;
}

.admin-help-media-card__preview img,
.admin-help-media-card__preview video {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.admin-help-media-card__body {
    display: grid;
    gap: 8px;
    padding: 12px;
}

.admin-help-media-card__title {
    color: var(--ink-50);
    font-size: 15px;
    font-weight: 800;
    line-height: 1.25;
}

.admin-help-media-card__meta,
.admin-help-media-card__caption {
    font-size: 12px;
    line-height: 1.35;
}

.admin-help-media-code {
    display: block;
    padding: 7px 8px;
    border-radius: 10px;
    background: rgba(var(--slate-rgb), 0.68);
    color: var(--couleur-accent-doux);
    font-size: 12px;
    overflow-x: auto;
}

.admin-help-media-card__actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 4px;
}

.admin-help-media-card__actions form {
    margin: 0;
}

.admin-help-media-card__actions .btn {
    width: auto;
}

.admin-help-media-picker {
    padding: 12px;
    border-radius: 14px;
    background: rgba(var(--slate-rgb), 0.26);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.admin-help-media-picker__head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 10px;
    margin-bottom: 10px;
}

.admin-help-media-picker__title {
    color: var(--ink-50);
    font-size: 14px;
    font-weight: 800;
    line-height: 1.25;
}

.admin-help-media-picker__hint {
    margin-top: 3px;
    font-size: 12px;
    line-height: 1.35;
}

.admin-help-media-picker__link {
    width: auto;
    padding: 7px 10px;
    font-size: 13px;
}

.admin-help-media-picker__list {
    display: grid;
    gap: 8px;
    max-height: 340px;
    overflow-y: auto;
    padding-right: 4px;
}

.admin-help-media-picker__item {
    appearance: none;
    width: 100%;
    display: grid;
    gap: 4px;
    padding: 9px 10px;
    border-radius: 12px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.04);
    color: inherit;
    text-align: left;
    cursor: pointer;
}

.admin-help-media-picker__item:hover {
    background: rgba(var(--blue-rgb), 0.12);
    border-color: rgba(var(--blue-light-rgb), 0.24);
}

.admin-help-media-picker__type {
    color: rgba(var(--blue-pale-rgb), 0.72);
    font-size: 11px;
    font-weight: 800;
    line-height: 1.2;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.admin-help-media-picker__name {
    color: var(--ink-50);
    font-size: 13px;
    line-height: 1.3;
    font-weight: 700;
}

.admin-help-media-picker__item code {
    color: var(--couleur-accent-doux);
    font-size: 12px;
    overflow-wrap: anywhere;
}

.admin-help-media-picker__empty {
    font-size: 13px;
    line-height: 1.4;
}

@media (max-width: 980px) {
    .admin-help-media-layout {
        grid-template-columns: 1fr;
    }

    .admin-help-media-upload {
        position: static;
    }
}

@media (max-width: 640px) {
    .admin-help-media-card__actions {
        align-items: stretch;
        flex-direction: column;
    }

    .admin-help-media-card__actions .btn,
    .admin-help-media-card__actions form {
        width: 100%;
    }
}

.admin-dashboard__top-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(320px, 0.65fr);
    gap: 16px;
    align-items: start;
}

.admin-processing-orders {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.admin-processing-table-wrap {
    overflow-x: auto;
}

.admin-processing-table {
    width: 100%;
    min-width: 650px;
    border-collapse: collapse;
}

.admin-processing-table th,
.admin-processing-table td {
    padding: 10px 9px;
    border-bottom: 1px solid rgba(var(--white-rgb), 0.08);
    text-align: left;
    vertical-align: top;
    font-size: 13px;
    line-height: 1.35;
}

.admin-processing-table th {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.62;
}

.admin-processing-table__date {
    white-space: nowrap;
    opacity: 0.8;
}

.admin-dashboard__activity {
    display: grid;
    grid-template-columns: 0.985fr 2.015fr;
    gap: 16px;
    align-items: start;
}

.admin-support-card {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

@media (max-width: 1180px) {
    .admin-dashboard__top-grid,
    .admin-dashboard__activity {
        grid-template-columns: 1fr;
    }
}

/* =========================================
   Admin: лендинг-презентация
   ========================================= */

.landing-presentation-admin {
    gap: 18px;
}

.landing-presentation-slide {
    display: grid;
    gap: 20px;
    padding: 20px;
}

.landing-presentation-slide__head {
    align-items: flex-start;
}

.landing-presentation-form {
    display: grid;
    gap: 16px;
}

.landing-presentation-grid {
    display: grid;
    gap: 14px;
}

.landing-presentation-grid--slide {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.landing-presentation-grid--option-meta {
    grid-template-columns: minmax(0, 1fr) 120px;
}

.landing-presentation-field {
    display: grid;
    gap: 7px;
    min-width: 0;
    font-size: 13px;
    font-weight: 800;
    color: rgba(var(--white-rgb), 0.82);
}

.landing-presentation-field--wide {
    grid-column: 1 / -1;
}

.landing-presentation-field input,
.landing-presentation-field textarea,
.landing-presentation-field select {
    width: 100%;
    min-height: 42px;
    padding: 10px 12px;
    border: 1px solid rgba(var(--white-rgb), 0.10);
    border-radius: 12px;
    background-color: rgba(var(--white-rgb), 0.04);
    color: inherit;
    outline: none;
}

.landing-presentation-field textarea {
    resize: vertical;
    line-height: 1.5;
}

.landing-presentation-field select {
    cursor: pointer;
}

.landing-presentation-field input:focus,
.landing-presentation-field textarea:focus,
.landing-presentation-field select:focus {
    border-color: rgba(var(--white-rgb), 0.24);
    background-color: rgba(var(--white-rgb), 0.06);
    box-shadow: 0 0 0 3px rgba(var(--white-rgb), 0.05);
}

.landing-presentation-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
}

.landing-presentation-check {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: rgba(var(--white-rgb), 0.78);
    font-size: 14px;
    line-height: 1.35;
    cursor: pointer;
}

.landing-presentation-check input {
    accent-color: var(--green-mid);
}

.landing-presentation-options {
    display: grid;
    gap: 14px;
    padding-top: 18px;
    border-top: 1px solid rgba(var(--white-rgb), 0.08);
}

.landing-presentation-options__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
}

.landing-presentation-option-card {
    display: grid;
    gap: 13px;
    min-width: 0;
    padding: 16px;
    border-radius: 18px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.04);
}

.landing-presentation-option-card__head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
}

.landing-presentation-option-card__title {
    color: rgba(var(--white-rgb), 0.96);
    font-size: 17px;
    line-height: 1.3;
    font-weight: 900;
}

.landing-presentation-option-card__meta {
    margin-top: 4px;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
    font-size: 12px;
    line-height: 1.35;
}

.landing-presentation-admin code {
    padding: 2px 6px;
    border-radius: 8px;
    background: rgba(var(--slate-rgb), 0.52);
    color: var(--couleur-accent-doux);
    font-size: 12px;
}

@media (max-width: 1180px) {
    .landing-presentation-options__grid {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 780px) {
    .landing-presentation-grid--slide,
    .landing-presentation-grid--option-meta {
        grid-template-columns: 1fr;
    }

    .landing-presentation-actions {
        align-items: stretch;
        flex-direction: column;
    }

    .landing-presentation-actions .btn {
        width: 100%;
    }
}

/* ===== Landing presentation: сценарий презентации ===== */

.landing-presentation-slide--create {
    border-color: rgba(var(--blue-light-rgb), 0.18);
    background:
        radial-gradient(circle at 0% 0%, rgba(66, 95, 71, 0.6), transparent 38%),
        rgba(54, 82, 51, 0.4);
}

.landing-presentation-head-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    flex-wrap: wrap;
}

.landing-presentation-option-create {
    display: grid;
    gap: 14px;
    padding: 16px;
    border-radius: 18px;
    border: 1px dashed rgba(var(--blue-soft-rgb), 0.26);
    background: radial-gradient(circle at 0% 0%, rgba(var(--blue-rgb), 0.08), transparent 40%),
        rgba(var(--white-rgb), 0.025);
}

.landing-presentation-option-create__head h4 {
    margin: 0;
    color: rgba(var(--white-rgb), 0.96);
    font-size: 18px;
    line-height: 1.25;
}

.landing-presentation-option-create__head p {
    margin: 5px 0 0;
    color: rgba(var(--white-rgb), 0.68);
    font-size: 13px;
    line-height: 1.4;
}

.landing-presentation-grid--option-create {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.landing-presentation-option-card__form {
    display: grid;
    gap: 13px;
    min-width: 0;
}

.landing-presentation-delete-form {
    display: flex;
    justify-content: flex-end;
    margin: -2px 0 0;
    padding-top: 12px;
    border-top: 1px solid rgba(var(--white-rgb), 0.06);
}

.landing-presentation-danger-btn {
    border-color: rgba(var(--teinte-rouge), 0.26);
    color: var(--couleur-danger-doux);
    background: rgba(var(--red-deep-rgb), 0.20);
}

.landing-presentation-danger-btn:hover {
    border-color: rgba(var(--teinte-rouge), 0.42);
    background: rgba(var(--red-deep-rgb), 0.32);
}

@media (max-width: 900px) {
    .landing-presentation-grid--option-create {
        grid-template-columns: 1fr;
    }

    .landing-presentation-head-actions {
        justify-content: flex-start;
    }
}

@media (max-width: 640px) {
    .landing-presentation-delete-form {
        justify-content: stretch;
    }

    .landing-presentation-delete-form .btn,
    .landing-presentation-head-actions form,
    .landing-presentation-head-actions .btn {
        width: 100%;
    }
}

.landing-presentation-field select {
    background-color: rgba(var(--white-rgb), 0.04);
    color: rgba(var(--white-rgb), 0.92);
    color-scheme: dark;
}

.landing-presentation-field select option {
    background: var(--slate-mid);
    color: var(--ink-50);
}

.landing-presentation-field select option:checked {
    background: #4056c9;
    color: var(--white);
}

.landing-presentation-field select option:disabled {
    color: rgba(var(--white-rgb), 0.48);
}
/* =========================================
   Admin: лендинг-презентация — компактный редактор
   ========================================= */

.landing-presentation-nav {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    position: static;
    z-index: auto;
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
}

.landing-presentation-nav__label {
    flex: 0 0 auto;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 13px;
    font-weight: 800;
}

.landing-presentation-nav__links {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    min-width: 0;
}

.landing-presentation-nav__link {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 30px;
    padding: 6px 10px;
    border-radius: 999px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.04);
    color: rgba(var(--white-rgb), 0.86);
    text-decoration: none;
    font-size: 13px;
    line-height: 1.2;
}

.landing-presentation-nav__link:hover {
    background: rgba(var(--white-rgb), 0.09);
    border-color: rgba(var(--white-rgb), 0.16);
    color: var(--white);
}

.landing-presentation-nav__link small {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
    font-size: 11px;
    font-weight: 800;
}

.landing-presentation-collapse,
.landing-presentation-subcollapse,
.landing-presentation-option-collapse {
    min-width: 0;
}

.landing-presentation-collapse > summary,
.landing-presentation-subcollapse > summary,
.landing-presentation-option-collapse > summary {
    list-style: none;
    cursor: pointer;
}

.landing-presentation-collapse > summary::-webkit-details-marker,
.landing-presentation-subcollapse > summary::-webkit-details-marker,
.landing-presentation-option-collapse > summary::-webkit-details-marker {
    display: none;
}

.landing-presentation-collapse__summary {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 14px;
    min-width: 0;
    padding: 2px 0;
}

.landing-presentation-collapse__summary::before,
.landing-presentation-subcollapse__summary::before,
.landing-presentation-option-collapse__summary::before {
    content: "▸";
    flex: 0 0 auto;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
    font-size: 14px;
    line-height: 1.35;
    transition: transform .18s ease, color .18s ease;
}

.landing-presentation-collapse[open] > .landing-presentation-collapse__summary::before,
.landing-presentation-subcollapse[open] > .landing-presentation-subcollapse__summary::before,
.landing-presentation-option-collapse[open] > .landing-presentation-option-collapse__summary::before {
    transform: rotate(90deg);
    color: rgba(var(--white-rgb), 0.86);
}

.landing-presentation-collapse__main,
.landing-presentation-option-collapse__main {
    flex: 1 1 auto;
    display: grid;
    gap: 5px;
    min-width: 0;
}

.landing-presentation-collapse__main strong,
.landing-presentation-option-collapse__main strong {
    color: rgba(var(--white-rgb), 0.96);
    font-size: 20px;
    line-height: 1.25;
    font-weight: 900;
}

.landing-presentation-option-collapse__main strong {
    font-size: 16px;
}

.landing-presentation-collapse__main span,
.landing-presentation-option-collapse__main span {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 13px;
    line-height: 1.35;
}

.landing-presentation-collapse__badges {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    flex-wrap: wrap;
}

.landing-presentation-mini-badge {
    display: inline-flex;
    align-items: center;
    min-height: 30px;
    padding: 0 10px;
    border-radius: 999px;
    background: rgba(var(--white-rgb), 0.08);
    border: 1px solid rgba(var(--white-rgb), 0.08);
    color: rgba(var(--white-rgb), 0.72);
    font-size: 12px;
    font-weight: 800;
    white-space: nowrap;
}

.landing-presentation-collapse__body {
    display: grid;
    gap: 14px;
    padding-top: 18px;
}

.landing-presentation-subcollapse {
    border: 1px solid rgba(var(--white-rgb), 0.08);
    border-radius: 16px;
    background: rgba(var(--white-rgb), 0.02);
    overflow: hidden;
}

.landing-presentation-subcollapse__summary {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 13px 14px;
    background: rgba(var(--slate-rgb), 0.24);
}

.landing-presentation-subcollapse__summary span {
    color: rgba(var(--white-rgb), 0.92);
    font-size: 15px;
    font-weight: 900;
    line-height: 1.25;
}

.landing-presentation-subcollapse__summary small {
    margin-left: auto;
    color: rgba(var(--white-rgb), 0.52);
    font-size: 12px;
    line-height: 1.3;
    text-align: right;
}

.landing-presentation-subcollapse__body {
    display: grid;
    gap: 14px;
    padding: 15px;
}

.landing-presentation-options__head {
    align-items: flex-start;
}

.landing-presentation-option-collapse {
    padding: 0;
    overflow: hidden;
}

.landing-presentation-option-collapse__summary {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 16px;
    min-height: 74px;
}

.landing-presentation-option-collapse__summary:hover {
    background: rgba(var(--white-rgb), 0.04);
}

.landing-presentation-option-collapse__body {
    display: grid;
    gap: 13px;
    padding: 0 16px 16px;
    border-top: 1px solid rgba(var(--white-rgb), 0.06);
}

.landing-presentation-option-collapse[open] .landing-presentation-option-collapse__body {
    padding-top: 15px;
}

.landing-presentation-grid--option-edit {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.landing-presentation-option-create {
    margin: 0;
}

.landing-presentation-delete-form--slide {
    margin-top: 0;
}

.landing-presentation-admin :target {
    scroll-margin-top: 90px;
}

@media (max-width: 900px) {
    .landing-presentation-nav {
        position: static;
        align-items: flex-start;
        flex-direction: column;
    }

    .landing-presentation-collapse__summary,
    .landing-presentation-option-collapse__summary {
        align-items: flex-start;
        flex-direction: column;
    }

    .landing-presentation-collapse__badges {
        justify-content: flex-start;
    }

    .landing-presentation-subcollapse__summary {
        align-items: flex-start;
        flex-direction: column;
    }

    .landing-presentation-subcollapse__summary small {
        margin-left: 0;
        text-align: left;
    }

    .landing-presentation-grid--option-edit {
        grid-template-columns: 1fr;
    }
}

/* =========================================
   Admin: выбор промо-изображения для лэндинга
   ========================================= */

.landing-promo-image-field {
    display: grid;
    gap: 9px;
    min-width: 0;
}

.landing-promo-image-picker {
    min-width: 0;
    border-radius: 14px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--slate-rgb), 0.24);
    overflow: hidden;
}

.landing-promo-image-picker__summary {
    list-style: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: 38px;
    padding: 9px 12px;
    cursor: pointer;
    color: rgba(var(--white-rgb), 0.88);
    font-size: 13px;
    line-height: 1.25;
    font-weight: 800;
}

.landing-promo-image-picker__summary::-webkit-details-marker {
    display: none;
}

.landing-promo-image-picker__summary::after {
    content: "▾";
    color: rgba(var(--white-rgb), 0.52);
    font-size: 12px;
    transition: transform .18s ease;
}

.landing-promo-image-picker[open] .landing-promo-image-picker__summary::after {
    transform: rotate(180deg);
}

.landing-promo-image-picker__summary:hover {
    background: rgba(var(--white-rgb), 0.04);
}

.landing-promo-image-picker__summary small {
    margin-left: auto;
    color: rgba(var(--white-rgb), 0.54);
    font-size: 12px;
    font-weight: 700;
}

.landing-promo-image-picker__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
    gap: 10px;
    max-height: 360px;
    overflow-y: auto;
    padding: 12px;
    border-top: 1px solid rgba(var(--white-rgb), 0.08);
}

.landing-promo-image-picker__grid::-webkit-scrollbar {
    width: 10px;
}

.landing-promo-image-picker__grid::-webkit-scrollbar-track {
    background: transparent;
}

.landing-promo-image-picker__grid::-webkit-scrollbar-thumb {
    background: rgba(var(--white-rgb), 0.16);
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: padding-box;
}

.landing-promo-image-picker__item {
    appearance: none;
    display: grid;
    gap: 7px;
    min-width: 0;
    padding: 8px;
    border-radius: 12px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.04);
    color: inherit;
    text-align: left;
    cursor: pointer;
    transition:
        transform .18s ease,
        background .18s ease,
        border-color .18s ease;
}

.landing-promo-image-picker__item:hover {
    transform: translateY(-1px);
    background: rgba(var(--blue-rgb), 0.12);
    border-color: rgba(var(--blue-light-rgb), 0.26);
}

.landing-promo-image-picker__item.is-selected {
    background: rgba(var(--green-state-rgb), 0.11);
    border-color: rgba(var(--green-state-rgb), 0.34);
    box-shadow: 0 0 0 1px rgba(var(--green-state-rgb), 0.10) inset;
}

.landing-promo-image-picker__thumb {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border-radius: 10px;
    background: rgba(var(--surface-sombre-rgb), 0.72);
    border: 1px solid rgba(var(--white-rgb), 0.06);
}

.landing-promo-image-picker__thumb img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.landing-promo-image-picker__name {
    color: rgba(var(--white-rgb), 0.94);
    font-size: 13px;
    line-height: 1.25;
    font-weight: 800;
    overflow-wrap: anywhere;
}

.landing-promo-image-picker__item code {
    width: fit-content;
    max-width: 100%;
    overflow-wrap: anywhere;
    color: var(--couleur-accent-doux);
    font-size: 11px;
}

.landing-promo-image-picker__empty {
    margin: 0;
    padding: 10px 12px;
    border-radius: 12px;
    background: rgba(var(--white-rgb), 0.04);
    border: 1px solid rgba(var(--white-rgb), 0.08);
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 13px;
    line-height: 1.4;
}

.landing-promo-image-picker__empty code {
    color: var(--couleur-accent-doux);
}

@media (max-width: 760px) {
    .landing-promo-image-picker__grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        max-height: 320px;
    }
}

@media (max-width: 460px) {
    .landing-promo-image-picker__grid {
        grid-template-columns: 1fr;
    }
}

/* =========================================
   Admin: статистика лендинг-презентации
   ========================================= */

.landing-presentation-stats {
    gap: 18px;
}

.landing-stats-cards {
    margin-bottom: 0;
}

.landing-stats-layout {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    align-items: start;
}

.landing-stats-section {
    display: grid;
    gap: 14px;
    padding: 18px;
    min-width: 0;
}

.landing-stats-section--wide {
    grid-column: 1 / -1;
}

.landing-stats-section__head {
    align-items: flex-start;
}

.landing-stats-table-wrap {
    min-width: 0;
    overflow-x: auto;
}

.landing-stats-table {
    min-width: 0;
}

.landing-stats-table--events {
    min-width: 1180px;
}

.landing-stats-muted-code {
    margin-top: 4px;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
    font-size: 12px;
    line-height: 1.35;
    word-break: break-word;
}

.landing-stats-payload {
    max-width: 320px;
    max-height: 160px;
    margin: 0;
    padding: 8px 10px;
    overflow: auto;
    border-radius: 10px;
    background: rgba(var(--slate-rgb), 0.60);
    color: rgba(var(--couleur-accent-doux-rgb), 0.92);
    font-size: 12px;
    line-height: 1.35;
    white-space: pre-wrap;
    word-break: break-word;
}

.landing-presentation-stats code {
    padding: 2px 6px;
    border-radius: 8px;
    background: rgba(var(--slate-rgb), 0.52);
    color: var(--couleur-accent-doux);
    font-size: 12px;
}

.landing-stats-table strong {
    display: inline-block;
    color: rgba(var(--white-rgb), 0.94);
    font-size: 15px;
    font-weight: 400;
    line-height: 1.3;
}

.landing-stats-path {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    min-width: 220px;
}

.landing-stats-path__item {
    display: inline-grid;
    gap: 3px;
    padding: 7px 9px;
    border-radius: 12px;
    background: rgba(var(--white-rgb), 0.06);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.landing-stats-path__item strong {
    color: rgba(var(--white-rgb), 0.92);
    font-size: 13px;
    line-height: 1.25;
}

.landing-stats-path__item code {
    width: fit-content;
}

.landing-stats-path__arrow {
    color: rgba(var(--white-rgb), var(--voile-mention-basse, 0.42));
    font-weight: 900;
}

.landing-stats-table--registrations {
    min-width: 760px;
}

.landing-stats-table--registrations th:nth-child(1),
.landing-stats-table--registrations td:nth-child(1) {
    width: 150px;
}

.landing-stats-table--registrations th:nth-child(2),
.landing-stats-table--registrations td:nth-child(2) {
    width: 220px;
}

.landing-stats-table--registrations th:nth-child(3),
.landing-stats-table--registrations td:nth-child(3) {
    width: auto;
}

@media (max-width: 1180px) {
    .landing-stats-layout {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 760px) {
    .landing-stats-section {
        padding: 14px;
    }

    .landing-stats-table {
        min-width: 720px;
    }

    .landing-stats-table--events {
        min-width: 1080px;
    }
}
/* =========================================
   Admin: лендинг-презентация — новые кнопки
   ========================================= */

.landing-presentation-buttons-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
}

.landing-presentation-checks-row {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}

.landing-presentation-mini-badge--gold {
    background: rgba(var(--teinte-or), 0.16);
    border-color: rgba(var(--teinte-or), 0.26);
    color: #fcd899;
}

.landing-presentation-mini-badge--green {
    background: rgba(var(--green-state-rgb), 0.14);
    border-color: rgba(var(--green-state-rgb), 0.28);
    color: var(--green-mid);
}

.landing-presentation-empty {
    padding: 16px;
}

.landing-slide-buttons-list {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
}

.landing-slide-button-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 92px;
    gap: 10px;
    align-items: start;
    padding: 12px;
    border-radius: 16px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.04);
}

.landing-slide-button-row.is-global {
    border-color: rgba(var(--teinte-or), 0.22);
    background: radial-gradient(circle at 0% 0%, rgba(var(--teinte-or), 0.08), transparent 42%),
        rgba(var(--white-rgb), 0.03);
}

.landing-slide-button-row__check {
    min-width: 0;
}

.landing-slide-button-row__check span {
    display: grid;
    gap: 4px;
    min-width: 0;
}

.landing-slide-button-row__check strong {
    color: rgba(var(--white-rgb), 0.94);
    font-size: 15px;
    line-height: 1.25;
    font-weight: 900;
}

.landing-slide-button-row__check small {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 12px;
    line-height: 1.35;
}

.landing-slide-button-row__sort {
    gap: 5px;
}

.landing-slide-button-row__sort input:disabled,
.landing-slide-button-row__check input:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}

.landing-slide-button-row__badges {
    grid-column: 1 / -1;
    justify-content: flex-start;
}

@media (max-width: 1180px) {
    .landing-presentation-buttons-grid {
        grid-template-columns: 1fr;
    }

    .landing-slide-buttons-list {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .landing-slide-button-row {
        grid-template-columns: minmax(0, 1fr) 92px;
    }
}

@media (max-width: 760px) {
    .landing-slide-buttons-list {
        grid-template-columns: 1fr;
    }

    .landing-slide-button-row {
        grid-template-columns: 1fr;
    }

    .landing-slide-button-row__sort {
        max-width: none;
    }

    .landing-presentation-checks-row {
        align-items: flex-start;
        flex-direction: column;
    }
}

/* =========================================
   Partner journey widget
   ========================================= */

/* --- 2. Le bloc du parcours praticien passe au cyan ---------------------
   C'est LA carte appuyee de la page, celle qui appelle un geste, et a ce titre
   elle a droit au traitement fort. Mais en violet elle appelle vers une
   couleur qui n'existe nulle part ailleurs dans le produit.

   On garde son intensite, on change sa teinte. La comparaison utile est la
   carte d'etape du parcours client : meme role, meme force, et desormais meme
   couleur.
   ------------------------------------------------------------------------ */
.partner-journey-widget.card {
    display: block;
    padding: 18px 20px;
    border-color: rgba(var(--blue-light-rgb), 0.22);
    background: radial-gradient(circle at 0% 0%,
            rgba(var(--portal-accent-rgb), 0.22), transparent 55%),
        rgba(var(--portal-accent-rgb), 0.10);
    border: var(--filet-epaisseur) solid var(--filet-action);
}

.partner-journey-widget__main {
    display: grid;
    gap: 14px;
    min-width: 0;
}

.partner-journey-widget__top {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 18px;
    align-items: start;
}

.partner-journey-widget__top > div {
    min-width: 0;
}

.partner-journey-widget__eyebrow {
    color: rgba(var(--blue-pale-rgb), 0.72);
    font-size: 12px;
    line-height: 1.2;
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.07em;
}

.partner-journey-widget__title {
    margin: 8px 0 0;
    color: rgba(var(--white-rgb), 0.98);
    font-size: 24px;
    line-height: 1.25;
}

.partner-journey-widget__text {
    max-width: none;
    width: 100%;
    margin: 7px 0 0;
    color: rgba(var(--white-rgb), 0.74);
    font-size: 14px;
    line-height: 1.5;
}

.partner-journey-widget__counter {
    min-width: 82px;
    padding: 12px 14px;
    border-radius: 16px;
    background: rgba(var(--white-rgb), 0.06);
    border: 1px solid rgba(var(--white-rgb), 0.08);
    text-align: center;
}

.partner-journey-widget__counter strong {
    display: block;
    color: rgba(var(--white-rgb), 0.98);
    font-size: 28px;
    line-height: 1;
    font-weight: 700;
}

.partner-journey-widget__counter span {
    display: block;
    margin-top: 4px;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 12px;
    line-height: 1.2;
}

.partner-journey-widget__bar {
    height: 12px;
    overflow: hidden;
    border-radius: 999px;
    background: rgba(var(--white-rgb), 0.08);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.partner-journey-widget__bar span {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(90deg, rgba(var(--blue-light-rgb), 0.95), rgba(var(--green-state-rgb), 0.82));
}

.partner-journey-widget__current {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 14px;
    align-items: center;
    padding: 13px 14px;
    border-radius: 16px;
    background: rgba(var(--slate-rgb), 0.28);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.partner-journey-widget__current-main {
    display: grid;
    gap: 5px;
    min-width: 0;
}

.partner-journey-widget__current span {
    color: rgba(var(--blue-pale-rgb), 0.68);
    font-size: 12px;
    line-height: 1.2;
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.partner-journey-widget__current strong {
    color: rgba(var(--white-rgb), 0.95);
    font-size: 17px;
    line-height: 1.3;
    font-weight: 700;
}

.partner-journey-widget__current p {
    margin: 0;
    color: rgba(var(--white-rgb), 0.70);
    font-size: 13px;
    line-height: 1.45;
}

/* --- Le repli « En savoir plus », troisieme nom du meme objet -------------
   -------------------------------------------------------------------------
   Vu en capture en comparant les deux pages : le meme repli existe sous TROIS
   noms selon l'ecran, `__step__details`, `__now__details` et ici
   `__widget__details`. Les deux premiers ont ete repris sur le parcours ; le
   troisieme gardait sa case, et c'est la plus voyante des trois : une barre
   pleine largeur, fond blanc 0,06, filet 0,09, rayon 14 px, posee au bas du
   bloc cyan ou elle pese autant que le bloc lui-meme.

   Meme regle que les deux autres : le repli est une ligne de texte qu'on peut
   ouvrir, pas une surface.
   ------------------------------------------------------------------------- */
.partner-journey-widget__details {
    margin-top: 2px;
    border-radius: 14px;
    background: none;
    border: 0;
    overflow: hidden;
    padding: 0;
}

.partner-journey-widget__details summary {
    list-style: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 34px;
    padding: 0 12px;
    color: rgba(var(--couleur-accent-doux-rgb), 0.94);
    font-size: 13px;
    line-height: 1;
    font-weight: 400;
}

.partner-journey-widget__details summary::-webkit-details-marker {
    display: none;
}

.partner-journey-widget__details summary::after {
    content: "▾";
    color: rgba(var(--white-rgb), 0.66);
    font-size: 12px;
    transition: transform .18s ease;
}

.partner-journey-widget__details[open] summary::after {
    transform: rotate(180deg);
}

.partner-journey-widget__details summary:hover {
    color: var(--white);
    background: rgba(var(--white-rgb), 0.06);
}

.partner-journey-widget__details-body {
    padding: 0 12px 12px;
    color: rgba(var(--white-rgb), 0.76);
    font-size: 13px;
    line-height: 1.5;
}

.partner-journey-widget__path-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 34px;
    /*
     * SANS `border-box`, LE BOUTON DEBORDE DE SA CARTE.
     *
     * Sous 900 px il passe en `width: 100%` pour prendre la ligne. En boite
     * de contenu, ces 100 % s'entendent hors rembourrage : 484 px de colonne
     * plus 28 de rembourrage et 2 de bordure faisaient 514, soit 30 px passes
     * par-dessus le bord droit de la carte, pile la largeur qu'on lui ajoute.
     */
    box-sizing: border-box;
    padding: 0 14px;
    border-radius: 999px;
    background: rgba(var(--blue-light-rgb), 0.16);
    border: 1px solid rgba(var(--blue-soft-rgb), 0.26);
    color: rgba(var(--blue-mist-rgb), 0.96);
    font-size: 13px;
    line-height: 1;
    font-weight: 400;
    text-decoration: none;
    white-space: nowrap;
}

.partner-journey-widget__path-link:hover {
    background: rgba(var(--blue-light-rgb), 0.24);
    border-color: rgba(var(--blue-soft-rgb), 0.38);
    color: var(--white);
}

.partner-journey-widget__current--done {
    border-color: rgba(var(--green-state-rgb), 0.24);
    background: rgba(var(--share-bright-rgb), 0.08);
}

.partner-journey-widget__metrics {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.partner-journey-widget__metrics span {
    display: inline-flex;
    align-items: center;
    min-height: 30px;
    padding: 0 10px;
    border-radius: 999px;
    background: rgba(var(--white-rgb), 0.06);
    border: 1px solid rgba(var(--white-rgb), 0.08);
    color: rgba(var(--white-rgb), 0.70);
    font-size: 12px;
    line-height: 1;
    font-weight: 400;
}

.partner-journey-widget__metrics strong {
    margin-left: 5px;
    color: rgba(var(--white-rgb), 0.94);
    font-weight: 400;
}

/* =========================================
   Partner journey page
   ========================================= */

.partner-journey-page {
    gap: 18px;
}

.partner-journey-page .partner-journey-glass {
    position: relative;
    overflow: hidden;
    background: transparent !important;
    isolation: isolate;
}

/* --- 2. LE VERRE : c'est lui qui peint toute la page ---------------------
   -------------------------------------------------------------------------
   PIEGE, ET IL EXPLIQUE POURQUOI RIEN NE PRENAIT. Chaque surface de cette page
   porte `partner-journey-glass`, dont la regle dit
   `background: transparent !important`. La couleur ne vient donc PAS du fond
   de l'element mais de DEUX pseudo-elements poses par-dessus :

     `::before`  une ardoise a 10 % plus `backdrop-filter: blur(24px)
                 saturate(145%)`, soit un flou de verre par surface ;
     `::after`   `var(--partner-journey-glass-tint)`, deux ou trois degrades
                 radiaux, redefini par chaque etat de carte.

   Repeindre `background` sur l'element ne pouvait donc rien donner : la
   declaration passait bien, et restait invisible sous les deux pseudos. Le
   meme piege que le panneau de progression de l'espace praticien, qui n'avait
   aucun fond et se voyait quand meme.

   ON GARDE LA MECANIQUE, ON CHANGE CE QU ELLE PEINT. Le `::before` devient la
   surface levee retenue pour les blocs, le `::after` porte la teinte. C'est
   moins de code qu'une bataille de `!important`, et surtout ca laisse la page
   fonctionner comme elle a ete concue.

   LE FLOU PART. Onze cartes floutees, plus le heros, plus les trois blocs :
   quinze recompositions de la zone situee derriere, a chaque image. La surface
   levee rend le meme service sans rien recomposer. */
.partner-journey-page .partner-journey-glass::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    border-radius: inherit;
    background: rgba(var(--white-rgb), 0.04);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    pointer-events: none;
}

.partner-journey-page .partner-journey-glass::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    border-radius: inherit;
    background: none;
    pointer-events: none;
}

.partner-journey-page .partner-journey-glass > * {
    position: relative;
    z-index: 1;
}

.partner-journey-page .journey-shell {
    padding: 22px 24px;
    border-radius: 18px;
    border: 1px solid rgba(216, 180, 254, 0.26);
    background: radial-gradient(circle at 8% 0%, rgba(var(--blue-light-rgb), 0.34), transparent 34%),
        radial-gradient(circle at 92% 10%, rgba(236, 72, 153, 0.22), transparent 34%),
        linear-gradient(135deg, rgba(99, 102, 241, 0.72), rgba(147, 51, 234, 0.62)),
        rgba(76, 29, 149, 0.72);
    box-shadow: 0 24px 68px rgba(30, 27, 75, 0.32),
        inset 0 1px 0 rgba(var(--white-rgb), 0.14);
}

.partner-journey-page .admin-dashboard__eyebrow {
    color: rgba(233, 213, 255, 0.84);
    opacity: 1;
}

.partner-journey-page .admin-dashboard__title {
    color: rgba(var(--white-rgb), 0.98);
    text-shadow: 0 2px 12px rgba(49, 46, 129, 0.32);
}

/* --- 11. La phrase d'accueil retrouve une longueur de ligne --------------
   -------------------------------------------------------------------------
   Le bouton du premier bloc bornait la colonne de texte sans qu'on l'ait
   voulu : en le retirant, la phrase s'est etalee sur toute la largeur du
   bloc. Mesure apres retrait : 1 286 px, soit 145 caracteres par ligne, pour
   un confort de lecture qui se situe entre 65 et 75.

   ON BORNE ICI, ET PAS DANS LA CARTE DE L ETAPE. La difference n'est pas
   d'humeur : la carte de l'etape occupe deja les deux tiers d'une grille,
   c'est elle qui borne la ligne. Ce bloc-ci n'a plus rien qui le borne, donc
   la borne doit etre ecrite.

   78ch et non 65 : c'est une phrase d'accueil sous un titre de 30 px, elle
   supporte d'etre plus large qu'un paragraphe de contenu. Elle tombe a
   environ 690 px, la moitie du bloc.
   ------------------------------------------------------------------------- */
.partner-journey-page .admin-dashboard__text {
    max-width: 78ch;
    color: rgba(var(--white-rgb), 0.86);
    opacity: 1;
}

.partner-journey-page .admin-dashboard__hero-actions .btn {
    border-color: rgba(var(--white-rgb), 0.24);
    background: rgba(var(--white-rgb), 0.13);
    color: rgba(var(--white-rgb), 0.96);
}

.partner-journey-page .admin-dashboard__hero-actions .btn:hover {
    background: rgba(var(--white-rgb), 0.20);
    border-color: rgba(var(--white-rgb), 0.34);
}

.partner-journey-empty {
    padding: 22px;
}

.partner-journey-empty h2 {
    margin: 0 0 8px;
}

.partner-journey-empty p {
    margin: 0;
    color: rgba(var(--white-rgb), 0.74);
    line-height: 1.5;
}

.partner-journey-bottom-cta {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 18px;
    align-items: center;
    padding: 20px;
    border-radius: 18px;
    border: 1px solid rgba(216, 180, 254, 0.28);
    background:
        radial-gradient(circle at 0% 0%, rgba(125, 211, 252, 0.18), transparent 34%),
        radial-gradient(circle at 100% 0%, rgba(216, 180, 254, 0.16), transparent 36%),
        rgba(var(--slate-mid-rgb), 0.34);
}

.partner-journey-bottom-cta > div:first-child {
    min-width: 0;
}

.partner-journey-bottom-cta__eyebrow {
    margin-bottom: 7px;
    color: rgba(var(--blue-pale-rgb), 0.78);
    font-size: 12px;
    line-height: 1.2;
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.partner-journey-bottom-cta h2 {
    margin: 0;
    color: rgba(var(--white-rgb), 0.98);
    font-size: 22px;
    line-height: 1.25;
}

.partner-journey-bottom-cta p {
    margin: 7px 0 0;
    max-width: 820px;
    color: rgba(var(--white-rgb), 0.74);
    font-size: 14px;
    line-height: 1.5;
}

.partner-journey-bottom-cta__actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    flex-wrap: wrap;
}

.partner-journey-bottom-cta {
    margin-top: 2px;
    border-color: rgba(var(--green-soft-rgb), 0.30);
    --partner-journey-glass-tint: radial-gradient(circle at 0% 0%, rgba(var(--share-bright-rgb), 0.22), transparent 36%),
        radial-gradient(circle at 100% 0%, rgba(125, 211, 252, 0.16), transparent 38%),
        rgba(20, 83, 45, 0.16);
}

.partner-journey-step__details {
    position: relative;
    z-index: 1;
    margin-top: 2px;
    border-radius: 14px;
    background: rgba(var(--white-rgb), 0.075);
    border: 1px solid rgba(var(--white-rgb), 0.08);
    overflow: hidden;
    backdrop-filter: blur(14px) saturate(120%);
    -webkit-backdrop-filter: blur(14px) saturate(120%);
}

.partner-journey-step__details summary {
    list-style: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 34px;
    padding: 0 11px;
    color: rgba(var(--couleur-accent-doux-rgb), 0.92);
    font-size: 13px;
    line-height: 1;
    font-weight: 400;
}

.partner-journey-step__details summary::-webkit-details-marker {
    display: none;
}

.partner-journey-step__details summary::after {
    content: "▾";
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 12px;
    transition: transform .18s ease;
}

.partner-journey-step__details[open] summary::after {
    transform: rotate(180deg);
}

.partner-journey-step__details summary:hover {
    color: var(--white);
    background: rgba(var(--white-rgb), 0.06);
}

.partner-journey-step__details .partner-journey-step__description {
    margin: 0;
    padding: 0 11px 12px;
}

.partner-journey-overview {
    display: grid;
    gap: 14px;
    padding: 20px;
    border-radius: 18px;
    border: 1px solid rgba(216, 180, 254, 0.24);
    --partner-journey-glass-tint: radial-gradient(circle at 0% 0%, rgba(var(--blue-rgb), 0.22), transparent 36%),
        radial-gradient(circle at 100% 0%, rgba(236, 72, 153, 0.16), transparent 38%),
        rgba(67, 56, 202, 0.18);
    box-shadow: 0 20px 52px rgba(var(--slate-rgb), 0.24),
        inset 0 1px 0 rgba(var(--white-rgb), 0.10);
}

.partner-journey-summary-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(320px, 0.72fr);
    gap: 14px;
    align-items: stretch;
}

.partner-journey-summary-grid--compact {
    grid-template-columns: minmax(0, 1fr) minmax(300px, 0.62fr);
}

.partner-journey-summary-card {
    display: grid;
    gap: 10px;
    align-content: start;
    padding: 14px 15px;
    border-radius: 18px;
    background: linear-gradient(135deg, rgba(var(--white-rgb), 0.14), rgba(var(--white-rgb), 0.07)),
        rgba(var(--slate-mid-rgb), 0.28);
    border: 1px solid rgba(var(--white-rgb), 0.15);
    box-shadow: inset 0 1px 0 rgba(var(--white-rgb), 0.10);
    backdrop-filter: blur(14px) saturate(125%);
    -webkit-backdrop-filter: blur(14px) saturate(125%);
}

.partner-journey-summary-card__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.partner-journey-summary-card__head div {
    display: grid;
    gap: 4px;
    min-width: 0;
}

.partner-journey-summary-card__head span {
    color: rgba(233, 213, 255, 0.82);
    font-size: 12px;
    line-height: 1.2;
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.partner-journey-summary-card__head strong {
    color: rgba(var(--white-rgb), 0.96);
    font-size: 14px;
    line-height: 1.35;
    font-weight: 400;
}

.partner-journey-summary-card__head em {
    min-width: 58px;
    padding: 7px 10px;
    border-radius: 999px;
    background: rgba(var(--white-rgb), 0.16);
    border: 1px solid rgba(var(--white-rgb), 0.18);
    color: rgba(var(--white-rgb), 0.98);
    font-size: 13px;
    line-height: 1;
    font-style: normal;
    text-align: center;
}

.partner-journey-summary-card.is-expired {
    border-color: rgba(var(--teinte-rouge), 0.28);
    background: radial-gradient(circle at 100% 0%, rgba(var(--teinte-rouge), 0.18), transparent 38%),
        rgba(var(--red-deep-rgb), 0.22);
}

.partner-journey-steps {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 14px;
    align-items: stretch;
}

/* L ETAT PAR DEFAUT, c'est-a-dire « pas encore fait ». Il prend le traitement
   des BLOCS DE CETTE PAGE, celui de « Votre prochaine etape » : la surface
   levee posee par le `::before` du verre, et le filet large.

   Premiere version : l'ardoise 0,7 de `.card`. Vu en capture, elle faisait une
   carte plus DENSE que le bloc juste au-dessus, alors qu'elle dit moins de
   choses. Une etape a venir n'a rien a annoncer ; elle doit peser le moins
   possible, et le moins possible sur cette page est deja defini. */
.partner-journey-page .partner-journey-step {
    position: relative;
    overflow: hidden;
    display: grid;
    grid-template-columns: 1fr;
    gap: 14px;
    min-height: 220px;
    padding: 17px;
    align-content: start;
    border-radius: 14px;
    border: var(--filet-epaisseur) solid var(--filet-large);
    --partner-journey-glass-tint: radial-gradient(circle at 0% 0%, rgba(125, 211, 252, 0.18), transparent 38%),
        radial-gradient(circle at 100% 100%, rgba(var(--blue-rgb), 0.12), transparent 42%),
        rgba(30, 64, 175, 0.14);
    box-shadow: none;
}

.partner-journey-page .partner-journey-step.is-current,
.partner-journey-page .partner-journey-step.is-progress {
    border-color: rgba(216, 180, 254, 0.48);
    --partner-journey-glass-tint:
        radial-gradient(circle at 0% 0%, rgba(232, 121, 249, 0.30), transparent 38%),
        radial-gradient(circle at 100% 100%, rgba(129, 140, 248, 0.24), transparent 44%),
        linear-gradient(135deg, rgba(126, 34, 206, 0.34), rgba(76, 29, 149, 0.24)),
        rgba(88, 28, 135, 0.18);
    box-shadow: 0 22px 58px rgba(88, 28, 135, 0.28),
        inset 0 1px 0 rgba(var(--white-rgb), 0.14);
}

.partner-journey-page .partner-journey-step.is-completed {
    border-color: rgba(var(--green-soft-rgb), 0.42);
    --partner-journey-glass-tint:
        radial-gradient(circle at 0% 0%, rgba(var(--green-soft-rgb), 0.22), transparent 38%),
        radial-gradient(circle at 100% 100%, rgba(129, 140, 248, 0.16), transparent 44%),
        linear-gradient(135deg, rgba(22, 163, 74, 0.24), rgba(88, 28, 135, 0.16)),
        rgba(20, 83, 45, 0.16);
}

.partner-journey-step__marker {
    position: relative;
    z-index: 1;
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 16px;
    background: rgba(186, 230, 253, 0.18);
    border: 1px solid rgba(186, 230, 253, 0.28);
    color: rgba(var(--ink-50-rgb), 0.96);
    font-size: 16px;
    font-weight: 400;
    box-shadow: inset 0 1px 0 rgba(var(--white-rgb), 0.12);
}

.partner-journey-step.is-current .partner-journey-step__marker,
.partner-journey-step.is-progress .partner-journey-step__marker {
    background: rgba(232, 121, 249, 0.22);
    border-color: rgba(240, 171, 252, 0.42);
    color: var(--violet-pale);
}

.partner-journey-step.is-completed .partner-journey-step__marker {
    background: rgba(var(--share-bright-rgb), 0.20);
    border-color: rgba(var(--green-soft-rgb), 0.38);
    color: var(--green-pale);
}

.partner-journey-step__body {
    position: relative;
    z-index: 1;
    display: grid;
    gap: 10px;
    min-width: 0;
}

.partner-journey-step__top {
    display: flex;
    justify-content: space-between;
    gap: 14px;
    align-items: flex-start;
}

.partner-journey-step__top h2 {
    margin: 0;
    color: rgba(var(--white-rgb), 0.98);
    font-size: 20px;
    line-height: 1.28;
}

.partner-journey-step__top p,
.partner-journey-step__description {
    margin: 6px 0 0;
    color: rgba(var(--white-rgb), 0.78);
    font-size: 14px;
    line-height: 1.5;
}

.partner-journey-step__status {
    display: inline-flex;
    align-items: center;
    min-height: 30px;
    padding: 0 10px;
    border-radius: 999px;
    background: rgba(186, 230, 253, 0.14);
    border: 1px solid rgba(186, 230, 253, 0.22);
    color: rgba(var(--couleur-accent-doux-rgb), 0.92);
    font-size: 12px;
    line-height: 1;
    font-weight: 400;
    white-space: nowrap;
}

.partner-journey-step.is-current .partner-journey-step__status,
.partner-journey-step.is-progress .partner-journey-step__status {
    background: rgba(232, 121, 249, 0.18);
    border-color: rgba(240, 171, 252, 0.34);
    color: var(--violet-pale);
}

.partner-journey-step.is-completed .partner-journey-step__status {
    background: rgba(var(--share-bright-rgb), 0.16);
    border-color: rgba(var(--green-soft-rgb), 0.30);
    color: var(--green-pale);
}

.partner-journey-step__count {
    width: fit-content;
    padding: 7px 10px;
    border-radius: 999px;
    background: rgba(var(--white-rgb), 0.10);
    border: 1px solid rgba(var(--white-rgb), 0.12);
    color: rgba(var(--white-rgb), 0.82);
    font-size: 13px;
    line-height: 1.4;
}

.partner-journey-step__count strong {
    color: rgba(var(--white-rgb), 0.98);
    font-weight: 400;
}

.partner-journey-access__bar {
    height: 10px;
    overflow: hidden;
    border-radius: 999px;
    background: rgba(var(--white-rgb), 0.08);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.partner-journey-access__bar span {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(90deg, rgba(var(--green-rgb), 0.94), rgba(125, 211, 252, 0.88), rgba(216, 180, 254, 0.82));
    transition: width .18s ease;
}

.partner-journey-access__note {
    padding: 9px 10px;
    border-radius: 12px;
    background: rgba(var(--red-rgb), 0.10);
    border: 1px solid rgba(var(--teinte-rouge), 0.22);
    color: var(--couleur-danger-doux);
    font-size: 12px;
    line-height: 1.45;
}

.partner-journey-access.is-expired {
    border-color: rgba(var(--teinte-rouge), 0.24);
    background: rgba(var(--red-deep-rgb), 0.12);
}

.partner-journey-access.is-expired .partner-journey-access__bar span {
    background: rgba(var(--teinte-rouge), 0.82);
}

.partner-pending-diagnostic__locked {
    display: grid;
    gap: 8px;
}

.partner-pending-diagnostic__locked .btn[disabled] {
    opacity: 0.55;
    cursor: not-allowed;
}

.partner-pending-diagnostic__locked-note {
    max-width: 260px;
    color: rgba(var(--white-rgb), 0.78);
    font-size: 12px;
    line-height: 1.35;
}

@media (max-width: 1180px) {
    .partner-journey-steps {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 980px) {
    .partner-journey-summary-grid,
    .partner-journey-summary-grid--compact {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 780px) {
    .partner-journey-steps,
    .partner-journey-widget__top,
    .partner-journey-widget__current,
    .partner-journey-now,
    .partner-journey-bottom-cta {
        grid-template-columns: 1fr;
    }

    .partner-journey-now__actions,
    .partner-journey-bottom-cta__actions {
        justify-content: flex-start;
    }

    .partner-journey-now__actions .btn,
    .partner-journey-bottom-cta__actions .btn {
        width: 100%;
        justify-content: center;
    }

    .partner-journey-overview__head,
    .partner-journey-step__top {
        flex-direction: column;
    }

    .partner-journey-widget__path-link {
        width: 100%;
    }
}

/* =========================================
   Admin: путь специалистов
   ========================================= */

.admin-partner-journeys-page {
    gap: 18px;
}

.admin-partner-journey-hero .admin-dashboard__text {
    max-width: none;
}

.admin-partner-journey-hero__stats {
    margin-top: 14px;
}

.admin-partner-journey-hero__stat--warning strong {
    color: var(--red-soft);
}

.admin-partner-journey-select {
    min-width: 260px;
    color-scheme: dark;
    cursor: pointer;
}

.admin-partner-journey-select option {
    background: var(--slate-mid);
    color: var(--ink-50);
}

.admin-partner-journey-select option:checked {
    background: #4056c9;
    color: var(--white);
}

.admin-partner-journey-select option:disabled {
    color: rgba(var(--white-rgb), 0.48);
}

.admin-partner-journeys {
    display: grid;
    gap: 16px;
    padding: 18px;
}

.admin-partner-journeys__head {
    display: block;
}

.admin-partner-journey-filter {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(280px, 420px);
    grid-template-areas:
        "title search"
        "status search";
    gap: 10px 16px;
    align-items: start;
    width: 100%;
}

.admin-partner-journeys__head-main {
    grid-area: title;
    min-width: 0;
}

.admin-partner-journey-filter__search {
    grid-area: search;
    justify-self: end;
    width: 100%;
    min-width: 0;
    max-width: 420px;
}

.admin-partner-journey-filter__status {
    grid-area: status;
    display: grid;
    grid-template-columns: minmax(220px, 320px) 96px;
    gap: 10px;
    align-items: stretch;
    width: min(430px, 100%);
}

.admin-partner-journey-filter .admin-users-panel__search,
.admin-partner-journey-filter .processing-input,
.admin-partner-journey-filter .btn {
    width: 100%;
    height: 42px;
    min-height: 42px;
    box-sizing: border-box;
}

.admin-partner-journey-filter .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 12px;
    line-height: 1;
}

/* LA COLONNE DE DROITE EST PARTIE, ET LA LISTE PREND SA PLACE.

   Elle posait `minmax(0, 1fr) 380px` : un tiers de la largeur pour une fiche
   qui disait « Selectionnez un praticien » tant qu'on n'avait rien choisi, et
   qui redisait ensuite le nom, l'etat et la progression que la ligne porte
   deja. Ce qu'elle portait seule est descendu dans le volet de la ligne. */
.admin-partner-journey-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
    align-items: start;
}

/* ET LA LISTE NE DEFILE PLUS DANS SA PROPRE BOITE. Les 850 px de hauteur
   existaient pour que la fiche de droite reste en vue pendant qu'on parcourait
   la liste. Sans elle, cette boite ne fait qu'ajouter une seconde barre de
   defilement a l'interieur de la page -- et un volet ouvert en bas de liste
   s'y retrouvait coupe. */
.admin-partner-journey-list {
    min-width: 0;
    display: grid;
    gap: 12px;
}

/* LES BARRES DE DEFILEMENT DE CES DEUX BOITES SONT PARTIES AVEC ELLES : la
   liste defile maintenant avec la page, et la fiche n'existe plus. */

.admin-partner-journey-table th,
.admin-partner-journey-table td {
    vertical-align: middle;
}

.admin-partner-journey-table th {
    padding-bottom: 6px;
}

/* Le decor de la ligne vient de la grammaire commune (`liste-carte`) : ce
   tableau n'apporte que SA couleur. */
.admin-partner-journey-row {
    --row-rgb: var(--teinte-violette);
    --row-solide: var(--violet-soft);
    cursor: pointer;
}

.admin-partner-journey-row__name {
    display: block;
    color: rgba(var(--white-rgb), 0.96);
    font-size: 16px;
    line-height: 1.25;
    font-weight: 400;
}

.admin-partner-journey-progress {
    display: grid;
    gap: 7px;
    min-width: 150px;
}

.admin-partner-journey-progress__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    color: rgba(var(--white-rgb), 0.74);
    font-size: 12px;
    line-height: 1.2;
}

.admin-partner-journey-progress__head strong {
    color: rgba(var(--white-rgb), 0.94);
    font-weight: 400;
}

.admin-partner-journey-progress__bar {
    height: 9px;
    overflow: hidden;
    border-radius: 999px;
    background: rgba(var(--white-rgb), 0.08);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.admin-partner-journey-progress__bar span {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(90deg, rgba(var(--blue-light-rgb), 0.94), rgba(var(--consultation-rgb), 0.84), rgba(var(--green-state-rgb), 0.82));
}

.admin-partner-journey-current {
    display: block;
    max-width: 260px;
    color: rgba(var(--white-rgb), 0.88);
    font-size: 13px;
    line-height: 1.35;
}

.admin-partner-journey-status {
    display: inline-flex;
    align-items: center;
    min-height: 28px;
    width: fit-content;
    padding: 0 10px;
    border-radius: 999px;
    background: rgba(var(--white-rgb), 0.08);
    border: 1px solid rgba(var(--white-rgb), 0.10);
    color: rgba(var(--white-rgb), 0.78);
    font-size: 12px;
    line-height: 1;
    font-weight: 400;
    white-space: nowrap;
}

.admin-partner-journey-status.is-active {
    background: rgba(var(--blue-rgb), 0.14);
    border-color: rgba(var(--blue-light-rgb), 0.28);
    color: var(--blue-mist);
}

.admin-partner-journey-status.is-expired {
    background: rgba(var(--red-rgb), 0.14);
    border-color: rgba(var(--teinte-rouge), 0.28);
    color: var(--couleur-danger-doux);
}

.admin-partner-journey-status.is-completed {
    background: rgba(var(--share-bright-rgb), 0.14);
    border-color: rgba(var(--green-soft-rgb), 0.28);
    color: var(--couleur-succes-doux);
}

.admin-partner-journey-status.is-disabled {
    background: rgba(var(--white-rgb), 0.06);
    border-color: rgba(var(--white-rgb), 0.10);
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
}

/* =========================================================================
   LE VOLET D UNE LIGNE DE PARCOURS
   =========================================================================
   LA FICHE DE DROITE EST DEVENUE CE VOLET. Elle etait collante, haute d'un
   ecran, et portait son propre defilement ; ici le detail s'ouvre sous la
   ligne qu'on interroge et ne coute de la place que le temps qu'on le regarde.

   LA MECANIQUE DU DEPLI est dans `reprise/composants/ligne-depliante.css`, la
   meme que la liste des clients du praticien. Ce qui suit n'en est que le
   dessin.
   ========================================================================= */

.apj-volet {
    display: grid;
    gap: 12px;
    padding: 14px 16px;

    background: rgba(var(--row-rgb), var(--voile-4, 0.09));
    border-left: 4px solid var(--row-solide, rgb(var(--row-rgb)));
    border-bottom: 1px solid rgba(var(--row-rgb), var(--voile-5, 0.14));
    border-right: 1px solid rgba(var(--row-rgb), var(--voile-5, 0.14));
    border-radius: 0 0 14px 14px;
}

.apj-volet__bloc {
    display: grid;
    gap: 8px;
    padding: 12px;
    border-radius: 14px;
    background: rgba(var(--white-rgb), 0.04);
    border: 1px solid rgba(var(--white-rgb), 0.08);
}

.apj-volet__titre {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .04em;
}

/* LES QUATRE COMPTEURS TIENNENT SUR UNE LIGNE. Dans la fiche de 380 px ils
   etaient sur deux colonnes ; le volet fait toute la largeur de la liste. */
.apj-volet__compteurs {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
}

.apj-volet__mesure {
    display: grid;
    gap: 2px;
    min-width: 0;
}

.apj-volet__mesure span {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 12px;
}

.apj-volet__mesure strong {
    font-size: 18px;
    line-height: 1.1;
}

/* LES ETAPES EN RANGEE, ET ELLES SE REPLIENT. Une colonne de douze etapes
   faisait, dans la fiche, un volet plus haut que l'ecran. */
.apj-volet__etapes {
    grid-template-columns: 1fr;
}

.apj-volet__etape {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 10px;
    padding: 6px 0;
    border-bottom: 1px solid rgba(var(--white-rgb), 0.06);
}

.apj-volet__etape:last-child {
    border-bottom: 0;
}

.apj-volet__etape strong {
    font-weight: 500;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.72));
}

/* UNE ETAPE FAITE SE LIT SANS COMPTER : c'est la seule qui porte l'encre
   pleine et la pastille. */
.apj-volet__etape.is-completed strong {
    color: rgb(var(--white-rgb));
}

.apj-volet__etape.is-completed strong::before {
    content: '¹3';
    margin-right: 6px;
    color: var(--vert-soft, rgb(var(--teinte-verte)));
}

.apj-volet__etape span {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.55));
    font-size: 12px;
}

/* LES TROIS FORMULAIRES COTE A COTE : le cadre, la masterclasse, la place dans
   le parcours. Ils se replient quand la place manque.

   TOUT CE QUI SE CLIQUE OU SE SAISIT FAIT LA MEME HAUTEUR, et elle est ecrite
   UNE FOIS. Champs et boutons la tenaient chacun de leur cote -- une valeur ici,
   le remplissage d'ailleurs la -- et il suffisait qu'une regle du produit
   rallonge l'un pour que la rangee se decale sans que rien ne le dise.

   `align-items: end` ALIGNE PAR LE BAS, et c'est la bonne ligne : deux des
   trois formulaires portent une etiquette au-dessus de leur champ, le
   troisieme n'est qu'un bouton. Alignes par le haut, le bouton flotterait a
   hauteur d'etiquette. */
.apj-volet__formulaires {
    --apj-hauteur: 38px;

    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 12px;
}

.apj-volet__formulaire {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 8px;
    margin: 0;
}

.apj-volet__formulaire .processing-field {
    display: grid;
    gap: 4px;
    min-width: 0;
    margin: 0;
    font-weight: 400;
}

.apj-volet__formulaire .processing-field span {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 12px;
    line-height: 1.25;
}

/* LE SELECTEUR COMPTE AUSSI, et il a sa propre famille de regles dans le
   produit : le nommer explicitement evite qu'il garde la hauteur d'ailleurs. */
.apj-volet__formulaire .processing-input,
.apj-volet__formulaire input.processing-input,
.apj-volet__formulaire select.processing-input,
.apj-volet__formulaire .btn {
    height: var(--apj-hauteur);
    min-height: var(--apj-hauteur);
    max-height: var(--apj-hauteur);
    margin: 0;
    box-sizing: border-box;
    line-height: 1.2;
}

.apj-volet__formulaire input[type="number"].processing-input {
    width: 110px;
}

.apj-volet__formulaire .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 14px;
}

.apj-volet__liens {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* LE SEUIL DE 1180 PX N A PLUS RIEN A REPLIER : la mise en page est a une
   colonne a toutes les largeurs depuis que la fiche est descendue dans la
   ligne. */

@media (max-width: 980px) {
    .admin-partner-journey-filter {
        grid-template-columns: minmax(0, 1fr) minmax(260px, 360px);
    }

    .admin-partner-journey-filter__search {
        max-width: 360px;
    }
}

@media (max-width: 720px) {
    /* QUATRE COMPTEURS SUR UNE LIGNE DE TELEPHONE feraient quatre colonnes de
       soixante pixels : le libelle passe a la ligne a chaque mot. Deux par
       deux, ils se lisent. */
    .apj-volet__compteurs {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .apj-volet__formulaire,
    .apj-volet__formulaire .processing-field,
    .apj-volet__formulaire .processing-input,
    .apj-volet__formulaire .btn {
        width: 100%;
        max-width: none;
    }

    .apj-volet__formulaire input[type="number"].processing-input {
        width: 100%;
    }

    .admin-partner-journey-filter,
    .admin-partner-journey-filter .admin-users-panel__search-wrap,
    .admin-partner-journey-filter .processing-input,
    .admin-partner-journey-filter .btn {
        width: 100%;
        max-width: none;
    }

    .admin-partner-journey-filter {
        grid-template-columns: 1fr;
        grid-template-areas:
            "title"
            "search"
            "status";
    }

    .admin-partner-journey-filter__search,
    .admin-partner-journey-filter__status {
        width: 100%;
        max-width: none;
    }

    .admin-partner-journey-filter__status {
        grid-template-columns: 1fr;
    }
}

/* LES REGLES DE LA FICHE DE DROITE SONT PARTIES AVEC ELLE : son bloc
   d'actions, son formulaire de cadre et sa grille a deux colonnes. Ce que ces
   formulaires portent vit maintenant dans `.apj-volet__formulaire`, plus haut,
   ou ils sont cote a cote au lieu d'etre empiles dans 340 px. */

/*Подсветка новых обработок с последнего захода*/
.admin-processing-table tbody
tr.admin-processing-table__row--new td {
    background: rgba(78, 166, 112, 0.16);
    border-bottom-color: rgba(var(--teinte-verte), 0.24);
}

.admin-processing-table tbody
tr.admin-processing-table__row--new td:first-child {
    box-shadow: inset 3px 0 0 rgba(var(--teinte-verte), 0.78);
}

.admin-processing-table tbody
tr.admin-processing-table__row--new:hover td {
    background: rgba(78, 166, 112, 0.22);
}

/* --- Facturation d'un compte, dans sa fiche ----------------------------- */

.admin-billing-account__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 12px;
    margin-bottom: 20px;
}

.admin-billing-account__label {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.6));
    font-size: 0.85rem;
}

.admin-billing-account__value {
    font-size: 1.25rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.admin-billing-account__note,
.admin-billing-account__ref {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.55));
    font-size: 0.85rem;
}

.admin-billing-account__ref {
    margin-top: 4px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.75rem;
    overflow-wrap: anywhere;
}

.admin-billing-account__empty {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.55));
}

/* Une ligne par code : le code, ce qu'il fait, s'il a servi, et le retrait. */
.admin-billing-codes__row {
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    align-items: center;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid rgba(var(--white-rgb), 0.08);
}

.admin-billing-codes__row:last-child {
    border-bottom: 0;
}

.admin-billing-codes__code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-weight: 600;
    letter-spacing: 0.04em;
}

.admin-billing-codes__state {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.55));
    font-size: 0.85rem;
    white-space: nowrap;
}

/* ===== Les acces offerts, en lignes lisibles =====

   Trois travees de texte brut ne disaient ni qui, ni quoi, ni jusqu'a quand
   sans qu'on lise tout. On reprend la grammaire des autres listes : une
   ligne posee sur une teinte, un liseré a gauche qui dit le type de compte,
   et l'etat en pastille a droite. */

.acces-offerts {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 14px;
}

.acces-offert {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1.6fr) auto;
    align-items: center;
    gap: 12px 16px;

    padding: 12px 14px;
    border-radius: 10px;

    /* La teinte vient de la ligne, pas d'ici : `--row-rgb` porte le type de
       compte, comme dans /users. */
    border-left: 3px solid rgba(var(--row-rgb), 0.75);
    background: rgba(var(--row-rgb), 0.07);
}

.acces-offert__qui {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/* Le courriel etait un lien au style par defaut : viole, souligne, plus
   voyant que la personne qu'il designe. Le nom porte le lien, l'adresse
   passe dessous en second plan. */
.acces-offert__nom {
    font-weight: 600;
    color: inherit;
    text-decoration: none;
    overflow-wrap: anywhere;
}

.acces-offert__nom:hover,
.acces-offert__nom:focus-visible {
    text-decoration: underline;
}

.acces-offert__mail {
    font-size: 0.82rem;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.55));
    overflow-wrap: anywhere;
}

.acces-offert__quoi {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
    min-width: 0;
    font-size: 0.88rem;
}

.acces-offert__formule {
    font-weight: 600;
}

.acces-offert__motif,
.acces-offert__par {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.55));
    overflow-wrap: anywhere;
}

.acces-offert__etat {
    display: flex;
    align-items: center;
    gap: 8px;
    justify-self: end;
}

.acces-offert__puce {
    padding: 3px 10px;
    border-radius: 999px;
    border: 1px solid rgba(var(--white-rgb), 0.16);
    font-size: 0.78rem;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* Sans terme : c'est celui qu'on oublie, il doit se voir en premier. */
.acces-offert__puce--sans-terme {
    border-color: rgba(var(--amber-rgb), 0.55);
    background: rgba(var(--amber-rgb), 0.14);
    font-weight: 600;
}

.acces-offert__puce--bientot {
    border-color: rgba(var(--red-rgb), 0.5);
    background: rgba(var(--red-rgb), 0.12);
}

.acces-offert__bientot {
    font-size: 0.78rem;
    color: rgb(var(--red-light-rgb));
}

/* En dessous de 720 px, les trois travees s'empilent : un courriel et un
   motif saisi a la main n'ont pas de longueur connue, et les garder cote a
   cote emportait la page vers la droite. */
@media (max-width: 720px) {
    .acces-offert {
        grid-template-columns: 1fr;
    }

    .acces-offert__etat {
        justify-self: start;
    }
}

.admin-billing-grant {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-top: 14px;
}

.admin-billing-orders__row {
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    align-items: center;
    gap: 12px;
    padding: 8px 0;
    border-bottom: 1px solid rgba(var(--white-rgb), 0.08);
    font-variant-numeric: tabular-nums;
}

.admin-billing-orders__row:last-child {
    border-bottom: 0;
}

@media (max-width: 720px) {
    .admin-billing-codes__row,
    .admin-billing-orders__row {
        grid-template-columns: minmax(0, 1fr) auto;
        row-gap: 4px;
    }

    /*
     * Un courriel et un motif saisi a la main n'ont pas de longueur connue.
     * Places en piste `auto`, ils se dimensionnaient sur leur contenu, et la
     * piste s'elargissait autant qu'il le fallait : la ligne sortait de
     * l'ecran, et la page avec elle (355 px de document pour 350 de fenetre
     * a 360 px de large).
     *
     * Ils prennent donc la largeur entiere et se coupent, `1fr` seul ne
     * suffisant pas puisque son plancher est la largeur du plus long mot.
     */
    .admin-billing-codes__code,
    .admin-billing-codes__what {
        grid-column: 1 / -1;
        min-width: 0;
        overflow-wrap: anywhere;
    }
}

/* Le visage en tête de la fiche d'un compte, avec le geste pour le retirer.
   Une photo montrée à des clients doit pouvoir se retirer sans chercher. */
.admin-user-tete {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-bottom: 8px;
}

.admin-user-tete__texte {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    min-width: 0;
}

.admin-user-tete__texte h1 {
    margin: 0;
}

/* =========================================================================
   LA GRAMMAIRE DES CARTES DU TABLEAU DE BORD

   /partner et /admin repondent a la meme question : qu'est-ce qui se passe
   sur ce compte, et ou vais-je pour agir. Chaque domaine tient dans une carte
   qui dit toujours les memes choses dans le meme ordre : le sujet, l'etat,
   les chiffres, le detail, la porte.

   Les cartes d'une meme rangee alignent leur pied, sinon l'oeil lit une
   colonne bancale la ou il n'y a qu'un contenu plus court.
   ========================================================================= */

.dashboard-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 18px;
    align-items: stretch;
}

/* CETTE REGLE NE PEINT PLUS RIEN : elle ne pose que la mise en page.
   La PEAU du bloc est decidee une seule fois, dans `lk.css`, par la regle
   `.dashboard-card` de la section « Les blocs passent en surface levee (B4) ».

   POURQUOI ELLE PEIGNAIT ENCORE, ET CE QUE CA COUTAIT. Elle declarait
   `background: rgba(--slate-mid, 0.7)` -- de l'ardoise a 70 %, donc une
   surface presque opaque. Les deux regles ont la MEME specificite (0,1,0), et
   cette feuille se charge APRES `lk.css` : a egalite, la derniere ecrite
   gagne. La peau unifiee ne s'appliquait donc nulle part sur /partner ni sur
   /admin, et ces deux espaces gardaient seuls l'ancien aplat gris pendant que
   tout le reste du produit passait en surface levee.

   RIEN N EST PERDU EN LA RETIRANT : `lk.css` porte deja le fond et l'ombre.
   Le repli `@supports` qui vivait ici part avec elle, et c'est correct : il
   rattrapait un fond translucide devenu lisible faute de flou, or la peau
   unifiee pose `backdrop-filter: none` et un fond fixe. Il n'y a plus rien a
   rattraper. */
.dashboard-card {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 20px;
    border-radius: var(--rayon-m);
    box-sizing: border-box;
    min-width: 0;
}

/* Ce qui demande une action passe devant, sur toute la largeur. */
/* --- 1. « Ce qui attend » est le bloc qui appelle un geste ----------------
   -------------------------------------------------------------------------
   Chaque page de la reprise a UN bloc qui dit ce qu'on attend du lecteur, et
   ce bloc porte le cyan et le filet appuye : le parcours sur l'espace
   praticien, « Vous pouvez passer au test » sur le parcours client, le titre
   sur le parcours praticien. Ici c'est « Ce qui attend », et le libelle le dit
   lui-meme : « Ce qui demande une decision de votre part maintenant ».

   IL ETAIT POURTANT LE PLUS DISCRET. Sept blocs identiques a la file, et
   celui qui compte se distinguait seulement par sa largeur. Or la largeur ne
   se lit qu'en comparant ; la teinte se lit tout de suite.

   La recette est recopiee valeur pour valeur de `praticien-essai.css`, pas
   rapprochee a vue : c'est ce qui evite le quatrieme dialecte de cyan.

   COMBIEN PAR ECRAN, ET LA REPONSE A ETE CORRIGEE LE 29/08. Ce paragraphe
   disait « c'est le seul de la page a porter `--filet-action` », en supposant
   qu'une seule carte serait marquee `large`. La mesure a montre le contraire :
   l'espace praticien en portait DEUX, plus le bloc du parcours, soit trois
   cadres appuyes sur un ecran.

   L'intruse etait la carte des reglages de notifications, qui n'avait rien a
   faire ici : le composant definit `large` comme « reservee a ce qui demande
   une action tout de suite ». Elle a perdu la classe.

   RESTENT DEUX BLOCS APPUYES SUR L ESPACE PRATICIEN, et c'est assume : le
   parcours, qui dit quoi faire ensuite, et « Ce qui attend », qui dit ce qui
   reclame une decision maintenant. Ils se lisent en paire, en haut de page,
   avant les cartes ordinaires. L'administration n'en porte qu'un, n'ayant pas
   de parcours. La regle n'est donc pas « un par ecran » mais « un par chose
   qui appelle un geste », et il n'y en a jamais plus de deux.
   ------------------------------------------------------------------------- */
.dashboard-card--large {
    grid-column: 1 / -1;
    background: radial-gradient(circle at 0% 0%,
            rgba(var(--portal-accent-rgb), 0.22), transparent 55%),
        rgba(var(--portal-accent-rgb), 0.10);
    border: var(--filet-epaisseur) solid var(--filet-action);
    box-shadow: none;
}

/* LES 22 px NE VALENT QUE DANS LA GRILLE. Ils detachent la carte accentuee des
   cartes ordinaires, qui la suivent a l'ecart serre de la grille. Sur l'espace
   praticien, elle a quitte la grille pour passer devant le parcours : elle est
   alors dans une colonne dont l'ecart est celui des SECTIONS, et les 22 px
   s'ajoutaient a un ecart deja pris. */
.dashboard-grid > .dashboard-card--large {
    margin-bottom: 22px;
}

/* Les clients portent un tableau : ils tiennent sur deux colonnes, sinon les
   noms se cassent en deux lignes des la premiere ligne. */
.dashboard-card--double {
    grid-column: span 2;
}

/* Un tableau dans une carte n'a pas de fond a lui : la carte le porte deja,
   et une seconde surface ferait un cadre dans un cadre. */
.dashboard-card .responsive-table {
    margin: 0;
}

/* Un tableau ne doit JAMAIS pouvoir deborder de sa carte. Entre le moment ou
   la grille passe a une colonne et celui ou les lignes s'empilent, il reste
   une plage ou cinq colonnes peuvent ne plus tenir : elles defilent alors
   dans leur propre boite, et la page ne part pas de travers.

   La boite est posee dans le gabarit plutot que par `:has()` : elle ne
   concerne qu'un tableau, et le corps des autres cartes ne doit surtout pas
   devenir une zone de defilement. */
.dashboard-card__tableau {
    overflow-x: auto;
}

.dashboard-card__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.dashboard-card__title-area {
    min-width: 0;
}

.dashboard-card__title {
    margin: 0;
    font-size: var(--taille-titre-s);
    font-weight: var(--graisse-titre);
    line-height: 1.25;
}

.dashboard-card__subtitle {
    margin: 4px 0 0;
    font-size: var(--taille-legende);
    line-height: 1.45;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
}

/* L'etat se lit sans lire la carte : une pastille, une teinte, un mot. */
.dashboard-card__state {
    flex: 0 0 auto;
    padding: 4px 10px;
    border-radius: var(--rayon-pilule);
    font-size: var(--taille-mention);
    font-weight: var(--graisse-forte);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    white-space: nowrap;
    border: 1px solid transparent;
}

.dashboard-card__state--muet {
    background: rgba(var(--white-rgb), 0.08);
    border-color: rgba(var(--white-rgb), 0.14);
    color: rgba(var(--white-rgb), 0.66);
}

.dashboard-card__state--ok {
    background: rgba(var(--share-bright-rgb), 0.16);
    border-color: rgba(var(--share-bright-rgb), 0.42);
    /* Le vert de ligne rend 3,17 sur ce voile en clair : l'encre de pastille
       descend d'un cran, le repli garde le vert du sombre. */
    color: rgb(var(--encre-etat-ok-rgb, var(--share-line-rgb)));
}

.dashboard-card__state--attention {
    background: rgba(var(--amber-rgb), 0.16);
    border-color: rgba(var(--amber-rgb), 0.42);
    /* Meme mesure que la pastille verte : 3,89 sur son propre voile en clair. */
    color: rgb(var(--encre-etat-attention-rgb, var(--amber-rgb)));
}

.dashboard-card__state--alerte {
    background: rgba(var(--red-rgb), 0.18);
    border-color: rgba(var(--red-rgb), 0.46);
    color: rgba(var(--red-light-rgb), 1);
}

/* UNE GRILLE, PAS UN ALIGNEMENT LIBRE. En flex, chaque chiffre prend la
   largeur de son libelle : « e-mails en echec » ecarte ses voisins et les
   nombres ne tombent plus sur une verticale. Ils se lisent pourtant en
   balayant la ligne, donc ils doivent etre a intervalle regulier. */
.dashboard-card__figures {
    display: grid;
    /* CETTE DECLARATION NE REND RIEN, ET C'EST ECRIT ICI POUR QU'ON NE LA
       CORRIGE PAS UNE SECONDE FOIS. `cartes-retenues.css` declare la meme
       classe avec son propre plancher et est chargee APRES : c'est elle qui
       l'emporte, et c'est la que le repli de `auto-fit` a ete corrige le
       28/10/2026. Perdu une demi-heure a corriger celle-ci en mesurant un
       essai injecte en fin de page, qui gagnait sur les deux. */
    grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
    gap: 14px 22px;
    padding-bottom: 16px;
    margin-bottom: 4px;
    border-bottom: 1px solid rgba(var(--white-rgb), 0.08);
}

.dashboard-figure {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

/* UN ZERO N'EST PAS UNE NOUVELLE. Sans teinte, un chiffre compte quelque
   chose qui n'attend pas : il s'efface pour que l'oeil tombe d'abord sur ce
   qui demande une decision. Il reste lisible, il ne crie plus. */
/* --- 6. Les chiffres ressortent ----------------------------------------
   MESURE. Le chiffre est a 42 % de blanc, son libelle a 40 %. Ils ont donc la
   meme presence, alors que l'un porte l'information et l'autre l'explique. La
   taille (22 px contre 12) et la graisse (800 contre normale) font tout le
   travail, la couleur n'en fait aucun.

   On rend au chiffre son contraste et on laisse le libelle ou il est : c'est
   l'ECART entre les deux qui se lit, pas leur valeur absolue.

   SELECTEUR RECOPIE A L IDENTIQUE, `:not()` compris. Il vaut (0,3,0) : une
   version plus courte perdrait en silence, ce qui m'est arrive trois fois
   aujourd'hui.

   A NOTER POUR PLUS TARD. La regle d'origine eteint TOUTE figure sans
   modificateur. Si l'intention etait d'eteindre les ZEROS, ce qui se defend,
   il faut une classe posee par le serveur : « rien a voir ici » est une
   information, « pas de modificateur » n'en est pas une.
   ------------------------------------------------------------------------ */
.dashboard-figure:not([class*="dashboard-figure--"]) .dashboard-figure__value {
    color: rgba(var(--white-rgb), 0.88);
}

.dashboard-figure:not([class*="dashboard-figure--"]) .dashboard-figure__label {
    /* LE RETRAIT NE PEUT PAS SE PAYER EN LISIBILITE. Ce libelle recule d'un
       plan par rapport a un chiffre plein ; au cran bas des mentions il rendait
       3,07 en sombre et 3,66 en clair, a 12 px. Le retrait tient deja dans la
       valeur au-dessus (0,88 contre 0,96) : le libelle rejoint le cran des
       mentions, comme son jumeau non qualifie. */
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
}

.dashboard-figure__value {
    font-size: var(--taille-titre-m);
    font-weight: var(--graisse-titre);
    line-height: 1.1;
    color: rgba(var(--white-rgb), 0.96);
    font-variant-numeric: tabular-nums;
}

.dashboard-figure__label {
    font-size: var(--taille-legende);
    line-height: 1.3;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
}

.dashboard-figure--ok .dashboard-figure__value { color: rgba(var(--share-line-rgb), 1); }
.dashboard-figure--attention .dashboard-figure__value { color: rgba(var(--amber-rgb), 1); }
.dashboard-figure--alerte .dashboard-figure__value { color: rgba(var(--red-light-rgb), 1); }

/* Le corps prend la place restante : c'est lui qui fait tenir les pieds de
   cartes voisines sur une meme ligne. */
.dashboard-card__body {
    flex: 1 1 auto;
    min-width: 0;
    font-size: var(--taille-corps-l);
    line-height: 1.5;
    color: rgba(var(--white-rgb), 0.82);
}

.dashboard-card__body > :first-child { margin-top: 0; }
.dashboard-card__body > :last-child { margin-bottom: 0; }

.dashboard-card__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-top: auto;
    padding-top: 14px;
    border-top: 1px solid rgba(var(--white-rgb), 0.10);
}

.dashboard-card__link {
    margin-left: auto;
}

/* La carte des notifications n'a pas de porte vers une page : son bouton
   d'enregistrement EST son pied, et doit donc s'en donner l'allure, sinon
   c'est la seule carte de la rangee sans trait de separation. */
.dashboard-card .partner-client-notifications__actions {
    margin-top: auto;
    padding-top: 14px;
    border-top: 1px solid rgba(var(--white-rgb), 0.10);
}

/* Le formulaire porte la fin de la carte : sans cela son bouton reste colle
   au dernier interrupteur, quelle que soit la hauteur de la rangee.

   Il faut que la CHAINE entiere s'etire, du corps de carte au formulaire :
   un `height: 100%` sur le seul formulaire ne resout rien tant que son parent
   n'a pas de hauteur a lui. */
.dashboard-card__body:has(> .partner-client-notifications__form) {
    display: flex;
    flex-direction: column;
}

.dashboard-card .partner-client-notifications__form {
    display: flex;
    flex-direction: column;
    gap: 12px;
    flex: 1 1 auto;
}

/* --- Le contenu courant d'une carte ------------------------------------ */

/* Une suite de lignes « intitule / valeur » : les couts, les derniers
   echanges, tout ce qui s'enumere sans etre un tableau. */
.dashboard-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.dashboard-list__item {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    font-size: var(--taille-corps-l);
}

.dashboard-list__item {
    padding: 9px 12px;
    border-radius: 12px;
    background: rgba(var(--white-rgb), 0.04);
    background-clip: padding-box;
    border: 1px solid rgba(var(--white-rgb), 0.06);
    transition: background .14s ease, border-color .14s ease;
}

.dashboard-list__item:hover {
    background: rgba(var(--white-rgb), 0.06);
    border-color: rgba(var(--white-rgb), 0.12);
}

.dashboard-list__label {
    text-decoration: none;
    font-weight: 600;
}

.dashboard-list__item:hover .dashboard-list__label {
    text-decoration: underline;
}

/* Chaque echange est une carte : le filet qui les separait n'a plus lieu
   d'etre, et les liens souligne bleu du navigateur non plus. */
.dashboard-list__item + .dashboard-list__item {
    padding-top: 8px;
    border-top: 1px solid rgba(var(--white-rgb), 0.08);
}

.dashboard-list__label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: rgba(var(--white-rgb), 0.82);
}

.dashboard-list__value {
    flex: 0 0 auto;
    font-weight: var(--graisse-forte);
    color: rgba(var(--white-rgb), 0.96);
    font-variant-numeric: tabular-nums;
}

.dashboard-list__value--muet {
    font-weight: var(--graisse-normale);
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
}

/* Une barre de progression sobre, sans chiffre repete a l'interieur. */
.dashboard-bar {
    height: 8px;
    border-radius: var(--rayon-pilule);
    background: rgba(var(--white-rgb), 0.10);
    overflow: hidden;
}

.dashboard-bar__fill {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(
        90deg,
        rgba(var(--share-fill-rgb), 1),
        rgba(var(--share-line-rgb), 1)
    );
}

/* Une rangee de portes : les espaces qu'on ne visite pas tous les jours, et
   les gestes a faire quand quelque chose attend. Elles s'enroulent plutot que
   de se comprimer, un libelle tronque ne dit plus ou il mene. */
/* Les boutons sont une ACTION, la ligne au-dessus un constat : ils ne se
   touchent pas. Sans cette marge, le bouton semblait appartenir a la phrase
   qui le precede. */
.dashboard-liens {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 16px;
}

.dashboard-liens .btn {
    flex: 0 1 auto;
}

/* Une rangee de portes vers des ESPACES, par opposition a une rangee de
   gestes a faire. Elle seule passe en colonnes sur telephone : les libelles
   d'un geste sont des phrases (« Traiter les demandes d'acces (2) ») et se
   casseraient en trois lignes dans une demi-largeur. */
.dashboard-liens--grille {
    gap: 8px;
}

.dashboard-vide {
    margin: 0;
    font-size: var(--taille-corps-l);
    color: rgba(var(--white-rgb), var(--voile-mention, 0.56));
}

/* =========================================================================
   UN DOSSIER QUI PEUT REJOINDRE UN COMPTE
   =========================================================================
   L'ADMIN, LE 17/10/2026 : « pas forcement un chiffre en plus mais une action
   proposee en dessous, la ou il y a "Rien n'attend de vous en ce moment." ».

   ELLE NE POSE PAS SON PROPRE FILET, ET C EST UNE CORRECTION.

   L'ADMIN, LE 17/10/2026 : « il y a visuellement 2 barres au-dessus de la
   proposition de fusion ». Mesure : `.dashboard-card__figures` porte deja un
   `border-bottom` a 392,5, et celui pose ici en tombait un second a 410,5 --
   deux traits a dix-huit pixels l'un de l'autre, pour une seule separation.

   LA CARTE SAIT DEJA SEPARER SES CHIFFRES DE CE QUI SUIT. On s'appuie dessus
   plutot que d'en ajouter un : l'espacement du corps de carte, dix-huit
   pixels, suffit a dire que ceci est d'une autre nature.

   UNE LIGNE : L INFO A GAUCHE, LE GESTE A DROITE. L'Admin, le 17/10/2026,
   devant la premiere pose : « Texte/info a gauche, action a droite, une
   ligne ». Le titre qui annoncait la phrase est parti -- la phrase dit deja
   tout, noms compris -- et ce qui restait tient sur une rangee.

   LE GESTE NE SE COMPRIME PAS (`flex: 0 0 auto`) et le texte prend ce qui
   reste (`min-width: 0`) : sans ces deux-la, un nom long aurait pousse le
   bouton hors de la carte, ou l'aurait replie sur deux lignes.
   ========================================================================= */
/* ELLE SE DETACHE DE LA LISTE DES TESTS EN ATTENTE.

   L'ADMIN, LE 18/10/2026 : « espacement entre les elements, c'est colle ».
   Mesure sur la page reelle : zero pixel entre le bas de la carte d'attente
   et le haut de cette ligne. Le corps de carte est en `display: block`, il
   n'a donc pas de `gap` qui aurait espace ses blocs, et la ligne n'avait ni
   marge ni bordure -- je lui avais retire sa bordure haute la veille parce
   qu'il y en avait deja une, et rien n'a pris le relais de l'ecart.

   SEIZE PIXELS, PARCE QUE C'EST CE QUE LES CARTES DE CETTE PAGE UTILISENT
   DEJA entre deux blocs distincts : mesure des ecarts reels dans tous les
   `.dashboard-card__body` de la page, 16, 12 et 4 px. La ligne parle d'un
   autre sujet que la liste au-dessus, elle prend le plus large. */
.partner-liaison-probable {
    margin-top: var(--espace-l);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.partner-liaison-probable__texte {
    flex: 1 1 260px;
    min-width: 0;
}

/* LES LIGNES SE SERRENT : ce sont des variantes d'une meme phrase, pas des
   paragraphes. Trois d'entre elles a l'ecart d'un paragraphe se liraient
   comme trois sujets. */
.partner-liaison-probable__ligne {
    margin: 0 0 2px;
    font-size: var(--taille-corps-l);
    color: rgba(var(--white-rgb), var(--voile-mention, 0.56));
}

.partner-liaison-probable__ligne:last-child {
    margin-bottom: 0;
}

/* LES DEUX GESTES VONT ENSEMBLE, A DROITE. Ils ne se comprime pas
   (`flex: 0 0 auto`) : sans cela, un nom long aurait pousse « Lier » hors de
   la carte ou l'aurait replie sur deux lignes. */
.partner-liaison-probable__gestes {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
}

/* LE NOM COMPARE SE LIT AVANT LA PHRASE QUI L ENTOURE. L'Admin, le
   17/10/2026 : « Gras pour les noms de ce message ». L'encre monte avec la
   graisse -- un gras dans la teinte de mention se lit comme une tache, pas
   comme un accent. */
.partner-liaison-probable__ligne strong {
    font-weight: 600;
    color: rgba(var(--white-rgb), var(--voile-12, 0.94));
}

/* Le lien de parrainage : on le LIT avant de l'envoyer, souvent pour le
   dicter. Il ne peut donc pas vivre seulement dans un bouton de copie. */
/*
 * LE CHAMP ET SON BOUTON FONT UN SEUL OBJET.
 *
 * Ils etaient separes de huit pixels, le bouton en ardoise : on lisait un
 * champ, puis une commande, alors que la commande ne sert qu'a ce champ-la.
 * Ils prennent la facture de « Televerser une therapie » : coins arrondis a
 * gauche pour le champ, a droite pour le bouton, aucune couture entre eux.
 *
 * TOUT CE QUI CONCERNE CETTE PAIRE EST ICI. Le reglage etait eparpille en cinq
 * endroits de la feuille, dont trois plus bas qui defaisaient le premier : un
 * `flex-wrap: wrap`, un `flex-direction: column` et un `width: 100%` sur le
 * champ. Ecrire une sixieme regle par-dessus aurait allonge la pile ; elles
 * sont donc supprimees et leurs raisons reprises ici.
 */
.dashboard-lien-copie {
    display: flex;
    /* Une paire soudee ne se coupe pas en deux. Sous 620 px elle se dessoude
       proprement, voir le point de rupture plus bas. */
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 0;
}

/*
 * DEUX CLASSES, PAS UNE.
 *
 * `.dashboard-lien-copie__champ` pese (0,1,0) et perd contre le bloc
 * `input[type="text"], ...` de lk.css, qui pese (0,1,1) : son rayon de 10 px et
 * sa marge basse de 16 px survivaient a tout ce qu'on ecrivait ici. En nommant
 * le conteneur on passe a (0,2,0), qui l'emporte.
 *
 * `flex: 1 1 350px` : une adresse d'invitation mesure environ 340 px, et un
 * lien coupe ne se verifie pas. Le champ demande donc de quoi la montrer en
 * entier, et ne cede que lorsque la colonne ne le permet plus.
 */
.dashboard-lien-copie .dashboard-lien-copie__champ {
    flex: 1 1 350px;
    min-width: 0;
    height: 46px;
    padding: 0 14px;
    box-sizing: border-box;
    /* Arrondi a gauche seulement : la droite est fermee par le bouton. */
    border-radius: 12px 0 0 12px;
    border: 1px solid rgba(var(--white-rgb), 0.12);
    border-right: none;
    background: rgba(var(--ink-900-rgb), 0.36);
    color: rgba(var(--white-rgb), 0.9);
    font-size: var(--taille-legende);
    font-family: inherit;
    margin: 0;
}

.dashboard-lien-copie .dashboard-lien-copie__champ:focus {
    outline: none;
    /* Le vert du bouton d'a cote : la paire s'allume d'un seul tenant. */
    border-color: rgba(var(--teinte-verte), 0.55);
}

/*
 * LA PAIRE NE SE DESSOUDE JAMAIS.
 *
 * L'ADMIN, LE 28/10/2026 : « Le conteneur du lien peut se retrecir, mais
 * jamais separer les deux, champ/bouton. » Puis, sur ma formule « elle se
 * dessoude trop tot » : « Y'a pas de "trop tot", c'est "jamais". »
 *
 * CE QUI ETAIT LA, ET POURQUOI CA PARTAIT. Un point de rupture a 640 px
 * faisait passer le bouton sous le champ, parce qu'a cette largeur le champ
 * tombait a une trentaine de pixels. Le raisonnement etait juste et la mesure
 * aussi ; la conclusion ne l'etait pas. Une paire soudee est UN objet : le
 * dessouder pour gagner de la place revient a casser ce qu'on voulait
 * preserver, et le resultat se voit -- un champ a quatre coins ronds, un
 * bouton a quatre coins ronds, et plus rien qui dise qu'ils vont ensemble.
 *
 * CE QUI REMPLACE : le champ RETRECIT. Il porte deja `min-width: 0` et un
 * `flex-shrink` de 1, donc sa base de 350 px n'est qu'un souhait : il cede
 * jusqu'a ce que la place manque vraiment. Le bouton, lui, garde sa largeur
 * propre -- `flex: 0 0 auto` sur la famille -- donc la paire fait toujours la
 * largeur de son conteneur, jamais plus.
 *
 * ET LE BOUTON NE SE COUPE PAS EN DEUX NON PLUS : `white-space: nowrap` est
 * pose sur `.bouton-programme`, dans `lk.css`, pour la meme demande du meme
 * jour.
 */

/* Le libelle du lien respire : colle a la phrase des paliers, il se lisait
   comme sa suite. */
.dashboard-lien-copie,
.paliers + .dashboard-card__subtitle {
    margin-top: 4px;
}

.paliers + .dashboard-card__subtitle {
    margin-top: 14px;
}

/* --- Points de rupture -------------------------------------------------- */

@media (max-width: 1200px) {
    .dashboard-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* Deux colonnes sur deux, c'est toute la rangee : autant le dire ainsi,
       sinon la carte suivante se retrouve seule sur la sienne. */
    .dashboard-card--double {
        grid-column: 1 / -1;
    }
}

@media (max-width: 820px) {
    .dashboard-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .dashboard-card--double {
        grid-column: auto;
    }

    .dashboard-card {
        padding: 16px;
    }

    /* Le titre et l'etat se superposaient des que le libelle d'etat tenait
       deux mots : l'etat passe sous le titre plutot que de le comprimer. */
    .dashboard-card__head {
        flex-direction: column;
        align-items: flex-start;
        gap: 8px;
    }

    .dashboard-card__link {
        margin-left: 0;
        width: 100%;
        text-align: center;
    }

    /* Deux colonnes plutot qu'une pile. Six portes empilees faisaient six
       lignes pleine largeur, pour six mots : la carte devenait la plus haute
       de l'ecran alors qu'elle est la moins urgente. */
    .dashboard-liens--grille {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        align-items: stretch;
    }

    .dashboard-liens--grille .btn {
        width: 100%;
        text-align: center;
        /* Un libelle de deux lignes ne doit pas rendre son bouton plus haut
           que son voisin : la rangee se lit comme une grille, pas comme un
           escalier. */
        display: flex;
        align-items: center;
        justify-content: center;
    }
}

/* =========================================================================
   LA BARRE DES PALIERS DE PARRAINAGE

   Un chemin, pas une jauge. Une jauge dit « combien sur un total » ; ici la
   question est « ou j'en suis entre deux paliers », et le total n'interesse
   personne. D'ou les jalons poses le long de la piste, et un curseur qui
   avance de l'un a l'autre.

   L'echelle n'est pas celle des nombres : chaque palier occupe le meme
   segment. Les seuils vont de 1 a 25, et a l'echelle reelle les deux premiers
   se tasseraient dans le premier dixieme. La geometrie vit dans
   `NiveauParrainage::barre()`, pas ici : deux ecrans l'affichent.
   ========================================================================= */

.paliers {
    display: flex;
    flex-direction: column;
    gap: 34px;

    /* La largeur d'un jalon. Elle sert deux fois : a le dimensionner, et a
       reserver la place qu'il prend en debordant de la piste. */
    --paliers-jalon: 84px;

}

/*
 * LA TEINTE DU PALIER ATTEINT, posee sur la CARTE et non sur la barre.
 *
 * Quatre endroits la reprennent : le remplissage, le halo du curseur, les noms
 * franchis, et la pastille d'etat. Cette derniere vit dans l'entete, hors de la
 * barre : c'est pour elle que la teinte remonte d'un cran, sans quoi elle ne
 * pourrait pas l'atteindre. Ils diraient sinon quatre choses differentes.
 */
/* Les quatre couleurs, declarees une fois. Elles servent deux fois : a teinter
   la carte selon le palier COURANT, et a donner a chaque nom de palier la
   sienne, quel que soit celui qu'on a atteint. */
.paliers--bronze,
.paliers--argent,
.paliers--or,
.paliers--saphir,
.paliers--aucun {
    --palier-bronze: 205, 127, 50;
    --palier-argent: 192, 200, 214;
    --palier-or: var(--teinte-or);
    --palier-saphir: var(--teinte-bleue);
}

.paliers--bronze { --paliers-teinte: var(--palier-bronze); }
.paliers--argent { --paliers-teinte: var(--palier-argent); }
.paliers--or     { --paliers-teinte: var(--palier-or); }
.paliers--saphir { --paliers-teinte: var(--palier-saphir); }

/* Aucun palier : la piste reste neutre. La colorer avant le premier seuil
   annoncerait une progression qui n'a pas commence. */
.paliers--aucun { --paliers-teinte: var(--white-rgb); }

/* La pastille d'etat porte le nom du palier : elle en porte donc la couleur.
   Plus specifique que `--muet` et `--ok`, qui la peignaient en neutre. */
.dashboard-card.paliers--bronze .dashboard-card__state,
.dashboard-card.paliers--argent .dashboard-card__state,
.dashboard-card.paliers--or .dashboard-card__state,
.dashboard-card.paliers--saphir .dashboard-card__state {
    background: rgba(var(--paliers-teinte), 0.16);
    border-color: rgba(var(--paliers-teinte), 0.45);
    color: rgba(var(--paliers-teinte), 1);
}

.paliers__piste {
    position: relative;
    height: 8px;
    border-radius: var(--rayon-pilule);
    background: rgba(var(--white-rgb), 0.10);

    /*
     * De la place pour les insignes au-dessus et les noms en dessous : ils
     * debordent de la piste, qui n'est qu'un trait.
     *
     * Et sur les COTES : un jalon est centre sur sa position, donc celui de
     * 100 % deborde de sa demi-largeur. Sans cette marge, le dernier palier
     * sortait de la carte, qui se mettait a defiler horizontalement.
     */
    margin: 92px calc(var(--paliers-jalon) / 2) 0;
}

.paliers__parcouru {
    position: absolute;
    inset: 0 auto 0 0;
    border-radius: inherit;
    background: linear-gradient(
        90deg,
        rgba(var(--paliers-teinte), 0.45),
        rgba(var(--paliers-teinte), 1)
    );
}

.paliers__jalon {
    position: absolute;
    /*
     * AU-DESSUS de la piste, pas dessus. Centre sur elle, l'insigne la touchait
     * et le nom passait dessous : la barre traversait le jalon en son milieu.
     * Elle reste desormais un trait libre, que les jalons surplombent.
     *
     * `left` porte la position, la translation horizontale recentre le jalon
     * dessus.
     */
    bottom: calc(100% + 14px);
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    width: var(--paliers-jalon);
    text-align: center;
}

.paliers__insigne {
    width: 30px;
    height: 30px;
    object-fit: contain;
    /* Un palier pas encore atteint se montre, eteint : le cacher priverait de
       ce qu'on vise, et c'est precisement ce qu'on vient lire. */
    filter: grayscale(1);
    opacity: 0.38;
    transition: filter var(--transition), opacity var(--transition);
}

.paliers__jalon.is-atteint .paliers__insigne {
    filter: none;
    opacity: 1;
}

.paliers__nom {
    font-size: var(--taille-mention);
    font-weight: var(--graisse-forte);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    /* 0,42 rendait 4,01 sur la piste des paliers ; le cran de mention du
       produit rend 5,2 et ne se confond pas avec le nom atteint, qui porte la
       couleur de son palier. */
    color: rgba(var(--white-rgb), var(--voile-mention, 0.54));
    white-space: nowrap;
}

/* CHAQUE NOM PORTE SA PROPRE COULEUR, celle de son insigne, et non celle du
   palier ou l'on se trouve. Un nom teint par le palier courant changeait de
   couleur a chaque franchissement, comme si Bronze devenait argente en passant
   Argent : ce sont quatre reperes distincts, pas une seule jauge coloree. */
.paliers__jalon--bronze.is-atteint .paliers__nom { color: rgba(var(--palier-bronze), 1); }
.paliers__jalon--argent.is-atteint .paliers__nom { color: rgba(var(--palier-argent), 1); }
.paliers__jalon--or.is-atteint .paliers__nom     { color: rgba(var(--palier-or), 1); }
.paliers__jalon--saphir.is-atteint .paliers__nom { color: rgba(var(--palier-saphir), 1); }

/* 0,34 DE BLANC REND 3,07 SUR LE SOL DU TABLEAU DE BORD. La peau de page le
   corrige deja, mais elle ne se charge que la ou les couches reprises se
   chargent : une correction de contraste vit dans la feuille du PRODUIT, a la
   regle fautive (`REGLES_CONSTRUCTION.md`, section 6). Ecrite seulement dans la
   peau, elle laissait le defaut en ligne et le faisait passer pour regle --
   c'est le piege qui s'est deja referme trois fois. */
.paliers__seuil {
    font-size: var(--taille-mention);
    color: rgba(var(--white-rgb), var(--voile-mention, 0.54));
    font-variant-numeric: tabular-nums;
}

.paliers__jalon.is-atteint .paliers__seuil {
    color: rgba(var(--white-rgb), var(--voile-mention, 0.58));
}

/* Le curseur passe DEVANT les insignes : c'est le seul repere qui reponde a
   « et moi, ou suis-je ».

   IL PORTE LA COULEUR DU PALIER ATTEINT. Il etait blanc, avec un halo teinte :
   le halo disait le palier, le rond ne disait rien, et l'oeil cherchait le lien
   entre ce blanc et l'insigne allume le plus a gauche. `--paliers-teinte` est
   deja pose par la classe de la carte, quinze regles plus haut ; il n'y avait
   qu'a la lire. */
.paliers__curseur {
    position: absolute;
    top: 50%;
    width: 14px;
    height: 14px;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    background: rgba(var(--paliers-teinte), 1);
    box-shadow: 0 0 0 4px rgba(var(--paliers-teinte), 0.35);
    z-index: 2;
}

/* SANS PALIER, LE ROND EST GRIS, et pas blanc : `--paliers-teinte` vaut alors
   le blanc de la piste neutre, et un rond blanc sur une barre blanche est le
   repere le plus voyant des cinq, pour l'etat ou l'on n'a rien franchi. Le gris
   est ecrit ici plutot que pose sur `--paliers-teinte`, qui sert aussi la barre
   parcourue et la pastille d'etat. */
.paliers--aucun .paliers__curseur {
    background: rgb(148, 163, 184);
}

.paliers__reste {
    margin: 0;
    font-size: var(--taille-corps-l);
    color: rgba(var(--white-rgb), 0.82);
}

/* Sur telephone, quatre jalons de 84 px ne tiennent pas dans 300 : les noms
   se chevaucheraient. On garde les insignes, qui se reconnaissent, et le
   detail passe dans la phrase sous la barre. */
@media (max-width: 620px) {
    /* Le jalon retrecit, et la marge laterale de la piste avec lui, puisque
       les deux sont tenus par la meme mesure. */
    .paliers {
        --paliers-jalon: 34px;
    }

    .paliers__nom,
    .paliers__seuil {
        display: none;
    }

    .paliers__piste {
        /* Sans les noms ni les seuils, l'insigne seul demande moins de hauteur. */
        margin-top: 56px;
    }
}

/* Les interrupteurs de notification, quand leur carte occupe toute la rangee :
   empiles sur cette largeur, chacun tirerait sa description sur une seule
   ligne tres longue, penible a parcourir. */
.dashboard-card--large .partner-client-notifications__list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}

@media (max-width: 820px) {
    .dashboard-card--large .partner-client-notifications__list {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* =========================================================================
   L'ETAPE EN COURS, en tete du parcours praticien

   L'ecran rendait compte d'un avancement. Il dit desormais la seule chose a
   faire maintenant, et donne le bouton pour la faire : c'est ce bloc. Le
   chemin complet reste dessous, comme carte, et non comme consigne.
   ========================================================================= */

.partner-journey-page .partner-journey-now {
    padding: 26px 28px;
    margin-bottom: 22px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;

    /*
     * LE SEUL BLOC A ANGLES DROITS DE LA PAGE.
     *
     * Il n'avait ni rayon ni bordure. Ses deux calques de verre font
     * `border-radius: inherit` : ils heritaient donc de zero, et le bloc le
     * plus voyant de l'ecran se posait en dalle carree entre `.journey-shell`
     * a 18 px et les cartes a 12. Un `inherit` n'invente pas la valeur qu'il
     * attend, il recopie celle qui existe.
     */
    border-radius: 18px;
    border: 1px solid rgba(var(--white-rgb), 0.10);
}

/* L'action du bloc est le geste principal de la page : elle prend l'accent du
   parcours, et non le bleu generique de `.btn`, qui n'appartient a aucune des
   couleurs de cet ecran. */
.partner-journey-page .partner-journey-now__action {
    background: rgba(var(--portal-accent-rgb), 0.92);
    color: rgb(var(--surface-sombre-rgb));
    font-weight: var(--graisse-forte);
}

.partner-journey-page .partner-journey-now__action:hover,
.partner-journey-page .partner-journey-now__action:focus-visible {
    background: rgb(var(--portal-accent-clair-rgb));
}

.partner-journey-now__eyebrow {
    font-size: var(--taille-mention);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    font-weight: var(--graisse-forte);
    color: rgba(var(--teinte-or), 1);
}

.partner-journey-now__titre {
    margin: 0;
    font-size: var(--taille-titre-m);
    line-height: 1.22;
    font-weight: var(--graisse-titre);
}

.partner-journey-now__mot {
    margin: 0;
    max-width: 68ch;
    font-size: var(--taille-intro);
    line-height: 1.55;
    color: rgba(var(--white-rgb), 0.84);
}

/* L'action est le point d'arrivee du bloc : elle se detache du texte plutot
   que de le suivre en petit. */
.partner-journey-now__action {
    margin-top: 4px;
}

/* Une etape d'attente n'a pas de bouton. Le dire noir sur blanc vaut mieux que
   de laisser un vide, qu'on lirait comme un ecran casse. */
.partner-journey-now__attente {
    margin: 0;
    font-size: var(--taille-corps-l);
    color: rgba(var(--white-rgb), var(--voile-mention, 0.56));
    font-style: italic;
}

/*
 * LE MEME REPLI QUE CELUI DES ETAPES.
 *
 * Deux accordeons vivaient sur cette page. Celui des etapes avait sa boite
 * arrondie, son fond teinte et son chevron ; celui-ci gardait le marqueur natif
 * du navigateur, un triangle noir colle au texte. C'etait le plus visible des
 * deux, en tete de page.
 */
.partner-journey-now__details {
    margin: 2px 0 0;
    max-width: 72ch;
    border-radius: 14px;
    background: rgba(var(--white-rgb), 0.075);
    border: 1px solid rgba(var(--white-rgb), 0.08);
    overflow: hidden;
}

.partner-journey-now__details summary {
    list-style: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 34px;
    padding: 0 11px;
    color: rgba(var(--couleur-accent-doux-rgb), 0.92);
    font-size: 13px;
    line-height: 1;
}

.partner-journey-now__details summary::-webkit-details-marker {
    display: none;
}

.partner-journey-now__details summary::after {
    content: "▾";
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 12px;
    transition: transform .18s ease;
}

.partner-journey-now__details[open] summary::after {
    transform: rotate(180deg);
}

.partner-journey-now__details summary:hover {
    color: var(--white);
    background: rgba(var(--white-rgb), 0.06);
}

.partner-journey-now__details > div {
    margin: 0;
    padding: 0 11px 12px;
    font-size: var(--taille-corps-l);
    line-height: 1.6;
    color: rgba(var(--white-rgb), 0.78);
}

/* Les compteurs des trois premiers cas, sur l'etape qu'ils mesurent. */
.partner-journey-now .partner-journey-widget__metrics {
    margin: 0;
}

@media (max-width: 640px) {
    .partner-journey-page .partner-journey-now {
        padding: 20px 18px;
    }

    .partner-journey-now__action {
        width: 100%;
        text-align: center;
    }
}

/* « 1 sur 3 » : le compte d'une etape qui se repete. */
.partner-journey-now__compte {
    font-size: var(--taille-corps-l);
    font-weight: var(--graisse-forte);
    color: rgba(var(--teinte-or), 1);
    font-variant-numeric: tabular-nums;
}

/* =========================================================================
   LA FORMATION ET LES LECTURES DE CAS
   ========================================================================= */

.formation-formulaire {
    display: flex;
    flex-direction: column;
    gap: 10px;
    align-items: flex-start;
}

.formation-formulaire__champ {
    width: 100%;
    box-sizing: border-box;
    padding: 12px 14px;
    border-radius: var(--rayon-s);
    border: 1px solid rgba(var(--white-rgb), 0.14);
    background: rgba(var(--black-rgb), 0.22);
    color: rgba(var(--white-rgb), 0.92);
    font-family: inherit;
    font-size: var(--taille-corps-l);
    line-height: 1.6;
    resize: vertical;
    margin-bottom: 0;
}

.formation-formulaire__champ:focus {
    outline: none;
    border-color: rgba(var(--portal-accent-rgb), 0.6);
}

/* Le mot du relecteur : il s'adresse a quelqu'un, il ne se noie donc pas dans
   le reste de la carte. */
.formation-retour {
    border-left: 3px solid rgba(var(--share-line-rgb), 0.7);
    background: rgba(var(--share-line-rgb), 0.07);
    padding: 12px 16px;
    border-radius: 0 var(--rayon-s) var(--rayon-s) 0;
}

.formation-retour--reprise {
    border-left-color: rgba(var(--amber-rgb), 0.8);
    background: rgba(var(--amber-rgb), 0.08);
}

.formation-retour__titre {
    font-size: var(--taille-mention);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    font-weight: var(--graisse-forte);
    color: rgba(var(--white-rgb), 0.66);
    margin-bottom: 6px;
}

.formation-retour p {
    margin: 0;
    line-height: 1.6;
}

/* --- La file de relecture ---------------------------------------------- */

.case-reading {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.case-reading__tete {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 14px;
}

/* La copie telle qu'elle a ete ecrite : les retours a la ligne comptent, et
   le texte reste du texte plutot que du balisage fabrique. */
.case-reading__copie {
    white-space: pre-line;
    line-height: 1.7;
    font-size: var(--taille-corps-l);
    color: rgba(var(--white-rgb), 0.88);
    background: rgba(var(--black-rgb), 0.22);
    border-radius: var(--rayon-s);
    padding: 18px 20px;
    max-height: 460px;
    overflow-y: auto;
}

/* Les deux verdicts cote a cote : valider et renvoyer sont deux gestes
   symetriques, et l'un ne doit pas paraitre plus naturel que l'autre. */
.case-reading__verdict {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 16px;
}

.case-reading__verdict form {
    display: flex;
    flex-direction: column;
    gap: 10px;
    align-items: flex-start;
}

/* -------------------------------------------------------------------------
   UNE PARTIE FERMEE, ET ELLE MONTRE CE QU'IL Y A DERRIERE
   -------------------------------------------------------------------------

   Voir le composant `cadre-verrouille` pour la regle qui compte : ce qui est
   floute est un DECOR, jamais la vraie donnee. Le flou est une propriete
   d'affichage, le contenu reste dans la page ; flouter des donnees reelles
   reviendrait a les publier en croyant les cacher.

   Le decor est donc fabrique en CSS et en barres vides. Il n'evoque que la
   FORME de ce qui existera : des lignes de personnes, des paves, du texte.
   ------------------------------------------------------------------------- */

.cadre-verrouille {
    position: relative;
    overflow: hidden;
    border-radius: var(--rayon-carte);
    border: 1px solid var(--trait-sur-sombre);
    background: rgba(var(--slate-mid-rgb), 0.55);
    min-height: 320px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--espace-xxl) var(--espace-xl);
    box-sizing: border-box;
}

/* Le decor occupe le fond, sous le voile et sous le mot. */
.cadre-verrouille__decor {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--espace-l);
    padding: var(--espace-xl);
    box-sizing: border-box;

    /* Deux flous se cumulent : celui-ci brouille la forme, celui du voile
       brouille ce qui passerait encore. Un seul, plus fort, ecraserait le
       decor en aplat et il n'y aurait plus rien a deviner. */
    filter: blur(3px);
    opacity: .85;
    pointer-events: none;
    user-select: none;
}

.cadre-verrouille__ligne {
    display: flex;
    align-items: center;
    gap: var(--espace-m);
}

.cadre-verrouille__pastille {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    border-radius: var(--rayon-pilule);
    background: rgba(255, 255, 255, 0.34);
}

.cadre-verrouille__barre {
    display: block;
    height: 10px;
    border-radius: var(--rayon-pilule);
    background: rgba(255, 255, 255, 0.28);
}

.cadre-verrouille__barre--courte {
    flex: 0 0 auto;
    width: 54px;
    background: rgba(255, 255, 255, 0.18);
}

.cadre-verrouille__pave {
    display: flex;
    flex-direction: column;
    gap: var(--espace-s);
    padding: var(--espace-l);
    border-radius: var(--rayon-m);
    background: rgba(255, 255, 255, 0.09);
}

/* Le voile pose le contraste : sans lui, le mot se lit mal sur le decor. */
.cadre-verrouille__voile {
    position: absolute;
    inset: 0;
    background: radial-gradient(
        ellipse at center,
        rgba(var(--slate-rgb), 0.88) 0%,
        rgba(var(--slate-rgb), 0.70) 48%,
        rgba(var(--slate-rgb), 0.42) 100%
    );
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    pointer-events: none;
}

@supports not ((backdrop-filter: blur(6px)) or (-webkit-backdrop-filter: blur(6px))) {
    /* Sans flou de fond, le decor resterait trop lisible : on l'assombrit. */
    .cadre-verrouille__voile {
        background: rgba(var(--slate-rgb), 0.93);
    }
}

.cadre-verrouille__mot {
    position: relative;
    z-index: 1;
    max-width: 42ch;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--espace-m);
}

.cadre-verrouille__cadenas {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    border-radius: var(--rayon-pilule);
    border: 1px solid rgba(var(--teinte-or), 0.35);
    background: rgba(var(--teinte-or), 0.10);
    color: rgb(var(--teinte-or));
}

.cadre-verrouille__titre {
    margin: 0;
    font-size: var(--taille-titre-s);
    font-weight: var(--graisse-moyenne);
    color: var(--texte-sur-sombre);
    text-wrap: balance;
}

.cadre-verrouille__raison {
    margin: 0;
    font-size: var(--taille-corps-l);
    line-height: 1.5;
    color: var(--texte-discret-sur-sombre);
}

.cadre-verrouille__detail {
    width: 100%;
    font-size: var(--taille-corps);
    color: var(--texte-discret-sur-sombre);
}

.cadre-verrouille__action {
    margin-top: var(--espace-xs);
}

@media (max-width: 640px) {
    .cadre-verrouille {
        min-height: 260px;
        padding: var(--espace-xl) var(--espace-l);
    }

    .cadre-verrouille__decor {
        padding: var(--espace-l);
        gap: var(--espace-m);
    }
}

/* -------------------------------------------------------------------------
   LA FICHE LATERALE, EN MODALE SUR PETIT ECRAN
   -------------------------------------------------------------------------

   Voir `public/js/fiche-modale.js` pour le pourquoi. En resume : sous 1180px
   la mise en page retombe sur une colonne et la fiche se retrouvait sous la
   liste, longue, invisible tant qu'on n'avait pas fait defiler jusqu'en bas.
   Choisir quelqu'un ne montrait donc rien.

   Au-dessus du seuil, aucune de ces regles ne s'applique : la fiche reste
   dans sa colonne.
   ------------------------------------------------------------------------- */

.fiche-modale__fond {
    display: none;
}

.fiche-modale__fermer {
    display: none;
}

@media (max-width: 1180px) {

    .fiche-modale__fond:not([hidden]) {
        display: block;
        position: fixed;
        inset: 0;
        /* Au-dessus de la barre du haut (1500), et JUSTE EN DESSOUS des
           modales du produit (9999) : la fiche peut en ouvrir une, et elle
           doit alors passer devant. */
        z-index: 9990;
        background: rgba(0, 0, 0, 0.62);
        backdrop-filter: blur(2px);
        -webkit-backdrop-filter: blur(2px);
    }

    /* La fiche NON ouverte disparait : la laisser en bas de page ferait
       doublon avec la modale, et on lirait deux fois la meme chose. */
    [data-fiche-modale]:not(.fiche-modale--ouverte) {
        display: none;
    }

    [data-fiche-modale].fiche-modale--ouverte {
        display: block;
        position: fixed;
        z-index: 9991;

        /* Une feuille posee au centre, avec une marge partout : collee aux
           bords, elle se confondrait avec la page. */
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: min(560px, calc(100vw - 2 * var(--espace-l)));
        max-height: calc(100vh - 2 * var(--espace-xl));
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;

        box-sizing: border-box;
        padding: var(--espace-xl);
        padding-top: var(--espace-xxl);
        border-radius: var(--rayon-carte);
        border: 1px solid var(--trait-sur-sombre);
        background: rgba(var(--slate-mid-rgb), 0.98);
        box-shadow: var(--ombre-flottante);
    }

    .fiche-modale--ouverte .fiche-modale__fermer {
        display: flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: var(--espace-m);
        right: var(--espace-m);
        width: 34px;
        height: 34px;
        padding: 0;
        font-size: 24px;
        line-height: 1;
        border-radius: var(--rayon-pilule);
        border: 1px solid var(--trait-sur-sombre);
        background: rgba(255, 255, 255, 0.06);
        color: var(--texte-sur-sombre);
        cursor: pointer;
    }

    .fiche-modale--ouverte .fiche-modale__fermer:hover {
        background: rgba(255, 255, 255, 0.12);
    }

    /* Le fond ne defile pas pendant qu'on lit la fiche : sans cela, refermer
       la modale rendait une page qui avait bouge toute seule. */
    body.fiche-modale-ouverte {
        overflow: hidden;
    }
}

/* -------------------------------------------------------------------------
   LA LISTE DES UTILISATEURS, COTE ADMINISTRATION
   -------------------------------------------------------------------------

   Elle reprend la grammaire `liste-carte` : tout le decor de la ligne vient
   de la, et il n'y a ici que ce qui lui est propre.

   LA COULEUR DIT LE TYPE DE COMPTE, posee sur la ligne par le gabarit. Elle
   melait clients, praticiens et administrateurs sans qu'aucun signe ne les
   distingue : il fallait ouvrir une fiche pour savoir a qui on avait affaire.
   ------------------------------------------------------------------------- */

.admin-users-table th,
.admin-users-table td {
    vertical-align: middle;
}

.admin-users-table th {
    padding-bottom: 6px;
}

/* 15 px, COMME LE NOM DE /clients : c'est la meme chose qu'on lit, et l'Admin
   a demande le 23/10/2026 d'aligner les trois ecrans sur celui-la. Il en
   faisait 13. */
.admin-user-name {
    font-size: 15px;
    font-weight: var(--graisse-moyenne);
    color: var(--texte-sur-sombre);
}

/* =========================================================================
   LES LARGEURS DE CETTE LISTE NE SE DECIDENT PLUS ICI
   =========================================================================
   CETTE FEUILLE POSAIT 26 % SUR « Personne » ET 20 % SUR « Etat du compte »,
   trouves par mesure le 18/10/2026 (26/20 etait le premier partage qui tenait
   l'etat sur deux lignes). Deux autres feuilles decidaient en meme temps des
   memes colonnes, et c'est la que ca cassait : le 06/11/2026, la liste etait
   gouvernee ici pendant que `composants/liste-clients.css` croyait la
   gouverner -- un mecanisme livre, mesure, et inerte.

   UNE LARGEUR DE COLONNE DE LISTE SE DECLARE DESORMAIS A UN SEUL ENDROIT,
   `composants/liste-clients.css`, et de la meme facon pour toutes les listes :
   l'identite demande une taille, le moteur repartit le reste selon les
   besoins. Le 26/20 n'a pas ete perdu, il a ete remplace par une regle qui
   vaut aussi pour les listes qu'on ecrira ensuite.
   ========================================================================= */

/* LE NOM ET L ADRESSE SE COUPENT PLUTOT QUE DE SE PLIER. Ce sont des objets
   qu'on reconnait d'un coup d'oeil ; coupes en deux, ils demandent d'etre
   relus pour etre recomposes. Les points de suspension disent qu'il en reste,
   et la fiche les montre en entier.

   LE NUMERO N EST PAS DANS CETTE REGLE : il porte un drapeau, donc il est une
   RANGEE et non une ligne de texte. Sa consigne est plus bas, avec la sienne
   -- un `display: block` pose ici lui aurait retire son alignement. */
.admin-users-table .admin-user-name,
.admin-users-table .admin-user-mail {
    display: block;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* L'adresse passe sous le nom. Elle identifie, elle ne se lit pas en premier :
   elle occupait une travee entiere du tableau pour une information dont on n'a
   besoin qu'une fois la bonne ligne trouvee. */
.admin-user-mail {
    display: block;
    margin-top: 2px;
    font-size: 0.8rem;
    color: rgba(var(--white-rgb), 0.52);
}

/* LE NUMERO, SOUS L ADRESSE. Meme encre et meme taille : ce sont deux facons
   de joindre la meme personne, et rien ne justifie d'en avantager une.

   `inline-flex` POUR QUE LE DRAPEAU SE CALE SUR LE MILIEU DES CHIFFRES, pas
   sur leur ligne de base : une image alignee en base-line se pose sur le
   jambage et remonte le reste de la ligne. */
.admin-user-tel {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    margin-top: 2px;
    overflow: hidden;
    white-space: nowrap;
    font-size: 0.8rem;
    color: rgba(var(--white-rgb), 0.52);
}

/* ----- L'etat du compte, et les deux dates ----- */

/*
 * LA CELLULE RESTE UNE CELLULE, LA MISE EN LIGNE SE FAIT DEDANS.
 *
 * `display: flex` etait pose sur le `<td>` lui-meme. Une cellule ainsi sortie
 * du tableau ne s'etire plus a la hauteur de sa ligne : elle mesurait 41 px
 * quand les six autres en faisaient 68, et le fond de la ligne apparaissait
 * dessous en rectangle vide, large comme la colonne. Le defaut ne se voyait
 * que sur les lignes hautes, celles dont le nom passe sur deux lignes.
 */
.admin-user-etat__contenu {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 8px;
}

.puce-etat {
    display: inline-flex;
    align-items: center;
    padding: 2px 9px;
    border-radius: 999px;
    border: 1px solid rgba(var(--white-rgb), 0.16);
    font-size: 0.76rem;
    white-space: nowrap;
}

/* Un compte jamais active n'a rien fait et ne fera rien : c'est le seul etat
   qui appelle un geste, et il porte donc la seule couleur d'alerte. */
.puce-etat--attente {
    border-color: rgba(var(--amber-rgb), 0.42);
    background: rgba(var(--amber-rgb), 0.16);
    font-weight: var(--graisse-moyenne);
    color: color-mix(in srgb, rgb(var(--amber-rgb)) 82%, #ffffff);
}

.puce-etat--actif {
    border-color: rgba(var(--share-bright-rgb), 0.5);
    background: rgba(var(--share-bright-rgb), 0.12);
}

.puce-etat--offert {
    border-color: rgba(var(--teinte-violette), 0.5);
    background: rgba(var(--teinte-violette), 0.12);
}

/* « Sans abonnement » et « sans praticien » sont des ABSENCES, pas des
   problemes : elles se disent sans couleur, sinon la liste s'allume pour
   des lignes ou il n'y a rien a faire. */
.puce-etat--sans {
    color: rgba(var(--white-rgb), 0.82);
    background: rgba(var(--white-rgb), 0.06);
    border-color: rgba(var(--white-rgb), 0.14);
}

.admin-user-solde {
    font-size: 0.8rem;
    color: rgba(var(--white-rgb), 0.7);
    font-variant-numeric: tabular-nums;
}

/* D OU VIENT CE COMPTE : DEUX LIGNES ETIQUETEES.
   L'Admin, le 23/10/2026 : « dans /users remplacer "Programmes actifs" par
   (sur 2 lignes) "Referent : {referent}" et "Venu de : {parrain}" ».

   L ETIQUETTE S EFFACE, LE NOM SE LIT. Deux lignes de meme poids se seraient
   lues comme quatre informations ; ici chaque ligne pose sa question en gris
   et repond en clair.

   PAS DE `nowrap` : la colonne porte des noms propres et des noms d'organisme,
   dont certains sont longs. Un nom tronque par la colonne voisine ne se voit
   pas, il se devine -- et c'est le genre de cellule ou l'on cherche justement
   le nom en entier. Il passe donc a la ligne. */
.admin-user-provenance {
    font-size: 0.8rem;
}

/* L ETIQUETTE PASSE AU-DESSUS, ET C EST CE QUI REND LE NOM ENTIER.

   L'ADMIN, LE 23/10/2026, capture a l'appui : « a ajuster, idealement pas de
   retour a la ligne. Mettre a la ligne ? reduire un peu les autres colonnes ?
   en laissant le minimum sans coupure et un maximum pour l'identite. »

   REDUIRE LES AUTRES COLONNES A ETE ESSAYE, ET MESURE : la somme des besoins
   fait 1167 px pour une table de 1082, donc il n'y a RIEN a prendre -- chaque
   colonne est deja a son minimum ou presque. Pousser la provenance a 14 %
   prenait sur « Personne », qui tombait de 281 a 254 px : l'inverse exact de
   « un maximum pour l'identite ». Et forcer les colonnes etroites a leur
   contenu (`width: 1%`) n'a rien change du tout, mesure a l'identique.

   L ETIQUETTE EMPILEE, ELLE, NE PREND RIEN A PERSONNE. Cote a cote,
   « Referent : » mangeait 55 des 137 px de la colonne et il en restait 82 au
   nom -- « Florent Naudin » en demande 90, d'ou la coupure. Au-dessus, le nom
   recoit les 137. */
.admin-user-provenance__ligne {
    display: flex;
    flex-direction: column;
    gap: 0;
}

.admin-user-provenance__ligne + .admin-user-provenance__ligne {
    margin-top: 5px;
}

/* Elle se fait plus discrete encore maintenant qu'elle a sa ligne : c'est une
   question posee au-dessus d'une reponse, pas une colonne de plus a lire. */
.admin-user-provenance__quoi {
    font-size: 11px;
    line-height: 1.25;
    color: rgba(var(--white-rgb), 0.45);
}

/* UN NOM PROPRE NE SE PLIE PAS, IL SE COUPE.

   L'ADMIN, LE 23/10/2026, capture a l'appui : « a ajuster, idealement pas de
   retour a la ligne [...] en laissant le minimum sans coupure et un maximum
   pour l'identite ». « Florent Naudin » rendait « Florent » puis « Naudin »
   sur deux lignes, et la rangee doublait de hauteur.

   C'EST LA MEME REGLE QUE LE NOM ET L ADRESSE de la colonne « Personne »,
   ecrite trente lignes plus bas : un nom coupe en deux demande d'etre relu
   pour etre recompose, alors que les points de suspension disent simplement
   qu'il en reste.

   `min-width: 0` EST CE QUI FAIT MORDRE L ELLIPSE. Dans un conteneur flex, un
   enfant ne descend pas sous sa largeur de contenu par defaut : sans cette
   ligne, le nom pousse la cellule au lieu de se couper, et `text-overflow` ne
   sert a rien. Meme mecanique que le `max-width: 0` du tableau plus bas. */
.admin-user-provenance__qui {
    min-width: 0;
    color: rgba(var(--white-rgb), 0.82);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Une absence se dit plus bas que ce qui est la, et sans couleur : la liste
   n'a pas a s'allumer pour une ligne ou il n'y a rien a faire. C'est la meme
   regle que `.puce-etat--sans` plus haut. */
.admin-user-provenance__qui--sans {
    color: rgba(var(--white-rgb), 0.42);
}

.admin-user-dates {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.admin-user-dates__inscrit {
    display: block;
    font-size: 0.85rem;
}

.admin-user-dates__vu {
    display: block;
    margin-top: 2px;
    font-size: 0.78rem;
    color: rgba(var(--white-rgb), 0.52);
}

/* Plus d'un mois sans venir : le compte existe, la personne non. La nuance
   vaut d'etre visible sans etre criarde. */
.admin-user-dates__vu--loin {
    color: rgba(var(--amber-rgb), 0.85);
}

/* La pastille reprend la couleur de la ligne : elle ECRIT ce que la teinte
   dit deja, pour qui ne distingue pas les couleurs ou lit en noir et blanc. */
.admin-user-type {
    display: inline-flex;
    align-items: center;
    box-sizing: border-box;
    min-height: 26px;
    padding: 0 10px;
    border-radius: var(--rayon-pilule);
    border: 1px solid rgba(var(--row-rgb, var(--teinte-bleue)), 0.34);

    /* HUIT CENTIEMES DE VOILE, PAS QUATORZE. L'encre de la pastille et son fond
       sont la MEME teinte : plus le voile monte, plus le fond se rapproche de
       l'encre, et moins elle se lit. Sur une ligne deja teintee par le role, le
       cumul des trois couches -- carte, cellule, pastille -- rendait 4,33 pour
       4,5 exiges. A huit centiemes, le fond redescend vers la carte et la
       pastille rend 4,9, sans rien perdre de sa teinte : c'est elle qui dit le
       role, et elle reste. */
    background: rgba(var(--row-rgb, var(--teinte-bleue)), 0.08);
    color: rgb(var(--row-rgb, var(--teinte-bleue)));
    font-size: var(--taille-legende);
    font-weight: var(--graisse-moyenne);
    white-space: nowrap;
}

/* 880 px, et non 640 : c'est la largeur ou `.responsive-table` bascule en
   cartes. En dessous de sa propre bascule, une reparation repare dans le vide. */
@media (max-width: 880px) {
    /* Empilee, la carte donne son nom en titre : le nom prend la taille qui
       va avec, comme dans la liste de clients. */
    .admin-users-table .admin-user-name {
        font-size: var(--taille-titre-s);
        font-weight: var(--graisse-normale);
    }

    /*
     * LES TROIS ACTIONS SUR UNE RANGEE, pas en colonne.
     *
     * Le tableau generique empile ses boutons et les etire sur toute la
     * largeur : trois boutons ajoutaient 130 px a chaque carte, et l'ecran
     * ne montrait plus que deux personnes. Leurs libelles sont courts, ils
     * tiennent a trois de front.
     */
    .admin-users-table .responsive-table__actions {
        flex-direction: row;
        flex-wrap: wrap;
        gap: var(--espace-s);
    }

    .admin-users-table .responsive-table__actions .btn {
        flex: 1 1 0;
        width: auto;
        min-width: 0;
        padding-inline: var(--espace-s);
    }

    /* « Actions » au-dessus de trois boutons n'apprend rien : ils se
       reconnaissent seuls. */
    .admin-users-table td:has(> .responsive-table__actions) > .responsive-table__label {
        display: none;
    }

    /*
     * L'IDENTIFIANT SE POSE EN HAUT A DROITE, AU NIVEAU DU NOM.
     *
     * Il occupait deux lignes en bas de carte, « ID » puis son numero, pour
     * quatre caracteres. Un identifiant sert a designer quelqu'un dont on
     * parle : on le cherche quand on a deja le nom sous les yeux, donc a
     * cote du nom, et jamais en le lisant de haut en bas.
     *
     * Pose hors du flux plutot que reordonne : la carte est une colonne, et
     * une colonne ne met pas deux choses sur la meme ligne. Le titre reserve
     * la place a sa droite pour qu'un nom long ne passe pas dessous.
     *
     * Reserve a CETTE liste : le pied de la liste des clients porte une date
     * d'inscription, plus longue, et qui a sa place en bas.
     */
    .admin-users-table tbody tr.liste-carte__ligne {
        position: relative;
    }

    /* `.liste-carte` est nomme ICI AUSSI, et ce n'est pas du bavardage : la
       regle qui remet le pied en `display: block` pese exactement autant et
       s'ecrit plus bas dans la feuille. A poids egal, c'est la derniere qui
       gagne, et le pied restait en deux lignes. */
    .admin-users-table.liste-carte tbody tr.liste-carte__ligne > td.cellule--pied {
        position: absolute;
        /* Le meme retrait que le rembourrage de la carte : l'identifiant se
           cale sur son coin, pas a cote. */
        top: var(--espace-l);
        right: var(--espace-l);
        /* `width: auto` CONTRE le `width: 100%` que le tableau empile donne a
           chaque cellule : sans lui, la boite posee hors du flux s'etirait sur
           toute la carte et passait sous le nom. */
        width: auto;
        display: flex;
        align-items: baseline;
        gap: 6px;
        margin: 0;
        padding: 0;
        border: none;
    }

    .admin-users-table.liste-carte tbody tr.liste-carte__ligne > td.cellule--titre {
        padding-right: 76px;

        /* LES 76 PIXELS SE PRENNENT DANS LA LARGEUR, ILS NE S Y AJOUTENT PAS.
           La case est en `content-box` : sa largeur calculee, 301 px, ne compte
           pas ses creux, et les 88 px de remplissage s'ajoutaient par-dessus --
           389 dans une rangee de 338, et la page debordait de 45 px sans barre,
           puisque la rangee laisse deborder. Meme piege que le pied de page.

           `min-width: 0` reste : une case de flex refuse par defaut de
           descendre sous la largeur de son contenu, et la reserve du bouton
           d'action l'y aurait ramenee au premier nom un peu long. */
        box-sizing: border-box;
        min-width: 0;
    }

    /*
     * LA DATE NE FLOTTE PLUS AU MILIEU.
     *
     * La cellule range trois choses en `space-between` : l'etiquette, la date
     * d'arrivee, la derniere visite. A trois, celle du milieu se pose au
     * centre et se lit comme un titre centre, alors que c'est une valeur.
     *
     * La marge automatique groupe les deux dates a droite, ou sont toutes les
     * autres valeurs de la carte.
     */
    .admin-users-table .admin-user-dates {
        gap: 6px 12px;
    }

    .admin-users-table .admin-user-dates .admin-user-dates__inscrit {
        margin-left: auto;
    }
}

/* -------------------------------------------------------------------------
   CONFIER DES CLIENTS A UN AUTRE PRATICIEN
   -------------------------------------------------------------------------

   C'etait un tableau nu : deux colonnes, un liste deroulant par ligne, un
   bouton. Rien ne disait que ce geste est le plus lourd de l'ecran — chaque
   personne change d'accompagnant et en est avertie sur-le-champ.

   La liste reprend donc la grammaire des cartes du produit, avec le rail
   violet du praticien, et le passage de l'un a l'autre se lit dans la ligne
   elle-meme grace a la fleche.
   ------------------------------------------------------------------------- */

.reassignation__liste {
    display: flex;
    flex-direction: column;
    /* En `gap` et non en marges : deux marges voisines s'additionnent, et la
       pile montrait des trous inegaux. */
    gap: 8px;
    margin: 14px 0 4px;
}

.reassignation__ligne {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
    align-items: center;
    gap: 14px;
    box-sizing: border-box;
    padding: 12px 14px;
    border-radius: 14px;
    background: rgba(var(--teinte-violette), 0.09);
    background-clip: padding-box;
    border: 1px solid rgba(var(--teinte-violette), 0.14);
    border-left: 4px solid rgba(var(--teinte-violette), 0.76);
}

.reassignation__personne {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.reassignation__personne a {
    color: var(--white);
    text-decoration: none;
    font-weight: 600;
}

.reassignation__personne a:hover {
    text-decoration: underline;
}

.reassignation__courriel {
    font-size: 12px;
    color: rgba(var(--white-rgb), 0.5);
    overflow: hidden;
    text-overflow: ellipsis;
}

.reassignation__vers {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.reassignation__vers select {
    margin-bottom: 0;
    min-width: 0;
    width: 100%;
}

/* La fleche porte le sens de la ligne : de cette personne, vers ce praticien.
   Dans sa propre boite flexible, comme celle du retour : « → » ne s'assied
   pas sur la ligne de base comme une lettre. */
.reassignation__fleche {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    font-size: 16px;
    color: rgba(var(--teinte-violette), 0.9);
}

/* --- La confirmation ---------------------------------------------------
   Elle prend la place du bouton, au meme endroit : la decision se lit la ou
   on venait de cliquer, sans que l'ecran saute. */

.reassignation__confirmation {
    margin-top: 12px;
    padding: 16px;
    border-radius: 14px;
    background: rgba(var(--amber-deep-rgb), 0.10);
    background-clip: padding-box;
    border: 1px solid rgba(var(--amber-deep-rgb), 0.34);
}

.reassignation__confirmation-titre {
    margin: 0 0 4px;
    font-weight: 700;
    color: var(--white);
}

.reassignation__confirmation-intro {
    margin: 0 0 12px;
    font-size: 13px;
    color: rgba(var(--white-rgb), 0.66);
}

.reassignation__recapitulatif {
    list-style: none;
    margin: 0 0 14px;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 7px;
}

.reassignation__recapitulatif li {
    display: flex;
    align-items: center;
    gap: 9px;
    flex-wrap: wrap;
    font-size: 14px;
    color: rgba(var(--white-rgb), 0.86);
}

.reassignation__recapitulatif strong {
    color: var(--white);
}

.reassignation__confirmation-boutons {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

@media (max-width: 640px) {
    .reassignation__ligne {
        grid-template-columns: 1fr;
        gap: 10px;
    }
}

/* -------------------------------------------------------------------------
   L'ECRAN DES CONNEXIONS
   -------------------------------------------------------------------------

   Deux sources, deux questions : les sessions disent qui est la MAINTENANT,
   le journal dit qui est ENTRE. La premiere oublie tout a l'expiration, d'ou
   la seconde.

   La ligne reprend la grammaire des autres listes : rail de couleur a
   gauche, la personne a droite. La teinte dit le type de compte, et le rouge
   les echecs.
   ------------------------------------------------------------------------- */

.connexions-fenetre {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}

.connexions-fenetre__intitule {
    font-size: 12.5px;
    color: rgba(var(--white-rgb), 0.5);
}

.connexions-fenetre__choix {
    display: inline-flex;
    align-items: center;
    height: 34px;
    padding: 0 14px;
    border-radius: 12px;
    border: 1px solid rgba(var(--slate-light-rgb), 0.20);
    background: rgba(var(--slate-rgb), 0.55);
    background-clip: padding-box;
    color: rgba(var(--white-rgb), 0.86);
    font-size: 14px;
    line-height: 1;
    text-decoration: none;
    transition: transform .14s ease, filter .14s ease, border-color .14s ease;
}

.connexions-fenetre__choix:hover {
    transform: translateY(-1px);
    filter: brightness(1.08);
    border-color: rgba(var(--cyan-rgb), 0.48);
}

.connexions-fenetre__choix:active {
    transform: translateY(0);
    filter: brightness(0.92);
}

/* Le meme marquage que les onglets de la fiche : c'est le meme geste, choisir
   ce qu'on regarde. */
.connexions-fenetre__choix.is-active {
    border-width: 2px;
    border-color: rgba(var(--cyan-rgb), 0.85);
    background: rgba(var(--cyan-rgb), 0.20);
    color: var(--white);
}

.connexions-chiffres {
    display: flex;
    flex-wrap: wrap;
    gap: 26px;
    margin-bottom: 18px;
}

.connexions-chiffre {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.connexions-chiffre strong {
    font-size: 26px;
    line-height: 1.1;
    font-weight: 700;
}

.connexions-chiffre span {
    font-size: 12.5px;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.55));
}

/* Un echec compte pour rien quand il n'y en a pas ; des qu'il y en a, le
   chiffre doit se voir sans qu'on le cherche. */
.connexions-chiffre--attention strong {
    color: rgb(248, 113, 113);
}

.connexions-liste {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

.connexions-ligne {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 150px 120px;
    align-items: center;
    gap: 14px;
    box-sizing: border-box;
    padding: 10px 14px;
    border-radius: 14px;
    border: 1px solid rgba(var(--row-rgb, var(--teinte-bleue)), 0.14);
    border-left: 4px solid rgba(var(--row-rgb, var(--teinte-bleue)), 0.76);
    background: rgba(var(--row-rgb, var(--teinte-bleue)), 0.07);
    background-clip: padding-box;
}

.connexions-ligne__qui {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.connexions-ligne__qui strong {
    font-size: 15px;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.connexions-ligne__qui span {
    font-size: 12.5px;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.55));
}

/* Les adresses et les heures s'alignent en colonne : on les compare du regard
   d'une ligne a l'autre, donc les chiffres doivent avoir la meme chasse. */
.connexions-ligne__adresse,
.connexions-ligne__quand {
    font-size: 13px;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-variant-numeric: tabular-nums;
}

.connexions-ligne__quand {
    text-align: right;
}

.card--attention {
    border-color: rgba(248, 113, 113, 0.34);
}

@media (max-width: 700px) {
    .connexions-ligne {
        grid-template-columns: 1fr;
        gap: 6px;
    }

    .connexions-ligne__quand {
        text-align: left;
    }
}

/* -------------------------------------------------------------------------
   LES BARRES DES STATISTIQUES
   -------------------------------------------------------------------------

   Un tableau de chiffres oblige a comparer de tete. La barre porte la
   comparaison : on voit d'un regard lequel domine, et de combien.

   La longueur est relative au PLUS GRAND de la liste, pas a un total : on
   compare des rangs entre eux, pas des parts d'un tout.
   ------------------------------------------------------------------------- */

.stats-deux-colonnes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 16px;
    align-items: start;
}

.stats-barres {
    display: flex;
    flex-direction: column;
    gap: 9px;
    margin-top: 12px;
}

.stats-barre {
    display: grid;
    grid-template-columns: minmax(0, 140px) minmax(0, 1fr) 48px;
    align-items: center;
    gap: 12px;
}

.stats-barre__nom {
    font-size: 13.5px;
    color: rgba(var(--white-rgb), 0.86);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.stats-barre__piste {
    height: 8px;
    border-radius: 999px;
    background: rgba(var(--white-rgb), 0.06);
    overflow: hidden;
}

.stats-barre__part {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg, rgba(var(--cyan-rgb), 0.85), rgba(var(--cyan-rgb), 0.42));
}

/* --- LE TUNNEL DU TEST GRATUIT ------------------------------------------ */

/* Cinq marches cote a cote, dans l'ordre du parcours. Une par colonne tant
   qu'elles tiennent, empilees ensuite : une marche de 60 px ne se lit pas. */
.stats-tunnel {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
    gap: 10px;
    margin-top: 14px;
}

.stats-tunnel__marche {
    padding: 12px 14px;
    border-radius: 10px;
    background: rgba(var(--white-rgb), 0.04);
    border: 1px solid rgba(var(--white-rgb), 0.07);
}

/* LE TEST PASSE EST LA MARCHE QUI COMPTE. Les quatre autres existent pour
   expliquer celle-la, donc elle se distingue, et une seule se distingue. */
.stats-tunnel__marche--cle {
    background: rgba(var(--cyan-rgb), 0.1);
    border-color: rgba(var(--cyan-rgb), 0.3);
}

.stats-tunnel__marche > strong {
    display: block;
    font-size: 26px;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.stats-tunnel__quoi {
    display: block;
    margin-top: 5px;
    font-size: 12.5px;
    color: rgba(var(--white-rgb), 0.72);
}

.stats-tunnel__marche-part {
    display: block;
    margin-top: 8px;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    color: rgba(var(--white-rgb), 0.55);
}

.stats-tunnel__marche-part em {
    font-style: normal;
    opacity: 0.72;
}

.stats-canaux__titre {
    margin: 22px 0 0;
    font-size: 14px;
}

.stats-canaux {
    width: 100%;
    margin-top: 10px;
    border-collapse: collapse;
}

.stats-canaux th,
.stats-canaux td {
    padding: 9px 8px;
    text-align: right;
    border-bottom: 1px solid rgba(var(--white-rgb), 0.07);
    font-variant-numeric: tabular-nums;
    font-size: 13.5px;
}

/* Le nom du canal est du texte, pas un nombre : il se lit a gauche. */
.stats-canaux th:first-child,
.stats-canaux td:first-child {
    text-align: left;
    font-variant-numeric: normal;
}

.stats-canaux th {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: rgba(var(--white-rgb), 0.55);
}

/* La provenance n'est pas de la meme nature qu'un domaine choisi : elle dit
   d'ou l'on vient, pas ce qu'on a fait. Une autre teinte evite de croire que
   les deux listes se comparent. */
.stats-barre__part--source {
    background: linear-gradient(90deg, rgba(var(--teinte-violette), 0.85), rgba(var(--teinte-violette), 0.42));
}

.stats-barre__valeur {
    font-size: 13.5px;
    font-variant-numeric: tabular-nums;
    text-align: right;
    color: rgba(var(--white-rgb), 0.72);
}

@media (max-width: 560px) {
    .stats-barre {
        grid-template-columns: minmax(0, 1fr) 44px;
    }

    /* La piste passe sous le nom : a cette largeur, trois colonnes ne
       laissent plus assez de place a la barre pour qu'elle compare. */
    .stats-barre__piste {
        grid-column: 1 / -1;
    }
}

/* Fermer une session : une action discrete, posee au bout de la ligne. Elle
   deconnecte quelqu'un, donc elle demande confirmation ; mais elle n'a pas a
   crier pour autant, on la cherche rarement. */
.connexions-fermer {
    appearance: none;
    height: 30px;
    padding: 0 12px;
    border-radius: 10px;
    border: 1px solid rgba(248, 113, 113, 0.34);
    background: rgba(248, 113, 113, 0.12);
    color: rgb(248, 143, 143);
    font: inherit;
    font-size: 12.5px;
    line-height: 1;
    cursor: pointer;
    transition: transform .14s ease, filter .14s ease, border-color .14s ease;
}

/* Meme raison que pour `.btn` : 30 px se visent mal au doigt, et fermer une
   session par erreur deconnecte quelqu'un. On ouvre la hauteur sur mobile, la
   largeur ne bouge pas. */
@media (max-width: 768px) {
    .connexions-fermer {
        height: 44px;
    }
}

.connexions-fermer:hover {
    transform: translateY(-1px);
    filter: brightness(1.08);
    border-color: rgba(248, 113, 113, 0.62);
}

.connexions-fermer:active {
    transform: translateY(0);
    filter: brightness(0.92);
}

.connexions-ligne__mienne {
    font-size: 12px;
    color: rgba(var(--white-rgb), var(--voile-mention-basse, 0.42));
    font-style: italic;
    text-align: right;
}

/* La ligne compte une colonne de plus depuis qu'elle porte une action. */
.connexions-liste[data-sessions] .connexions-ligne {
    grid-template-columns: minmax(0, 1fr) 150px 120px 90px;
}

@media (max-width: 700px) {
    .connexions-liste[data-sessions] .connexions-ligne {
        grid-template-columns: 1fr;
    }
}

/* Les jours en colonnes : le temps se lit de gauche a droite, et c'est la
   SILHOUETTE qu'on cherche, pas la valeur de chaque barre. */
.stats-jours {
    display: flex;
    align-items: flex-end;
    gap: 4px;
    height: 120px;
    margin-top: 14px;
    overflow-x: auto;
    padding-bottom: 2px;
}

.stats-jour {
    flex: 1 0 22px;
    min-width: 22px;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
    gap: 5px;
}

.stats-jour__colonne {
    width: 100%;
    border-radius: 5px 5px 0 0;
    background: linear-gradient(180deg, rgba(var(--cyan-rgb), 0.82), rgba(var(--cyan-rgb), 0.28));
}

.stats-jour__date {
    font-size: 10.5px;
    color: rgba(var(--white-rgb), var(--voile-mention-basse, 0.42));
    font-variant-numeric: tabular-nums;
    white-space: nowrap;

    /* --- LA LIGNE D ETIQUETTE EST RESERVEE, ECRITE OU NON ---------------

       L'ADMIN, LE 11/11/2026 : « les infos sous les barres desalignent ».

       UNE ETIQUETTE SUR TROIS EST ECRITE sur le graphique des heures, pour
       que vingt-quatre nombres ne se chevauchent pas. Les vingt-et-une
       autres etaient des `span` VIDES, donc hauts de zero : la colonne
       au-dessus descendait de quinze pixels de plus que ses voisines
       etiquetees. Mesure : deux lignes de base, 923 et 939, dans le meme
       graphique. Ce n'est pas l'etiquette qui se decalait, c'est la BARRE.

       `1lh` EST LA HAUTEUR DE SA PROPRE LIGNE, donc le reglage suit la
       taille du texte sans la recopier. Le repli en pixels est la valeur
       d'aujourd'hui, pour les navigateurs qui ne connaissent pas l'unite.
       --------------------------------------------------------------- */
    min-height: 15px;
    min-height: 1lh;
}

/* --- LE RYTHME : TROIS GRAPHIQUES, LE MEME DESSIN ------------------------

   L'ADMIN, LE 11/11/2026 : « un graph de visites par heure dans une journee,
   jours par semaine, par mois ».

   ILS REPRENNENT LA COLONNE DE L EVOLUTION, qui existait deja : une seconde
   facon de dessiner une colonne aurait diverge de la premiere au premier
   reglage de hauteur. Seules trois choses changent ici.
   ------------------------------------------------------------------------- */

/* LE TITRE DE CHAQUE DECOUPAGE. Trois graphiques a la suite sans titre, ce
   sont trois silhouettes dont on ne sait pas ce qu'elles mesurent. */
.stats-rythme__titre {
    margin: 22px 0 0;
    font-size: 13px;
    font-weight: var(--graisse-moyenne, 600);
    color: rgba(var(--white-rgb), 0.72);
}

/* Le premier titre suit son texte d'introduction, il n'a pas a s'en
   detacher autant que les suivants se detachent du graphique d'avant. */
.stats-rythme__titre:first-of-type {
    margin-top: 10px;
}

/* LES CASES SE PARTAGENT LA LARGEUR AU LIEU DE DEFILER. Vingt-quatre heures,
   sept jours ou quatre mois tiennent tous dans la carte : un defilement
   horizontal cacherait la moitie du rythme, c'est-a-dire ce qu'on vient
   chercher. `flex: 1 1 0` laisse la colonne retrecir, contrairement au
   `1 0 22px` de l'evolution, qui doit pouvoir defiler sur trois mois. */
.stats-jours--rythme {
    overflow-x: visible;
    gap: 3px;
}

.stats-jours--rythme .stats-jour {
    flex: 1 1 0;
    min-width: 0;
}

/* --- LA SERIE DATEE : ELLE TIENT, OU ELLE DEFILE -------------------------

   Le jour apres jour n'a pas de nombre de cases connu d'avance -- sept,
   trente, ou quatre-vingt-quatorze sur « tout ». Les deux reglages existants
   echouaient chacun d'un cote : `1 0 22px` defilait des trente jours sur un
   grand ecran, et `1 1 0` ecrasait les colonnes a ZERO pixel de large sous
   375 px, ou les quatre-vingt-quatorze etiquettes se chevauchaient treize
   fois. Mesure du 11/11/2026.

   SIX PIXELS DE PLANCHER, DEUX D ECART : la colonne retrecit tant qu'elle
   reste lisible, et c'est le CADRE qui defile en dessous. Les deux valeurs
   se tiennent -- a trois pixels d'ecart, les quatre-vingt-treize intervalles
   pesaient 279 px a eux seuls et la serie defilait encore sur un ecran de
   1440. Mesure : 94 colonnes tiennent en 750 px, donc elles tiennent.

   SUR UN TELEPHONE, ELLE DEFILE, et c'est la reponse honnete : quatre-vingt-
   quatorze points sur 340 px ne s'ecrasent pas, ils se parcourent.
   ------------------------------------------------------------------------- */
.stats-jours--serie {
    gap: 2px;
}

.stats-jours--serie .stats-jour {
    flex: 1 1 6px;
    min-width: 6px;
}

/* UNE CASE A ZERO GARDE SA PLACE ET PERD SA COULEUR. Le creux de la nuit est
   une information ; un trait colore de quatre pixels se lirait comme une
   petite valeur, et un vide se lirait comme une case manquante. */
.stats-jour__colonne--vide {
    background: rgba(var(--white-rgb), 0.12);
}

.stats-barre__part--appareil {
    background: linear-gradient(90deg, rgba(var(--teinte-or), 0.85), rgba(var(--teinte-or), 0.42));
}

/* -------------------------------------------------------------------------
   LA CARTE DU MONDE
   -------------------------------------------------------------------------

   Un fond converti une fois en chemins SVG, peint par le SERVEUR : la teinte
   d'un pays est calculee la ou vivent les chiffres, et le script n'y touche
   jamais. Tenir la meme regle a deux endroits, c'est se preparer a la voir
   diverger.
   ------------------------------------------------------------------------- */

.carte-monde__cadre {
    position: relative;
    margin-top: 14px;
    padding: 10px;
    border-radius: 14px;
    background: rgba(var(--ink-900-rgb, 12, 18, 33), 0.34);
    border: 1px solid rgba(var(--white-rgb), 0.06);
}

.carte-monde {
    display: block;
    width: 100%;
    height: auto;
}

.carte-monde path {
    /* Le trait separe les pays sans les cerner : sur une carte a cette
       echelle, un contour epais mange les petits pays. */
    stroke: rgba(var(--ink-900-rgb, 12, 18, 33), 0.55);
    stroke-width: 0.5;
    transition: filter .12s ease;
}

.carte-monde path:hover {
    filter: brightness(1.35);
    cursor: default;
}

/* L'infobulle suit le pointeur : la bulle native attend une seconde avant de
   paraitre et ne se laisse pas mettre en forme. */
.carte-monde__bulle {
    position: absolute;
    z-index: 4;
    padding: 6px 10px;
    border-radius: 10px;
    background: rgba(var(--ink-900-rgb, 12, 18, 33), 0.94);
    border: 1px solid rgba(var(--cyan-rgb), 0.42);
    color: var(--white);
    font-size: 12.5px;
    line-height: 1.3;
    white-space: nowrap;
    pointer-events: none;
}

.carte-monde__filtre {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 16px;
}

.carte-monde__filtre label {
    margin: 0;
    font-size: 12.5px;
    color: rgba(var(--white-rgb), var(--voile-mention, 0.55));
    white-space: nowrap;
}

.carte-monde__filtre input {
    margin-bottom: 0;
    max-width: 280px;
    /* Le meme rayon que les pastilles de fenetre juste au-dessus : les deux
       servent a restreindre ce qu'on regarde. */
    border-radius: 12px;
    padding: 9px 13px;
    font-size: 14px;
}

/* La mise au point se voit : on tape dedans, il faut savoir ou. */
.carte-monde__filtre input:focus {
    outline: none;
    border-color: rgba(var(--cyan-rgb), 0.62);
    box-shadow: 0 0 0 3px rgba(var(--cyan-rgb), 0.16);
}

/* La croix de vidage que Chrome ajoute aux champs de recherche est grise
   et presque invisible sur ce fond : on la remonte a la couleur du texte. */
.carte-monde__filtre input::-webkit-search-cancel-button {
    filter: invert(1) opacity(0.55);
    cursor: pointer;
}

.carte-monde__vide {
    margin-top: 10px;
}

/* Le drapeau ou, a defaut, le code du pays. Voir le commentaire de la vue :
   l'emoji drapeau ne rend pas sous Windows. */
.carte-monde__drapeau {
    flex: 0 0 auto;
    border-radius: 2px;
    vertical-align: -2px;
}

.carte-monde__code {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 24px;
    height: 15px;
    padding: 0 4px;
    border-radius: 3px;
    background: rgba(var(--white-rgb), 0.10);
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .04em;
}

/* Le nom et son drapeau forment une paire : ils ne se separent pas quand la
   colonne se resserre. */
.stats-barre__nom {
    display: flex;
    align-items: center;
    gap: 7px;
}

/* =========================================================================
   UNE CANDIDATURE DE PRATICIEN.

   La fiche etait une suite de paragraphes bruts, et le lien d'inscription y
   tenait la place la plus voyante : en caracteres de code, au milieu. Or le
   lien ne se lit pas, il se copie une fois la decision prise. Ce qui se lit,
   c'est qui demande et qui le recommande.

   L'ordre suit donc la decision : l'identite et son statut, les moyens de
   joindre la personne, le referent qui fait pencher, puis le geste qui clot —
   statut, lien a copier, note.
   ========================================================================= */
.candidature {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.candidature__tete {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.candidature__nom {
    margin: 0;
    font-size: 1.06rem;
}

.candidature__metier {
    margin-top: 2px;
    /* 0,72 rend 4,09 sur la carte de candidature en clair : ce metier est la
       seule ligne qui dit QUI est la personne, on la lit vraiment. */
    color: rgba(var(--ink-200-rgb), 0.88);
    font-size: 0.9rem;
}

/* Le statut se lit d'un coup d'oeil dans une liste : il porte sa couleur,
   celle du systeme d'actions. Bleu tant qu'il reste quelque chose a faire,
   vert quand c'est accepte, rouge quand c'est refuse, neutre entre les deux. */
.candidature__statut {
    flex: none;
    padding: 4px 11px;
    border-radius: 999px;
    border: 1px solid transparent;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    white-space: nowrap;
}

.candidature__statut--new {
    background: rgba(var(--blue-rgb), 0.16);
    border-color: rgba(var(--blue-rgb), 0.45);
    /* LE BLEU DE DONNEE NE PASSE NI D UN COTE NI DE L AUTRE : 2,53 en clair
       sur son propre voile, 4,06 en sombre. Il lui faut un cran de chaque
       cote -- plus profond en clair, plus clair en sombre. */
    color: rgb(var(--encre-etat-info-rgb, 147, 197, 253));
}

.candidature__statut--contacted,
.candidature__statut--invited {
    background: rgba(var(--ink-200-rgb), 0.10);
    border-color: rgba(var(--ink-200-rgb), 0.24);
    color: rgba(var(--ink-200-rgb), 0.86);
}

.candidature__statut--accepted {
    background: rgba(var(--green-rgb), 0.16);
    border-color: rgba(var(--green-rgb), 0.45);
    color: rgb(var(--encre-etat-ok-rgb, var(--green-rgb)));
}

.candidature__statut--declined {
    background: rgba(var(--red-rgb), 0.14);
    border-color: rgba(var(--red-rgb), 0.42);
    color: rgba(var(--red-rgb), 1);
}

/* Le contact : une rangee de faits, separes par des points mediands poses en
   CSS. Ecrits dans le gabarit, ils restaient quand un champ manquait. */
.candidature__contact {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    color: rgba(var(--ink-200-rgb), 0.78);
    font-size: 0.9rem;
}

/* Le point est pose sur l'ENVELOPPE, jamais sur le lien : dans le lien, il
   heritait du soulignement et paraissait en faire partie. */
.candidature__contact > span + span::before {
    content: '·';
    margin-right: 14px;
    color: rgba(var(--ink-200-rgb), 0.34);
    text-decoration: none;
}

.candidature__referent,
.candidature__compte {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 10px;
    padding: 10px 13px;
    border-radius: 12px;
    background: rgba(var(--black-rgb), 0.22);
    border: 1px solid rgba(var(--white-rgb), 0.06);
    font-size: 0.92rem;
}

.candidature__etiquette {
    /* UNE ETIQUETTE EN CAPITALES DE 12,5 px N A PAS DE MARGE. A 0,60 elle rend
       2,45 en clair ; elle nomme le champ d'a cote, elle se lit pleine. */
    color: rgb(var(--ink-200-rgb));
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.candidature__actif {
    color: rgba(var(--green-rgb), 0.9);
}

.candidature__compte form {
    margin: 0;
}

/* Le mot du candidat est une citation : il se lit dans sa voix, pas dans la
   notre. Un filet plutot que des guillemets, qui se melent au texte. */
.candidature__mot {
    margin: 0;
    padding: 8px 0 8px 14px;
    border-left: 2px solid rgba(var(--blue-rgb), 0.42);
    color: rgba(var(--ink-200-rgb), 0.86);
    font-style: italic;
}

.candidature__suite {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin: 2px 0 0;
    padding-top: 14px;
    border-top: 1px solid rgba(var(--white-rgb), 0.08);
}

/* Le statut et le lien vont ensemble : on choisit l'un et on copie l'autre
   dans le meme geste. Le statut ne prend que la place de son plus long
   libelle, le lien recoit le reste. */
/* Les deux colonnes commencent EN HAUT, pas en bas : cale sur le bas, la
   colonne la plus courte descendait, et son libelle ne se lisait plus sur la
   meme ligne que celui d'a cote. Ce sont les libelles qu'on parcourt. */
.candidature__champs {
    display: grid;
    grid-template-columns: minmax(0, 240px) minmax(0, 1fr);
    gap: 12px 16px;
    align-items: start;
}

/* Le champ et le select prennent la meme hauteur, sinon les deux colonnes
   s'alignent en haut et se decalent en bas. */
.candidature__champs .candidature__champ > select,
.candidature__champ .dashboard-lien-copie__champ {
    min-height: 44px;
}

.candidature__champ {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.candidature__champ label {
    margin: 0;
    /* 0,72 rend 4,09 en clair a 13 px : un libelle de champ se lit avant le
       champ, il ne peut pas etre le texte le plus faible de la carte. */
    color: rgba(var(--ink-200-rgb), 0.92);
    font-size: 0.82rem;
    font-weight: 600;
}

.candidature__champ select,
.candidature__champ textarea {
    margin: 0;
}

/* Le champ part d'une base NULLE, pas de son contenu.
   `flex: 1 1 auto` prend pour base la largeur du texte, et une adresse
   complete est plus large que la colonne : le bouton passait a la ligne
   suivante, seul, loin du champ qu'il copie. */
/*
 * LE BOUTON A LA HAUTEUR DU CHAMP QU'IL COPIE, PARTOUT.
 *
 * C'etait ecrit pour la seule fiche de candidature. La cause etait pourtant
 * generale : dans cette ligne, le champ mesure 43 px et le bouton 35, donc le
 * centrage posait le bouton quatre pixels plus bas que ce qu'il copie. Et tout
 * `input` de l'interface porte 16 px de marge basse, faits pour un champ seul
 * dans sa colonne, qui allongeaient la ligne quand il en partage une.
 *
 * La regle vit maintenant sur le composant lui-meme : le lien d'affiliation du
 * praticien, le code d'invitation, le lien a envoyer a un candidat et l'entete
 * des candidatures s'alignent de la meme facon, sans qu'on ait a y repenser.
 */
/*
 * LE BOUTON PASSE A LA LIGNE PLUTOT QUE D'ECRASER LE CHAMP.
 *
 * En `nowrap`, le bouton garde la largeur de son intitule et le champ prend ce
 * qui reste : a 375 px il ne restait que 26 px, soit un champ ou l'on ne lit
 * rien de ce qu'on va copier. Mesure faite avant correction : champ 26 px,
 * bouton 299.
 *
 * Le champ demande donc 220 px avant de ceder : au-dela il s'etire, en deca le
 * bouton descend sur sa propre ligne et le champ reprend toute la largeur.
 * C'est le meme reglage qui evite la troncature a 1280 px.
 */
/* La largeur du champ, sa marge et le repli de la paire sont regles une fois
   pour toutes avec le composant, plus haut dans cette feuille. Dans la liste
   des candidatures la colonne est plus etroite : le champ y cede sa largeur
   de confort. */
.candidature__champ .dashboard-lien-copie .dashboard-lien-copie__champ {
    flex: 1 1 0;
}

/* Dans l'en-tete, le champ vit hors d'une fiche : il lui faut sa propre
   respiration et une largeur qui ne s'etale pas sur toute la banniere. */
.candidature__champ--entete {
    max-width: 620px;
    margin-top: 16px;
}

.candidature__champ--entete label {
    font-weight: 700;
    color: var(--ink-100, rgba(var(--ink-200-rgb), 0.95));
}

/*
 * LE FILTRE ACTIF SE DISTINGUE DES AUTRES.
 *
 * Actif et inactif differaient de 1,19 pour 1 en contraste (#334155 contre
 * #3a4e58) et de rien d'autre : on ne pouvait pas dire quel filtre on
 * regardait, et la liste semblait donc parfois incomplete sans raison.
 *
 * Un fond marque, un liseré, et le texte a pleine clarte : trois signes
 * plutot qu'un seul, pour que ca tienne aussi quand l'ecran est mal regle.
 */
.admin-dashboard .btn.btn-primary,
.card .btn.btn-primary {
    box-shadow: inset 0 0 0 1px rgba(var(--blue-rgb), 0.55);
}

.candidature__pied {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 14px;
}

@media (max-width: 760px) {
    .candidature__champs {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* =========================================================================
   LE CODE D'INVITATION, SEUL.

   La grille portait DEUX parts : le lien d'inscription praticien et le code.
   Deux champs a copier pour un seul identifiant faisaient hesiter sur lequel
   envoyer, et l'adresse ne disait rien de plus que le code qu'elle traine au
   bout. Le lien est parti ; la seconde colonne resterait vide.

   Le code garde la largeur de son libelle, pas celle de la carte : onze
   caracteres etales sur toute la largeur promettent une saisie qu'on n'attend
   pas. Le champ retombe a `auto` sous 900 px, plus bas dans cette feuille.
   ========================================================================= */
.dashboard-invitation {
    display: grid;
    grid-template-columns: minmax(0, auto);
    justify-content: start;
    gap: 12px 16px;
    align-items: start;
    margin-top: 4px;
}

.dashboard-invitation__part {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

/* Le code prend la largeur de sa colonne, qui est calee sur son contenu : un
   champ ajuste au caractere pres a l'air d'un afficheur, pas d'une valeur
   qu'on selectionne et qu'on copie. */
.dashboard-invitation__part--code {
    width: 44ch;
}

/*
 * LE BOUTON SOUS SON CHAMP, TOUJOURS.
 *
 * A cote, il prenait sa part de la largeur, et le champ changeait de taille
 * selon la longueur de l'intitule et selon la place restante : le lien tenait
 * a une largeur, se coupait a une autre, et le bouton descendait parfois.
 * Le champ prend la largeur de sa colonne, le bouton garde la sienne : un
 * bouton large comme un champ se lit comme une barre, et on ne sait plus ou
 * cliquer.
 */
.dashboard-invitation .dashboard-lien-copie {
    margin-top: 0;
}

/* Le libelle du code se lit sur la meme ligne que celui du lien : sans cette
   hauteur commune, un libelle qui passe a deux lignes decalerait son champ. */
.dashboard-invitation .dashboard-card__subtitle {
    margin: 0;
}

/*
 * SOUS 420 px, MEME TOUTE LA LARGEUR NE SUFFIT PLUS.
 *
 * A 375 px, le champ recoit 297 px et l'adresse en demande 338 : elle se coupe
 * quoi qu'on fasse de la mise en page. Deux points de police en moins la
 * ramenent a 293 px, donc lisible en entier, et c'est le seul endroit du
 * produit ou l'on descend sous la taille de saisie courante. On l'accepte ici
 * parce qu'on ne saisit pas dans ce champ : on le lit et on le copie.
 */
@media (max-width: 420px) {
    .dashboard-lien-copie .dashboard-lien-copie__champ {
        font-size: 13px;
    }
}

@media (max-width: 900px) {
    .dashboard-invitation {
        grid-template-columns: minmax(0, 1fr);
    }

    .dashboard-invitation__part--code {
        width: auto;
    }
}

/* ======================================================================
   QUI PEUT QUOI
   ======================================================================
   Une fiche par praticien, ses droits en grille. Trois etats a distinguer d'un
   coup d'oeil, et pas deux : ouvert, ferme, et SUSPENDU, c'est-a-dire accorde
   un jour mais sans effet aujourd'hui faute d'abonnement. Confondre les deux
   derniers ferait chercher la panne au mauvais endroit.
   ====================================================================== */

/*
 * UNE LIGNE PAR PERSONNE, DEPLIEE A LA DEMANDE.
 *
 * Le premier jet montrait les dix droits de chacun, tout le temps : lisible a
 * trois praticiens, un mur a cinquante, alors qu'on vient ici quelques fois
 * pour accorder UN droit a UNE personne.
 */
/*
 * LA MEME FACTURE QUE LES AUTRES LISTES DU PRODUIT.
 *
 * Des cartes detachees, avec un rail de couleur a gauche qui porte le type de
 * compte : l'or pour un administrateur, le violet pour un praticien. Ce sont
 * les teintes de `liste-carte`, pas des valeurs posees ici, pour qu'une liste
 * ne se lise pas autrement qu'une autre.
 */
.capacites-liste {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.capacites-ligne {
    box-sizing: border-box;
    border: 1px solid rgba(var(--row-rgb, var(--teinte-bleue)), 0.14);
    border-left: 4px solid rgba(var(--row-rgb, var(--teinte-bleue)), 0.76);
    border-radius: var(--rayon-l, 14px);
    background: rgba(var(--row-rgb, var(--teinte-bleue)), 0.09);
}

/* Ouverte, la carte s'affirme : on sait laquelle on manipule quand la page a
   defile et que le resume est sorti de l'ecran. */
.capacites-ligne[open] {
    border-color: rgba(var(--row-rgb, var(--teinte-bleue)), 0.34);
    background: rgba(var(--row-rgb, var(--teinte-bleue)), 0.15);
}

/* La fleche du navigateur est remplacee par la notre, qui tourne. */
.capacites-ligne > summary {
    list-style: none;
}

.capacites-ligne > summary::-webkit-details-marker {
    display: none;
}

.capacites-ligne__resume {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 16px;
    padding: 14px 18px;
    cursor: pointer;
    border-radius: var(--rayon-l, 14px);
}

.capacites-ligne__resume:hover {
    background: rgba(var(--row-rgb, var(--teinte-bleue)), 0.10);
}

/* Le clavier doit voir ou il est : c'est le resume qui recoit le focus. */
.capacites-ligne > summary:focus-visible {
    outline: 2px solid rgba(var(--portal-accent-rgb), 0.8);
    outline-offset: 2px;
}

.capacites-ligne__identite {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
    flex: 1 1 240px;
}

.capacites-ligne__nom {
    font-weight: 600;
    overflow-wrap: anywhere;
}

/* UNE ADRESSE NE SE COUPE PAS AU MILIEU D UN CARACTERE.

   RELEVE PAR L ADMIN, capture a l appui : « praticien@strannik.tes » sur une
   ligne, « t » tout seul sur la suivante. C est `overflow-wrap: anywhere` qui
   fait exactement ce qu il dit -- couper N IMPORTE OU -- et le resultat se
   lit comme une panne.

   POURQUOI L ELLIPSE PLUTOT QU UNE COUPURE PROPRE. On est dans une LISTE, ou
   la regularite des lignes vaut autant que leur contenu : une adresse qui
   passe a la ligne fait varier la hauteur de chaque carte, et la liste se met
   a onduler. Ici l adresse est un APPOINT -- c est le nom qui identifie le
   praticien --, donc elle peut ceder la place tant qu elle reste atteignable.

   ET ELLE LE RESTE : le gabarit pose l adresse entiere en `title`, donc elle
   s affiche au survol et se copie a la selection. Tronquee a l oeil,
   complete a la main.

   `anywhere` RESTE SUR LE NOM, juste au-dessus, et c est voulu : un nom long
   DOIT passer a la ligne plutot que disparaitre, puisque c est lui qu on lit
   pour reconnaitre la personne. Les deux lignes n ont pas le meme role, elles
   n ont pas la meme regle. */
.capacites-ligne__mail {
    font-size: 13px;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.capacites-ligne__compte {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
    font-size: 13px;
}

.capacites-ligne__chiffre {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.capacites-ligne__suspendues {
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 12px;
    color: var(--ink-50);
    background: rgba(var(--amber-rgb), 0.16);
    border: 1px solid rgba(var(--amber-rgb), 0.45);
}

.capacites-ligne__chevron {
    display: inline-flex;
    flex: none;
    width: 18px;
    height: 18px;
    opacity: .6;
    transition: transform .16s ease;
}

.capacites-ligne[open] .capacites-ligne__chevron {
    transform: rotate(180deg);
}

.capacites-ligne[open] .capacites-grille {
    margin: 4px 18px 18px;
}

@media (prefers-reduced-motion: reduce) {
    .capacites-ligne__chevron {
        transition: none;
    }
}

.capacites-pastille--admin {
    padding: 4px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    color: var(--ink-50);
    background: rgba(var(--blue-rgb), 0.22);
    border: 1px solid rgba(var(--blue-rgb), 0.45);
}

.capacites-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 230px), 1fr));
    gap: 12px;
}

.capacites-case {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    padding: 14px;
    border-radius: 12px;
    border: 1px solid rgba(var(--slate-light-rgb), 0.22);
    background: rgba(var(--slate-light-rgb), 0.05);
}

/* Le liseré porte l'etat, pas seulement la couleur du texte : sur un ecran mal
   regle, une nuance de gris ne se lit pas, un bord si. */
.capacites-case.is-ouverte {
    border-color: rgba(var(--share-bright-rgb), 0.5);
    background: rgba(var(--share-bright-rgb), 0.08);
}

.capacites-case.is-suspendue {
    border-color: rgba(var(--amber-rgb), 0.55);
    background: rgba(var(--amber-rgb), 0.10);
}

.capacites-case__nom {
    font-weight: 600;
}

.capacites-case__etat {
    font-size: 13px;
    font-weight: 600;
    opacity: .9;
}

.capacites-case__source,
.capacites-case__echeance,
.capacites-case__raison {
    font-size: 12px;
    opacity: .72;
    overflow-wrap: anywhere;
}

/* Le geste se pose en bas, aligne d'une case a l'autre quel que soit le nombre
   de lignes de detail au-dessus. */
.capacites-case__geste {
    margin: 10px 0 0;
    display: flex;
}

.capacites-case__geste .btn {
    width: 100%;
    min-height: 40px;
}

/*
 * REPRENDRE NE CRIE PAS, MAIS SE VOIT.
 *
 * Le bouton rouge plein est juste pour un geste isole. Ici il y en a un par
 * droit ouvert, soit neuf sur une seule fiche : la grille devenait un mur
 * rouge sur un ecran qu'on vient d'abord LIRE, et le rouge ne distinguait plus
 * rien puisqu'il etait partout.
 *
 * Il garde sa couleur, en contour : on le reconnait, il ne domine plus. La
 * modale de confirmation, elle, reste rouge plein, la ou la question se pose
 * vraiment et ou il n'y a qu'un bouton.
 */
/* Un voile de sa teinte derriere le contour : voir `.bouton-programme--creux`,
   meme raison. Il etait le seul autre bouton du produit a n'avoir rien. */
.capacites-case__geste .btn-danger {
    background: rgba(var(--red-rgb), 0.12);
    border: 1px solid rgba(var(--red-rgb), 0.55);
    color: var(--couleur-danger-doux);
}

.capacites-case__geste .btn-danger:hover {
    background: rgba(var(--red-rgb), 0.22);
    border-color: rgba(var(--red-rgb), 0.85);
}

.capacites-fiche + .capacites-fiche {
    margin-top: 0;
}

/* ----------------------------------------------------------------------
   LES FAMILLES DE CAPACITES.

   Elles etaient douze d'affilee, dont quatre pour le seul espace business :
   on ne savait plus ou regarder. Un titre discret et un espace entre les
   groupes suffisent -- un cadre par famille aurait fait une boite dans une
   boite dans une carte, trois niveaux pour dire deux choses.
   ---------------------------------------------------------------------- */
.capacites-famille + .capacites-famille {
    margin-top: 18px;
}

.capacites-famille__nom {
    margin: 0 0 8px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    opacity: .66;
}

/* ======================================================================
   L ACCES AUX PAGES DU PRESENTIEL
   ======================================================================
   La LISTE emprunte sa facture a l'ecran des capacites (`capacites-ligne`) :
   meme forme, des praticiens qu'on deplie. Le CORPS, lui, a ses propres
   classes, et c'est une correction. Le premier jet reprenait aussi
   `capacites-case__geste`, qui est un conteneur a UN bouton : il portait
   l'interrupteur du mode, puis la rangee des modeles, et les deux sortaient de
   travers. Emprunter une classe pour ce qu'elle FAIT, pas pour ce qu'elle veut
   dire, se paie a la premiere mise en page.

   TROIS RANGS, ET ILS SE LISENT DANS CET ORDRE : l'acces au mode, les huit
   pages, les gestes. C'est l'ordre de la decision -- on n'ouvre pas une page a
   quelqu'un qui n'entre pas.
   ====================================================================== */

.acces-corps {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 4px 18px 18px;
}

.acces-note {
    margin: 0;
    font-size: 13px;
    opacity: .78;
}

/* ----------------------------------------------------------------------
   L INTERRUPTEUR DU MODE : une bande, pas une case parmi les autres.

   Il ne decide pas la meme chose que les huit cases dessous -- il decide si
   le praticien ENTRE. Le mettre en bande au-dessus rend cet ordre visible
   sans l'ecrire ; aligne avec les pages, il se lirait comme une neuvieme.
   ---------------------------------------------------------------------- */
/* LES TROIS POSITIONS DE L'ACCES AU MODE, empilees et espacees.
   Chaque position est une `.acces-interrupteur`, qui est elle-meme une boite
   flex : sans ce conteneur elles se toucheraient, et trois bandes collees se
   lisent comme une seule. */
.acces-positions {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.acces-interrupteur {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 14px;
    border-radius: 12px;
    border: 1px solid rgba(var(--slate-light-rgb), 0.22);
    background: rgba(var(--slate-light-rgb), 0.05);
    cursor: pointer;
    transition: border-color .16s, background .16s;
}

.acces-interrupteur.is-ouvert {
    border-color: rgba(var(--share-bright-rgb), 0.5);
    background: rgba(var(--share-bright-rgb), 0.08);
}

.acces-interrupteur:hover {
    border-color: rgba(var(--portal-accent-rgb), 0.55);
}

/* Le clavier doit voir ou il est : c'est l'input qui recoit le focus, et le
   contour se pose sur la bande entiere. */
.acces-interrupteur:focus-within {
    outline: 2px solid rgba(var(--portal-accent-rgb), 0.8);
    outline-offset: 2px;
}

.acces-interrupteur__texte {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.acces-interrupteur__titre {
    font-weight: 600;
}

.acces-interrupteur__note {
    font-size: 13px;
    line-height: 1.45;
    opacity: .72;
}

/* ----------------------------------------------------------------------
   LES HUIT PAGES.

   `auto-fill` avec un minimum de 230 px : quatre colonnes au bureau, deux sur
   une tablette, une sur un telephone, sans palier ecrit. Le `min(100%, ...)`
   evite la seule facon dont cette formule deborde -- une piste plus large que
   son conteneur quand il est plus etroit que le minimum.
   ---------------------------------------------------------------------- */
.acces-pages {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 230px), 1fr));
    gap: 12px;
    margin: 0;
}

/* Dans un modele, il n'y a que les noms : les cases tiennent a moins. */
.acces-pages--serree {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 190px), 1fr));
}

.acces-page {
    display: flex;
    flex-direction: column;
    gap: 7px;
    min-width: 0;
    padding: 13px 14px;
    border-radius: 12px;
    border: 1px solid rgba(var(--slate-light-rgb), 0.22);
    background: rgba(var(--slate-light-rgb), 0.05);
    cursor: pointer;
    transition: border-color .16s, background .16s;
}

/* Le lisere porte l'etat, pas seulement la couleur du texte : sur un ecran mal
   regle, une nuance de gris ne se lit pas, un bord si. Meme regle que sur
   l'ecran des capacites. */
.acces-page.is-ouverte {
    border-color: rgba(var(--share-bright-rgb), 0.5);
    background: rgba(var(--share-bright-rgb), 0.08);
}

.acces-page:hover {
    border-color: rgba(var(--portal-accent-rgb), 0.55);
}

.acces-page:focus-within {
    outline: 2px solid rgba(var(--portal-accent-rgb), 0.8);
    outline-offset: 2px;
}

.acces-page__tete {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.acces-page__nom {
    font-weight: 600;
    overflow-wrap: anywhere;
}

.acces-page__note {
    font-size: 12px;
    line-height: 1.45;
    opacity: .72;
}

/* ----------------------------------------------------------------------
   LA BARRE DES GESTES.

   Elle est HORS du formulaire, son bouton d'envoi le visant par `form=` : les
   modeles et le retrait sont des formulaires voisins, et un formulaire
   imbrique dans un autre est retire du document par l'analyseur HTML -- son
   bouton n'enverrait rien. Chaque formulaire est donc un element de la rangee.
   ---------------------------------------------------------------------- */
.acces-barre {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

.acces-barre > form {
    margin: 0;
}

.acces-barre__etiquette {
    font-size: 13px;
    opacity: .72;
    margin-inline-start: 6px;
}

/* Le retrait du reglage s'eloigne des autres : ce n'est pas un geste du meme
   rang, et le coller au dernier modele le ferait prendre pour un troisieme. */
.acces-barre__fin {
    margin-inline-start: auto;
}

.acces-barre .btn {
    min-height: 38px;
}

/* ----------------------------------------------------------------------
   LES MODELES, en bas de page.
   ---------------------------------------------------------------------- */
.acces-modele {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px 0;
    border-top: 1px solid rgba(var(--slate-light-rgb), 0.18);
}

.acces-modele--neuf {
    border-top-style: dashed;
}

.acces-modele h3 {
    margin: 0 0 12px;
}

.acces-champ {
    display: flex;
    flex-direction: column;
    gap: 5px;
    max-width: 340px;
}

.acces-champ__etiquette {
    font-size: 13px;
    opacity: .72;
}

/* ----------------------------------------------------------------------
   AU TELEPHONE.

   La grille se replie seule. Ce qui ne se replie pas seul, c'est le geste
   pousse a droite : sur une rangee qui a deja passe a la ligne, `auto` le
   laisse seul au bout d'une ligne vide. On le remet dans le flux.
   ---------------------------------------------------------------------- */
@media (max-width: 640px) {
    .acces-corps {
        padding: 4px 12px 14px;
        gap: 12px;
    }

    .acces-barre__fin {
        margin-inline-start: 0;
    }

    .acces-barre__etiquette {
        margin-inline-start: 0;
        flex-basis: 100%;
    }

    .acces-champ {
        max-width: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .acces-interrupteur,
    .acces-page {
        transition: none;
    }
}

/* ======================================================================
   LA BOUTIQUE PRATICIEN
   ======================================================================
   Une carte par lot. Le prix et la duree se lisent d'un bloc, a droite du nom,
   parce que ce sont les deux choses qu'on compare entre deux lots. La liste
   des capacites vient dessous : c'est ce qu'on achete, et une etiquette ne le
   dit pas.
   ====================================================================== */

/* LA GRILLE DES LOTS.

   Les memes pistes que les lots de credits juste au-dessus : a 1206 px, quatre
   colonnes de 289 px, et la page se lit en trois rayons de tuiles au lieu de
   deux rayons et une bande.

   `auto-fill` GARDE LES PISTES VIDES. C'est tout l'interet ici : un seul lot
   au catalogue -- l'etat d'aujourd'hui -- occupe une piste et non la page.
   `auto-fit`, qui replie les pistes vides, rendrait exactement le defaut
   corrige. */
.boutique-lots {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
    align-items: start;
}

.boutique-lot__tete {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px 20px;
}

.boutique-lot__identite {
    min-width: 0;
    flex: 1 1 260px;
}

.boutique-lot__nom {
    margin: 0;
    font-size: 20px;
}

.boutique-lot__description {
    margin: 4px 0 0;
    overflow-wrap: anywhere;
}

/* DANS UNE TUILE, LE PRIX EST SOUS LE NOM, A GAUCHE.

   Il etait cale a droite parce que la carte faisait la page : le nom d'un cote,
   le prix de l'autre, et on comparait deux lots d'un coup d'oeil. A 289 px il
   passe a la ligne, et colle a droite il se lisait comme s'il appartenait a la
   ligne suivante -- c'est le defaut que la requete `max-width: 560px` corrigeait
   deja pour les petits ecrans. Ce n'est pas la fenetre qui le cause, c'est la
   largeur de la CARTE : la regle suit donc la grille, pas le seuil. */
.boutique-lots .boutique-lot__prix {
    align-items: flex-start;
}

/* Le prix ne se coupe pas en deux lignes au milieu d'un nombre. */
.boutique-lot__prix {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    font-size: 20px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.boutique-lot__duree {
    font-size: 13px;
    font-weight: 500;
    opacity: .72;
}

.boutique-lot__capacites {
    margin: 16px 0 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.boutique-lot__capacites li {
    padding: 5px 12px;
    border-radius: 999px;
    font-size: 13px;
    border: 1px solid rgba(var(--slate-light-rgb), 0.28);
    background: rgba(var(--slate-light-rgb), 0.07);
}

.boutique-lot__geste {
    margin-top: 18px;
}

.boutique-lot__geste .btn {
    min-height: 44px;
}

/* Un lot deja ouvert ne propose plus rien : il le dit, et se distingue au
   liseré pour qu'on ne le relise pas a chaque passage. */
.boutique-lot.is-ouvert {
    border: 1px solid rgba(var(--share-bright-rgb), 0.45);
}

.boutique-lot__possede {
    font-weight: 600;
    color: var(--couleur-succes-doux);
}

@media (max-width: 560px) {
    /* Le prix repasse a gauche : colle a droite sous le nom, il se lisait
       comme s'il appartenait a la ligne suivante. */
    .boutique-lot__prix {
        align-items: flex-start;
    }

    .boutique-lot__geste .btn {
        width: 100%;
    }
}

/* Un lot que seul l Admin voit : la marque le dit, discrete mais lisible. */
.boutique-lot__ferme {
    align-self: flex-start;
    padding: 4px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    color: var(--ink-50);
    background: rgba(var(--amber-rgb), 0.16);
    border: 1px solid rgba(var(--amber-rgb), 0.45);
}

/* --- Un prereglage se deplie ------------------------------------------
   Ils etaient tous deroules, cinq champs chacun, pour des valeurs qu'on
   regarde une fois par an. Le resume suffit a s'y retrouver. */
.processing-preset--depliable > summary {
    list-style: none;
    cursor: pointer;
}

.processing-preset--depliable > summary::-webkit-details-marker {
    display: none;
}

.processing-preset--depliable > summary:focus-visible {
    outline: 2px solid rgba(var(--portal-accent-rgb), 0.8);
    outline-offset: 2px;
    border-radius: 10px;
}

.processing-preset__chevron {
    display: inline-flex;
    flex: none;
    width: 18px;
    height: 18px;
    opacity: .6;
    transition: transform .16s ease;
}

.processing-preset--depliable[open] .processing-preset__chevron {
    transform: rotate(180deg);
}

.processing-preset--depliable[open] .processing-preset__grid {
    margin-top: 14px;
}

@media (prefers-reduced-motion: reduce) {
    .processing-preset__chevron {
        transition: none;
    }
}

/* ===== Le catalogue de la boutique client =====

   Meme grammaire que la liste des capacites : une ligne par element, depliee
   a la demande, une seule ouverte a la fois. On vient ici regler UN produit,
   pas comparer le catalogue entier. */

.catalogue-base {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 16px;
    margin-top: 14px;
}

.catalogue-base .champ {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 180px;
}

/* Le cout de traitement se lit A COTE du prix, pas ailleurs sur la page :
   fixer un prix sans voir ce qu'il couvre, c'est fixer un prix a l'aveugle. */
.catalogue-cout {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 8px 14px;
    border-radius: 10px;
    border: 1px solid rgba(var(--white-rgb), 0.12);
    background: rgba(var(--white-rgb), 0.04);
    font-variant-numeric: tabular-nums;
}

.catalogue-cout__titre {
    font-size: 0.76rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    opacity: .66;
}

.catalogue-cout__valeur {
    font-size: 0.9rem;
    font-weight: 600;
}

.catalogue-cout__marge {
    font-size: 0.84rem;
    color: rgba(var(--share-bright-rgb), 0.95);
}

/* Une marge negative, c'est vendre a perte. Elle ne se murmure pas. */
.catalogue-cout__marge--negative {
    color: rgb(var(--red-light-rgb));
    font-weight: 700;
}

.catalogue-avertissement {
    margin: 10px 0 0;
    padding: 10px 14px;
    border-radius: 10px;
    border-left: 3px solid rgba(var(--amber-rgb), 0.7);
    background: rgba(var(--amber-rgb), 0.09);
    font-size: 0.88rem;
}

.catalogue-liste {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 14px;
}

.catalogue-ligne {
    border-radius: 12px;
    border: 1px solid rgba(var(--white-rgb), 0.10);
    border-left: 3px solid rgba(var(--row-rgb, var(--slate-light-rgb)), 0.75);
    background: rgba(var(--row-rgb, var(--slate-light-rgb)), 0.06);
    overflow: hidden;
}

.catalogue-ligne__resume {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 16px;
    cursor: pointer;

    /* Le triangle natif se place mal dans une boite en `flex` : un chevron
       qui pivote dit la meme chose et suit l'etat ouvert. */
    list-style: none;
}

.catalogue-ligne__resume::-webkit-details-marker { display: none; }

.catalogue-ligne__resume::after {
    content: "▾";
    color: rgba(var(--white-rgb), var(--voile-mention, 0.62));
    font-size: 12px;
    transition: transform .18s ease;
    flex: 0 0 auto;
}

.catalogue-ligne[open] > .catalogue-ligne__resume::after {
    transform: rotate(180deg);
}

.catalogue-ligne__nom {
    font-weight: 600;
    min-width: 0;
    overflow-wrap: anywhere;
}

.catalogue-ligne__code {
    margin-left: 8px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.78rem;
    font-weight: 400;
}

.catalogue-ligne__etat {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
    margin-right: 8px;
}

.catalogue-ligne__prix {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.catalogue-formulaire {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 4px 16px 18px;
}

.catalogue-formulaire__rangee {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 12px 16px;
}

.catalogue-formulaire .champ {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.catalogue-formulaire .champ input,
.catalogue-formulaire .champ select,
.catalogue-formulaire .champ textarea {
    width: 100%;
    box-sizing: border-box;
}

.catalogue-pages,
.catalogue-langue {
    margin: 0;
    padding: 12px 14px;
    border: 1px solid rgba(var(--white-rgb), 0.10);
    border-radius: 10px;
}

.catalogue-pages legend,
.catalogue-langue legend {
    padding: 0 6px;
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    opacity: .7;
}

.catalogue-langue {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.catalogue-pages__case {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 0;
    cursor: pointer;
}

.catalogue-pages__case input[type="checkbox"] {
    width: 18px;
    height: 18px;
    margin: 0;
    accent-color: var(--couleur-accent);
    flex: 0 0 auto;
}

/* La ligne de creation se distingue de celles qui modifient l'existant. */
.catalogue-ligne--nouveau {
    border-style: dashed;
}

/* Deux portes cote a cote sous les interrupteurs : voir la boutique praticien,
   regler le catalogue client. Empilees, elles s'etiraient chacune sur toute la
   largeur du bloc de reglage. */
.reglage-boutique__portes {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

/* ===== L'etat de l'agent de traitement =====

   Une PRESENCE CONSTATEE, pas une disponibilite : le pont est a sens unique,
   on ne peut pas lui demander s'il va bien, seulement voir qu'il est passe. */

/* La ligne du pont dit un ETAT, les chiffres au-dessus comptent des choses a
   faire. Le filet et l'air qui les separent disent cette difference de
   nature, que rien d'autre ne signale. */
.dashboard-pont {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;

    /* UN SEUL RACCOURCI, et il vient en dernier : un `margin-top` pose plus
       haut se faisait effacer par le `margin` qui suivait, et la ligne
       restait collee a ce qui la precede. */
    margin: 14px 0 0;
    font-size: 0.88rem;
}

.dashboard-pont__pastille {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex: 0 0 auto;
}

.dashboard-pont--ok .dashboard-pont__pastille {
    background: rgb(var(--share-bright-rgb));

    /* Un halo doux : le point seul se perd dans une carte chargee, et c'est
       le premier signe qu'on vient chercher. */
    box-shadow: 0 0 0 3px rgba(var(--share-bright-rgb), 0.18);
}

.dashboard-pont--ok {
    color: rgba(var(--white-rgb), 0.78);
}

.dashboard-pont--muet .dashboard-pont__pastille {
    background: rgb(var(--amber-rgb));
    box-shadow: 0 0 0 3px rgba(var(--amber-rgb), 0.18);
}

.dashboard-pont--muet {
    color: rgba(var(--amber-rgb), 0.95);
}

/* Le nombre de tests qui attendent : il ne s'affiche que s'il y en a, et c'est
   lui qui fait la difference entre un silence banal et un silence qui coute.

   ELLE TIENT SEULE DEPUIS LE 02/09. Elle vivait dans la ligne d'etat du
   pont, qui a ete retiree : sans le `display` ci-dessous, un paragraphe
   s'etire sur toute la largeur et la pastille devient une barre. */
.dashboard-pont__file {
    display: inline-block;
    margin: 14px 0 0;
    padding: 2px 9px;
    border-radius: 999px;
    border: 1px solid currentColor;
    font-size: 0.78rem;
    opacity: .9;
}

/* ======================================================================
   LE SOLDE DE TRAITEMENT, SUR LA FICHE D'UN COMPTE
   ======================================================================
   Ces classes etaient posees dans le gabarit et traduites nulle part : la
   carte rendait « 100 Solde » en deux morceaux de texte brut, sans le
   moindre style. Le nombre est ce qu'on vient lire, il porte donc le poids ;
   la phrase autour reste discrete.
   ====================================================================== */
/* --- L ECOLE DE FORMATION, SUR LA FICHE D UN COMPTE ---------------------- */

/* Un champ et un bouton : ils tiennent sur une ligne au large et s'empilent au
   serre, sans largeur imposee qui deborderait. */
.admin-ecole__form {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px;
}

.admin-ecole__champ {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1 1 180px;
    min-width: 0;
}

.admin-ecole__champ > span {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--texte-discret);
}

.admin-ecole__champ input {
    width: 100%;
    min-width: 0;
}

.admin-ecole__etat {
    margin: 14px 0 10px;
    color: var(--texte-discret);
}

.admin-users-credits__aide {
    margin: 0 0 14px;
    color: var(--texte-discret);
}

.admin-users-credits__etat {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 10px;
    margin: 0 0 14px;
    padding: 10px 14px;
    border-radius: 12px;
    border: 1px solid rgba(var(--portal-accent-rgb), 0.22);
    background: rgba(var(--portal-accent-rgb), 0.07);
    /*
     * PAS `--texte-fort` ICI. Ce nom de role vaut #111827, l'encre du PORTAIL
     * CLAIR. Pose sur une carte sombre, il donnait du noir sur bleu nuit :
     * 1,4 de rapport, illisible. Quand le role contredit la surface, on
     * descend sur l'echelle neutre, celle que prend deja le titre de la carte.
     */
    color: var(--ink-200);
    font-weight: 600;
    /* Les chiffres s'alignent d'une fiche a l'autre. */
    font-variant-numeric: tabular-nums;
}

/* La reserve est une precision, pas le solde : elle ne rivalise pas avec lui. */
.admin-users-credits__reserve {
    color: var(--texte-discret);
    font-weight: 400;
}

/* ======================================================================
   LA PAGE DES PROGRAMMES D'UN CLIENT
   ======================================================================
   Elle n'avait aucune feuille a elle : le navigateur rendait des boutons
   bleus, verts et rouges par defaut, un champ de fichier natif, et sept
   lignes de « Libelle: valeur » par programme.

   La couleur suit la regle du produit : l'or appartient aux programmes,
   le rouge a ce qui est irreversible, et rien d'autre n'est peint.
   ====================================================================== */

.programmes-tete h1 {
    margin: 6px 0 2px;
}

.programmes-tete__mail {
    margin: 0;
    color: var(--texte-discret);
}

/* Un lien, pas un second bouton de retour empile sous le premier. */
.programmes-tete__lien {
    display: inline-block;
    margin-top: 12px;
    color: var(--texte-discret);
    text-decoration: none;
    border-bottom: 1px solid rgba(var(--white-rgb), 0.18);
    padding-bottom: 1px;
}

.programmes-tete__lien:hover {
    color: var(--ink-200);
    border-bottom-color: rgba(var(--white-rgb), var(--voile-mention-basse, 0.42));
}

/* ---- La barre d'actions ---- */
.programmes-barre {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px 16px;
}

.programmes-depot {
    display: flex;
    /*
     * `center`, PAS `stretch`. Le jeton anti-rejeu de `@csrf` est un champ
     * cache, et une regle generale des formulaires lui donne une marge basse :
     * en `stretch` il ajoutait huit pixels a la ligne, et le depot se
     * retrouvait quatre pixels plus haut que le bouton d'a cote. On le sort du
     * flux pour de bon, et on centre le reste.
     */
    align-items: center;
    margin: 0;
    /* Le depot est l'action principale : il prend la place qui reste. */
    flex: 1 1 420px;
    min-width: 0;
}

/*
 * LE CHOIX DU FICHIER ET LE DEPOT SONT UN SEUL OBJET.
 *
 * Deux boites accolees : a gauche on choisit, a droite on envoie. Le champ
 * natif est masque mais reste dans le `<label>`, donc tout le bloc gauche est
 * cliquable et le clavier y arrive toujours.
 */
.programmes-fichier {
    /*
     * PAS DE MARGE. C'est un `<label>`, et la regle generale des formulaires
     * leur donne huit pixels sous le menton. Centre dans la ligne, sa boite de
     * marge faisait 54 px quand celle du bouton en faisait 46 : le champ se
     * calait quatre pixels plus haut, et les deux moities du meme objet ne se
     * touchaient plus. Mesure avant : champ 400..446, bouton 404..450.
     */
    margin: 0;
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 12px;
    flex: 1 1 auto;
    min-width: 0;
    height: 46px;
    padding: 0 14px;
    box-sizing: border-box;
    border: 1px solid rgba(var(--white-rgb), 0.12);
    border-right: none;
    border-radius: 12px 0 0 12px;
    background: rgba(var(--ink-900-rgb), 0.36);
    cursor: pointer;
}

.programmes-depot input[type="hidden"] {
    display: none;
}

.programmes-fichier .file-picker__input {
    /* Ni `display: none` ni `visibility` : le champ doit rester focalisable. */
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.programmes-fichier__choisir {
    flex: 0 0 auto;
    color: var(--ink-200);
    font-weight: 600;
    white-space: nowrap;
}

/*
 * LE NOM PREND TOUTE LA PLACE LIBRE.
 *
 * Il portait aussi `therapy-upload-combo__name`, uniquement parce que le
 * script la cherchait -- et cette classe plafonne a 220 px, largeur pensee
 * pour l'ancienne boite etroite. Dans le champ pleine largeur d'aujourd'hui,
 * un nom se coupait a 220 px alors que 535 etaient libres. La classe est
 * retiree du balisage, et le plafond neutralise ici par precaution.
 */
.programmes-fichier__nom {
    flex: 1 1 auto;
    /* `min-width: 0` autorise le retrecissement sous la largeur du texte :
       sans lui, un element flexible refuse de descendre sous son contenu et
       c'est le champ qui deborde au lieu du texte qui se coupe. */
    min-width: 0;
    max-width: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--texte-discret);
    font-size: 14px;
}

.programmes-fichier:focus-within {
    border-color: rgba(var(--teinte-or), 0.55);
}

/*
 * TOUT RETIRER RESTE POSSIBLE, SANS ETRE CE QU'ON VOIT EN PREMIER.
 *
 * C'etait le bouton le plus voyant de la page : un rectangle rouge plein,
 * plus large que celui qui depose un programme. Il devient un lien, il garde
 * sa couleur d'avertissement, et il demande toujours confirmation.
 */
.programmes-barre__retrait {
    margin: 0 0 0 auto;
}

.lien-danger {
    appearance: none;
    border: none;
    background: none;
    padding: 6px 2px;
    color: rgb(var(--red-light-rgb));
    font: inherit;
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-color: rgba(var(--red-rgb), 0.45);
    cursor: pointer;
}

.lien-danger:hover {
    text-decoration-color: rgb(var(--red-light-rgb));
}

.lien-danger:disabled {
    color: var(--texte-discret);
    text-decoration: none;
    cursor: default;
}

/* ---- Le tableau ---- */
.programmes-table td {
    vertical-align: top;
}

/* -------------------------------------------------------------------------
   LA PLACE VA AU TITRE -- ET C EST `lk.css` QUI LA DONNE DESORMAIS
   -------------------------------------------------------------------------
   L'Admin, le 17/10/2026 : « la place va pour le Titre ». La reponse d'alors
   etait `width: 100%` sur la deuxieme colonne, c'est-a-dire « prends tout ce
   qui reste » : les autres se reduisaient a la largeur de leur contenu.

   ELLE DONNAIT TOUT LE MOU A UN SEUL ENDROIT, et c'est le defaut que le lot
   des listes a corrige le 06/11/2026 sur `/users` et `/clients` -- « etendre
   uniquement l'identite jusqu'a [...] une taille donnee, puis repartir ce
   qu'il reste ensuite dans les autres colonnes pour etre harmonieux ». Le
   mecanisme vit dans `lk.css`, qui porte deja `.responsive-table` et qui est
   chargee partout : `.liste-carte thead th.colonne--titre` demande une taille
   a l'identite, `.colonne--actions` en demande une a la rangee de boutons, et
   le tableau repartit le reste entre les colonnes de texte.

   LES DEUX LISTES DE PROGRAMMES DECLARENT DONC LEURS COLONNES, dans leur
   en-tete, comme les trois autres listes du produit. Garder EN PLUS ce
   `width: 100%` ferait deux mecanismes pour un seul partage, et c'est
   l'ancien qui gagnerait.
   ------------------------------------------------------------------------- */

/* LE RANG EST UN REPERE, PAS UNE VALEUR.

   L'ADMIN, LE 08/11/2026 : « la premiere colonne prend beaucoup de place et
   est enorme en taille ». Vingt pixels en gras, soit la taille d'un titre de
   section, pour un chiffre dont le seul role est de dire dans quel ordre les
   programmes se suivent. Il se lisait plus fort que le nom du programme a
   cote, qui est ce qu'on vient chercher.

   IL GARDE SA CHASSE FIXE : c'est elle qui aligne la colonne quand on passe
   de 9 a 10, et elle ne coute rien.

   LA REGLE SERT LES DEUX LISTES DE PROGRAMMES, celle de l'administration et
   celle du praticien, qui partagent ce balisage. Le meme chiffre y etait
   aussi gros, pour la meme raison. */
.programme-emplacement {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--texte-second);
}

.programme-id {
    color: var(--texte-discret);
    font-variant-numeric: tabular-nums;
}

.programme-nom {
    display: block;
    font-weight: 700;
    color: var(--ink-200);
}

.programme-description {
    display: block;
    margin-top: 3px;
    color: var(--texte-discret);
    font-size: 13px;
}

/*
 * DEUX COLONNES, PAS UNE PHRASE PAR LIGNE.
 *
 * « Seances effectuees: 1 » puis « Limite de seances: ∞ » en texte courant
 * mettait le libelle et le chiffre a une place differente a chaque ligne :
 * aucun nombre n'etait comparable a celui du dessous. Ici l'oeil descend une
 * seule colonne de chiffres.
 */
.programme-paires {
    display: grid;
    /* `min-content` ET NON `0` : avec `minmax(0, 1fr)`, la grille accepte de
       descendre jusqu'a rien, et comme ses libelles sont en `nowrap`, ils
       debordaient de leur cellule des que la colonne du titre reclamait la
       place (mesure : « Seances effectuees » par-dessus « Modifier »). En
       refusant de passer sous la largeur de son texte, la grille impose a sa
       colonne une largeur minimale que le titre ne peut plus lui prendre. */
    grid-template-columns: minmax(min-content, 1fr) auto;
    gap: 3px 14px;
    margin: 0;
    font-size: 13px;
}

.programme-paires dt {
    color: var(--texte-discret);

    /* « SEANCES RECOMMANDEES » SUR UNE LIGNE, PAS SUR DEUX.

       La colonne « Utilisation » repliait ses trois libelles, ce qui faisait
       une ligne de tableau haute de trois rangs pour trois nombres. La place
       vient du retrait de la colonne « Type / source », qui portait la meme
       valeur sur toutes les lignes et un nom de fichier tronque illisible.
       L'Admin, le 17/10/2026. */
    white-space: nowrap;
}

.programme-paires dd {
    margin: 0;
    text-align: right;
    color: var(--ink-200);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.programme-eteint {
    display: inline-block;
    margin-top: 8px;
    color: rgb(var(--red-light-rgb));
    font-size: 12px;
    font-weight: 600;
}

.programme-type {
    display: block;
    font-weight: 600;
    color: var(--ink-200);
}

.programme-source {
    display: block;
    margin-top: 3px;
    color: var(--texte-discret);
    font-size: 13px;
}

.programme-lien {
    display: inline-block;
    margin-top: 6px;
    color: rgb(var(--portal-accent-rgb));
    font-size: 13px;
}

/* ---- Les deux actions d'une ligne ---- */
.programme-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

/* UN BOUTON DE LIGNE QUI NE PORTE QU'UN SIGNE. Meme boite, meme filet, meme
   hauteur que ses voisins : seule sa largeur suit son contenu au lieu de son
   libelle, pour qu'un engrenage ne prenne pas la place d'un mot. */
.bouton-ligne--carre {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding-inline: 9px;
}

/* L'ENGRENAGE ET « SUPPRIMER » TIENNENT SUR UNE LIGNE.

   Mesure du 17/10/2026 : 44 px pour l'engrenage, 89 pour « Supprimer », 8
   d'ecart, soit 141 ; la colonne n'en prenait que 89 et les deux s'empilaient,
   ce qui rendait chaque rangee haute de 102 px au lieu de 88.

   145 PLUTOT QUE 180 : la valeur precedente tenait « Modifier » et
   « Supprimer », deux mots. La modification s'est deplacee sur les elements,
   l'engrenage a pris sa place, et garder l'ancienne largeur reprendrait 35 px
   au titre sans rien donner.

   PAS AU TELEPHONE : sous 641 px la table s'empile en cartes, chaque cellule
   prend la largeur entiere, et une largeur minimale y pousserait la page a
   defiler de cote. */
@media (min-width: 641px) {
    .programmes-table .programme-actions {
        min-width: 145px;
    }
}

.programme-actions form {
    margin: 0;
}

/*
 * MODIFIER N'EST PAS BLEU. Le bleu du produit dit « poster, envoyer » ;
 * ouvrir un formulaire d'edition n'envoie rien. Ces deux commandes sont
 * neutres, seule celle qui detruit porte sa couleur.
 */
.bouton-ligne {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 34px;
    padding: 0 14px;
    box-sizing: border-box;
    border: 1px solid rgba(var(--white-rgb), 0.16);
    border-radius: 9px;
    background: rgba(var(--white-rgb), 0.06);
    color: var(--ink-200);
    font: inherit;
    font-size: 13px;
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
    transition: background .14s ease, border-color .14s ease, color .14s ease;
}

.bouton-ligne:hover {
    background: rgba(var(--white-rgb), 0.12);
    border-color: rgba(var(--white-rgb), 0.30);
}

.bouton-ligne--danger {
    border-color: rgba(var(--red-rgb), 0.32);
    /* UNE TEINTE DE DONNEE N EST PAS UNE ENCRE. `--etat-charge` sert a REMPLIR
       une carte d'organe en charge ; pose comme texte il rend 4,15 en sombre et
       2,71 en clair, mesure. Aucun rouge unique ne passe 4,5 des deux cotes :
       il faut le role qui bascule. `--couleur-danger-doux` est ce role, pale
       sur sombre et profond sur clair, et c'est deja lui qui a repare
       `.status.active`. */
    color: var(--couleur-danger-doux);
}

.bouton-ligne--danger:hover {
    background: rgba(var(--red-rgb), 0.14);
    border-color: rgba(var(--red-rgb), 0.55);
}

.bouton-ligne:disabled {
    opacity: .55;
    cursor: default;
}

/* Le lisere de ligne reprend le ton de l'etat, comme sur la liste des comptes. */
.programme-ligne--actif   { --row-rgb: var(--teinte-verte); }
.programme-ligne--attente { --row-rgb: var(--teinte-or); }
.programme-ligne--sans    { --row-rgb: var(--teinte-bleue); }

/* -------------------------------------------------------------------------
   TOUTE LA LIGNE OUVRE LE PROGRAMME
   -------------------------------------------------------------------------
   L'Admin, le 17/10/2026 : « c'est cliquer sur le programme qui le deplie,
   pas juste la petite fleche ». Une cible de douze pixels pour un geste qu'on
   fait a chaque consultation.

   LA CLASSE EST POSEE PAR LE SCRIPT, et seulement sur les lignes qui ONT
   quelque chose a deplier : un programme a un element seul garde le curseur
   ordinaire, parce que le clic n'y ferait rien.
   ------------------------------------------------------------------------- */
.programme-ligne.est-depliante {
    cursor: pointer;
}

/* LE SURVOL EST DEJA PEINT, et pas ici : `.liste-carte__ligne:hover td` monte
   la teinte de 0,09 a 0,15 sur les CELLULES. Une regle posee sur la `<tr>`
   aurait ete recouverte par le fond des cellules sans rien changer a l'ecran.

   Il ne reste donc que la fleche, qui doit suivre le survol de la ligne
   entiere maintenant que la ligne entiere est la cible. */
.programme-ligne.est-depliante:hover .programme-depli {
    opacity: 1;
}

@media (max-width: 900px) {
    .programmes-depot {
        flex: 1 1 100%;
        flex-wrap: wrap;
    }

    .programmes-fichier {
        flex: 1 1 100%;
        border-right: 1px solid rgba(var(--white-rgb), 0.12);
        border-radius: 12px;
    }

    /* `.programmes-barre .bouton-programme` ET PAS `.bouton-programme` NU.

       Cette regle a ete ecrite pour le bouton de depot de la barre des
       programmes, qui passe sur sa propre ligne quand la barre se replie. Nue,
       elle atteignait TOUS les boutons de cette famille sous 900 px -- a
       commencer par le « Copier » du lien d'invitation, qui porte les memes
       classes et vit dans une rangee de deux.

       MESURE DU 16/10/2026 A 726 PX sur le tableau de bord : champ 230 px,
       bouton 428 px. Le bouton prenait presque le double du champ qu'il sert,
       et l'adresse a copier etait coupee a « SO- ». L'Admin l'a vu avant moi. */
    .programmes-barre .bouton-programme {
        flex: 1 1 100%;
        margin-top: 8px;
        border-radius: 12px;
    }

    .programmes-barre__retrait {
        margin-left: 0;
    }
}

/* ======================================================================
   LES TABLEAUX D'EXPLOITATION
   ======================================================================
   `.admin-table` etait posee dans plusieurs vues d'administration (file
   d'attente, fiche d'un compte) et traduite nulle part : le navigateur
   rendait un tableau brut, colonnes collees, sans separation de lignes.
   ====================================================================== */
.admin-table {
    width: 100%;
    /* Separees et non fusionnees : c'est la seule facon pour qu'une entete
       collante peigne son propre fond. Voir la table des operations. */
    border-collapse: separate;
    border-spacing: 0;
    font-size: 14px;
}

.admin-table th {
    padding: 8px 12px;
    text-align: left;
    color: var(--texte-discret);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    border-bottom: 1px solid rgba(var(--white-rgb), 0.12);
    white-space: nowrap;
}

.admin-table td {
    padding: 10px 12px;
    vertical-align: top;
    border-bottom: 1px solid rgba(var(--white-rgb), 0.06);
    color: var(--ink-200);
}

.admin-table tbody tr:last-child td {
    border-bottom: none;
}

.admin-table tbody tr:hover td {
    background: rgba(var(--white-rgb), 0.04);
}

/* ======================================================================
   LA FICHE D'UNE PERSONNE : TOUT CE QUI LA CONCERNE
   ====================================================================== */
.profil-bloc + .profil-bloc {
    margin-top: 18px;
}

.profil-bloc h2 {
    margin: 0 0 4px;
}

.profil-sous-titre {
    margin: 20px 0 8px;
    font-size: 14px;
    color: var(--texte-discret);
    font-weight: 600;
}

/*
 * UNE CARTE VIDE LE DIT, ELLE NE DISPARAIT PAS.
 *
 * Un bloc absent se lit comme un bloc qu'on n'a pas pense a regarder. La
 * phrase, elle, repond a la question posee.
 */
.profil-vide {
    margin: 12px 0 0;
    padding: 14px;
    border-radius: 10px;
    border: 1px dashed rgba(var(--white-rgb), 0.12);
    color: var(--texte-discret);
    text-align: center;
}

.profil-reste {
    margin: 10px 0 0;
    color: var(--texte-discret);
    font-size: 13px;
}

.profil-lien-ecran {
    margin: 14px 0 0;
}

/* Les tableaux d'une fiche peuvent etre larges : ils defilent chez eux, la
   page ne part jamais de travers. */
.profil-tableau {
    margin-top: 12px;
    overflow-x: auto;
}

.profil-table__nombre {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.profil-table__quand {
    color: var(--texte-discret);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/*
 * DISCRET PAR LA COULEUR, PAS PAR LA TAILLE.
 *
 * Le motif d'une operation portait `profil-note` -- une classe de seconde ligne
 * DANS une cellule, avec ses 12 px et son retrait de 2 px en haut. Sur le `td`,
 * ce retrait descendait le texte de deux pixels sous le reste de la rangee, et
 * la taille plus petite lui donnait une autre ligne de base. Une cellule garde
 * la taille de sa table ; seule sa couleur dit qu'elle est secondaire.
 */
.profil-table__discret {
    color: var(--texte-discret);
}

/* Un code technique reste un code : on ne le deguise pas en phrase. */
.profil-operation {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    background: rgba(var(--white-rgb), 0.06);
    border: 1px solid rgba(var(--white-rgb), 0.10);
    color: var(--ink-200);
    font-size: 12px;
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;

    /*
     * LA PASTILLE RENDAIT SA RANGEE DE TRAVERS, et rien dans les regles
     * d'alignement ne le disait. Les cellules sont calees en haut ; la
     * pastille, elle, porte 2 px de remplissage et 1 px de filet AVANT son
     * texte, qui descendait donc de trois pixels sous « #45 » et sous la date
     * de la meme rangee. Le retrait negatif sort la BOITE de la ligne sans
     * bouger le texte, et le remplissage de la cellule l'absorbe.
     */
    margin-block: -3px;
}

.profil-objet {
    display: block;
    color: var(--ink-200);
}

.profil-note {
    display: block;
    margin-top: 2px;
    color: var(--texte-discret);
    font-size: 12px;
}

.profil-note--erreur {
    color: rgb(var(--red-light-rgb));
}

/*
 * LE SIGNE PORTE LA COULEUR. En descendant la colonne, un debit et un credit
 * se distinguent sans lire le chiffre.
 */
.profil-delta {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.profil-delta--plus  { color: var(--green-soft); }
.profil-delta--moins { color: rgb(var(--red-light-rgb)); }

/* ---- La rangee de chiffres en tete de carte ----
 *
 * UNE GRILLE, ET `auto-fill` PLUTOT QUE `auto-fit`. En flex, une tuile qui
 * passe a la ligne suivante est seule a se partager toute la largeur : la
 * quatrieme -- l'etape du parcours -- s'etalait en bande pleine largeur sous
 * trois tuiles alignees. `auto-fit` aurait fait pareil, puisqu'il replie les
 * colonnes vides. `auto-fill` les GARDE : la tuile orpheline reste large d'une
 * colonne, sous la premiere, et les blocs a deux ou trois tuiles ne bougent
 * pas.
 */
.profil-chiffres {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
    gap: 10px;
    margin-top: 14px;
}

.profil-chiffre {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    padding: 12px 14px;
    border-radius: 12px;
    border: 1px solid rgba(var(--white-rgb), 0.08);
    background: rgba(var(--white-rgb), 0.04);
}

.profil-chiffre__valeur {
    font-size: 24px;
    font-weight: 700;
    line-height: 1.1;
    color: var(--ink-200);
    font-variant-numeric: tabular-nums;
}

/* L'etape n'est pas un nombre : elle garde la taille du texte. */
.profil-chiffre__valeur--texte {
    font-size: 14px;
    font-weight: 400;
}

.profil-chiffre__quoi {
    color: var(--texte-discret);
    font-size: 12px;
}

/* Ce qui attend d'etre envoye n'est pas une panne, mais ca se regarde. */
.profil-chiffre--attention {
    border-color: rgba(var(--amber-rgb), 0.35);
    background: rgba(var(--amber-rgb), 0.07);
}


/* ---- Le reseau : des paires ---- */
.profil-paires {
    display: grid;
    grid-template-columns: minmax(0, auto) minmax(0, 1fr);
    gap: 8px 18px;
    margin: 14px 0 0;
}

.profil-paires dt {
    color: var(--texte-discret);
}

.profil-paires dd {
    margin: 0;
    color: var(--ink-200);
}

.profil-liste {
    margin: 8px 0 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 8px;
}

.profil-liste li {
    padding: 8px 12px;
    border-radius: 10px;
    background: rgba(var(--white-rgb), 0.04);
}

@media (max-width: 700px) {
    .profil-paires {
        grid-template-columns: minmax(0, 1fr);
        gap: 2px 0;
    }

    .profil-paires dd {
        margin-bottom: 10px;
    }
}

/* ----------------------------------------------------------------------
   L'HISTORIQUE DES OPERATIONS : CHERCHER ET TOURNER LES PAGES
   ----------------------------------------------------------------------
   La barre de recherche est devenue un formulaire : elle porte le champ, le
   nombre de lignes par page et le bouton, sur une seule ligne.
   ---------------------------------------------------------------------- */
.processing-transactions-search {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    margin: 0;
}

/*
 * LES TROIS COMMANDES ONT LA MEME HAUTEUR ET LA MEME LIGNE.
 *
 * Le champ de recherche portait 16 px de marge basse, herites de la regle
 * generale des champs de formulaire : sa boite faisait 55 px de haut quand le
 * menu et le bouton en faisaient 34. Centres dans la barre, les trois se
 * calaient a trois hauteurs differentes -- champ a 743, les deux autres a 754.
 *
 * On annule la marge et on impose une hauteur commune. Selecteur a deux
 * classes : une classe seule ne l'emporterait pas sur les regles de champ de
 * cette feuille.
 */
.processing-transactions-search .admin-users-panel__search-wrap,
.processing-transactions-search .admin-users-panel__search,
.processing-transactions-search select,
.processing-transactions-search .bouton-ligne {
    margin: 0;
}

.processing-transactions-search .admin-users-panel__search,
.processing-transactions-search select,
.processing-transactions-search .bouton-ligne {
    height: 38px;
    min-height: 38px;
    box-sizing: border-box;
}

/* Le champ garde son rembourrage a droite pour la croix d'effacement. */
.processing-transactions-search .admin-users-panel__search {
    padding-top: 0;
    padding-bottom: 0;
}

.processing-par-page {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    /* C'est un `<label>` : la marge basse generale des formulaires le
       decalerait de quatre pixels par rapport a ses voisins. */
    margin: 0;
    color: var(--texte-discret);
    font-weight: 400;
    white-space: nowrap;
}

.processing-par-page select {
    margin: 0;
    min-height: 34px;
    padding: 0 8px;
}

.processing-pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px 16px;
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid rgba(var(--white-rgb), 0.08);
}

/*
 * COMBIEN ON VOIT, SUR COMBIEN.
 *
 * Sans ce compte, une page pleine ne dit pas s'il en reste, et une recherche
 * ne dit pas ce qu'elle a trouve : deux questions qu'on se pose a chaque fois.
 */
.processing-pagination__compte {
    margin: 0;
    color: var(--texte-discret);
    font-size: 13px;
    font-variant-numeric: tabular-nums;
}

.processing-pagination .table-pagination {
    margin: 0;
}

/* ======================================================================
   LA FICHE D'UN PROGRAMME
   ======================================================================
   Les huit champs etaient empiles sur une colonne pleine page : un champ de
   onze cents pixels pour saisir « 15 ». En grille, les courts se rangent
   par deux ou trois et l'ensemble se voit d'un coup, sans defiler.
   ====================================================================== */
.programme-fiche__tete h1 {
    margin: 6px 0 12px;
}

.programme-fiche__etats {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 12px;
}

/*
 * POUR QUI ON CREE. Sur la fiche d'un programme existant, le nom du client est
 * dans la commande de retour et n'a pas a etre repete. Sur un ecran de
 * CREATION, rien d'autre ne le dit : on fabrique quelque chose pour quelqu'un.
 */
.programme-fiche__pour {
    margin: 6px 0 0;
    color: var(--texte-discret);
}

.programme-fiche__type {
    color: var(--texte-discret);
    font-size: 13px;
}

/* Un nom de fichier ne se lit pas, il se reconnait : il ne merite pas de
   pousser la colonne des valeurs. */
.programme-fiche__fichier {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    font-size: 13px;
}

/* Les paires d'une fiche ont de la place : le libelle ne se serre pas. */
.programme-paires--large {
    grid-template-columns: minmax(0, auto) minmax(0, 1fr);
    gap: 8px 20px;
    font-size: 14px;
}

.programme-paires--large dd {
    text-align: left;
}

/* ---- La grille des champs ---- */
.grille-champs {
    display: grid;
    /*
     * `auto-fit` PLUTOT QU'UN NOMBRE DE COLONNES FIXE : la fiche d'une therapie
     * a un champ de plus que celle d'une video, et le nombre de colonnes doit
     * suivre la largeur disponible, pas le contenu.
     */
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 14px 18px;
    margin-bottom: 18px;
}

.champ {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

/* Ce qui s'ecrit en toutes lettres prend la ligne entiere. */
.champ--large {
    grid-column: 1 / -1;
}

/*
 * LES MARGES DES CHAMPS SONT REPRISES ICI.
 *
 * La regle generale donne huit pixels sous chaque `<label>` et seize sous
 * chaque champ. Dans une grille qui pose deja son propre ecart, ces marges
 * s'ajoutent au lieu de le remplacer : les lignes se decalent les unes par
 * rapport aux autres et rien ne s'aligne plus.
 */
.grille-champs label,
.grille-champs input,
.grille-champs textarea,
.grille-champs select {
    margin: 0;
    width: 100%;
    box-sizing: border-box;
}

.grille-champs label {
    /* `--texte-discret` rend 3,84 a 13 px sur une carte claire (mesure). Ce
       libelle est du texte de formulaire, pas une legende : il prend le meme
       cran que les autres libelles du produit. */
    color: rgba(var(--white-rgb), var(--voile-mention, 0.54));
    font-size: 13px;
    font-weight: 600;
}

.grille-champs textarea {
    min-height: 76px;
    resize: vertical;
}

/* ---- Les deux interrupteurs ---- */
.programme-fiche__bascules {
    display: flex;
    flex-wrap: wrap;
    gap: 10px 14px;
    margin-bottom: 18px;
}

.bascule {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    /* Un `<label>` : sa marge basse generale desalignerait la rangee. */
    margin: 0;
    padding: 10px 14px;
    border-radius: 11px;
    border: 1px solid rgba(var(--white-rgb), 0.10);
    background: rgba(var(--white-rgb), 0.04);
    color: var(--ink-200);
    font-weight: 500;
    cursor: pointer;
}

.bascule input {
    width: auto;
    margin: 0;
}

.bascule:hover {
    border-color: rgba(var(--white-rgb), 0.24);
}

/*
 * CELUI QUI EFFACE PORTE SA COULEUR MEME AU REPOS.
 *
 * « Remettre a zero l'activation » efface l'avancement du client. Pose a cote
 * de « programme disponible » dans la meme boite grise, rien ne disait que
 * l'un est un reglage et l'autre une perte.
 */
.bascule--attention {
    border-color: rgba(var(--amber-rgb), 0.34);
    background: rgba(var(--amber-rgb), 0.07);
    color: var(--amber-pale);
}

.bascule--attention:hover {
    border-color: rgba(var(--amber-rgb), 0.58);
}

/* La carte de suppression se detache de celle qui la precede. */
.programme-fiche .card-danger {
    margin-top: 18px;
}


/* ----------------------------------------------------------------------
   LES DEUX GESTES D'UNE NOTIFICATION
   ----------------------------------------------------------------------
   « Ouvrir » emmene, « Marquer comme lu » range et laisse sur place. Cote a
   cote, et de meme facture : aucun des deux n'est plus important que l'autre,
   ils repondent a deux situations differentes.
   ---------------------------------------------------------------------- */
.notifications-item__actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    flex: 0 0 auto;
}

.notifications-item__actions form {
    margin: 0;
}

/* Le bouton d'export, dans la ligne du fichier de therapie. */
.programme-fiche__export {
    margin-left: 12px;
    vertical-align: middle;
}

@media (max-width: 640px) {
    .notifications-item__actions {
        width: 100%;
    }

    .notifications-item__actions form,
    .notifications-item__actions .bouton-ligne {
        flex: 1 1 auto;
    }
}

/* ======================================================================
   LA LISTE EN CARTES, SUR TELEPHONE : DEUX FUITES DE HAUTEUR
   ======================================================================
   Mesure sur un client du tableau de bord praticien, ecran de 812 px :
   UNE carte occupait 433 px. Moins de deux clients par ecran pour une liste
   qui sert justement a les parcourir.

   LA REQUETE DIT 880 px, ET C'EST LA MESURE CI-DESSUS QUI LE PROUVE : elle a
   ete prise a 812 px, largeur que l'ancienne borne de 640 excluait. Le tableau
   bascule en cartes a 880 (`.responsive-table`, lk.css) ; tout ce qui repare
   cette bascule doit commencer au meme endroit. Entre 641 et 880, les trois
   pastilles d'action heritaient donc du `width: 100%` du tableau generique et
   s'empilaient en trois barres de 740 px portant un emoji seul.
   ====================================================================== */
@media (max-width: 880px) {
    /*
     * 1. LES PASTILLES D'ACTION REPRENNENT LEUR TAILLE.
     *
     * Elles portent `btn` ET `ligne-action`. Sous 640 px, `.btn` impose
     * `width: 100%` : une classe seule ne l'emporte pas sur une autre classe
     * seule, et c'est la derniere ecrite qui gagne. Les trois pastilles de
     * 46 px devenaient donc trois barres de 270, empilees : 170 px pour trois
     * icones qui tiennent sur une ligne.
     *
     * Selecteur a deux classes, donc plus fort, et local a ces pastilles-la.
     */
    .btn.ligne-action {
        width: 46px;
        min-width: 46px;
        flex: 0 0 auto;
    }

    /*
     * ET LEUR RANGEE REDEVIENT UNE RANGEE.
     *
     * `.responsive-table__actions` passe en colonne sous 640 px, ce qui est le
     * bon reglage pour une cellule qui porte des boutons pleine largeur
     * (« Modifier », « Supprimer »). Ce n'est pas le bon pour trois pastilles
     * de 46 px, qui tiennent cote a cote meme sur le plus etroit des ecrans.
     *
     * `:has()` distingue les deux cas sans avoir a marquer le balisage : on ne
     * remet en ligne que les rangees qui portent des pastilles.
     */
    .responsive-table__actions:has(.ligne-action),
    .ligne-actions {
        flex-direction: row;
        flex-wrap: nowrap;
        width: auto;
    }

    /*
     * 2. L'ETIQUETTE SE MET A COTE DE SA VALEUR, PAS AU-DESSUS.
     *
     * Chaque cellule empilee ecrivait son intitule sur une ligne et sa valeur
     * sur la suivante : cinq cellules, dix lignes. En paire sur la meme ligne,
     * l'etiquette a gauche et la valeur a droite, on lit la meme chose en
     * cinq.
     *
     * Le titre garde son traitement : son etiquette reste cachee, il est le
     * titre de la carte.
     */
    .liste-carte tbody tr.liste-carte__ligne > td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 10px 14px;
        flex-wrap: wrap;
    }

    .liste-carte tbody tr.liste-carte__ligne > td .responsive-table__label {
        flex: 0 0 auto;
        margin: 0;
        color: var(--texte-discret);
        font-size: 12px;
        font-weight: 600;
    }

    /* Le titre et le pied restent en bloc : l'un est un titre, l'autre une
       mention de bas de carte. */
    .liste-carte tbody tr.liste-carte__ligne > td.cellule--titre,
    .liste-carte tbody tr.liste-carte__ligne > td.cellule--pied {
        display: block;
    }

    /*
     * LES PASTILLES SE CENTRENT, elles ne se rangent pas a droite.
     *
     * Elles y etaient posees comme les valeurs des autres lignes, par une
     * marge automatique a gauche. Mais une valeur repond a une etiquette et se
     * lit en face d'elle ; ces pastilles n'ont plus d'etiquette en carte, et
     * une rangee de boutons seule, calee dans un coin, se lit comme un reste.
     * Au centre, elle se lit comme la barre de commandes de la carte.
     */
    .liste-carte tbody tr.liste-carte__ligne > td:has(.ligne-actions) .ligne-actions {
        margin-left: auto;
        margin-right: auto;
        justify-content: center;
    }

    /*
     * ET SON ETIQUETTE S'EFFACE, sinon le centre n'est pas le centre.
     *
     * « Actions » restait a gauche et poussait la rangee : les pastilles se
     * centraient dans ce qui restait, a 29 px du milieu de la carte. Ni
     * alignees ni centrees.
     *
     * Elle ne manque a personne : trois pastilles se reconnaissent seules, et
     * la liste des comptes s'en passait deja. Les deux listes cessent au
     * passage de diverger sur la meme rangee de boutons.
     */
    .liste-carte tbody tr.liste-carte__ligne > td:has(.ligne-actions) > .responsive-table__label {
        display: none;
    }
}


/* --- Pas de cadre dans le cadre -------------------------------------------
   -------------------------------------------------------------------------
   Le formulaire des reglages est deja une carte, avec sa bordure et son fond.
   Chaque bloc y posait les siens : deux cadres emboites, et l'oeil compte les
   bordures au lieu de lire les titres.

   On garde le RYTHME sans le cadre : un filet entre les blocs, et rien sur le
   premier. Les blocs depliables gardent le leur, eux : leur bordure dit qu'il
   y a quelque chose a ouvrir. */
.admin-settings-card > .processing-preset:not(.processing-preset--depliable) {
    border: 0;
    background: none;
    border-radius: 0;
    padding: 18px 0 0;
    border-top: 1px solid rgba(var(--white-rgb), 0.08);
}

.admin-settings-card > .processing-preset:not(.processing-preset--depliable):first-of-type {
    border-top: 0;
    padding-top: 0;
}

/* =========================================================================
   LE COUT D'UN TEST, REGLABLE SUR LE TABLEAU DE BORD
   =========================================================================
   Il se reglait dans une ligne du tableau des produits de `/admin/processing`.
   C'est le chiffre le plus consulte du produit, et il fallait savoir ou
   chercher : il est desormais lisible et modifiable sur la carte du
   traitement, qui menait deja a cet ecran.

   UNE SEULE LIGNE, ET ELLE SE REPLIE. Le libelle, le champ et le bouton
   tiennent cote a cote sur une carte double ; sous 560 px le champ passe a la
   ligne plutot que de se reduire a trois caracteres.

   LE CHAMP EST ETROIT A DESSEIN. Un cout tient en trois ou quatre chiffres, et
   un champ large invite a y ecrire autre chose qu'un nombre.
   ========================================================================= */
.dashboard-cout {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid rgba(var(--white-rgb), 0.08);
}

/* LE LIBELLE EST SUR LA MEME LIGNE, DONC IL N A PAS DE MARGE BASSE. Celle
   d'un `<label>` ordinaire vaut 8 px ; comptee dans la boite par
   `align-items: center`, elle posait le mot quatre pixels au-dessus du champ
   qu'il nomme. Mesure au centre des trois boites : 1518,7 contre 1522,7. */
.dashboard-cout .dashboard-cout__libelle {
    margin: 0;
    font-size: 13px;
    font-weight: 600;
    color: rgba(var(--white-rgb), 0.78);
}

/*
 * DEUX CLASSES, PAS UNE -- la meme raison que pour le lien a copier, trois
 * sections plus haut, et le meme prix paye une seconde fois.
 *
 * `.dashboard-cout__champ` pese (0,1,0). Le bloc `input[type="text"], …,
 * input[type="number"], …` de `lk.css` pese (0,1,1) et gagne : il imposait
 * `padding: 12px 14px`, `border-radius: 10px`, `width: 100%` et surtout
 * `margin-bottom: 16px`. Rien de ce qui s'ecrivait ici n'arrivait sur le champ.
 *
 * CE QUE CA DONNAIT A L ECRAN, mesure le 24/09/2026 : champ 45 px de haut
 * contre 37 au bouton, et une marge basse de 16 px que `align-items: center`
 * comptait dans la boite -- le champ se retrouvait huit pixels PLUS HAUT que
 * le bouton qu'il touche. Les deux autres couples du produit
 * (`processing-soldes__form`, `dashboard-lien-copie`) sont a 42/42 et 46/46 :
 * celui-ci etait le seul decale, parce qu'il etait le seul a compter sur son
 * rembourrage pour faire sa hauteur.
 *
 * LA HAUTEUR EST DECLAREE UNE FOIS, sur le conteneur, et les deux commandes la
 * lisent. Un couple qui se lit comme une ligne n'a pas deux hauteurs.
 */
.dashboard-cout {
    --cout-hauteur: 38px;
}

.dashboard-cout .dashboard-cout__champ {
    width: 92px;
    height: var(--cout-hauteur);
    padding: 0 10px;
    margin: 0;
    box-sizing: border-box;
    border-radius: 8px;
    border: 1px solid rgba(var(--white-rgb), 0.18);
    background: rgba(var(--black-rgb), 0.28);
    color: var(--white);
    font-size: 14px;
    font-variant-numeric: tabular-nums;
}

.dashboard-cout .dashboard-cout__champ:focus {
    outline: none;
    border-color: rgba(var(--portal-accent-rgb), 0.65);
}

/* Le meme bouton d'action que partout ailleurs, a la taille d'une ligne de
   reglage : c'est un enregistrement, pas l'action principale de la page.
   `inline-flex` parce que `.btn` est en `inline-block` : sans lui, une hauteur
   declaree ne centre pas le texte, elle le laisse en haut de la boite. */
.dashboard-cout .dashboard-cout__valider {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: var(--cout-hauteur);
    padding: 0 14px;
    font-size: 13px;
}

/* =========================================================================
   LE SENS DE L'OPERATION SE LIT SUR LA PASTILLE
   =========================================================================
   Vert pour ce qui entre, rouge pour ce qui sort, comme la ligne de `/users`
   dit le type de compte par sa teinte.

   LA TEINTE RESTE SUR LA PASTILLE ET SUR LE NOMBRE, jamais sur la ligne. Un
   debit manuel est une ecriture normale et correcte ; une ligne rouge en
   ferait un incident, alors que le rouge annonce ailleurs une erreur sur ces
   ecrans. On donne la lecture d'un coup d'oeil sans faire crier une operation
   banale.

   LE MOT RESTE ECRIT dans la pastille : la couleur double l'information, elle
   ne la remplace pas. C'est la regle de `/users`, et elle vaut pour qui ne lit
   pas les couleurs comme pour qui imprime en noir et blanc.
   ========================================================================= */
.processing-transaction-type--credit {
    background: rgba(var(--green-rgb, 34, 197, 94), 0.14);
    border-color: rgba(var(--green-rgb, 34, 197, 94), 0.34);
    color: #86efac;
}

.processing-transaction-type--debit {
    background: rgba(var(--red-rgb, 239, 68, 68), 0.13);
    border-color: rgba(var(--red-rgb, 239, 68, 68), 0.32);
    color: #fca5a5;
}

/* =========================================================================
   LE MOUVEMENT ET SON RESULTAT SUR UNE SEULE LIGNE
   =========================================================================
   « +100 -> 100 » : ce qui est entre, puis ou en est le compte apres. Deux
   colonnes portaient ces deux nombres ; depuis que la reserve se tait quand
   elle est nulle, chacune n'en portait plus qu'un seul, et ils se lisent
   ensemble.

   LA FLECHE PORTE LE SENS, et elle est masquee aux lecteurs d'ecran : elle
   remplace un libelle, elle n'en ajoute pas un. Les deux nombres se suivent
   dans l'ordre de la lecture, le mouvement puis l'etat.
   ========================================================================= */
.processing-mouvement {
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.processing-mouvement__fleche {
    color: rgba(var(--white-rgb), 0.32);
}

/* L'etat qui suit la fleche n'est pas un mouvement : il ne prend ni le vert ni
   le rouge, sinon deux nombres de teintes differentes se disputeraient la
   lecture alors que l'un explique l'autre. */
.processing-mouvement__apres {
    color: rgba(var(--white-rgb), 0.88);
}

.processing-mouvement__reserve {
    margin-top: 4px;
    font-size: 12px;
    color: rgb(var(--amber-rgb));
    display: flex;
    align-items: baseline;
    gap: 6px;
    flex-wrap: wrap;
}

/* --- Un titre de page ne se pose pas dans une carte -----------------------
   -------------------------------------------------------------------------
   « Reglages systeme / Parametres / Modes generaux... » etait encadre comme
   les reglages qu'il annonce. Deux cartes empilees, la premiere ne se reglant
   pas : on la lisait comme un premier bloc de reglages vide.

   L ESPACE N EST PAS REPOSE ICI. `.admin-dashboard` est un flex en colonne
   avec `gap: var(--espace-section)` : le conteneur rend deja l'air. La marge
   basse de `card` s'y ajoutait -- 86 px mesures sous le titre une fois le
   cadre retire. Le conteneur decide, la piece ne redecide pas.
   ------------------------------------------------------------------------- */
.admin-dashboard__hero--nu {
    margin-bottom: 0;
}


/* =========================================================================
   LE MODE PRESENTIEL, VU DE L ADMIN
   =========================================================================
   ELLE ETAIT ECRITE DANS UN `<style>` EN LIGNE, dans le gabarit de la page.
   Trois choses s'y perdent : les themes ne la voient pas, les outils qui
   mesurent la page non plus, et personne ne la trouve en cherchant d'ou vient
   un defaut d'alignement -- il a fallu lire le HTML rendu pour savoir que ces
   neuf regles existaient.
   ========================================================================= */

.admin-presentiel__tete {
    margin-bottom: 18px;
}

/* -------------------------------------------------------------------------
   LA RANGEE D IMPORT : cinq commandes, une seule ligne de base
   -------------------------------------------------------------------------
   `align-items: end` ALIGNE LES BAS, et c'est la bonne intention : les cinq
   cellules n'ont pas la meme hauteur (un libelle au-dessus d'un champ, un
   bouton tout seul), donc c'est par le bas qu'elles se rejoignent.

   MAIS ELLE ALIGNAIT DES MARGES, PAS DES COMMANDES. Le bloc generique des
   champs de `lk.css` pose `margin-bottom: 16px` sur tout `input` et tout
   `select` : la cellule d'un champ mesurait donc 16 px de plus que ce qu'on y
   voit. Mesure du 24/09/2026, les cinq bas de boite tous a 432 px -- et les
   commandes, elles, a 432, 416, 416, 416, 432. Le bouton et le choix de
   fichier sur une ligne, les trois champs seize pixels plus haut.

   C'est le MEME piege que le cout d'un test du tableau de bord, corrige ce
   matin : une marge basse pensee pour un formulaire EMPILE, qui devient un
   vide invisible des qu'on met le formulaire sur une ligne.

   LE SELECTEUR EST DOUBLE pour peser (0,2,1) : `.admin-presentiel__import
   input` ne pese que (0,1,1), autant que `input[type="text"]`, et l'egalite
   se tranche alors par l'ordre des feuilles -- ce qui marchait ici par
   accident et se serait defait au premier deplacement de cette regle.

   ET IL SE DOUBLE SANS ESPACE. `.a .a input` demande un `.a` DANS un `.a`,
   donc il ne designe rien du tout ; `.a.a input` est le meme element nomme
   deux fois. Ecrit avec l'espace la premiere fois : la marge de 16 px etait
   toujours la a la mesure d'apres, et la regle avait pourtant l'air posee.
   ------------------------------------------------------------------------- */
.admin-presentiel__import {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 14px;
    /* LES CELLULES PRENNENT TOUTE LA HAUTEUR DE LA RANGEE, et ce sont elles
       qui alignent ce qu'elles portent -- voir la regle suivante. Cale sur
       `end`, la cellule se retrecissait autour de son contenu et le libelle
       descendait avec : « Carte .pac » se posait 26 px sous « Nom ». */
    align-items: stretch;
}

/* DEUX LIGNES PAR CELLULE : le libelle EN HAUT, la commande EN BAS.
   Les cinq commandes n'ont pas la meme hauteur -- 21 px pour le choix de
   fichier, 47 pour le menu, 45 pour un champ, 37 pour le bouton -- donc une
   seule ligne de reference ne peut pas les tenir toutes. Il en faut deux :
   les libelles se rejoignent par le haut, les commandes par le bas. */
.admin-presentiel__import > div {
    display: grid;
    grid-template-rows: auto 1fr;
    align-items: end;
}

/* LA CELLULE DU BOUTON N A PAS DE LIBELLE, donc son unique enfant tombe dans
   la PREMIERE ligne, celle des intitules : le bouton remontait de 33 px et se
   posait sur la ligne des libelles. On le place nommement dans la SECONDE
   ligne, celle des commandes, plutot que de compter sur un `align-content`
   qui perd contre la regle de cellule juste au-dessus -- (0,1,0) contre
   (0,1,1), mesure faite.

   `justify-items: start` garde au bouton sa largeur propre : une cellule de
   grille etire ses enfants, et « Importer » occupait toute la colonne. */
.admin-presentiel__import > .admin-presentiel__envoi {
    justify-items: start;
}

.admin-presentiel__import > .admin-presentiel__envoi > * {
    grid-row: 2;
}

.admin-presentiel__import label {
    display: block;
    margin-bottom: 6px;
}

/* LE BOUTON PREND LA HAUTEUR DES CHAMPS, PAR LEUR RECETTE.

   L'Admin, le 17/10/2026 : « C'est aligne ca ? ». Non : les quatre commandes
   rendaient 45,2 ou 45,6 et le bouton 36,6. Ils partageaient bien leur bord
   BAS -- la rangee les y cale -- mais neuf pixels de moins se lisent comme un
   bouton pose de travers.

   12 PX DE HAUT ET DE BAS, INTERLIGNE 1,4 SUR 14 : c'est ce qui donne 45,2 a
   un champ de texte, donc ca donne 45,2 au bouton. Ecrire `min-height: 45px`
   aurait fige un nombre qui se defait au premier changement de taille du
   texte. Les 18 px horizontaux restent : le texte d'un bouton a besoin d'air
   sur les cotes, un champ non.

   POURQUOI PAS `align-self: stretch`, qui serait plus direct : la cellule du
   bouton n'a pas de libelle, donc sa premiere rangee se replie a zero et la
   seconde prend toute la cellule -- le bouton passait a 70,5 px et remontait
   sur la ligne des intitules. Un `subgrid` repare ca, mesure faite, mais il
   impose l'ecart de rangee de la grille entre l'intitule et sa commande,
   14 px au lieu de 6, et demande de reprendre l'espacement des lignes
   repliees sur ecran etroit. Trois reglages deplaces pour ce qu'une recette
   de hauteur fait seule. */
.admin-presentiel__import > .admin-presentiel__envoi > .btn {
    padding: 12px 18px;
    font-size: 14px;
    line-height: 1.4;
}

.admin-presentiel__import.admin-presentiel__import input,
.admin-presentiel__import.admin-presentiel__import select {
    width: 100%;
    box-sizing: border-box;
    margin-bottom: 0;
}

/* -------------------------------------------------------------------------
   LES GESTES D UNE LIGNE DE TABLEAU
   ------------------------------------------------------------------------- */
.admin-presentiel__gestes {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
}

.admin-presentiel__gestes form {
    display: flex;
    gap: 6px;
    align-items: center;
    margin: 0;
}

/* LA MEME MARGE FANTOME QUE PLUS HAUT, et le meme remede : ces champs-la sont
   sur la ligne de leur bouton, pas empiles au-dessus de lui. */
.admin-presentiel__gestes.admin-presentiel__gestes select,
.admin-presentiel__gestes.admin-presentiel__gestes input {
    max-width: 220px;
    margin-bottom: 0;
}

/* UN DOSSIER JETE SE LIT EN RETRAIT, mais ses gestes restent lisibles : on ne
   demande pas de decider sur un texte a 60 %. */
.admin-presentiel__jete td {
    opacity: 0.6;
}

.admin-presentiel__jete .admin-presentiel__gestes {
    opacity: 1;
}


/* -------------------------------------------------------------------------
   LA LIGNE DE PROGRAMME ET SON DEPLI
   -------------------------------------------------------------------------
   La table posait une ligne par ELEMENT : quinze lignes pour quatre
   programmes. Elle en pose une par programme, et le detail se deplie dans une
   rangee soeur -- une rangee de tableau ne peut pas vivre dans une cellule.
   ------------------------------------------------------------------------- */

.programme-depli {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 4px;
    padding: 0;
    background: none;
    border: 0;
    /*
     * L'ENCRE EST CELLE DE LA CELLULE, ET LE RETRAIT SE FAIT A L'OPACITE.
     *
     * Elle etait posee par jeton : `--ink-300` au repos, `--ink-100` au
     * survol. Or `--ink-100` n'est declare nulle part, le survol retombait
     * donc sur son repli blanc, et en theme clair le libelle disparaissait
     * (contraste 1,35 mesure). Herite plutot que nomme, l'encre suit les deux
     * themes sans qu'aucun jeton ait a exister.
     */
    color: inherit;
    opacity: 0.72;
    font-size: 12px;
    cursor: pointer;
}

.programme-depli:hover,
.programme-depli:focus-visible {
    opacity: 1;
}

.programme-depli__chevron {
    display: inline-block;
    transition: transform 0.18s ease;
}

.programme-depli.is-open .programme-depli__chevron {
    transform: rotate(180deg);
}

/* CE QUI DIFFERE D'UN ELEMENT A L'AUTRE SE DIT, ET SE VOIT.
   Une valeur commune s'ecrit comme un nombre ; celle-ci est une mention, et
   elle ne doit pas se lire comme une valeur. */
.programme-divergent {
    font-style: italic;
    /* 0,7 rendait 3,64 de contraste sur la ligne teintee du theme clair
       (mesure), sous les 4,5 exiges. L'italique suffit a dire que c'est une
       mention et non une valeur ; l'opacite n'a pas a le payer d'illisible. */
    opacity: 0.8;
}

/*
 * SOUS UN CHAMP, LA MENTION NE PESE PAS PLUS QUE SON ETIQUETTE.
 *
 * Elle etait dans le `placeholder` du champ et rendait « valeurs differ... » :
 * le produit plafonne tout champ de nombre a 9em, ce qui est le bon reglage
 * pour un nombre. La mention est donc passee sous le champ, et elle y prend le
 * cran des libelles de formulaire.
 */
.champ > .programme-divergent {
    font-size: 13px;
}

.programme-composition > td {
    padding-top: 0;
}

.programme-elements {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.programme-element {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 6px 10px;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.03);
    font-size: 13px;
}

/* -------------------------------------------------------------------------
   LES DEUX FLECHES QUI DEPLACENT
   -------------------------------------------------------------------------
   Un programme entre les programmes, un element dans le sien. Le geste est
   rare : les fleches se tiennent en retrait, et ne prennent leur encre qu'au
   survol de ce qu'elles deplacent.

   CHAQUE FLECHE EST UN FORMULAIRE, parce que ce geste ECRIT. Les formulaires
   ont une marge basse generale dans le produit, qui decalerait les deux l'une
   par rapport a l'autre : elle est reprise ici.
   ------------------------------------------------------------------------- */
.ordre-fleches {
    display: inline-flex;
    flex-direction: column;
    gap: 2px;
    vertical-align: middle;
}

.ordre-fleches__forme {
    margin: 0;
    line-height: 0;
}

.ordre-fleche {
    display: block;
    /* UNE CIBLE QU'ON PEUT VISER. Elle mesurait 13 x 12 px, ce qui demande une
       souris posee : le remplissage la porte a 24 x 18 sans changer le signe
       lui-meme. */
    padding: 3px 7px;
    border: 0;
    background: none;
    color: inherit;
    /* 0,38 RENDAIT 3,12 DE CONTRASTE (mesure), sous les 4,5 exiges : la fleche
       etait discrete au point de ne plus se lire. Discrete veut dire « en
       retrait », pas « invisible ». */
    opacity: 0.55;
    font-size: 12px;
    line-height: 1;
    cursor: pointer;
    transition: opacity 0.14s ease;
}

.programme-ligne:hover .ordre-fleche,
.programme-element:hover .ordre-fleche {
    opacity: 0.8;
}

/* DANS UNE LIGNE D'ELEMENT, LES DEUX FLECHES SE METTENT COTE A COTE. Empilees,
   elles mesureraient 38 px de haut pour une ligne qui en fait 34, et chaque
   element y gagnerait une hauteur qu'il n'a pas besoin de prendre. */
.programme-element .ordre-fleches {
    flex-direction: row;
    gap: 0;
}

.ordre-fleche:hover,
.ordre-fleche:focus-visible {
    opacity: 1;
}

/* CELLE QUI NE MENE NULLE PART GARDE SA PLACE. Cachee, elle ferait sauter
   l'autre d'une ligne a la suivante et la colonne ne tiendrait plus en
   place. */
.ordre-fleche:disabled {
    opacity: 0.12;
    cursor: default;
}

.programme-ligne:hover .ordre-fleche:disabled,
.programme-element:hover .ordre-fleche:disabled {
    opacity: 0.12;
}

/* LA COLONNE DU RANG PORTE DESORMAIS DEUX CHOSES : le numero et ses fleches,
   cote a cote et centres l'un sur l'autre. */
.programme-emplacement {
    white-space: nowrap;
}

.programme-emplacement .ordre-fleches {
    margin-left: 6px;
}

/* LE RANG DE L'ELEMENT DANS SON PROGRAMME. Un chiffre de reperage, pas une
   valeur : il se tient en retrait du nom, et sa chasse fixe aligne la colonne
   quand on passe de 9 a 10. */
.programme-element__rang {
    flex: 0 0 auto;
    min-width: 1.4em;
    color: var(--texte-discret);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.programme-element__nom {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.programme-element__compte,
.programme-element__acces {
    flex: 0 0 auto;
    font-variant-numeric: tabular-nums;
    opacity: 0.8;
}

.programme-fiche__portee {
    margin-top: 12px;
}

/* AU TELEPHONE, la ligne d'element s'empile : cinq informations cote a cote
   ne tiennent pas sur 360 px, et le nom se serait reduit a trois lettres. */
@media (max-width: 640px) {
    .programme-element {
        flex-wrap: wrap;
        gap: 6px 10px;
    }

    .programme-element__nom {
        flex: 1 0 100%;
        white-space: normal;
    }
}

html[data-theme="clair"] .programme-element {
    background: rgba(15, 23, 42, 0.04);
}

/* --- Les gestes d'une ligne de la file d'attente ------------------------
   TROIS BOUTONS DANS UNE CELLULE DE TABLEAU, et ils doivent pouvoir se
   replier. `.responsive-table__actions` est en `nowrap` depuis le jour ou
   deux boutons de 200 px se repliaient dans une colonne de 164 : la regle
   est juste pour ce tableau-la, et elle ne l'est plus ici, ou la colonne
   porte « Ouvrir » plus un bouton par moteur. Un `nowrap` deborderait la
   cellule au lieu de passer a la ligne.

   LES VALEURS VIENNENT DE LA MEME MAISON : ce sont celles des rangees de
   l'administration des comptes, juste au-dessus. Deux tableaux du meme
   ecran qui espacent leurs boutons differemment se lisent comme deux
   ecrans.
   ------------------------------------------------------------------------ */
.file-attente__gestes {
    flex-wrap: wrap;
    gap: var(--espace-s);
}

.file-attente__gestes .btn {
    width: auto;
    min-width: 0;
    padding-inline: var(--espace-s);
}

/* --- Les tests passes par un code --------------------------------------
   UNE CARTE PAR SEANCE, parce que treize renseignements ne tiennent pas en
   colonnes : un tableau les aurait fait defiler de cote. Les faits se
   posent en grille, les gestes en dessous.

   AUCUNE COULEUR EN DUR : tout vient des jetons, sinon la page serait
   juste dans un theme et fausse dans l'autre. C'est exactement ainsi que
   du texte sombre est parti sur fond sombre le 20/10.
   ------------------------------------------------------------------------ */
.codes-resultats__chiffres {
    display: flex;
    flex-wrap: wrap;
    gap: var(--espace-xl);
}

/* LA LIGNE REPLIEE, ET CE QU IL FAUT DEFAIRE POUR L OBTENIR.

   `summary` arrive avec un marqueur (le triangle) et, sur WebKit, un
   pseudo-element a lui : les deux se retirent, sinon la fiche s'ouvre sur une
   fleche noire que rien dans cette page ne porte. Le chevron qui la remplace
   est dessine en bordures, il tourne a l'ouverture, et il se tient tranquille
   quand la personne a demande moins de mouvement.

   LA LIGNE NE SE SOULIGNE PAS AU SURVOL et le curseur dit qu'elle s'ouvre :
   sans ces deux-la, rien ne distingue un en-tete d'un en-tete cliquable. */
.codes-resultat {
    padding-block: var(--espace-l);
}

.codes-resultat > summary {
    list-style: none;
    cursor: pointer;
}

.codes-resultat > summary::-webkit-details-marker {
    display: none;
}

.codes-resultat__tete {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--espace-m);
    margin-bottom: 0;
}

/* LA LIGNE REPLIEE EST UNE GRILLE, PAS UNE RANGEE SOUPLE.

   L'ADMIN, LE 09/11/2026 : « les elements ne sont pas alignes dans la ligne ».
   Mesure sur la page reelle, trois fiches a la suite : le mode tombait a 401,
   311 et 285 px selon la longueur du code et de l'etat qui le precedent. Vingt-
   quatre lignes empilees, et la meme information danse a chaque ligne : une
   rangee souple place ses elements bout a bout, elle ne tient aucune colonne.

   LES LARGEURS SONT MESUREES, PAS CHOISIES. Maximum constate sur les vingt-
   quatre fiches : code 8,88 rem, etat 7,5, mode 3,5, numero 1,38, date 4,19.
   On arrondit au-dessus pour ce qui peut s'allonger -- le numero passera a
   quatre chiffres, une traduction allemande est plus longue -- et `minmax`
   laisse la colonne s'elargir plutot que de couper. Une fiche exceptionnelle
   se decale alors seule, au lieu de decaler les vingt-trois autres.

   LE CODE A SA LARGEUR A LUI : il est toujours de la meme forme
   (`XX-XXXX-XXXX`), sauf le tiret des seances sans code, qui garde la colonne.

   LA DERNIERE COLONNE EST `1fr` : c'est elle qui porte le chevron et qui
   mange la largeur restante, donc le chevron tient le bord droit quelle que
   soit la fiche. */
@media (min-width: 901px) {
    .codes-resultat > .codes-resultat__tete {
        display: grid;
        grid-template-columns:
            9rem
            minmax(7.5rem, max-content)
            minmax(4rem, max-content)
            3rem
            minmax(4.5rem, max-content)
            max-content
            1fr;
        align-items: center;
        /* UNE PASTILLE FAIT LA TAILLE DE SON MOT.

           L'ADMIN, LE 09/11/2026 : « la taille des pastilles ». Une grille
           ETIRE ses elements par defaut, et la colonne de l'etat a un plancher
           de 7,5 rem : « Ouverte » se retrouvait dans une pastille de 120 px,
           aussi large que « Entrainement fait ». Mesure sur la page reelle,
           huit fiches : toutes les pastilles de statut a 120 px, quel que soit
           leur mot.

           LA COLONNE GARDE SON PLANCHER -- c'est lui qui aligne les lignes
           entre elles -- mais ce qu'elle contient s'arrete a son texte. */
        justify-items: start;
    }

    /* LE CHEVRON SE PLACE, IL NE SE LAISSE PAS POUSSER. Sans terme a afficher
       -- une seance qui n'a pas de date de fin -- la ligne ne porte que six
       elements, et le septieme qu'est le chevron prendrait la place du terme,
       au milieu de la ligne. On le cloue a la derniere colonne. */
    .codes-resultat > .codes-resultat__tete::after {
        grid-column: 7;
        justify-self: end;
        margin-left: 0;
    }
}

/* L EN-TETE NE GARDE SA MARGE BASSE QUE DEPLIE : repliee, elle laisserait un
   vide sous chaque ligne de la liste. */
.codes-resultat[open] > .codes-resultat__tete {
    margin-bottom: var(--espace-l);
}

.codes-resultat__tete::after {
    content: '';
    margin-left: auto;
    width: 8px;
    height: 8px;
    border-right: 2px solid var(--texte-discret);
    border-bottom: 2px solid var(--texte-discret);
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform 0.16s ease;
}

.codes-resultat[open] > .codes-resultat__tete::after {
    transform: rotate(-135deg) translate(-2px, -2px);
}

@media (prefers-reduced-motion: reduce) {
    .codes-resultat__tete::after {
        transition: none;
    }
}

/* LA DATE DU TEST, DANS LA LIGNE REPLIEE. Elle est courte ici et longue dans
   le detail : on parcourt la ligne, on lit la fiche. */
.codes-resultat__resume {
    color: var(--texte-discret);
    font-variant-numeric: tabular-nums;
}

/* LE TERME NE COLLE PAS A LA DATE quand la ligne reste souple (sous 901 px) :
   en grille, c'est la colonne qui l'ecarte. */
.codes-resultat__terme {
    margin-left: var(--espace-s);
}

@media (min-width: 901px) {
    .codes-resultat__terme {
        margin-left: 0;
    }
}

/* LA POUBELLE OUVRE LE DETAIL, elle ne s'ajoute pas a la pile : sa rangee ne
   prend aucune hauteur a elle, elle ne fait que la pousser a droite. */
.codes-resultat__rangee-poubelle {
    display: flex;
}

/* LA POUBELLE, SEULE DE SON COTE.

   `margin-left: auto` la pousse au bord droit de l'en-tete, loin des gestes
   du bas : un geste sans retour ne se range pas a cote de ceux qui se
   defont. Elle n'emprunte pas `.btn` -- elle n'en a ni la forme, ni le
   poids, et un bouton de meme encre que « Prolonger » pour supprimer serait
   un piege. Elle est discrete au repos et rouge sous le doigt. */
.codes-resultat__poubelle {
    margin-left: auto;
    display: flex;
}

.codes-resultat__poubelle-bouton {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 0;
    border-radius: var(--rayon-s);
    background: none;
    color: var(--texte-discret);
    cursor: pointer;
    transition: color 0.16s ease, background 0.16s ease;
}

.codes-resultat__poubelle-bouton:hover,
.codes-resultat__poubelle-bouton:focus-visible {
    color: var(--couleur-danger);
    background: rgba(var(--surface-sombre-rgb), 0.5);
}

.codes-resultat__poubelle-bouton svg {
    width: 17px;
    height: 17px;
}

/* LE CODE EST CE QU ON CHERCHE : il est le seul element en gros, et en
   chasse fixe parce qu'on le recopie caractere par caractere. */
.codes-resultat__code {
    font-size: 1.25rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    user-select: all;
}

.codes-resultat__faits {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--espace-m) var(--espace-xl);
    margin: 0 0 var(--espace-l);
}

.codes-resultat__faits dt {
    font-size: 0.8125rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--texte-discret);
    margin-bottom: var(--espace-xs);
}

.codes-resultat__faits dd {
    margin: 0;
}

/* UN TERME DEPASSE SE VOIT. Le resultat existe toujours et n'est plus
   servi : c'est la seule ligne de la carte qui appelle un geste. */
.codes-resultat__eteint {
    color: var(--couleur-danger);
}

/* LA RANGEE DE GESTES RESTE UNE RANGEE, A TOUTES LES LARGEURS.

   L'ADMIN, LE 09/11/2026 : « et le visuel des boutons ! rien ne te choque ? ».
   Sous 880 px, les cinq gestes s'empilaient l'un sous l'autre, chacun centre
   au milieu de la fiche, alors que tout le reste de la carte est aligne a
   gauche. Vu a l'ecran a 703 px.

   D OU CA VIENT. `.responsive-table__actions` (lk.css) bascule en
   `flex-direction: column; align-items: stretch` sous 880 px, avec ses boutons
   en pleine largeur. C'est le bon reglage pour ce qu'elle vise : une CELLULE
   de tableau devenue etroite, ou « Modifier » et « Supprimer » gagnent a
   prendre toute la colonne. Ici elle habille une rangee dans une CARTE, qui a
   la place de ses boutons -- le seuil juge la fenetre, pas la largeur recue.

   ON CHANGE DONC LA CONDITION, PAS LA REGLE : celle de lk.css garde son sens
   partout ailleurs, et cette rangee-ci s'en exclut. Le selecteur passe par
   l'enfant direct pour peser plus lourd que le media qu'il annule. */
.codes-resultat > .codes-resultat__gestes {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-start;
}

.codes-resultat > .codes-resultat__gestes .btn {
    width: auto;
    /* UN BOUTON NE SE FAIT PAS ECRASER SOUS SON PROPRE TEXTE.

       A 375 px, « Changer de compte » etait contraint a 103 px pour 130 px de
       texte : le `nowrap` pose plus haut l'empechait de se couper, donc il
       debordait de son cadre et se lisait « hanger de compte ». Mesure a
       l'ecran le 09/11/2026.

       IL GARDE DONC SA TAILLE et la rangee enroule, ce qu'elle sait faire. */
    flex-shrink: 0;
}

/* LE SIGNE SEUL, MAIS SEULEMENT QUAND LE MOT NE TIENT PLUS.

   L'ADMIN, LE 09/11/2026 : « icone seulement si trop petit ». Un signe se
   devine, un mot se lit : on ne retire le mot que lorsqu'il coute la mise en
   page, pas par principe.

   LE SEUIL EST MESURE, PAS CHOISI. Sur la fiche la plus chargee de la page,
   avec ses mots, la rangee demande 803 px : les deux gestes ecrits (132 et
   149), le geste du compte (371, dont un champ qui prend la largeur du nom
   qu'il porte), « Remettre en file » (127) et les quatre ecarts de 8. Au-dessus
   de cette largeur tout tient en ligne et les mots restent ; en dessous, les
   deux gestes qui ne font qu'OUVRIR UNE PAGE se replient sur leur signe, ce
   qui rend 179 px a la rangee.

   `@container` ET NON `@media`, et c'est le fond de l'affaire. La question
   n'est pas « quelle est la largeur de la fenetre » mais « reste-t-il de la
   place dans CETTE rangee » : la meme page a une rangee large quand le menu
   lateral est replie et etroite quand il est ouvert, et le champ du compte
   change de largeur d'une fiche a l'autre. Un seuil de fenetre aurait repondu
   la meme chose aux deux. */
.codes-resultat__gestes {
    container-type: inline-size;
}

.codes-resultat__geste-signe {
    display: inline-flex;
    align-items: center;
    gap: var(--espace-xs);
}

.codes-resultat__geste-signe svg {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
}

@container (max-width: 803px) {
    .codes-resultat__geste-signe {
        justify-content: center;
        width: 44px;
        min-width: 44px;
        padding-inline: 0;
        gap: 0;
    }

    .codes-resultat__geste-signe > span {
        display: none;
    }
}

/* ET LE GESTE PASSE A LA LIGNE ENTIER, au lieu de se replier sur lui-meme.

   LES TROIS REGLAGES VONT ENSEMBLE, et il a fallu les trois. Avec le seul
   `flex-wrap`, le geste se faisait contracter par la rangee et, son bouton ne
   cedant plus, c'est a l'INTERIEUR qu'il se repliait : a 950 px « Changer de
   compte » descendait sous son champ alors que la ligne suivante etait libre.
   Vu a l'ecran apres le reglage precedent.

   `flex-shrink: 0` le fait donc passer ENTIER a la ligne. `max-width: 100%`
   garde la porte de sortie pour le telephone : la, le geste ne tient pas meme
   seul sur sa ligne, il se contracte malgre tout, et c'est `flex-wrap` qui
   fait alors descendre le bouton sous son champ -- dans la carte. */
.codes-resultat__geste {
    flex-wrap: wrap;
    flex-shrink: 0;
    max-width: 100%;
}

/* LE MOT QUI REMPLACE LA RANGEE DE GESTES quand aucun geste ne s'applique :
   il prend la place qu'elle aurait prise, pas davantage. */
.codes-resultat__sans-geste {
    margin: var(--espace-l) 0 0;
    font-size: 0.9rem;
}

.codes-resultat__gestes {
    flex-wrap: wrap;
    gap: var(--espace-s);
    align-items: center;
}

/* Les deux gestes a saisie portent leur champ et leur bouton cote a cote :
   separes, le champ s'etirait sur toute la rangee et poussait le bouton a
   la ligne suivante. */
.codes-resultat__geste {
    display: flex;
    gap: var(--espace-xs);
    align-items: center;
}

.codes-resultat__geste .form-control {
    width: auto;
    min-width: 0;
}

/* LES DEUX CHAMPS DU RATTACHEMENT NE PRENNENT QUE CE QU IL LEUR FAUT.

   L'ADMIN, LE 03/11/2026 : « reduire taille selecteur pour que tout rentre
   (de preference) sur une ligne ». La liste s'etirait sur le plus long de ses
   dix-neuf libelles -- un nom suivi d'un courriel -- et poussait seule la
   rangee de gestes a la ligne suivante.

   DEUX PLAFONDS PLUTOT QU UNE LARGEUR FIXE : en dessous, les champs restent
   libres de se contracter avec la carte. Le filtre n'a que quelques lettres a
   montrer, la liste un nom ; ce qui depasse se coupe, et la liste ouverte
   montre de toute facon ses libelles en entier. */
.codes-resultat__geste input[type="search"] {
    max-width: 140px;
}

.codes-resultat__geste select[name="compte"] {
    max-width: 230px;
}

/* LA SAISIE D UN CODE ET CE QU ELLE OUVRE, MOITIE-MOITIE.

   L'ADMIN, LE 03/11/2026 : « ces 2 blocs peuvent etre a cote 50/50 ».

   `1fr 1fr` ET NON `auto` : deux moities exactes, quel que soit le texte.
   Les cartes s'etirent a la meme hauteur -- c'est le defaut de la grille --
   et c'est ce qu'on veut ici, sinon la carte de gauche, plus courte, laisserait
   un decrochement sous elle.

   SOUS 900 PX ELLES SE REMETTENT L UNE SOUS L AUTRE : deux moities n'y sont
   plus deux colonnes, ce sont deux boites etroites ou le code n'a plus la
   place de s'ecrire en entier. */
.codes-resultat__duo {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--espace-section);
    align-items: stretch;
}

@media (max-width: 900px) {
    .codes-resultat__duo {
        grid-template-columns: 1fr;
    }
}

.codes-resultat__gestes .btn {
    width: auto;
    min-width: 0;
    padding-inline: var(--espace-m);
    /* UN INTITULE DE BOUTON NE SE CASSE PAS EN DEUX.

       Le champ du compte prend desormais la largeur de ce qu'il montre, et sur
       une fiche au nom long il ne reste plus assez pour « Changer de compte » :
       le bouton se repliait sur deux lignes et depassait en hauteur ses quatre
       voisins, qui paraissaient alors mal poses. Mesure sur la page reelle le
       09/11/2026.

       LA RANGEE SAIT DEJA QUOI FAIRE DU TROP-PLEIN : elle enroule
       (`flex-wrap: wrap`). Un bouton qui ne se coupe pas descend a la ligne
       suivante entier, ce qui est lisible ; un bouton coupe ne l'est pas. */
    white-space: nowrap;
}

/* --- Le suivi financier -------------------------------------------------
   AUCUNE COULEUR EN DUR : tout vient des jetons, sinon la page serait juste
   dans un theme et fausse dans l'autre.

   LA COURBE EST DU SVG POSE PAR LE SERVEUR, pas une bibliotheque. Ses
   couleurs sont donc des `fill` et des `stroke` qui lisent les memes
   variables que le reste de la page, et elle suit le theme sans une ligne
   de JavaScript.
   ------------------------------------------------------------------------ */
.finances__chiffres {
    display: flex;
    flex-wrap: wrap;
    gap: var(--espace-xl);
    align-items: flex-end;
}

/* Un chiffre d'argent se lit d'un coup d'oeil, et ses colonnes s'alignent :
   les chiffres tabulaires evitent que « 1 240 » et « 9 870 » n'aient pas la
   meme largeur. */
.finances__chiffre {
    display: block;
    font-size: 1.5rem;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.finances__courbe {
    margin: var(--espace-xl) 0 0;
}

.finances__svg {
    width: 100%;
    height: auto;
    display: block;
    overflow: visible;
}

/* LA MEME VALEUR QUE LES BORDURES DE `.admin-table`, et pas le jeton
   `--trait`. L'administration est bâtie sur fond sombre : `--trait` vaut
   `--ink-200`, un gris tres clair qui ferait de l'axe le trait le plus
   voyant de la page. Un voile de blanc suit le fond comme le font les
   tableaux juste a cote. */
.finances__axe {
    stroke: rgba(var(--white-rgb), 0.12);
    stroke-width: 1;
}

.finances__barre {
    fill: var(--couleur-accent);
}

.finances__mois,
.finances__annee {
    fill: var(--texte-discret);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
}

/* UN TERME ABSENT EST LA SEULE LIGNE QUI APPELLE UNE DECISION : un acces
   offert sans fin ne se refermera jamais tout seul. */
.finances__sans_terme {
    color: var(--couleur-danger);
}

.finances__rendu {
    color: var(--couleur-danger);
    font-size: 0.875rem;
}

/* --- L'arbre des parrainages -------------------------------------------
   L INDENTATION EST LA SEULE CHOSE QUI DIT LE NIVEAU, donc elle doit etre
   nette : vingt-quatre pixels par cran, et un trait court devant chaque
   ligne pour que l'oeil suive la colonne sans compter les espaces.

   LE NIVEAU VIENT D UNE VARIABLE POSEE SUR LA LIGNE, pas d'une classe par
   profondeur : onze classes quasi identiques se seraient desaccordees des
   qu'on aurait touche au pas, et la profondeur est deja bornee par la
   requete.

   A L ETROIT, LE PAS SE RESSERRE. Dix niveaux a 24 px font 240 px de marge :
   sur un telephone, le nom du dixieme filleul n'aurait plus de place. Le pas
   tombe a 12 px sous 760 px de large, ce qui garde l'etagement lisible sans
   pousser le texte hors de l'ecran.
   ------------------------------------------------------------------------ */
.arbre {
    list-style: none;
    margin: var(--espace-l) 0 0;
    padding: 0;
}

.arbre__noeud {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--espace-s);
    padding: 6px 0;
    padding-inline-start: calc(var(--niveau, 0) * 24px);
    border-bottom: 1px solid rgba(var(--white-rgb), 0.06);
}

.arbre__noeud:last-child {
    border-bottom: none;
}

/* Le trait de rattachement : il n'a de sens que sous un parent, donc la
   racine n'en porte pas. */
.arbre__trait {
    width: 14px;
    height: 1px;
    background: rgba(var(--white-rgb), 0.24);
    flex: 0 0 auto;
}

.arbre__noeud[style*="--niveau: 0"] .arbre__trait {
    visibility: hidden;
}

.arbre__nom {
    font-weight: 600;
}

.arbre__role,
.arbre__niveau,
.arbre__date {
    font-size: 0.875rem;
}

/* La date part a droite : elle se consulte, elle ne se lit pas en premier. */
.arbre__date {
    margin-inline-start: auto;
}

@media (max-width: 760px) {
    .arbre__noeud {
        padding-inline-start: calc(var(--niveau, 0) * 12px);
    }

    /* A l'etroit, la date sous le nom plutot qu'une colonne ecrasee. */
    .arbre__date {
        margin-inline-start: 0;
    }
}

/* --- La recherche qui n'attend pas le rechargement ----------------------
   « Les champs de recherche actualisent en direct ce qu'ils trient, qu'il n'y
   ait pas a recharger ou actualiser » (l'Admin, le 03/11/2026).
   `js/recherche-vivante.js` fait le travail ; il ne reste ici que les deux
   consequences visibles.

   LE BOUTON D ENVOI S EFFACE QUAND LE SCRIPT A PRIS LA MAIN, et seulement
   alors : la marque est posee par le script lui-meme, apres ses gardes. Sans
   JavaScript le bouton reste, et la recherche marche comme avant. Un bouton
   qui ne sert plus a rien est pire qu'un bouton absent -- on le cherche, on
   l'appuie, et rien ne se passe de plus.

   LE CADRE DES PAGES VIDE NE PREND PAS DE PLACE. Il est desormais rendu
   TOUJOURS, meme sans page a afficher : une zone qui disparait d'une reponse a
   l'autre ferait retomber la recherche sur le rechargement complet. Vide, il
   ne doit rien peser.
   ------------------------------------------------------------------------ */
form[data-recherche-vivante-active] button[type="submit"] {
    display: none;
}

.table-pagination:empty {
    display: none;
}


/* --- L'organigramme des parrainages ------------------------------------
   LA MEME CHAINE, DESSINEE. Demande par l'Admin le 03/11/2026 : « une vue
   comme ca, en plus de seulement une liste ». La liste indentee repond a
   « qui est rattache a qui » ; l'organigramme repond a « quelle forme a ce
   reseau » -- une branche large, une branche longue, un parrain qui en tient
   douze -- et cette question-la se compte peniblement sur une liste.

   DES LISTES EMBOITEES, ET LES TRAITS SONT DES BORDURES. Aucune bibliotheque,
   aucune toile, aucun script : le groupe d'enfants est un `<ul>` en flex,
   chaque enfant porte la moitie gauche et la moitie droite du trait
   horizontal, et le `<ul>` porte la tige qui descend du parent. Un
   organigramme ainsi fait se selectionne, s'imprime, se lit au clavier et
   suit le theme, ce qu'un dessin pose sur une toile ne sait faire d'aucune
   des quatre facons.

   LA MESURE QUI COMMANDE TOUTES LES AUTRES : le reseau reel porte treize
   personnes sur une seule rangee sous la racine (production, 03/11/2026),
   dont quatre praticiens -- et le dessin ne porte que les praticiens depuis
   la demande de l'Admin du meme jour. Ce n'est donc pas la profondeur qui
   menace la mise en page, c'est la LARGEUR, et rien ne borne une rangee.
   D'ou une pastille etroite, un nom sur deux lignes au plus, et le cadre a
   defilement du gabarit -- la meme classe que les tableaux, pas un second
   remede pour le meme defaut.

   LE TRAIT NE PART PAS DES BORDS DE LA RANGEE. Les deux moities du trait
   horizontal sont posees sur CHAQUE enfant ; le premier n'a donc pas de
   moitie gauche et le dernier pas de moitie droite, sinon la barre
   depasserait de la rangee des deux cotes et pointerait vers personne.
   ------------------------------------------------------------------------ */
.organigramme {
    margin-top: var(--espace-l);
    padding-bottom: var(--espace-s);
}

.organigramme__niveau {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    list-style: none;
    margin: 0;
    padding: 0;
    /* `fit-content` pour que la rangee ne s'ecrase pas dans le cadre qui
       defile : sans lui, treize pastilles se serreraient jusqu'a l'illisible
       au lieu de demander du defilement. */
    width: fit-content;
    min-width: 100%;
}

/* La rangee de la racine n'a pas de parent au-dessus, donc pas de tige. */
.organigramme__niveau:not(.organigramme__niveau--racine) {
    position: relative;
    padding-top: 22px;
}

.organigramme__niveau:not(.organigramme__niveau--racine)::before {
    content: "";
    position: absolute;
    top: 0;
    left: 50%;
    width: 1px;
    height: 22px;
    background: rgba(var(--white-rgb), 0.24);
}

.organigramme__branche {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 22px 6px 0;
}

/* Les deux moities du trait horizontal, et la descente vers l'enfant. */
.organigramme__branche::before,
.organigramme__branche::after {
    content: "";
    position: absolute;
    top: 0;
    width: 50%;
    height: 22px;
    border-top: 1px solid rgba(var(--white-rgb), 0.24);
}

.organigramme__branche::before {
    right: 50%;
}

.organigramme__branche::after {
    left: 50%;
    border-left: 1px solid rgba(var(--white-rgb), 0.24);
}

/* Aux deux bouts, la barre s'arrete : elle ne pointe vers personne au-dela. */
.organigramme__branche:first-child::before {
    border-top: 0;
}

.organigramme__branche:last-child::after {
    border-top: 0;
}

/* UN ENFANT UNIQUE N A PAS DE BARRE A PARTAGER, juste une tige droite. Sans
   ce cas, un parent a un seul enfant recevait un trait horizontal de largeur
   nulle qui ne se voyait pas, mais dont la bordure gauche doublait la tige. */
.organigramme__branche:only-child::before {
    border-top: 0;
}

.organigramme__branche:first-child:last-child::after {
    border-top: 0;
}

/* La racine n'est l'enfant de personne : ni barre ni tige au-dessus d'elle. */
.organigramme__niveau--racine > .organigramme__branche {
    padding-top: 0;
}

.organigramme__niveau--racine > .organigramme__branche::before,
.organigramme__niveau--racine > .organigramme__branche::after {
    content: none;
}

/* --- La personne ------------------------------------------------------- */
.organigramme__noeud {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    /* UNE LARGEUR FIXE, ET C EST ELLE QUI TIENT L ALIGNEMENT. Les traits se
       posent a 50 % de la branche : si chaque personne prenait la largeur de
       son nom, la tige d'un parent tomberait a cote du milieu de ses enfants.
       Treize fois 112 px tient dans le cadre qui defile. */
    width: 112px;
    padding: 8px 4px;
    border-radius: var(--rayon-bloc, 12px);
    text-align: center;
    text-decoration: none;
    color: inherit;
}

.organigramme__noeud:hover,
.organigramme__noeud:focus-visible {
    background: rgba(var(--white-rgb), 0.06);
}

.organigramme__pastille {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: rgba(var(--white-rgb), 0.10);
    border: 1px solid rgba(var(--white-rgb), 0.16);
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    /* La pastille est un reperage, pas une information : elle ne doit pas
       crier plus fort que le nom qu'elle accompagne. */
    color: var(--texte-discret);
}

/* LE ROLE SE DIT PAR LA TEINTE DE LA PASTILLE, en plus du mot dessous. Sur
   treize personnes alignees, c'est ce qui laisse voir d'un coup qu'une
   branche est faite de clients et une autre de praticiens. */
.organigramme__noeud--partner .organigramme__pastille {
    background: rgba(var(--portal-accent-rgb), 0.16);
    border-color: rgba(var(--portal-accent-rgb), 0.38);
    color: var(--couleur-accent);
}

.organigramme__noeud--admin .organigramme__pastille {
    background: rgba(var(--consultation-rgb), 0.18);
    border-color: rgba(var(--consultation-rgb), 0.38);
}

.organigramme__nom {
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1.25;
    /* DEUX LIGNES AU PLUS, et la coupure plutot que le debordement : un nom
       long ne doit pas elargir sa colonne, sinon il decale les traits de
       toute la rangee. */
    overflow-wrap: anywhere;
}

.organigramme__role {
    font-size: 0.6875rem;
    color: var(--texte-discret);
}

/* La bascule entre les deux vues, a droite du titre comme le bouton qu'elle
   accompagne. */
.organigramme__bascule {
    display: flex;
    flex-wrap: wrap;
    gap: var(--espace-s);
}

@media (max-width: 760px) {
    /* A l'etroit, la colonne se resserre : le cadre defile deja, mais moins
       de defilement vaut mieux que plus. */
    .organigramme__noeud {
        width: 92px;
    }

    .organigramme__pastille {
        width: 34px;
        height: 34px;
    }
}

/* UN MOIS OU L ARGENT SORT ne se distingue pas d'un mois ou il entre par sa
   seule position : sur un dessin de 180 pixels, une barre de deux pixels
   sous l'axe ressemble a une barre de deux pixels au-dessus. La couleur
   tranche, et c'est la meme que partout ailleurs pour ce qui part. */
.finances__barre--sortie {
    fill: var(--couleur-danger);
}

/* --- Un tableau trop large defile dans SON cadre, pas dans la page -------
   MESURE DU 02/11/2026, dans une iframe de 390 px : les ecrans batis sur
   `.admin-table` poussent la PAGE de 230 a 370 pixels vers la droite, et
   c'est toute la mise en page qui part de travers -- en-tete compris --
   pour une colonne de trop.

   Le defaut n'est pas neuf : `/admin/invites`, qui n'a rien a voir avec ce
   lot, deborde de 231 px de la meme facon. Il est SIGNALE, pas corrige
   d'autorite : sa vue n'est pas a moi.

   `max-width: 100%` AUTANT QUE `overflow-x` : sans lui, le cadre prend la
   largeur de son contenu et ne defile jamais, il pousse. C'est la moitie
   qu'on oublie, et elle ne se voit pas tant qu'on ne mesure pas.
   ------------------------------------------------------------------------ */
.table-qui-deborde {
    max-width: 100%;
    overflow-x: auto;
    /* Le defilement tactile garde son inertie, comme ailleurs dans l'admin. */
    -webkit-overflow-scrolling: touch;
}

/* =========================================================================
   LE TABLEAU DE BORD DES VISITES
   =========================================================================

   L'ADMIN, LE 11/11/2026 : « fait une passe de rendu, regarde ce qui se
   fait pour ce domaine, la c'est moche et illisible [...] visuel,
   harmonieux, aligne et de preference pour eviter le vide inutile, c'est un
   dashboard ».

   CE QU IL REGARDAIT, mesure avant : ONZE cartes empilees sur toute la
   largeur, 6 425 px de haut, soit six ecrans et demi. Trois d'entre elles
   faisaient 1 110 px de large pour porter quatre nombres, et « Mois apres
   mois » etalait deux colonnes sur un metre. Le vide n'etait pas une marge,
   c'etait de la place perdue.

   UNE GRILLE DE DOUZE, et les blocs y prennent la largeur de ce qu'ils ont
   a dire : le fil du temps toute la largeur, les trois rythmes un tiers
   chacun, les quatre listes un quart. Douze se divise par 2, 3, 4 et 6, ce
   qui est exactement la raison pour laquelle les grilles de tableau de bord
   en ont douze.

   ALIGNE VEUT DIRE `stretch`, PAS `start` : deux cartes cote a cote qui ne
   portent pas le meme nombre de lignes finissent a deux hauteurs, et la
   rangee se lit comme un escalier. Elles s'etirent sur la plus haute, et
   leur contenu reste en haut.
   ========================================================================= */
.tdb {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: 16px;
    align-items: stretch;
}

/* LA CARTE PERD SA MARGE DU BAS : dans une grille, c'est le `gap` qui
   espace, et les deux s'additionnaient en bas de chaque rangee. */
.tdb > .card {
    margin-bottom: 0;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.tdb__3 { grid-column: span 3; }
.tdb__4 { grid-column: span 4; }
.tdb__6 { grid-column: span 6; }
.tdb__8 { grid-column: span 8; }
.tdb__12 { grid-column: span 12; }

/* LE TITRE DE CARTE, LE MEME PARTOUT. Les `h2` du produit sont dimensionnes
   pour une page ; dans une tuile de tableau de bord ils prenaient le tiers
   de la hauteur disponible. */
.tdb .card > h2 {
    margin: 0 0 2px;
    font-size: 15px;
    letter-spacing: 0.01em;
}

.tdb .card > p.muted {
    margin: 0 0 12px;
    font-size: 12px;
    line-height: 1.45;
}

/* --- LA RANGEE DE CHIFFRES ----------------------------------------------

   SIX TUILES QUI SE PARTAGENT LA LARGEUR, au lieu de quatre nombres poses a
   gauche d'une carte vide. Chacune porte sa valeur, son nom et son ecart
   avec la periode d'avant.
   ------------------------------------------------------------------------- */
.tdb-chiffres {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 1px;
    background: rgba(var(--white-rgb), 0.07);
    border-radius: 10px;
    overflow: hidden;
}

/* LE FILET EST UN INTERSTICE, PAS UNE BORDURE : un `gap` d'un pixel sur un
   fond clair dessine la separation sans qu'aucune tuile ne porte de bord, et
   les angles de la rangee restent nets. */
/* --- LES TROIS LIGNES D UNE TUILE SONT LES MEMES PARTOUT ----------------

   L'ADMIN, LE 11/11/2026 : « alignement, c'est decale par les infos sous les
   barres ».

   EN COLONNE SOUPLE, CHAQUE TUILE EMPILAIT CE QU ELLE AVAIT : « liens de
   parrainage ouverts » prend deux lignes la ou « Inscriptions » en prend
   une, et l'ecart se posait donc treize pixels plus bas dans cette tuile-la.
   Sept tuiles, trois hauteurs d'ecart differentes, et la rangee se lisait
   comme un escalier.

   TROIS RANGEES FIXES : la valeur en haut, le nom qui prend le mou, l'ecart
   colle en bas. Les valeurs s'alignent parce qu'elles sont toutes en
   premiere rangee, les ecarts parce qu'ils sont tous en derniere, et un nom
   de deux lignes ne deplace plus rien.
   ------------------------------------------------------------------------- */
.tdb-chiffre {
    background: rgba(var(--slate-mid-rgb), 0.92);
    padding: 14px 16px;
    display: grid;
    grid-template-rows: auto 1fr auto;
    gap: 3px;
    min-width: 0;
}

.tdb-chiffre__valeur {
    font-size: 26px;
    font-weight: 700;
    line-height: 1.05;
    color: var(--ink-200);
    font-variant-numeric: tabular-nums;
}

.tdb-chiffre__nom {
    font-size: 11.5px;
    line-height: 1.3;
    color: var(--texte-discret);
}

/* --- L ECART AVEC LA PERIODE D AVANT ------------------------------------

   PAS DE ROUGE : dans ce produit le rouge est la couleur d'alerte, et une
   semaine a moins de visites n'est pas une panne. La baisse prend l'ambre,
   qui dit deja « ca se regarde » sur la tuile des courriels en attente ; la
   hausse prend le vert tendre des mouvements positifs.
   ------------------------------------------------------------------------- */
.tdb-ecart {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-top: 2px;
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    color: var(--texte-discret);
}

.tdb-ecart__fleche {
    font-size: 9px;
    line-height: 1;
}

.tdb-ecart--hausse { color: var(--green-soft); }
.tdb-ecart--baisse { color: rgb(var(--amber-rgb)); }

/* L AMBRE NE BASCULE PAS AVEC LE THEME, et c'est voulu : `jetons.css` le dit
   en toutes lettres, il peint des ETATS et un etat jaune qui devient brun ne
   dit plus rien. Mais ici il peint du TEXTE, et 251 191 36 sur une tuile
   blanche donne 1,8:1 -- mesure, illisible. On prend donc l'encre que le
   theme aurait donnee, et seulement pour ce texte-ci. */
html[data-theme="clair"] .tdb-ecart--baisse {
    color: rgb(122, 82, 4);
}

/* --- LES LISTES EN BARRES, DANS UNE TUILE -------------------------------

   `stats-barres` existe et sert partout ; ce qui change ici est qu'elle vit
   dans une tuile etroite. Le nom se coupe plutot que de pousser la barre
   hors de la tuile.
   ------------------------------------------------------------------------- */
.tdb .stats-barre__nom {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* La liste pousse la carte en hauteur ; sa place est en haut, pas centree
   sur ce que la rangee a de plus grand. */
.tdb .stats-barres {
    margin-top: auto;
    margin-bottom: 0;
}

.tdb .stats-barres:first-of-type {
    margin-top: 0;
}

/* --- LE FIL DU TEMPS, EN GRAND ------------------------------------------

   C'est la colonne vertebrale d'un tableau de bord de visites : il prend
   toute la largeur et une vraie hauteur, les trois rythmes se partagent la
   rangee d'en dessous.
   ------------------------------------------------------------------------- */
.tdb .stats-jours--fil {
    height: 170px;
}

.tdb .stats-jours--rythme {
    height: 110px;
}

/* --- LA CARTE DU MONDE ET SA LISTE, COTE A COTE -------------------------

   Elles etaient l'une sous l'autre : 958 px de haut pour un fond de carte de
   400. La liste des pays est un index de la carte, elle se lit A COTE.
   ------------------------------------------------------------------------- */
.tdb .carte-monde__cadre {
    margin: 0;
}

.tdb-pays {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* Au-dela d'une dizaine de pays la liste deborderait la hauteur de la carte
   d'a cote : elle defile chez elle, la rangee garde son alignement. */
.tdb-pays .stats-barres {
    overflow-y: auto;
    max-height: 320px;
}

/* --- LE JOURNAL, RACCOURCI ----------------------------------------------

   Il listait tout ce que la fenetre contenait : 2 948 px pour une seule
   carte, soit trois ecrans de lignes identiques. Les douze dernieres
   suffisent a savoir ce qui se passe maintenant ; le reste est de
   l'historique, et ce n'est pas la question d'un tableau de bord.
   ------------------------------------------------------------------------- */
.tdb .connexions-liste {
    gap: 6px;
}

/* --- SOUS 1 100 PX, LA GRILLE SE REPLIE ---------------------------------

   Un quart de douze fait 1,5 colonne de texte sur un ordinateur portable :
   les quatre listes passent a deux, puis a une sur telephone. Les seuils
   suivent le contenu, pas une taille d'appareil.
   ------------------------------------------------------------------------- */
@media (max-width: 1100px) {
    .tdb__3 { grid-column: span 6; }
    .tdb__4 { grid-column: span 6; }
    .tdb__8 { grid-column: span 12; }
}

@media (max-width: 720px) {
    .tdb {
        gap: 12px;
    }

    .tdb__3,
    .tdb__4,
    .tdb__6,
    .tdb__8 {
        grid-column: span 12;
    }
}

/* --- L EN-TETE : LE TITRE ET LA FENETRE SUR UNE LIGNE --------------------

   La fenetre avait sa bande a elle, sous la carte d'en-tete : une rangee
   entiere de page pour trois pastilles. Elle commande tout ce qui suit, sa
   place est a cote de ce qu'elle commande, et la page gagne sa hauteur.
   ------------------------------------------------------------------------- */
.tdb-tete {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
}

.tdb-tete__fenetre {
    margin: 0;
    flex: 0 0 auto;
}

/* Le texte d'introduction ne s'etale pas sur toute la largeur : au-dela
   d'une soixantaine de caracteres, l'oeil perd la ligne en revenant. */
.tdb-tete > div:first-child {
    max-width: 62ch;
}

/* --- L ENGAGEMENT, EN LISTE ---------------------------------------------

   Cinq nombres de vingt-six pixels dans un quart de rangee se bousculent, et
   aucun n'est le chiffre qu'on vient chercher : ceux-la sont dans la rangee
   du haut. Ici c'est une liste de reperes, nom a gauche, valeur a droite.
   ------------------------------------------------------------------------- */
.tdb-mesures {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 7px;
}

.tdb-mesure {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

.tdb-mesure dt {
    font-size: 12px;
    color: var(--texte-discret);
    min-width: 0;
}

.tdb-mesure dd {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    color: var(--ink-200);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* L ANCIENNETE DE LA VALEUR COMPAREE reste plus discrete que l'ecart
   lui-meme : c'est le mouvement qu'on lit, le point de depart ne sert qu'a
   le verifier. */
.tdb-ecart__avant {
    color: var(--texte-discret);
}
