/* ============================================================================
   HELLO — DESIGN SYSTEM PARTAGÉ
   ----------------------------------------------------------------------------
   Créé le 2026-08-12, en extrayant le `<style>` de `configurateur-pergola.html`.
   C'est la dette écrite dans `plateforme/00-ARCHITECTURE.md` §4 : « le design system est
   aujourd'hui dupliqué… à la première page créée, on extrait `assets/hello.css` ».

   ⚠️ CE FICHIER NE PORTE QUE CE QUI EST PARTAGÉ. Tout ce qui n'appartient qu'au
   configurateur — la scène 3D, le dock, les tiroirs, l'accordéon horizontal, les planches —
   reste chez lui. Un design system qui absorbe les composants d'un seul écran cesse d'être
   un socle et devient une seconde copie du même fichier.

   ⚠️ LE PROTO NE LE REPREND PAS ENCORE. Il le fera quand les trois pages seront posées :
   toucher un fichier d'un million d'octets pendant qu'on en écrit trois neufs, c'est se
   priver du seul repère qui dit laquelle des deux modifications a cassé quoi.

   ⚠️ LES CHEMINS D'IMAGE SONT RELATIFS À CE FICHIER, donc à `assets/`. Le proto écrit
   `url('assets/logo-hello-violet.png')` parce que son style vit dans le HTML ; ici c'est
   `url('logo-hello-violet.png')`. Recopier l'ancien chemin donnerait `assets/assets/…`.
   ============================================================================ */

/* ============ Tokens ============ */
/* 🐛 🔻 **CETTE CLASSE ÉTAIT UTILISÉE PAR QUATRE LIBELLÉS ET N'EXISTAIT NULLE PART**
   (2026-09-11). Je l'avais écrite dans deux écrans neufs en la croyant au socle : les libellés
   censés n'exister que pour les lecteurs d'écran s'affichaient donc à l'œil, et leur apparence
   était un accident plutôt qu'une décision.
   ⚠️ **UNE CLASSE QUI N'EXISTE PAS NE CASSE RIEN, ET C'EST LE PROBLÈME** : le navigateur
   l'ignore en silence, la page reste jolie, et personne ne voit que l'intention s'est perdue en
   route. *Ce qui manque dans une feuille de style ne lève jamais.*
   ⚠️ **ON LA MET AU SOCLE, PAS DANS UN ÉCRAN** : c'est un outil d'accessibilité, et le prochain
   qui en aura besoin la cherchera ici.
   ⚠️ **PAS `display:none`, PAS `visibility:hidden`** — les deux retirent l'élément de l'arbre
   d'accessibilité, donc du lecteur d'écran : on obtiendrait l'inverse exact de ce qu'on veut.
   La recette ci-dessous est celle qui fait consensus : un pixel, hors du flux, détouré. */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0;
}

:root{
  --bg:#f4f5f8;
  --card:#ffffff;

  /* Marque : violet primaire */
  --primary:#7b5cff;
  --primary-600:#6636e0;
  /* 🔻 **LE DÉGRADÉ DU BOUTON ET LE LISERÉ DE FOCUS ÉTAIENT ÉCRITS EN DUR, SIX FOIS**
     (relevé le 2026-08-25). Tant qu'il n'existait qu'un seul thème, cela ne se voyait pas ;
     le jour où l'administration a dû passer au rouge, il aurait fallu recopier le rouge à
     six endroits — et *ce qui est écrit deux fois diverge*. On redéfinit des tokens, on ne
     repeint pas les éléments un par un : c'est exactement la règle déjà appliquée à la
     sidebar sombre, remontée d'un cran. */
  --btn-1:#8f74ff;                        /* haut du dégradé du bouton primaire */
  --btn-2:#6636e0;                        /* bas du dégradé */
  --btn-ombre:rgba(102,54,224,.28);
  --focus-bord:#c9c0ff;                   /* liseré au survol et à la prise de focus */
  --focus-fond:#faf9ff;
  --primary-700:#5628c4;
  --primary-soft:#f1edff;
  --primary-soft-2:#e6dfff;
  --ink-violet:#2b1a63;

  --text:#1e2a4a;
  --text-2:#48536b;
  --muted:#8a93a8;
  --border:#edeef2;
  --border-2:#e4e7ee;

  --green:#1aa260;   --green-bg:#e7f6ee;
  --orange:#e08a1e;  --orange-bg:#fdf1e0;
  --red:#e0483d;     --red-bg:#fde8e6;
  --blue:#3d6fe3;    --blue-bg:#e8f0fe;

  --radius:14px;
  --shadow:0 1px 2px rgba(22,32,64,.04), 0 6px 20px rgba(22,32,64,.05);
  --shadow-lg:0 1px 3px rgba(20,30,60,.05), 0 10px 26px rgba(20,30,60,.055);
  /* ⚠️ Pile système, actée le 2026-07-21 après comparaison en direct de six polices.
     Ne pas reproposer de changement sans demande explicite. */
  --font:'Segoe UI', -apple-system, BlinkMacSystemFont, Roboto, Helvetica, Arial, sans-serif;

  /* 🔻 **236 → 220 px** (Benjamin, 2026-09-09, point 10 : *« sur cet écran qui est réellement
     le cœur de Hello, je réduirais légèrement sa largeur et je renforcerais la zone radar »*).
     ⚠️ **SEIZE PIXELS, PAS QUARANTE.** La barre porte huit entrées dont « Mon abonnement » :
     trop étroite, les libellés se rognent — et *une entrée de menu tronquée ne nomme plus rien*,
     ce qui coûterait plus cher que les pixels gagnés. On prend ce qui se prend sans casser. */
  --sidebar:220px;
  --sidebar-min:76px;
  --topbar:60px;
  /* La colonne de détail : 346 px est la signature des écrans où l'on sélectionne quelque
     chose (récapitulatif du configurateur, détail de « Mes projets »). On retrouve le détail
     là où on a appris à le chercher. */
  --rail:346px;
}
*{box-sizing:border-box}
html,body{margin:0;padding:0;height:100%}

/* 🐛 ⚠️ **LA TAILLE PAR DÉFAUT D'UNE ICÔNE.** Un `<svg>` sans règle de taille prend sa taille
   naturelle et remplit sa colonne : un cadenas de 16 px devient un bloc noir de 300 px. Le défaut
   s'est produit **quatre fois** ici, toujours en ajoutant une icône dans un bloc neuf dont
   personne n'avait encore écrit le `.parent svg{}`.
   ⚠️ **CETTE RÈGLE EST VOLONTAIREMENT FAIBLE** — un simple sélecteur de classe (0,1,0). Toutes
   les règles existantes s'écrivent `.parent svg{}` (0,1,1) et la battent : rien de ce qui est
   déjà habillé ne bouge. Elle ne sert qu'aux icônes que personne n'a habillées, et leur donne
   une taille sensée au lieu d'une taille absurde.
   ⚠️ **LA PEINTURE AUSSI EST UN DÉFAUT MANQUANT.** Toutes ces icônes sont des tracés au trait :
   sans règle, SVG les remplit en noir plein et les dessine sans contour — le cadenas devient une
   tache. Donner la taille sans donner le trait ne corrigeait qu'une moitié du défaut.
   ⚠️ **`currentColor`, pas une couleur fixe** : l'icône prend la couleur du texte qu'elle
   accompagne, donc elle suit les thèmes clair et sombre de la sidebar sans règle de plus.
   ⚠️ **Elle ne dispense pas d'écrire la règle du bloc** : 16 px est un défaut, pas un choix. */
.ic{
  width:16px;height:16px;flex:0 0 auto;vertical-align:-2px;
  fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;
}
body{
  font-family:var(--font);background:var(--bg);color:var(--text);
  font-size:14px;line-height:1.45;-webkit-font-smoothing:antialiased;overflow:hidden;
}
button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit}
input,select,textarea{font-family:inherit}
a{color:inherit;text-decoration:none}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:#d7dbe4;border-radius:10px;border:2px solid #fff}

/* ============ Shell ============ */
/* 🔻 🔴 **`100vh` REND L'ÉCRAN INATTEIGNABLE SUR SAFARI iOS** (Benjamin, 2026-09-16, sur iPad 9,7"
   en paysage : *« je ne peux pas faire défiler l'écran jusqu'en bas pour accéder au bas de la
   sidebar »*). Sur iOS, `100vh` vaut la hauteur de l'écran **sans** les barres du navigateur — 768
   points quand la zone visible en fait ~590. L'application était donc dessinée 180 points plus bas
   que le bord visible, et comme le document ne défile pas (c'est `.page` qui défile), ces 180
   points n'existaient pour personne.
   ⚠️ **MESURÉ AILLEURS, INVISIBLE AILLEURS** : à 1024 × 618 sous Chromium, rien n'est coupé. Aucun
   navigateur sans tête ne reproduit la barre dynamique d'iOS — ce défaut ne se voit que sur
   l'appareil, et c'est pour ça qu'il a vécu si longtemps.
   ⚠️ **LES DEUX LIGNES, DANS CET ORDRE** : `100vh` reste pour les navigateurs qui ignorent `dvh`,
   `100dvh` gagne partout ailleurs. Une seule des deux serait soit un défaut, soit une régression. */
.app{display:flex;height:100vh;height:100dvh;overflow:hidden}
.main{flex:1;min-width:0;display:flex;flex-direction:column}
/* ⚠️ C'est la ZONE qui défile, pas le document : `body` est en `overflow:hidden` pour que la
   sidebar et la barre du haut restent fixes. Une page qui ferait défiler le document entier
   emporterait le chrome avec elle. */
.page{flex:1;min-height:0;overflow-y:auto}

/* 🐛 🔻 **LES PAGES PUBLIQUES N'ONT PAS DE COQUILLE, ET ELLES NE DÉFILAIENT PLUS** (Benjamin et
   Jean-François, 2026-09-05 : *« le menu ne déroule pas après la fenêtre métiers et votre zone »*,
   sur Safari ET sur Chrome).
   `body{overflow:hidden}` juste au-dessus est juste pour l'application : c'est `.page` qui défile,
   et la colonne de gauche doit rester fixe. Mais `compte.html`, `pro-inscription.html` et
   `admin-connexion.html` n'ont **pas** de `.app` : elles héritaient d'un document qui ne défile
   pas, avec un conteneur en `min-height:100vh` — donc qui GRANDIT avec son contenu au lieu de le
   faire défiler. Tout ce qui dépassait la hauteur de l'écran était **inatteignable**.
   ⚠️ **`height`, PAS `min-height`** : c'est la différence entre un conteneur qui s'allonge hors du
   cadre et un conteneur qui devient la zone de défilement. Les pages gardent leur `min-height`,
   les deux propriétés coexistent.
   ⚠️ **LA RÈGLE VIT ICI, PAS DANS LES TROIS PAGES.** Écrite trois fois, elle aurait été oubliée
   par la quatrième — et une page publique qui ne défile pas ne se voit que si son formulaire est
   long. `admin-connexion.html` porte le même défaut depuis toujours et ne l'a jamais montré.
   ⚠️ **ET LE CENTRAGE NE DOIT PAS ROGNER** : `align-items:center` sur un conteneur qui déborde
   coupe le HAUT du contenu, hors d'atteinte du défilement. `margin:auto` sur l'enfant centre sans
   jamais rogner. */
.page-pub{height:100vh;height:100dvh;overflow-y:auto}

/* ---- L'œil du mot de passe (2026-09-04, descendu dans le socle le 2026-09-05) ----
   🔻 **IL ÉTAIT ÉCRIT DANS `compte.html`, ET `pro-inscription.html` EN AVAIT BESOIN À
   L'IDENTIQUE.** Le recopier aurait donné deux œils à maintenir — et c'est la quatrième fois de la
   semaine que la recopie serait le vrai défaut. Le style vit ici, le balisage dans
   `hello-shell.js` : un seul œil, deux écrans.
   ⚠️ **LE CHAMP GARDE SA LARGEUR, L'ŒIL SE POSE DESSUS.** À côté, il rétrécirait le champ de
   40 px sur toutes les pages, y compris là où il n'y a pas d'œil. */
.ch-mdp{position:relative}
.ch-mdp input{padding-right:44px}
.ch-oeil{
  position:absolute;right:6px;top:50%;transform:translateY(-50%);
  width:32px;height:32px;display:flex;align-items:center;justify-content:center;
  border:0;background:none;border-radius:8px;cursor:pointer;color:#8a93a8;padding:0;
}
.ch-oeil:hover{color:var(--primary-600);background:var(--primary-soft)}
.ch-oeil svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.9}
/* La barre oblique dit « masqué ». Elle disparaît quand le mot de passe est en clair : l'icône
   décrit l'ÉTAT, pas l'action — c'est ce qu'on lit d'un coup d'œil sans réfléchir. */
.ch-oeil.on{color:var(--primary-600)}
.ch-oeil.on .barre{display:none}
.page-pub[data-centre],.page-pub.centre{align-items:flex-start}
.page-pub[data-centre] > *,.page-pub.centre > *{margin:auto}

/* ---- Sidebar ---- */
.sidebar{
  width:var(--sidebar);flex:0 0 var(--sidebar);background:#fff;border-right:1px solid var(--border);
  display:flex;flex-direction:column;padding:22px 16px;transition:width .22s ease,flex-basis .22s ease;
  /* 🔻 **ET ELLE DÉFILE** (2026-09-16) : la correction de `dvh` suffit sur un iPad en paysage, mais
     un écran plus court — iPhone en paysage, fenêtre réduite, zoom du navigateur à 150 % — coupe
     encore le bloc du compte. Une ceinture, pas une rustine : l'unité corrige la hauteur, ceci
     rend le dépassement atteignable. ⚠️ `overscroll-behavior` empêche le geste de défilement de
     passer à la page derrière une fois la colonne au bout. */
  overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;
}
/* ⚠️ **DEVENU UN `<a>` LE 2026-09-04** : il faut donc annuler le soulignement et la couleur de
   lien hérités, sinon le logo se met à porter les attributs d'un lien texte. Le curseur, lui,
   doit rester une main — c'est ce qui dit qu'on peut cliquer. */
.brand{display:flex;align-items:center;padding:2px 6px 22px;overflow:hidden;
  text-decoration:none;color:inherit;border-radius:10px}
.brand:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
/* Le logo a un ratio de 3,38 : posé en fond, on peut n'en montrer que la pastille « smiley »
   une fois la sidebar repliée, au lieu de le tronquer. */
.brand .brand-logo{
  height:38px;width:130px;flex:0 0 auto;
  background:url('logo-hello-violet.png') left center/auto 100% no-repeat;
  transition:width .22s ease;
}

/* ============================================================================
   🔻 LA SIDEBAR DU PROFESSIONNEL — SOMBRE, ET ÉTIQUETÉE (Benjamin, 2026-08-20)
   ----------------------------------------------------------------------------
   Deux interfaces qui se ressemblent trait pour trait finissent par être confondues, et se
   tromper de côté n'est pas anodin ici : le particulier et le pro ne voient pas les mêmes
   projets, ne dépensent pas les mêmes choses, n'ont pas les mêmes droits.

   ⚠️ **ON REDÉFINIT LES TOKENS, ON NE REPEINT PAS LES ÉLÉMENTS UN PAR UN.** Toute la sidebar est
   écrite avec `--text`, `--text-2`, `--border`… : les redéclarer sur `[data-role="pro"]` suffit,
   et **une entrée de menu ajoutée demain sera sombre sans qu'on y pense**. Repeindre `.nav a`,
   `.compte`, `.promo` un par un aurait garanti d'en oublier un — c'est la leçon des trois
   compteurs, transposée au style.

   ✅ **LE LOGO BLANC EXISTE, ET C'EST LUI QU'ON UTILISE** (Benjamin, 2026-08-20).
   `assets/logo-hello-blanc.png` (330 × 98, ratio 3,37 — le violet est à 3,38, les deux cadrent
   donc pareil et la sidebar ne change pas de proportions selon le rôle).
   ⚠️ **Extrait de la planche « USAGES MONOCHROMES · SUR FOND FONCÉ »**, détouré par la
   LUMINANCE : le logo est blanc pur sur un navy uni, donc la luminance EST l'alpha — et les
   bords antialiasés récupèrent une transparence partielle au lieu d'un liseré sombre. Un keying
   « couleur == navy » aurait laissé un halo sur chaque pixel intermédiaire.
   ⚠️ **LE BASELINE EST EXCLU DU CADRAGE** : « Votre relation client, simplement. » vient du
   template CRM et ne s'applique pas à Hello (décision de cadrage n°3). Le logo violet a été
   recadré de la même façon en juillet — les deux doivent montrer la même chose.
   🐛 Avant ça : j'avais tenté `brightness(0) invert(1)` sur le logo violet, qui a rendu un
   rectangle blanc plein. Son PNG déclare un canal alpha (type 6) mais son fond est opaque —
   **un canal alpha présent ne veut pas dire un fond transparent.** L'outil d'extraction vit dans
   `outils/logo-blanc.js` si la planche évolue.
   ============================================================================ */
.sidebar[data-role="pro"],
.sidebar[data-role="admin"]{
  --text:#f2f4fa;
  --text-2:#b9c0d4;
  --muted:#7e8699;
  --border:rgba(255,255,255,.09);
  --border-2:rgba(255,255,255,.14);
  --primary-soft:rgba(139,110,255,.20);
  --primary-soft-2:rgba(139,110,255,.28);
  --primary-600:#c3b2ff;
  --primary-700:#d5c9ff;
  /* ⚠️ `--ink-violet` sert au titre du bloc conseiller : oublié, il laissait « Besoin d'un coup
     de main ? » en violet sombre sur fond sombre, donc illisible. **Un token qu'on ne redéfinit
     pas dans un thème inversé est un texte qu'on perd** — et il ne se voit qu'à l'œil. */
  --ink-violet:#e6e0ff;
  background:#171d31;
  border-right-color:rgba(255,255,255,.08);
}
/* ============================================================================
   🔻 L'ADMINISTRATION EST ROUGE (Benjamin, 2026-08-25) — bande noire depuis le 2026-09-04
   ----------------------------------------------------------------------------
   *« je veux pouvoir bien différencier sur quel compte je suis »*. La sidebar admin était un
   navy à peine plus sombre que celle du pro : deux colonnes sombres côte à côte se confondent,
   et se tromper de face n'est pas anodin — celle-ci valide des comptes, crédite des soldes et
   dépose des factures.
   ⚠️ **DEPUIS LE 2026-09-04, LA BANDE ELLE-MÊME EST NOIRE** (`#101217`) et ce sont les ACCENTS
   qui portent le rouge. Le repère a changé de support, pas disparu — mais il est redevenu plus
   ténu qu'en août : si les deux colonnes se confondent de nouveau à l'usage, c'est ici qu'il
   faudra reprendre.

   ⚠️ **LE ROUGE DU CHROME N'EST PAS LE ROUGE D'ALERTE, ET LES DEUX COEXISTENT SUR L'ÉCRAN.**
   `--red` (#e0483d) reste réservé à l'état « critique » — une échéance dépassée, un rappel
   manqué. Le chrome prend un **carmin plus sombre et moins orangé** (#a81d2c), qui ne se
   confond pas avec lui à côté. ⚠️ **Et les alertes ne s'appuient jamais sur la seule couleur** :
   icône + libellé + fond teinté, c'est ce qui les tient sur un écran devenu rouge.

   ⚠️ **LES GRAPHIQUES NE SUIVENT PAS LE CHROME.** Leurs barres restent violettes : la donnée et
   le décor sont deux canaux distincts, et des barres rouges sur un écran dont les alertes sont
   rouges feraient lire une valeur comme un avertissement.
   ============================================================================ */
.sidebar[data-role="admin"]{
  --primary-soft:rgba(255,120,130,.18);
  --primary-soft-2:rgba(255,120,130,.26);
  --primary-600:#ffb8bd;
  --primary-700:#ffd4d7;
  --ink-violet:#ffe2e4;
  /* 🔻 **LA BANDE EST PASSÉE AU NOIR LE 2026-09-04** (Benjamin : *« je voudrais que tu passes la
     bande de la sidebar de rouge à noir »*). Le carmin `#4e121c` était très présent sur toute la
     hauteur de l'écran.
     ⚠️ **LES ACCENTS RESTENT ROUGES, ET C'EST CE QUI SAUVE LA DISTINCTION.** Le rouge existait
     parce que *« deux colonnes sombres côte à côte se confondent »* — et le noir rapproche à
     nouveau cette colonne du navy `#171d31` du pro. Ce sont donc les accents (icônes, avatar,
     survols, et tout le chrome de la page via `.app[data-role="admin"]`) qui portent désormais le
     signal seuls. *On a déplacé le repère, on ne l'a pas retiré.*
     ⚠️ Pas `#000` : un noir absolu à côté d'un contenu blanc se lit comme un trou dans l'écran. */
  background:#101217;
  border-right-color:rgba(255,255,255,.10);
}
.sidebar[data-role="admin"] .nav svg{stroke:#d99aa2}
.sidebar[data-role="admin"] .compte-av{background:rgba(255,120,130,.22);color:#ffd4d7}

/* 🔻 **LE RÔLE SE PORTE AUSSI SUR `.app`, ET C'EST CE QUI TEINTE LA PAGE.** Sans cela, seule la
   colonne changeait : les boutons, les liens et les badges restaient violets, et l'écran ne
   disait plus d'une seule voix où l'on se trouve. ⚠️ On redéfinit **les tokens**, jamais les
   éléments : un bouton ajouté demain sera rouge sans qu'on y pense. */
.app[data-role="admin"]{
  --primary:#b3202f;
  --primary-600:#a81d2c;
  --primary-700:#8a1523;
  --primary-soft:#fdecee;
  --primary-soft-2:#f8d8dc;
  --ink-violet:#4a0d17;
  --btn-1:#c9293b;
  --btn-2:#a81d2c;
  --btn-ombre:rgba(168,29,44,.26);
  --focus-bord:#eeb6bd;
  --focus-fond:#fffafa;
}
.sidebar[data-role="pro"] .brand-logo,
.sidebar[data-role="admin"] .brand-logo{
  background-image:url('logo-hello-blanc.png');
}
.sidebar[data-role="pro"] .nav svg,
.sidebar[data-role="admin"] .nav svg{stroke:#8892a8}
.sidebar[data-role="pro"] .nav a:hover,.sidebar[data-role="pro"] .nav button:hover,
.sidebar[data-role="admin"] .nav a:hover,.sidebar[data-role="admin"] .nav button:hover{
  background:rgba(255,255,255,.06);
}
/* Le bloc « conseiller » est un objet clair posé sur du sombre : on le rend sourd plutôt que de
   le repeindre, sinon il devient la chose la plus lumineuse d'une colonne qui doit s'effacer. */
.sidebar[data-role="pro"] .promo,
.sidebar[data-role="admin"] .promo{
  background:rgba(255,255,255,.05);border-color:rgba(255,255,255,.10);
}
/* Le pictogramme de support : sobre, sur le fond sombre. ⚠️ Pas de pastille blanche ici — le
   `.p-ico` du parcours particulier en porte une, qui ferait une tache sur une colonne sombre. */
.promo[data-pro="1"] .p-ico{
  background:rgba(139,110,255,.20);box-shadow:none;width:32px;height:32px;
}
.promo[data-pro="1"] .p-ico svg{width:18px;height:18px;stroke:#c3b2ff;fill:none;stroke-width:1.9}
.sidebar[data-role="pro"] .compte-av,
.sidebar[data-role="admin"] .compte-av{background:rgba(139,110,255,.22);color:#d5c9ff}
.sidebar[data-role="pro"] .apercu:hover,
.sidebar[data-role="admin"] .apercu:hover{background:rgba(255,255,255,.07)}

/* ---- L'étiquette de contexte ----
   ⚠️ **ELLE N'EST PAS DANS LE LOGO.** « Hello PRO » n'existe pas comme marque : c'est Hello, vu
   par un professionnel. D'où une pastille posée À CÔTÉ, qui se retire sans toucher au logo.
   ⚠️ Elle disparaît avec la sidebar repliée : sur 72 px, le logo devient une pastille et il n'y a
   plus de place pour un mot — mieux vaut rien qu'un fragment. */
.brand-role{
  margin-left:9px;padding:3px 8px;border-radius:7px;
  font-size:10.5px;font-weight:800;letter-spacing:.10em;
  background:var(--primary);color:#fff;white-space:nowrap;
}
/* ⚠️ **SUR UNE COLONNE ROUGE, UNE PASTILLE ROUGE DISPARAÎT** (2026-08-25) : l'étiquette
   ADMIN était grise sur du navy, elle serait invisible sur du carmin. Un voile clair la
   détache sans introduire une quatrième couleur. */
.brand-role[data-a="1"]{background:rgba(255,255,255,.20);color:#fff}
.sidebar.mini .brand-role{display:none}

.nav{display:flex;flex-direction:column;gap:3px;margin-top:4px}
.nav a,.nav button{
  display:flex;align-items:center;gap:12px;padding:10px 12px;border-radius:10px;width:100%;
  color:var(--text-2);font-weight:600;font-size:14px;transition:.15s;position:relative;text-align:left;
}
.nav svg{width:20px;height:20px;flex:0 0 20px;stroke:#9aa2b4;fill:none;stroke-width:1.8}
.nav .lbl{white-space:nowrap;overflow:hidden}
.nav a:hover,.nav button:hover{background:#f6f7fa;color:var(--text)}
.nav .active{background:var(--primary-soft);color:var(--primary-600)}
.nav .active svg{stroke:var(--primary-600)}
/* ⚠️ **UNE ENTRÉE QUI NE MÈNE NULLE PART LE DIT.** Trois pages de la sidebar n'existent pas
   encore. Les laisser cliquables enverrait sur un 404 ; les masquer ferait croire que le
   produit s'arrête là. Elles restent visibles, éteintes, et l'infobulle donne la raison. */
.nav [aria-disabled="true"]{opacity:.45;cursor:default}
.nav [aria-disabled="true"]:hover{background:none;color:var(--text-2)}

/* Pastille de compteur d'une entrée de menu (messagerie non lue). */
.nav-n{
  margin-left:auto;flex:0 0 auto;min-width:21px;height:21px;padding:0 6px;border-radius:11px;
  background:var(--primary-soft-2);color:var(--primary-700);font-size:11.5px;font-weight:800;
  display:flex;align-items:center;justify-content:center;
}
.sidebar.mini .nav-n{display:none}

/* 🔻 **LE POINT VIOLET** (Benjamin, 2026-09-08) — il dit *qu'il y a quelque chose*, quand la
   pastille chiffrée dit *combien*. Une seule dimension, deux marques : elles sortent du même
   nombre et ne peuvent pas se contredire.
   ⚠️ **IL TIENT SUR L'ICÔNE, PAS EN BOUT DE LIGNE.** `.nav-n` disparaît quand la barre se
   replie (règle juste au-dessus) : sur un écran étroit — là où l'on consulte ses messages — plus
   rien n'alertait. *Un témoin qui s'efface quand la place manque alerte seulement quand tout va
   déjà bien.* Ancré à l'icône, il survit aux deux états de la barre.
   ⚠️ **`position:relative` EST DÉJÀ SUR L'ENTRÉE** (`.nav a`), donc l'ancrage ne coûte rien —
   mais il en dépend : le retirer ferait fuir le point vers le coin de la page. */
.nav-pt{
  position:absolute;left:23px;top:8px;width:8px;height:8px;border-radius:50%;
  background:var(--primary);
  /* Le liseré blanc détache le point de l'icône qu'il chevauche : sans lui, il se lit comme un
     trait du pictogramme et cesse d'être une alerte. */
  box-shadow:0 0 0 2px #fff;
}
.nav .active .nav-pt{box-shadow:0 0 0 2px var(--primary-soft)}

.side-spacer{flex:1}
.promo{
  background:linear-gradient(160deg,#f3f0ff,#eef3ff);border:1px solid #e7e6fb;
  border-radius:14px;padding:16px;margin-top:12px;overflow:hidden;
}
.promo .p-ico{
  width:30px;height:30px;border-radius:9px;background:#fff;display:flex;align-items:center;
  justify-content:center;box-shadow:var(--shadow);margin-bottom:10px;
}
.promo .p-ico svg{width:17px;height:17px;stroke:var(--primary-600);fill:none;stroke-width:2}
/* Le portrait de la conseillère, à la place de l'ancien pictogramme. */
.promo .p-av{
  width:52px;height:52px;border-radius:50%;overflow:hidden;margin-bottom:10px;
  background:linear-gradient(160deg,#efe9ff,#e2ecff);
  box-shadow:0 0 0 3px #fff, 0 0 0 4px var(--primary-soft-2);
}
.promo .p-av img{width:100%;height:100%;object-fit:cover;display:block}
.sidebar.mini .promo .p-av{margin:0 auto 10px;width:40px;height:40px}
.promo b{font-size:14px;color:var(--ink-violet);white-space:nowrap}
.promo p{margin:4px 0 12px;font-size:12.5px;color:var(--text-2)}
.promo button{
  width:100%;padding:9px;border-radius:9px;
  background:linear-gradient(135deg,var(--btn-1),var(--btn-2));color:#fff;font-weight:700;font-size:13px;
  box-shadow:0 2px 8px var(--btn-ombre);white-space:nowrap;
}
.promo button:hover{filter:brightness(1.05)}

/* ---- Le bloc COMPTE, en pied de sidebar (maquette du 2026-08-12) ----
   Il a pris la place du bouton « Réduire » du proto, qui ne figure pas sur la maquette. */
/* ---- L'interrupteur d'aperçu de démonstration (2026-08-19) ----
   ⚠️ Discret mais PERMANENT, et jamais grisé : c'est une commande d'auteur, pas une
   fonctionnalité du produit — mais une commande qu'on ne voit pas est une commande qui
   n'existe pas, et c'est précisément ce qui s'est passé. La pastille dit l'état AVANT le
   texte : on cherche « est-ce allumé ? », pas « comment ça s'appelle ? ». */
.apercu{
  display:flex;align-items:center;gap:9px;margin-top:14px;padding:9px 11px;border-radius:10px;
  border:1px dashed var(--border-2);font-size:12px;color:var(--muted);text-decoration:none;
  transition:background .15s,border-color .15s;
}
.apercu:hover{background:var(--primary-soft);border-color:var(--primary);color:var(--primary-700)}
.ap-txt{flex:1;min-width:0}
.ap-txt b{display:block;font-size:12px;font-weight:700;color:var(--text-2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ap-txt em{display:block;font-style:normal;font-size:11px;color:var(--muted)}
.apercu:hover .ap-txt b,.apercu:hover .ap-txt em{color:var(--primary-700)}
.ap-pt{
  width:8px;height:8px;flex:0 0 8px;border-radius:50%;background:var(--border-2);
}
.ap-pt[data-on="1"]{background:var(--primary);box-shadow:0 0 0 3px var(--primary-soft)}
.apercu:has(.ap-pt[data-on="1"]){border-style:solid;border-color:var(--primary);color:var(--primary-700)}

/* ⚠️ **DEVENU UN `<a>` LE 2026-09-04** — comme le logo avant lui : il faut donc annuler le
   soulignement et la couleur hérités, sinon le bloc se met à porter les attributs d'un lien
   texte. Et un retour visuel au survol, sans quoi rien ne dit qu'il mène quelque part — c'est
   très exactement le défaut qu'on corrige. */
.compte{
  display:flex;align-items:center;gap:11px;margin-top:16px;padding-top:16px;
  border-top:1px solid var(--border);
  text-decoration:none;color:inherit;border-radius:11px;
}
a.compte{margin-left:-6px;margin-right:-6px;padding-left:6px;padding-right:6px}
a.compte:hover{background:var(--primary-soft)}
.sidebar[data-role="pro"] a.compte:hover,
.sidebar[data-role="admin"] a.compte:hover{background:rgba(255,255,255,.06)}
a.compte:focus-visible{outline:2px solid var(--primary);outline-offset:1px}
.compte-av{
  width:34px;height:34px;flex:0 0 34px;border-radius:50%;background:var(--primary-soft);
  color:var(--primary-700);font-weight:800;font-size:14px;
  display:flex;align-items:center;justify-content:center;
}
.compte-txt{flex:1;min-width:0}
.compte-txt b{display:block;font-size:13.5px;font-weight:700;color:var(--text);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.compte-txt span{display:block;font-size:12px;color:var(--muted)}
.compte-cloche{
  flex:0 0 auto;width:32px;height:32px;border-radius:9px;display:flex;
  align-items:center;justify-content:center;color:var(--muted);
}
.compte-cloche:hover{background:#f6f7fa;color:var(--text-2)}
.compte-cloche svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.9}
.sidebar.mini .compte-txt,.sidebar.mini .compte-cloche{display:none}
.sidebar.mini .compte{justify-content:center}

/* --- Replié : icônes seules, logo réduit à la pastille --- */
.sidebar.mini{width:var(--sidebar-min);flex-basis:var(--sidebar-min);padding:22px 14px}
.sidebar.mini .brand{justify-content:center;padding-left:0;padding-right:0}
.sidebar.mini .brand .brand-logo{width:38px}
.sidebar.mini .nav a,.sidebar.mini .nav button{justify-content:center;padding:11px 0}
.sidebar.mini .nav .lbl,
.sidebar.mini .promo p,
.sidebar.mini .promo b{display:none}
.sidebar.mini .promo{padding:12px 10px}
.sidebar.mini .promo .p-ico{margin:0 auto 10px}
.nav .tip{
  position:absolute;left:calc(100% + 10px);top:50%;transform:translateY(-50%);background:#20263a;
  color:#fff;font-size:12px;font-weight:600;padding:5px 9px;border-radius:7px;white-space:nowrap;
  opacity:0;pointer-events:none;transition:.15s;z-index:60;display:none;
}
.sidebar.mini .nav .tip{display:block}
.sidebar.mini .nav a:hover .tip,
.sidebar.mini .nav button:hover .tip{opacity:1}
/* Une entrée éteinte garde son infobulle MÊME dépliée : c'est là qu'est la raison. */
.nav [aria-disabled="true"] .tip{display:block}
.nav [aria-disabled="true"]:hover .tip{opacity:1}

/* ---- Barre du haut ---- */
.topbar{
  height:var(--topbar);flex:0 0 var(--topbar);background:#fff;border-bottom:1px solid var(--border);
  display:flex;align-items:center;gap:18px;padding:0 20px;
}
.topbar h1{margin:0;font-size:15px;font-weight:700;color:var(--text);letter-spacing:-.1px}
.top-right{display:flex;align-items:center;gap:10px;margin-left:auto}
.back{
  display:flex;align-items:center;gap:8px;color:var(--text-2);font-weight:600;font-size:13.5px;
  padding:7px 11px;border-radius:9px;
}
.back:hover{background:#f5f6f9}
.back svg{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:2}

/* ============ Boutons ============ */
.btn-ghost{
  padding:9px 14px;border-radius:10px;border:1px solid var(--border-2);background:#fff;
  font-weight:600;font-size:13.5px;color:var(--text-2);display:inline-flex;align-items:center;gap:8px;
}
.btn-ghost:hover{background:#f7f8fa}
.btn-primary{
  padding:10px 18px;border-radius:10px;font-weight:700;font-size:13.5px;color:#fff;
  background:linear-gradient(135deg,var(--btn-1),var(--btn-2));box-shadow:0 2px 8px var(--btn-ombre);
  display:inline-flex;align-items:center;gap:8px;
}
.btn-primary:hover{filter:brightness(1.06)}
/* ⚠️ Un bouton désactivé doit se VOIR désactivé. Sans cette règle, « Confirmer » gardait son
   violet plein et son ombre : l'utilisateur clique, rien ne se passe, et il cherche l'erreur
   chez lui. L'attribut `disabled` sans style est un piège, pas une protection. */
.btn-primary:disabled,.btn-ghost:disabled{opacity:.45;cursor:not-allowed;box-shadow:none}
.btn-primary:disabled:hover,.btn-ghost:disabled:hover{filter:none;background:inherit}
.btn-primary svg,.btn-ghost svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2.2}

/* 🐛 🔻 **`.btn-mini` ÉTAIT UTILISÉ PAR TROIS ÉCRANS ET DÉFINI DANS UN SEUL** — le
   configurateur, qui ne le partage avec personne. « Marquer appelé » du planning des rappels et
   « Précédent / Suivant » de la liste des projets sortaient donc en **bouton nu du navigateur**,
   gris et carré, au milieu d'écrans dessinés. Rien ne le signalait : une classe sans règle ne
   casse pas une page, elle la laisse simplement se peindre autrement — et le navigateur ne
   trouve rien à redire à un nom de classe qu'aucune feuille ne connaît.
   ⚠️ **REMONTÉ ICI, PAS RECOPIÉ** : trois copies auraient divergé au premier ajustement, comme
   `jour()` recopié six fois disait « 1 nov. » cinq fois et « 1 novembre » une. Le configurateur
   garde la sienne pour l'instant — il est autoportant par construction — et c'est la seule
   duplication assumée. */
.btn-mini{
  padding:6px 11px;border:1px solid var(--border-2);border-radius:8px;background:#fff;
  font:inherit;font-size:11.5px;font-weight:700;color:var(--text-2);cursor:pointer;
}
.btn-mini:hover{border-color:var(--focus-bord);color:var(--primary-600)}
/* ⚠️ Même règle que les deux autres boutons : `disabled` sans style est un piège. */
.btn-mini:disabled{opacity:.45;cursor:not-allowed}
.btn-mini:disabled:hover{border-color:var(--border-2);color:var(--text-2)}

/* 🐛 **LA MÊME HISTOIRE QUE `.btn-mini`, LE MÊME JOUR.** Trois écrans d'administration —
   projets, données, comptes pro — définissaient chacun leur `.pagination`, à l'identique. La
   quatrième copie était en train d'être écrite quand je m'en suis aperçu.
   ⚠️ **CE N'EST PAS UNE ÉCONOMIE DE LIGNES, C'EST UNE ÉCONOMIE DE DIVERGENCE** : trois copies
   d'une même règle se ressemblent le premier jour et plus jamais ensuite. Remontée ici, elle
   n'a plus qu'un endroit où changer. */
.pagination{
  display:flex;gap:10px;align-items:center;margin-top:14px;
  font-size:12.5px;color:var(--text-2);flex-wrap:wrap;
}

/* ============ Blocs de contenu ============ */
.wrap{padding:26px 30px 40px;max-width:1180px}
/* 🔻 **1180 px CONVIENT À UN TEXTE, PAS À UN COCKPIT** (Benjamin, 2026-09-09 : *« la largeur de
   mon écran n'est pas exploitée comme il le faudrait »*). Le plafond existe pour la lecture : une
   ligne de 1600 px se relit mal, et la plupart des écrans de Hello sont des colonnes de texte.
   ⚠️ **MAIS LE RADAR N'EST PAS UNE PAGE, C'EST UN TABLEAU DE BORD** : deux colonnes qui se
   répondent, un dessin d'un côté, des fiches de l'autre. Sur un écran de 1920, il perdait plus de
   500 px — *une largeur qu'on n'utilise pas n'est pas de la respiration, c'est du gâchis quand
   les deux colonnes se serrent au même moment.*
   ⚠️ **UN MODIFICATEUR, PAS UN NOUVEAU PLAFOND POUR TOUT LE MONDE.** Élargir `.wrap` partout
   aurait allongé les lignes de la messagerie et des fiches, où le plafond fait son travail. */
.wrap.large{max-width:1760px}
.tete{margin-bottom:22px}
.tete h2{margin:0 0 4px;font-size:21px;font-weight:800;letter-spacing:-.2px;color:var(--text)}
.tete p{margin:0;font-size:13px;color:var(--text-2)}

.bloc{margin-bottom:28px}
.bloc-tete{display:flex;align-items:baseline;gap:12px;margin-bottom:12px}
.bloc-tete h3{margin:0;font-size:15px;font-weight:800;color:var(--text);letter-spacing:-.1px}
.bloc-tete .lien{margin-left:auto;font-size:13px;font-weight:600;color:var(--primary-600)}
.bloc-tete .lien:hover{text-decoration:underline}

.carte{
  background:#fff;border:1px solid var(--border-2);border-radius:var(--radius);padding:16px 18px;
}

/* ---- Badges et pastilles d'état ---- */
.badge{
  display:inline-block;font-size:11.5px;font-weight:700;padding:5px 11px;border-radius:20px;
  background:#eef0f4;color:var(--muted);white-space:nowrap;
}
.badge[data-ton="violet"]{background:var(--primary-soft);color:var(--primary-600)}
.badge[data-ton="vert"]{background:var(--green-bg);color:var(--green)}
.badge[data-ton="orange"]{background:var(--orange-bg);color:var(--orange)}
.badge[data-ton="bleu"]{background:var(--blue-bg);color:var(--blue)}
.badge[data-ton="rouge"]{background:var(--red-bg);color:var(--red)}

/* ---- Bandeau d'avertissement (dépôt volatil, mode démo…) ----
   ⚠️ Un état dégradé se DIT. C'est la règle du `Depot` depuis le 2026-08-05 : un brouillon
   silencieusement perdu est pire que pas de brouillon. */
.bandeau{
  display:flex;align-items:center;gap:10px;padding:11px 15px;border-radius:11px;
  font-size:13px;font-weight:600;margin-bottom:18px;
}
.bandeau svg{width:17px;height:17px;flex:0 0 17px;stroke:currentColor;fill:none;stroke-width:2}
.bandeau[data-ton="orange"]{background:var(--orange-bg);color:#8a5a10;border:1px solid #f3dcb4}
.bandeau[data-ton="violet"]{background:var(--primary-soft);color:var(--primary-700);border:1px solid #ddd4ff}
.bandeau .b-fin{margin-left:auto;font-weight:700;white-space:nowrap}

/* ============ FENÊTRE MODALE ============
   ⚠️ Elle vit dans le SOCLE parce que son déclencheur y vit : « Être rappelé » est dans la
   promo de la sidebar, donc sur toutes les pages. L'écrire dans une page l'aurait rendue
   indisponible depuis les autres — ou dupliquée, ce qui est pire. */
.mask{
  position:fixed;inset:0;background:rgba(20,26,48,.42);backdrop-filter:blur(2px);
  display:flex;align-items:center;justify-content:center;padding:24px;z-index:200;
  opacity:0;pointer-events:none;transition:opacity .18s;
}
.mask.on{opacity:1;pointer-events:auto}
.modal{
  background:#fff;border-radius:18px;box-shadow:0 18px 60px rgba(20,30,60,.22);
  width:min(560px,100%);max-height:calc(100vh - 48px);max-height:calc(100dvh - 48px);
  display:flex;flex-direction:column;
  transform:translateY(8px);transition:transform .18s;
}
.mask.on .modal{transform:none}
.modal-h{display:flex;align-items:flex-start;gap:14px;padding:22px 24px 14px}
.modal-av{
  flex:0 0 52px;width:52px;height:52px;border-radius:50%;overflow:hidden;
  background:linear-gradient(160deg,#efe9ff,#e2ecff);
  box-shadow:0 0 0 3px #fff, 0 0 0 4px var(--primary-soft-2);
}
.modal-av img{width:100%;height:100%;object-fit:cover;display:block}
.modal-h .t{flex:1;min-width:0}
.modal-h b{display:block;font-size:18px;font-weight:800;color:var(--text);letter-spacing:-.3px}
.modal-h p{margin:4px 0 0;font-size:13px;color:var(--text-2);line-height:1.5}
.modal-x{
  flex:0 0 34px;width:34px;height:34px;border-radius:10px;color:var(--muted);
  display:flex;align-items:center;justify-content:center;
}
.modal-x:hover{background:#f5f6f9;color:var(--text-2)}
.modal-x svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:2.2}
.modal-c{padding:4px 24px 8px;overflow-y:auto}
.modal-f{
  display:flex;align-items:center;gap:12px;padding:16px 24px 22px;border-top:1px solid var(--border);
  margin-top:12px;
}
.modal-f .note{flex:1;min-width:0;font-size:12px;color:var(--muted);line-height:1.4}
.modal-lg{display:block;font-size:12px;font-weight:700;color:var(--text-2);margin:16px 0 8px;
  letter-spacing:.2px}

/* ---- La fiche d'un professionnel (assets/fiche-pro.js) ----
   ⚠️ Ces règles vivaient dans `professionnels.html`. Elles ont suivi le gabarit dans le socle
   le jour où la messagerie a dû montrer la même fiche : un style resté derrière aurait donné
   la même fiche à deux apparences, ce qui est pire que deux fiches assumées. */
.fiche-h{display:flex;align-items:center;gap:16px;margin-bottom:4px}
.fiche-logo{
  flex:0 0 104px;width:104px;height:70px;border-radius:11px;background:var(--primary-soft);
  color:var(--primary-700);font-size:18px;font-weight:800;
  display:flex;align-items:center;justify-content:center;overflow:hidden;
}
.fiche-logo.img{background:none}
.fiche-logo img{width:100%;height:100%;object-fit:contain;display:block}
.fiche-dl{display:grid;grid-template-columns:132px 1fr;gap:9px 14px;margin:16px 0 0;font-size:13.5px}
.fiche-dl dt{color:var(--muted);font-weight:600}
.fiche-dl dd{margin:0;color:var(--text);font-weight:600}
.puces{display:flex;gap:6px;flex-wrap:wrap}
/* 🐛 ⚠️ **UN SVG SANS TAILLE PREND TOUTE LA PLACE, ET SANS `fill` IL EST NOIR.** Écrite en
   styles EN LIGNE, la mention n'héritait d'aucune règle `svg` : l'icône d'information sortait
   en disque noir de 180 px au milieu de la fiche. Les styles en ligne ne portent que ce qu'on
   y met — un `<svg>` a besoin de sa largeur, de sa hauteur, de `fill:none` et de son trait. */
/* 🔻 **LES CHANTIERS PRÉSENTÉS PAR UNE ENTREPRISE** (2026-09-12). La fiche ne montrait que des
   vérifications administratives — ce que Hello a contrôlé — et promettait les photos
   « prochainement » depuis le 2026-08-19.
   ⚠️ **DEUX PAR LIGNE, PAS TROIS.** À 180 px de large dans une fenêtre de 560, une photo de
   chantier ne montre plus ni la pose ni les proportions : elle devient une vignette décorative,
   c'est-à-dire exactement ce qu'on ne veut pas d'un élément de décision. */
.fiche-real{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:12px;margin-top:16px;
}
.fiche-real .fr{
  display:block;border:1px solid var(--border-2);border-radius:12px;overflow:hidden;
  background:#fff;text-decoration:none;color:inherit;
}
.fiche-real .fr:hover{border-color:var(--focus-bord)}
.fiche-real img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;background:#eef0f4}
.fiche-real b{display:block;padding:9px 11px 0;font-size:12.5px;font-weight:700;line-height:1.4}
.fiche-real span{display:block;padding:3px 11px 10px;font-size:11.5px;color:var(--muted)}
/* ⚠️ Sans le `:has`, un titre seul laisserait 11 px de vide sous lui : la marge basse vit sur la
   légende, qui n'existe pas toujours. */
.fiche-real .fr:not(:has(span)) b{padding-bottom:10px}

.fiche-note{
  display:flex;gap:9px;align-items:flex-start;font-size:12.5px;color:var(--text-2);
  background:#fbfbfd;border:1px solid var(--border);border-radius:11px;
  padding:12px 14px;margin-top:16px;
}
.fiche-note svg{
  width:15px;height:15px;flex:0 0 15px;stroke:var(--muted);fill:none;stroke-width:2;margin-top:2px;
}
/* Les gages : ce que Hello a vérifié. Ils remplacent la note étoilée des maquettes. */
.gage{
  display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:700;
  padding:5px 10px;border-radius:20px;background:#eef0f4;color:var(--text-2);white-space:nowrap;
}
.gage svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2}
/* Un seul gage est mis en avant : celui que Hello délivre lui-même. Les autres sont des pièces
   du pro, vérifiées mais pas décernées — la nuance mérite une couleur. */
.gage.ok{background:var(--green-bg);color:var(--green)}

/* Les jours, en onglets ; les créneaux, en grille. */
.jours{display:flex;gap:8px;overflow-x:auto;padding-bottom:2px}
.jour{
  flex:0 0 auto;padding:9px 14px;border-radius:11px;border:1px solid var(--border-2);
  background:#fff;font-size:13px;font-weight:600;color:var(--text-2);white-space:nowrap;
}
.jour:hover{background:#f7f8fa}
.jour.on{background:var(--primary-soft);border-color:#d6cbff;color:var(--primary-700);font-weight:700}
.creneaux{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:8px}
.creneau{
  padding:11px 8px;border-radius:11px;border:1px solid var(--border-2);background:#fff;
  font-size:13px;font-weight:600;color:var(--text);
}
.creneau:hover:not(:disabled){border-color:var(--focus-bord);background:var(--focus-fond)}
.creneau.on{background:var(--primary-600);border-color:var(--primary-600);color:#fff;font-weight:700}
/* ⚠️ Un créneau passé se voit ET ne se clique pas : le griser sans le désactiver laisserait
   choisir une heure révolue, et l'erreur n'apparaîtrait qu'au moment de l'appel. */
.creneau:disabled{opacity:.38;cursor:not-allowed;text-decoration:line-through}
.champ{
  width:100%;padding:11px 13px;border:1px solid var(--border-2);border-radius:11px;
  font-size:13.5px;color:var(--text);background:#fff;outline:none;
}
.champ:focus{border-color:var(--focus-bord);box-shadow:0 0 0 3px var(--primary-soft)}
.champ[aria-invalid="true"]{border-color:var(--red);background:var(--red-bg)}
.champ-err{display:none;font-size:12px;color:var(--red);margin-top:6px;font-weight:600}
.champ[aria-invalid="true"] ~ .champ-err{display:block}

/* ---- Vide assumé ----
   ⚠️ Un écran vide explique POURQUOI il l'est et ce qui le remplira. « Aucun résultat » tout
   seul se lit comme une panne. */
.vide{
  border:1px dashed var(--border-2);border-radius:var(--radius);padding:26px 22px;
  text-align:center;color:var(--text-2);background:#fbfbfd;
}
/* 🐛 `>` obligatoire : écrite `\.vide b`, la règle attrapait aussi les `<b>` d'emphase à
   l'intérieur des paragraphes et les passait en bloc — « quand VOUS décidez » se retrouvait
   seul sur sa ligne, au milieu d'une phrase coupée en trois. Un sélecteur de titre doit viser
   le titre, pas tout ce qui lui ressemble. */
.vide > b{display:block;font-size:14px;color:var(--text);margin-bottom:4px}
.vide p{margin:0;font-size:13px;max-width:460px;margin-inline:auto}

/* ============================================================================
   LA MESSAGERIE — le gabarit partagé (remonté ici le 2026-08-20)
   ----------------------------------------------------------------------------
   ⚠️ Ces règles vivaient dans `messagerie.html`. Elles montent dans le socle le jour où une
   SECONDE page en a besoin — la messagerie du professionnel — exactement comme la fiche pro l'a
   fait le 2026-08-13. La consigne était écrite en tête de `messagerie.html` : « ce qui servira
   aussi à une autre page remontera QUAND cette page existera, pas par anticipation ». Elle
   existe.
   ⚠️ **Recopier le gabarit aurait donné deux messageries qui divergent.** Sur ce projet, tout ce
   qui a été représenté deux fois a fini par diverger : deux sidebars, deux docks, deux listes de
   pages. Une messagerie qui diverge, c'est un particulier et un pro qui ne voient pas le même
   fil — le défaut le plus coûteux qu'on puisse fabriquer ici.
   ⚠️ Ce qui N'EST PAS monté : la mention « candidature à examiner » et le panneau d'ouverture
   (`.conv-att`, `.ouv-*`). Ce sont des gestes de PARTICULIER — lui seul ouvre une discussion
   (R2). Le socle ne porte que le partagé, sinon il redevient une seconde copie du même fichier.
   ============================================================================ */
/* ⚠️ CE QUI N'APPARTIENT QU'À CET ÉCRAN VIT ICI. Ce qui servira aussi à la carte remontera
     dans `assets/hello.css` QUAND cette page existera — pas par anticipation. */

  /* ⚠️ **LA MESSAGERIE NE DÉFILE PAS EN BLOC.** C'est un écran d'application : deux colonnes
     qui défilent CHACUNE de son côté, et un fil qui reste collé en bas. `.page` du socle fait
     défiler toute la zone — ici on la remplace par une grille de hauteur fixe, sinon la liste
     des conversations disparaîtrait vers le haut dès qu'on lit un long fil. */
  .msg{flex:1;min-height:0;display:flex}

  /* ---- Colonne 1 : les conversations ---- */
  .msg-liste{
    flex:0 0 316px;width:316px;background:#fff;border-right:1px solid var(--border);
    display:flex;flex-direction:column;min-height:0;
  }
  .msg-cherche{display:flex;align-items:center;gap:9px;padding:16px 16px 12px}
  .msg-champ{
    flex:1;min-width:0;display:flex;align-items:center;gap:8px;padding:9px 12px;
    border:1px solid var(--border-2);border-radius:10px;background:#fbfbfd;
  }
  .msg-champ svg{width:15px;height:15px;flex:0 0 15px;stroke:var(--muted);fill:none;stroke-width:2}
  .msg-champ input{
    flex:1;min-width:0;border:0;background:none;outline:none;font-size:13px;color:var(--text);
  }
  .msg-champ input::placeholder{color:var(--muted)}
  .msg-filtre{
    flex:0 0 38px;width:38px;height:38px;border:1px solid var(--border-2);border-radius:10px;
    display:flex;align-items:center;justify-content:center;color:var(--text-2);background:#fff;
  }
  .msg-filtre:hover{background:#f6f7fa}
  .msg-filtre svg{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:2}
  .msg-fils{flex:1;min-height:0;overflow-y:auto;padding:0 10px 14px}

  .conv{
    display:flex;align-items:center;gap:12px;padding:12px;border-radius:12px;
    width:100%;text-align:left;transition:.14s;
  }
  .conv:hover{background:#f7f8fb}
  .conv.on{background:var(--primary-soft)}
  .conv-av{
    flex:0 0 42px;width:42px;height:42px;border-radius:50%;background:var(--primary-soft-2);
    color:var(--primary-700);font-size:13px;font-weight:800;overflow:hidden;
    display:flex;align-items:center;justify-content:center;
  }
  .conv-av img{width:100%;height:100%;object-fit:cover;display:block}
  /* Les logos sont détourés : pas de pastille sombre, et `contain` pour ne jamais recadrer
     une marque. */
  .conv-av.sombre{background:none}
  .conv-av img,.bulle-av img{object-fit:contain}

  /* 🔻 **LES TROIS PETITS POINTS** (Benjamin, 2026-09-08). Ils vivent dans le fil, à la place
     où la prochaine bulle apparaîtra — pas dans un bandeau en tête : *une annonce posée ailleurs
     que là où la chose va se produire oblige l'œil à faire l'aller-retour.*
     ⚠️ **ILS S'ÉTEIGNENT TOUT SEULS.** Le serveur ne dit jamais « il a cessé d'écrire » : il ne
     le sait pas, et un onglet fermé ne prévient personne. C'est une minuterie d'écran qui les
     retire — *un témoin allumé par un signal doit s'éteindre sans en attendre un second.*
     ⚠️ **PARTAGÉ PAR LES DEUX MESSAGERIES**, comme le reste des styles de fil : deux copies
     auraient fini par battre à deux rythmes. */
  .frappe{display:flex;gap:4px;align-items:center;padding:6px 14px 10px;margin-left:44px}
  .frappe i{
    width:7px;height:7px;border-radius:50%;background:var(--muted);display:block;
    animation:frappepoint 1.2s infinite ease-in-out;
  }
  .frappe i:nth-child(2){animation-delay:.18s}
  .frappe i:nth-child(3){animation-delay:.36s}
  @keyframes frappepoint{0%,60%,100%{opacity:.25;transform:translateY(0)}
                         30%{opacity:1;transform:translateY(-3px)}}
  /* ⚠️ **RESPECTER QUI DEMANDE MOINS D'ANIMATION** : trois points qui sautent sans arrêt sont
     exactement le genre de mouvement que ce réglage existe pour supprimer. */
  @media (prefers-reduced-motion:reduce){ .frappe i{animation:none;opacity:.5} }
  .conv-txt{flex:1;min-width:0}
  .conv-txt b{
    display:block;font-size:13.5px;font-weight:700;color:var(--text);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }
  .conv-txt span{
    display:block;font-size:12.5px;color:var(--muted);margin-top:1px;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }
  .conv-fin{flex:0 0 auto;text-align:right}
  .conv-fin em{display:block;font-style:normal;font-size:11.5px;color:var(--muted)}
  .conv-fin .n{
    display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;
    padding:0 6px;border-radius:10px;background:var(--primary);color:#fff;
    font-size:11.5px;font-weight:800;margin-top:6px;
  }

  /* ---- Colonne 2 : la conversation ---- */
  .msg-conv{flex:1;min-width:0;display:flex;flex-direction:column;min-height:0}
  .conv-tete{
    flex:0 0 auto;display:flex;align-items:center;gap:14px;padding:16px 22px;
    background:#fff;border-bottom:1px solid var(--border);
  }
  .conv-tete .t{flex:1;min-width:0}
  .conv-tete b{display:block;font-size:16px;font-weight:800;color:var(--text);letter-spacing:-.2px}
  .conv-tete span{display:block;font-size:12.5px;color:var(--muted);margin-top:1px}
  .conv-act{
    flex:0 0 auto;width:36px;height:36px;border-radius:10px;color:var(--muted);
    display:flex;align-items:center;justify-content:center;
  }
  .conv-act:hover{background:#f5f6f9;color:var(--text-2)}
  .conv-act svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.9}

  .conv-fil{flex:1;min-height:0;overflow-y:auto;padding:22px 26px}
  .bulle{display:flex;gap:11px;margin-bottom:18px;align-items:flex-end}
  .bulle-av{
    flex:0 0 34px;width:34px;height:34px;border-radius:50%;overflow:hidden;background:var(--primary-soft-2);
    display:flex;align-items:center;justify-content:center;
    font-size:11.5px;font-weight:800;color:var(--primary-700);
  }
  .bulle-av img{width:100%;height:100%;object-fit:cover;display:block}
  .bulle-av.sombre{background:none}
  .bulle-c{max-width:min(560px,72%)}
  .bulle-txt{
    padding:12px 16px;border-radius:14px;font-size:13.5px;line-height:1.5;
    background:#f1f2f6;color:var(--text);white-space:pre-line;
  }
  /* L'heure se pose au bord SORTANT de la bulle, dans les deux sens — c'est la maquette, et
     c'est aussi ce qui garde l'œil sur une seule verticale quand on remonte un fil. */
  .bulle-h{display:block;font-size:11.5px;color:var(--muted);margin-top:5px;padding:0 4px;text-align:right}
  /* ⚠️ Le message SORTANT n'a pas d'avatar : on sait qui l'on est. La maquette le montre ainsi,
     et c'est ce qui distingue les deux sens plus vite que la couleur seule. */
  .bulle.moi{flex-direction:row-reverse}
  .bulle.moi .bulle-av{display:none}
  .bulle.moi .bulle-txt{
    background:linear-gradient(135deg,var(--btn-1),var(--btn-2));color:#fff;
  }
  .bulle.moi .bulle-h{text-align:right}
  .bulle-pre{
    display:block;font-size:11.5px;color:var(--muted);margin-top:5px;padding:0 4px;
    font-style:italic}
  /* Événement système et carte de contact : ni l'un ni l'autre n'est une bulle. Ils ne sont
     de personne, donc pas d'avatar, pas de côté, et une bordure plutôt qu'un fond coloré —
     sinon le fil laisse croire que quelqu'un a écrit ça. */
  .evt,.ct{
    max-width:min(560px,80%);margin:0 auto 14px;border:1px solid var(--border);
    border-radius:12px;background:#fff}
  .evt{display:flex;gap:10px;padding:13px 15px;align-items:flex-start}
  .evt svg{width:18px;height:18px;flex:0 0 18px;stroke:var(--green);fill:none;stroke-width:2;margin-top:1px}
  .evt p{margin:0;font-size:13px;line-height:1.45;color:var(--text)}
  .evt-h{display:block;font-size:11.5px;color:var(--muted);margin-top:4px}
/* ⚠️ **LE LIEN D'UN ÉVÉNEMENT DOIT SE VOIR COMME UN LIEN.** Ces cartes sont neutres par
   construction (ni bulle, ni couleur d'auteur) : un lien qui hérite de leur gris se lit comme du
   texte, et l'action annoncée n'est jamais faite. */
.evt p a{color:var(--primary-600);font-weight:700;text-decoration:none;white-space:nowrap}
.evt p a:hover{text-decoration:underline}
  .ct-t{display:flex;gap:9px;align-items:center;padding:12px 15px;border-bottom:1px solid var(--border)}
  .ct-t svg{width:19px;height:19px;flex:0 0 19px;stroke:var(--muted);fill:none;stroke-width:2}
  .ct-t b{font-size:14px}
  .ct-l{
    display:flex;gap:9px;align-items:center;padding:11px 15px;font-size:13.5px;
    color:var(--text);text-decoration:none;border-bottom:1px solid var(--border)}
  .ct-l:last-child{border-bottom:0}
  .ct-l:hover{background:#f6f7fa}
  .ct-l svg{width:16px;height:16px;flex:0 0 16px;stroke:var(--primary);fill:none;stroke-width:2}

  /* ---- Le composeur ---- */
  .conv-pied{flex:0 0 auto;padding:14px 26px 22px;background:transparent}
  .composeur{
    display:flex;align-items:center;gap:10px;background:#fff;border:1px solid var(--border-2);
    border-radius:14px;padding:9px 10px 9px 18px;box-shadow:var(--shadow);
  }
  .composeur input{
    flex:1;min-width:0;border:0;background:none;outline:none;font-size:13.5px;color:var(--text);
  }
  .composeur input::placeholder{color:var(--muted)}
  .composeur input:disabled{cursor:not-allowed}
  .comp-ico{
    flex:0 0 34px;width:34px;height:34px;border-radius:9px;color:var(--muted);
    display:flex;align-items:center;justify-content:center;
  }
  .comp-ico:hover{background:#f5f6f9;color:var(--text-2)}
  .comp-ico svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.8}
  .composeur .btn-primary{padding:10px 20px}
  .composeur[data-inerte="1"]{opacity:.6}
  .comp-note{
    display:flex;gap:7px;align-items:flex-start;margin:9px 4px 0;font-size:11.5px;color:var(--muted);
  }
  .comp-note svg{width:13px;height:13px;flex:0 0 13px;stroke:currentColor;fill:none;stroke-width:2;margin-top:2px}

  /* ---- Vides ---- */
  .msg-vide{
    flex:1;min-height:0;display:flex;align-items:center;justify-content:center;padding:40px;
  }
  .msg-vide .vide{max-width:520px}
  @media (max-width:900px){
    .msg{flex-direction:column}
    .msg-liste{flex:0 0 auto;width:auto;border-right:0;border-bottom:1px solid var(--border);max-height:44vh;max-height:44dvh}
  }


/* ============================================================================
   LE REPLI DE LA COLONNE (2026-09-16)
   ----------------------------------------------------------------------------
   🔻 **LE MODE RÉDUIT EXISTAIT DEPUIS AOÛT ET PERSONNE NE L'ALLUMAIT.** `.sidebar.mini` porte ses
   quatorze règles — icônes centrées, libellés masqués, infobulles — dans cette feuille ET dans
   celle du configurateur, mais **aucune ligne de code ne posait la classe**. Le bouton avait été
   retiré le 12/08 au profit du bloc « compte », avec cette note : *« le repli reviendra le jour où
   un écran en aura besoin »*. Cet écran est arrivé : un iPad 9,7" en paysage, 1024 points de large
   dont 236 pour la colonne.
   ⚠️ **AUTOMATIQUE PUIS MANUEL** (décision de Benjamin, 16/09) : replié sous le seuil, et un bouton
   pour en décider autrement — le choix est alors retenu et l'automatique ne le contredit plus.
   *Une mise en page qui se réarrange sous les doigts sans qu'on l'ait demandé se lit comme un
   bogue.*
   ============================================================================ */
.repli{
  display:flex;align-items:center;justify-content:center;gap:8px;
  margin:0 0 10px;padding:7px 10px;border-radius:9px;width:100%;
  color:var(--muted);font-size:12px;font-weight:700;letter-spacing:.02em;
  border:1px solid var(--border);background:transparent;cursor:pointer;transition:.15s;
}
.repli:hover{color:var(--text);border-color:var(--border-2);background:var(--primary-soft)}
.repli svg{width:16px;height:16px;flex:0 0 16px;stroke:currentColor;fill:none;stroke-width:2}
.sidebar.mini .repli .repli-mot{display:none}
.sidebar.mini .repli{padding:7px 0}

/* 🔻 **UN ÉCRAN COURT N'EST PAS UN ÉCRAN ÉTROIT** (2026-09-16). Sur un iPad en paysage, la largeur
   suffit — c'est la HAUTEUR qui manque (~590 points utiles). On resserre donc ce qui coûte de la
   hauteur sans toucher à la taille du texte de lecture : un texte rétréci se paie en fatigue, des
   marges rétrécies ne se paient pas.
   ⚠️ **LE BLOC D'ASSISTANCE PART LE PREMIER** : il pèse ~150 points et son geste — « Être rappelé »
   — reste accessible depuis « Mon compte ». Le bloc COMPTE, lui, reste : c'est l'identité et la
   sortie, et c'est précisément ce que Benjamin ne pouvait plus atteindre. */
@media (max-height:700px){
  .sidebar{padding-top:14px;padding-bottom:14px}
  .brand{padding-bottom:14px}
  .nav a,.nav button{padding-top:8px;padding-bottom:8px}
  .promo{display:none}
  .compte{margin-top:10px;padding-top:10px}
}

/* ============================================================================
   L OFFRE CHIFFRÉE DANS LE FIL — gabarit partagé (2026-08-20)
   ----------------------------------------------------------------------------
   ⚠️ Ces règles montent dans le socle DÈS LEUR ÉCRITURE, parce que les deux messageries en
   ont besoin le même jour : le pro voit son offre déposée, le particulier la même offre
   reçue. **Une seule entité, deux vues, jamais une copie** — et deux feuilles de style
   auraient fini par montrer deux documents.
   ============================================================================ */
/* ---- L'offre chiffrée dans le fil (2026-08-20) ----
     ⚠️ Elle ne ressemble ni à une bulle ni à un événement système : c'est un DOCUMENT. Un cadre
     net, le montant en grand, et la version quand il y en a plusieurs. */
  .off{
    max-width:min(560px,80%);margin:0 auto 14px;border:1px solid #bfe3cb;border-radius:12px;
    background:#f6fdf8;overflow:hidden;
  }
  .off-t{
    display:flex;gap:10px;align-items:center;padding:12px 15px;border-bottom:1px solid #d6ecdd;
  }
  .off-t svg{width:18px;height:18px;flex:0 0 18px;stroke:var(--green);fill:none;stroke-width:2}
  .off-t b{flex:1;min-width:0;font-size:13.5px;color:#1f6b41}
  .off-v{
    font-size:10.5px;font-weight:800;letter-spacing:.03em;padding:2px 7px;border-radius:999px;
    background:#dcf0e4;color:#1f6b41;
  }
  .off-c{padding:13px 15px}
  .off-m{font-size:26px;font-weight:800;color:#1f6b41;line-height:1.1}
  .off-m span{font-size:13px;font-weight:700;color:#4b7a5c}
  .off-l{display:flex;gap:18px;flex-wrap:wrap;margin-top:9px;font-size:12.5px;color:#4b7a5c}
  .off-l b{color:#1f6b41;font-weight:700}
  .off-pdf{
    display:flex;gap:8px;align-items:center;margin-top:11px;padding:9px 11px;border-radius:9px;
    background:#fff;border:1px solid #d6ecdd;font-size:12.5px;color:#1f6b41;font-weight:600;
  }
  .off-pdf svg{width:15px;height:15px;flex:0 0 15px;stroke:currentColor;fill:none;stroke-width:2}
/* La mention se range à droite du nom, en petit : elle informe sans disputer la lecture. */
.off-pdf em{margin-left:auto;font-style:normal;font-size:11.5px;font-weight:600;color:#7ba58c}
  .off-h{display:block;font-size:11.5px;color:#7ba58c;margin-top:9px}


/* ============================================================================
   LA DEMANDE AU CLIENT (2026-09-13) — la même carte dans les deux messageries et dans le dossier
   ⚠️ **ELLE SE DISTINGUE D'UNE BULLE** : c'est une question qui attend un geste, pas une phrase
   de plus dans la conversation. Bordure pointillée tant qu'elle est ouverte, pleine une fois close.
   ============================================================================ */
.dem{border:1.5px dashed var(--primary);border-radius:13px;background:var(--primary-soft);
     padding:12px 14px;margin:6px 0 18px;max-width:560px}
.dem[data-statut="repondue"]{border-style:solid;border-color:var(--green);background:var(--green-bg)}
.dem[data-statut="annulee"]{border-style:solid;border-color:var(--border-2);background:#f6f7fb;opacity:.85}
.dem-t{display:flex;align-items:center;gap:8px;font-size:12px;font-weight:800;color:var(--primary-700);
       text-transform:uppercase;letter-spacing:.03em}
.dem[data-statut="repondue"] .dem-t{color:var(--green)}
.dem[data-statut="annulee"] .dem-t{color:var(--text-2)}
.dem-q{font-size:13.5px;color:var(--text);margin:6px 0 4px;line-height:1.5;white-space:pre-wrap}
.dem-s{font-size:11.5px;color:var(--text-2)}
.dem-r{font-size:13px;color:var(--text);background:var(--card);border-radius:9px;padding:8px 10px;
       margin-top:8px;white-space:pre-wrap}
.dem-f{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}
.dem-f a{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;color:var(--primary-700);
         background:var(--card);border:1px solid var(--border-2);border-radius:9px;padding:4px 8px 4px 4px;max-width:220px}
.dem-f img{width:34px;height:34px;border-radius:6px;object-fit:cover;flex:0 0 34px}
.dem-f span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dem form{margin-top:10px;display:flex;flex-direction:column;gap:8px}
.dem textarea{width:100%;min-height:62px;padding:8px 10px;border-radius:9px;font:inherit;font-size:13px;
              border:1px solid var(--border-2);background:var(--card);color:var(--text);resize:vertical}
.dem input[type="file"]{font-size:12.5px}
.dem .dem-err{color:var(--red);font-size:12.5px;font-weight:600}
.dem .dem-actions{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
