/* ─── Refonte A — BARRE LATÉRALE ──────────────────────────────────────────────────────
   Porté de la maquette `Refonte A - Barre laterale.dc.html` (projet Claude Design
   « Refonte site luxe moderne »). Chargé APRÈS `shell.css` / `styles.css` : ce fichier est
   le dernier à parler, et c'est lui qui remplace le bandeau marine par le rail.

   ─── CE QUI EST PORTÉ, ET CE QUI NE L'EST PAS ──────────────────────────────────────
   La maquette change deux choses d'un coup : la NAVIGATION (bandeau haut → rail gauche) et
   la BASE TYPOGRAPHIQUE (Archivo 16 px → Albert Sans 13 px). Les deux n'ont pas le même
   risque, et elles ne sont donc pas traitées ensemble :

     · la navigation et la famille de caractères sont portées ici ;
     · la taille de base RESTE à 16 px — mais PAS pour la raison d'abord écrite ici. La
       première version de ce commentaire annonçait « 506 déclarations en rem » qu'un
       passage à 13 px aurait toutes rétrécies. Re-mesuré : le site en compte **58**, toutes
       dans `copilot/index.astro`. Le 506 comptait la sous-chaîne « rem » dans des mots
       français — « remise », « premier », « remplir ». Le motif est donc l'INVERSE : tout le
       site est calibré en `px`, il ne SUIVRAIT PAS la racine. Baisser celle-ci ne
       rapetisserait que la coquille, qui se retrouverait seule décalée face à un contenu
       resté à sa taille. Le vrai prix du 16 px, lui, est réel et se voit à la jonction : les
       treize `font-size` de ce fichier sont calibrées pour un corps de 13 px, donc ~19 %
       plus petites que ce que la maquette équilibrait.

   Les valeurs (couleurs, rayons, durées, géométrie) sont celles de la maquette, sauf
   là où un commentaire dit explicitement le contraire — accessibilité, cas mobile, et le
   bloc `.tb-btn.solid` / `.tb-chip.*` qui n'existe pas dans la maquette. */

:root {
  /* Géométrie du rail — 60 px replié, 208 px au survol, comme la maquette. */
  --rail-w: 60px;
  --rail-w-open: 208px;
  --modhead-h: 46px;

  /* Les deux barres du téléphone. Elles n'étaient nulle part en jeton, et la première page
     à coquille pleine hauteur (Freinage) a dû réécrire 48 et 60 en clair pour calculer sa
     zone défilante — c'est très exactement la faute que `--topbar-h` avait corrigée pour 46.
     Une constante recopiée dans une page ne suit pas la coquille qui la change. */
  --mobtop-h: 48px;
  --mobtabs-h: 60px;

  /* ⚠ `--topbar-h` SURCHARGÉ, et ce n'est pas cosmétique : `tyres/index.astro`
     ancre un tiroir latéral à `top: var(--topbar-h, 74px)`. Le bandeau de 74 px a été
     remplacé par un en-tête de module de 46 px ; sans cette ligne, le tiroir flotterait
     28 px trop bas, sous une bande de vide. Le jeton reste le point de rendez-vous. */
  --topbar-h: var(--modhead-h);

  --ray-line: oklch(0.90 0.014 70);
  --ray-ink: #1f2430;
  --ray-muted: oklch(0.50 0.02 60);
  --ray-muted-2: oklch(0.38 0.022 55);
  --ray-accent: #24537a;
  --ray-accent-2: #3276a6;
  --ray-accent-soft: #eaf2f9;
  --ray-navy: #1b2f45;
  --ray-danger: #b3413a;
  --ray-danger-soft: #fbe9e7;

  /* SUCCÈS et AVERTISSEMENT. Ils manquaient, et le manque se voyait : trois pages portées
     retombaient sur les `--ok-*` / `--warn-*` de l'ancienne direction — du vert-bleu et de
     l'ambre froid au milieu d'une palette chaude. Les valeurs sont celles de la maquette,
     pas des inventions : le vert est celui de sa pastille de session, l'ambre celui de sa
     pastille de gamme « Premium ». */
  --ray-ok: #2e7d4f;
  --ray-ok-soft: #e6f4ec;
  --ray-warn: #7a5c14;
  --ray-warn-soft: #f8f1df;

  /* Le fond de page de la maquette. `--paper` est le jeton que tout le site lit déjà :
     le redéfinir ici propage le nouveau fond sans toucher une page. */
  --paper: oklch(0.975 0.008 75);

  --font-display: 'Albert Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-body: 'Albert Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* LE FILET DE CHAMP et son survol. `oklch(0.84 0.016 70)` était écrit en clair dix-sept fois,
     sous sept noms de page (`--fld-line`, `--f-field`…) : il devient un jeton de la charte. */
  --ray-field: oklch(0.84 0.016 70);
  --ray-field-strong: oklch(0.76 0.02 70);
  /* La TEINTE CHAUDE de la maquette (bandeaux, en-têtes de liste, survols de ligne, pistes de
     segments), écrite en clair sous cinq noms (`--dt-tint`, `--f-soft`, `--cx-track`…). */
  --ray-tint: oklch(0.962 0.012 75);
  /* L'OMBRE. Les cartes de la maquette sont cernées d'un filet, pas portées : seul ce qui FLOTTE
     (fenêtre, menu) se détache du fond, d'une ombre chaude. */
  --ray-shadow-1: 0 1px 2px rgba(40, 30, 15, .08);
  --ray-shadow-pop: 0 30px 60px -24px rgba(40, 30, 15, .45), 0 4px 12px -6px rgba(40, 30, 15, .12);
  /* Le VOILE des fenêtres modales : un seul, chaud, au lieu des voiles bleu nuit recopiés. */
  --ray-voile: rgba(40, 30, 15, .35);

  /* LES RAYONS : 8 pour ce qu'on actionne (bouton, champ, segment), 12 pour ce qui contient
     (carte, liste, fenêtre, info-bulle), 6 pour l'intérieur d'un segment et les petits éléments
     (badge, code, case à cocher, jauge). Vignettes et pictogrammes encadrés : 8. Restent en
     pixels, délibérément : les filets et marques de 2-3 px et les pastilles de légende. */
  --ray-r-xs: 6px;
  --ray-r-sm: 8px;
  --ray-r: 12px;
  --ray-r-pill: 999px;

  /* L'ÉCHELLE TYPOGRAPHIQUE : huit tailles. Le site en comptait vingt-neuf, dont des centaines de
     demi-pixels (12.5, 11.5, 13.5…) qu'aucun œil ne distingue de leur voisin entier.
     La taille se choisit par le RÔLE du texte, jamais par la place disponible — et toute page
     n'emploie que ces jetons. Restent en pixels, délibérément : les pictogrammes (dessins, pas du
     texte), les champs à 16 px (seuil anti-zoom de Safari iOS) et le pavé de saisie du code. */
  --fs-2xs: 10px;   /* pastilles et badges serrés, étiquettes de formulaire compact, graduations */
  --fs-xs: 11px;    /* étiquettes en capitales, en-têtes de tableau, références et codes (mono) */
  --fs-sm: 12px;    /* descriptions, sous-titres, aides de champ, légendes, métadonnées, délais */
  --fs-base: 13px;  /* corps des tableaux et listes, boutons, liens d'action, messages et états vides */
  --fs-md: 14px;    /* champs de saisie, texte courant, paragraphes */
  --fs-lg: 15px;    /* titres de carte et de bloc, noms, en-tête de module */
  --fs-xl: 18px;    /* titres de section et de fenêtre, montants */
  --fs-2xl: 22px;   /* titre de page, chiffres clés (totaux, indicateurs) */

  /* ─── L'ANCIENNE DIRECTION (« Direction E ») RAMENÉE SUR LA CHARTE ────────────────────────
     `shell.css` et `styles.css` déclarent sur `:root` une palette marine FROIDE, et une partie du
     site la lit encore : la gestion, la plateforme, les préférences, et, par `compat.css`, les
     restes des modules. Plutôt que de réécrire chaque règle, les NOMS restent et leurs VALEURS
     deviennent celles de la charte — ce fichier parle en dernier dans les deux régimes de
     chargement, il a donc le dernier mot. Une page ne choisit plus sa palette en choisissant un
     nom de jeton.
     Les RAYONS (`--r`, `--r-lg`, `--r-xl`) ne sont PAS remappés ici : les modules déjà portés les
     lisent pour leur géométrie, et la changer d'un coup déformerait des écrans qui sont justes.
     Les pages reprises lisent `--ray-r*` directement. */
  --navy-900: var(--ray-navy);
  --navy-800: #22394f;
  --navy-700: var(--ray-accent);
  --navy-600: var(--ray-accent);
  --blue-700: var(--ray-accent);
  --blue-600: var(--ray-accent-2);
  --blue-500: var(--ray-accent-2);
  --blue-400: #7aa6cc;
  --blue-soft: var(--ray-accent-soft);
  --steel-50: oklch(0.985 0.006 75);
  --steel-100: var(--ray-tint);
  --steel-150: var(--ray-line);
  --steel-200: var(--ray-field);
  --steel-300: var(--ray-field-strong);
  --steel-400: oklch(0.64 0.02 62);
  --ink: var(--ray-ink);
  --ink-2: var(--ray-muted-2);
  --muted: var(--ray-muted);
  --muted-2: oklch(0.62 0.018 62);
  --ok: var(--ray-ok);
  --ok-soft: var(--ray-ok-soft);
  --ok-ink: #1f5e3c;
  --warn: #9a6a12;
  --warn-soft: var(--ray-warn-soft);
  --warn-ink: var(--ray-warn);
  --err: var(--ray-danger);
  --err-soft: var(--ray-danger-soft);
  --shadow-1: var(--ray-shadow-1);
  --shadow-2: var(--ray-shadow-1);
  --shadow-3: var(--ray-shadow-pop);
}

body {
  background: var(--paper);
  color: var(--ray-ink);
}
::selection { background: #d9e7f3; color: var(--ray-ink); }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb { background: oklch(0.84 0.016 70); border-radius: 999px; }

/* ============ LE FOCUS ============
   Constaté à l'atelier : « dans certaines zones de texte ou certains input, un cadre bleu
   foncé / noir apparaît ». C'est l'anneau PAR DÉFAUT du navigateur — noir sous Chrome
   Windows, et il n'a rien à voir avec la palette du site. Il ne se supprime pas, il se
   REMPLACE : un champ sans marque de focus est inutilisable au clavier, et la saisie de
   caisse se fait au clavier.

   La valeur est celle de la maquette (`input:focus-visible{outline:2px solid #3276a6}`),
   étendue à tout ce qui se focalise. `:focus-visible` et non `:focus` : rien n'apparaît
   au clic à la souris, seulement à la navigation clavier. */
:focus-visible {
  outline: 2px solid var(--ray-accent-2);
  outline-offset: 1px;
}
.skip-link:focus-visible,
.rail-item:focus-visible, .mobtab:focus-visible, .mobtop-btn:focus-visible,
.tb-btn:focus-visible, .tb-chip:focus-visible {
  outline-offset: 2px; border-radius: 8px;
}
/* ============ LES CHAMPS : AUCUNE MARQUE DE FOCUS ============
   Demandé explicitement par l'atelier, et redemandé après un premier essai « plus léger » :
   « Je ne veux pas une input plus légère, j'en veux aucune. » Un champ focalisé ne se
   distingue donc plus d'un champ au repos — ni contour, ni halo, ni changement de trait.

   `!important` est ici justifié et non paresseux : les feuilles de PAGE sont injectées
   APRÈS ce fichier par Astro (`renderHead()` suit le `<link>`), donc à spécificité égale
   c'est la page qui gagnerait. Une trentaine de règles réparties dans une douzaine de
   fichiers redessinaient ce halo ; les chasser une à une laisserait la prochaine revenir
   sans bruit. La règle vit ici, une fois, et elle a le dernier mot.

   Ce qui N'EST PAS concerné, et c'est délibéré : les BOUTONS, les LIENS et les pastilles à
   cocher gardent leur anneau. La demande porte sur les champs de saisie ; un bouton sans
   marque de focus rendrait le rail et les barres d'outils inutilisables au clavier. */
input:focus, input:focus-visible,
textarea:focus, textarea:focus-visible,
select:focus, select:focus-visible {
  outline: none !important;
  box-shadow: none !important;
}

/* Lien d'évitement : hors écran tant qu'il n'a pas le focus, puis posé par-dessus tout. */
.skip-link {
  position: fixed; top: 8px; left: -9999px; z-index: 200;
  padding: 8px 14px; border-radius: 8px;
  background: var(--ray-navy); color: #fff; font-size: 13px; font-weight: 600;
}
.skip-link:focus-visible { left: 8px; }

/* ============ LARGEURS DE PAGE — CRITIQUES AU PREMIER RENDU ============
   Constaté à l'atelier : « l'élément principal de l'accueil fait un mouvement très rapide
   de gauche à droite pour se positionner au centre », et la même chose sur Devis Pneu.

   Ce n'est pas une animation, c'est un DÉCALAGE DE MISE EN PAGE. En développement, Astro
   injecte les feuilles de PAGE par JavaScript (deux `<style data-vite-dev-id>` relevés sur
   l'accueil) : le premier rendu se fait donc sans elles. Une page dont la largeur maximale
   n'est déclarée que là s'affiche pleine largeur, puis se recentre quand l'injection
   arrive — le bord gauche glisse vers la droite, exactement ce qui est décrit.

   Mesuré : le site CONSTRUIT rend 0 de décalage (il sert ses styles dans le HTML), le dev
   est intermittent. Plutôt que de vivre avec une gêne quotidienne dans l'environnement de
   travail, la largeur — qui est une donnée de MISE EN PAGE, pas d'habillage — remonte ici,
   dans une feuille LIÉE, donc lue avant le premier pixel. Le reste de l'habillage de chaque
   page reste chez elle. */
.page-hub { max-width: 1120px; }
.page-pneu { max-width: 1620px; }

/* ============ RÉSULTATS DE RECHERCHE CLIENT / VÉHICULE ============
   Un SEUL dessin pour toutes les listes « client → véhicules » du site : Nouveau dossier
   (Commander), panneau client de Devis Pneu, et tout écran qui réemploiera le composant.

   Il vivait en DEUX copies — `commander.astro` et `tyres/index.astro` —, même
   balisage, deux feuilles, qui divergeaient déjà (nom en graisse 800 d'un côté, 700 de
   l'autre ; une ligne `.ccr-email` d'un seul côté). L'atelier a demandé que tous les champs
   de recherche similaires aient le même affichage : la seule forme qui le RESTE est une
   règle unique. Les pages ne portent plus de `.ccr-*` à elles.

   Le dessin suit la refonte : carte blanche cernée d'un filet, pas de bandeau gris sous le
   nom (il alourdissait chaque carte), statut en PASTILLE plutôt qu'en texte vert nu, et
   l'immatriculation en chasse fixe — elle se lit par colonne, pas par phrase. */
.ccr-listwrap { display: flex; flex-direction: column; gap: 8px; }
.ccr-card {
  background: #fff; border: 1px solid var(--ray-line); border-radius: 10px; overflow: hidden;
}
.ccr-card-head {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  padding: 9px 12px 7px; font-size: 12.5px;
}
.ccr-card-head .ccr-name { font-size: 13px; font-weight: 600; color: var(--ray-navy); }
.ccr-card-head .ccr-meta { font-size: 11.5px; color: var(--ray-muted); }
.ccr-email { margin-left: auto; font-size: 11.5px; color: var(--ray-ok); }
.ccr-email.refus { color: var(--ray-muted); }

/* Une ligne par véhicule : immatriculation · modèle · statut, en trois colonnes FIXES pour
   que les immatriculations s'alignent d'une carte à l'autre. */
.ccr-pick {
  display: grid; grid-template-columns: 96px minmax(0, 1fr) auto; align-items: center; gap: 10px;
  width: 100%; padding: 8px 12px; border: 0; border-top: 1px solid var(--ray-line);
  background: #fff; text-align: left; font: inherit; font-size: 12.5px; color: var(--ray-ink);
  cursor: pointer; transition: background .12s ease;
}
.ccr-pick:hover { background: var(--paper); }
.ccr-pick .ccr-immat { font-family: var(--font-mono); font-size: 12px; font-weight: 600; letter-spacing: .02em; }
.ccr-pick .ccr-marque { min-width: 0; color: var(--ray-muted-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ccr-pick .ccr-adr { color: var(--ray-muted); font-size: 11px; }
.ccr-pick .ccr-statut {
  font-size: 11px; font-weight: 600; white-space: nowrap;
  padding: 2px 8px; border-radius: 999px; background: var(--ray-ok-soft); color: var(--ray-ok);
}
/* Ex-propriétaire : la ligne s'efface, le statut devient neutre. On garde la ligne
   CLIQUABLE — l'ancien propriétaire d'un véhicule est parfois celui qu'on cherche. */
.ccr-pick.ccr-ex .ccr-immat, .ccr-pick.ccr-ex .ccr-marque { color: var(--ray-muted); }
.ccr-pick.ccr-ex .ccr-statut { background: var(--paper); color: var(--ray-muted); }
.ccr-empty { padding: 8px 12px; border-top: 1px solid var(--ray-line); font-size: 12px; color: var(--ray-muted); font-style: italic; }

.ccr-pager { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; padding: 6px 0 0; }
.ccr-page {
  min-width: 28px; height: 28px; padding: 0 6px; border: 1px solid var(--ray-line); border-radius: 7px;
  background: #fff; color: var(--ray-muted-2); font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
}
.ccr-page:hover:not(:disabled) { border-color: var(--ray-accent-2); color: var(--ray-accent); }
.ccr-page.active { background: var(--ray-accent-soft); border-color: var(--ray-accent-soft); color: var(--ray-accent); }
.ccr-page:disabled { cursor: default; opacity: .4; }
.ccr-page.active:disabled { opacity: 1; }
.ccr-total { margin-left: auto; font-size: 11.5px; color: var(--ray-muted); }

/* ============ LA COQUILLE ============ */
.shell { display: flex; min-height: 100vh; }
.shell-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* La colonne qui RÉSERVE la place du rail replié. Le rail lui-même est en `absolute`
   par-dessus : c'est ce qui lui permet de s'élargir au survol SANS pousser le contenu. */
.rail-slot {
  width: var(--rail-w); flex-shrink: 0;
  position: sticky; top: 0; height: 100vh; z-index: 70;
}
.rail {
  position: absolute; left: 0; top: 0; height: 100%; width: var(--rail-w);
  background: #fff; border-right: 1px solid var(--ray-line);
  display: flex; flex-direction: column; padding: 12px 10px; gap: 4px;
  overflow: hidden;
  transition: width 160ms ease, box-shadow 160ms ease;
}
/* Le FOCUS CLAVIER déplie aussi, en plus du survol — la maquette ne le fait pas, et sans lui le
   rail reste replié pour qui navigue au clavier : les libellés sont à `opacity:0`, donc on tabule
   dans une colonne d'icônes muettes.
   `:has(:focus-visible)` et non `:focus-within` (lot C2) : un CLIC donne aussi le focus à un
   bouton, et `:focus-within` le gardait. Relevé à la revue : menu du compte ouvert à la souris puis
   refermé, le focus revenu sur le bloc du compte ÉPINGLAIT le rail déplié par-dessus la page, souris
   partie. `:focus-visible` ne s'allume qu'au clavier (ou quand le navigateur juge un anneau utile) :
   Tab déplie toujours, un clic n'épingle plus. Aucune autre règle ne lisait `.rail:focus-within`
   (recensé : le bouton Identifiants ouvre une modale HORS du rail, les onglets sont au téléphone,
   où le rail est masqué).
   DEUX RÈGLES, jamais une liste `.rail:hover, .rail:has(…)` : une liste de sélecteurs tombe ENTIÈRE
   dès qu'un de ses membres est inconnu, et un navigateur sans `:has()` (Firefox ESR 115 à 120,
   Safari < 15.4) perdait alors aussi le SURVOL — rail figé à 60 px, libellés invisibles (relevé à la
   vérification du lot C2). Séparées, seule la règle `:has()` tombe là-bas. */
.rail:hover {
  width: var(--rail-w-open);
  box-shadow: 0 20px 50px -20px rgba(40, 30, 15, .35);
}
.rail:has(:focus-visible) {
  width: var(--rail-w-open);
  box-shadow: 0 20px 50px -20px rgba(40, 30, 15, .35);
}

/* Les libellés n'apparaissent qu'ouvert. `opacity` et non `display` : le texte reste dans
   l'arbre, donc lisible par un lecteur d'écran et par la recherche du navigateur. Deux règles, pour
   la même raison que ci-dessus. */
.rail-label { opacity: 0; transition: opacity 120ms; white-space: nowrap; }
.rail:hover .rail-label { opacity: 1; }
.rail:has(:focus-visible) .rail-label { opacity: 1; }

.rail-brand {
  display: flex; align-items: center; gap: 12px;
  height: 40px; padding: 0 3px; margin-bottom: 8px; color: inherit; white-space: nowrap;
}
.rail-mark {
  width: 34px; height: 34px; flex-shrink: 0; border-radius: 10px;
  background: var(--ray-navy); display: grid; place-items: center;
}
.rail-mark::after {
  content: ''; width: 12px; height: 12px; border-radius: 3px;
  background: #fff; transform: rotate(45deg); display: block;
}
.rail-brand .rail-label { font-weight: 600; font-size: 14px; color: var(--ray-navy); }

.rail-item {
  display: flex; align-items: center; gap: 12px; width: 100%;
  height: 40px; padding: 0 12px; border: 0; border-radius: 10px;
  background: transparent; color: var(--ray-muted);
  font-size: 13px; font-weight: 600; white-space: nowrap; text-align: left;
}
.rail-item i { font-size: 15px; width: 16px; text-align: center; flex-shrink: 0; }
.rail-item:hover { background: var(--ray-accent-soft); color: var(--ray-accent); }
/* Aplat seul, sans liseré : c'est le dessin de la maquette, et l'atelier l'a tranché.
   J'avais ajouté un liseré gauche à `--ray-accent` parce que l'aplat seul ne rend que
   1,13:1 de contraste ; il est retiré. Ce qui reste pour dire « vous êtes ici » : le
   changement de COULEUR DU TEXTE (`--ray-muted` → `--ray-accent`, 8,10:1), et
   `aria-current="page"` posé par le gabarit — donc l'annonce au lecteur d'écran est
   intacte, seul l'indice visuel est celui de la maquette. */
.rail-item.on { background: var(--ray-accent-soft); color: var(--ray-accent); }
.rail-item.danger:hover { background: var(--ray-danger-soft); color: var(--ray-danger); }
.rail-espace { flex: 1; }

/* ============ L'AVATAR D'UN PROFIL ============
   Dessiné par src/components/AvatarProfil.astro, habillé ICI : cette feuille est chargée par les
   deux gabarits (Ilypsis et Auth), donc la grille /profiles et le rail portent le même disque. Le
   composant pose trois jetons en ligne — le fond (la couleur DÉCLARÉE du profil, palette.ts), le
   diamètre, la taille des initiales — et rien d'autre : la forme est ici, une fois. */
.avatar-profil {
  position: relative; flex-shrink: 0;
  width: var(--avatar-taille, 30px); height: var(--avatar-taille, 30px); border-radius: 50%;
  display: grid; place-items: center;
  background: var(--avatar-fond, var(--ray-navy)); color: #fff;
  font-size: var(--avatar-texte, 12px); font-weight: 700; line-height: 1; letter-spacing: .02em;
}
.avatar-silhouette { width: 58%; height: 58%; display: block; }
.avatar-initiales { display: block; }
/* Le REPÈRE ADMIN, posé sur l'avatar (slot) au bas du rail et dans la barre mobile : rail REPLIÉ,
   l'étiquette « admin » est avec les libellés, invisible — seul l'avatar dit encore qui est
   connecté. Même marine que l'étiquette ; l'anneau blanc le détache du disque de couleur. */
.avatar-repere-admin {
  position: absolute; right: -3px; bottom: -3px;
  width: 14px; height: 14px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--ray-navy);
  box-shadow: 0 0 0 2px #fff;
}
.avatar-repere-admin svg { width: 9px; height: 9px; display: block; }

/* L'étiquette « admin » — la même au bas du rail, dans le menu du compte et sur la grille des
   profils. Marine plein, texte blanc : 13,6:1, lisible même à 10 px. */
.etiquette-admin {
  display: inline-flex; align-items: center; flex-shrink: 0;
  padding: 2px 6px; border-radius: 999px;
  background: var(--ray-navy); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 1.2; letter-spacing: .06em; text-transform: uppercase;
}

/* ============ LE BAS DU RAIL : LE COMPTE ET LE PROFIL ============
   Décision du propriétaire (28/09/2026) : le NOM DU COMPTE en gras et plus grand, le PROFIL
   dessous, l'étiquette « admin », un avatar de la couleur du profil. C'est un BOUTON — il ouvre le
   menu du compte (popover natif : ni script, ni gestion du clic extérieur, Échap compris) — là où
   ce n'était qu'un `div` d'initiales. Replié, seul l'avatar se voit, centré dans les 60 px comme
   l'était l'ancienne pastille (10 px de marge du rail + 5 px de rembourrage + 15 px de rayon). */
.rail-user {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 48px; padding: 6px 5px; margin-top: 6px;
  border: 0; border-radius: 10px; background: transparent;
  color: inherit; font: inherit; text-align: left; white-space: nowrap; cursor: pointer;
}
.rail-user:hover { background: var(--ray-accent-soft); }
.rail-user:focus-visible { outline-offset: 2px; }
.rail-user-textes { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; line-height: 1.2; }
.rail-user-compte {
  font-size: 14.5px; font-weight: 700; color: var(--ray-navy);
  overflow: hidden; text-overflow: ellipsis;
}
.rail-user-profil { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: 12px; color: var(--ray-muted-2); }
.rail-user-profil-nom { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* Pas de chevron : dans les 188 px utiles du rail ouvert, il prenait les 20 px qui manquaient à
   « Administration » + l'étiquette (tronqué en « Administr… », relevé en capture). Le bouton se
   signale par son fond au survol, et reste marqué tant que son menu est ouvert. */
body:has(.menu-compte:popover-open) .rail-user { background: var(--ray-accent-soft); }

/* Menu ouvert : le rail reste DÉPLIÉ. Le menu se pose au-dessus du bloc, dans la largeur du rail
   ouvert ; replié sous lui (la souris partie vers le menu, sans focus clavier dans le rail), il
   flotterait au-dessus d'une colonne d'icônes muettes. Règle À PART de `.rail:hover,
   .rail:has(:focus-visible)` : le menu vit hors du rail (cf. `.menu-compte`), `:has()` ne l'y voit pas.
   Menu FERMÉ, cette règle tombe, et avec elle le dépliage (sauf survol ou focus CLAVIER). */
body:has(.menu-compte:popover-open) .rail {
  width: var(--rail-w-open);
  box-shadow: 0 20px 50px -20px rgba(40, 30, 15, .35);
}
body:has(.menu-compte:popover-open) .rail-label { opacity: 1; }

/* ============ LE MENU DU COMPTE (popover natif) ============
   UN menu, DEUX déclencheurs : le bloc du rail (bureau) et l'avatar de la barre du haut (mobile).
   Il vit HORS du rail et HORS de la barre mobile, et ce n'est pas un choix de rangement : chacun
   des deux est en `display: none` à l'une des deux largeurs, et un popover dont un ANCÊTRE est en
   `display: none` ne s'affiche pas — la couche supérieure ne crée pas de boîte qu'un ancêtre refuse.
   ⚠ Aucun `display` hors de `:popover-open` : la règle d'AUTEUR l'emporterait sur le
   `[popover]:not(:popover-open) { display: none }` du navigateur, et le menu serait toujours ouvert.
   Le navigateur le pose centré (`inset: 0; margin: auto`) : on le place. */
.menu-compte {
  position: fixed; inset: auto auto 66px 10px; margin: 0;
  width: 236px; max-width: calc(100vw - 20px); padding: 6px;
  border: 1px solid var(--ray-line); border-radius: 12px;
  background: #fff; color: var(--ray-ink);
  box-shadow: 0 24px 50px -24px rgba(40, 30, 15, .45), 0 2px 6px rgba(40, 30, 15, .06);
}
.menu-compte:popover-open { display: flex; flex-direction: column; gap: 2px; }
.menu-compte-tete {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 6px 10px; margin-bottom: 4px; border-bottom: 1px solid var(--ray-line);
}
.menu-compte-identite { display: flex; flex-direction: column; gap: 3px; min-width: 0; line-height: 1.25; }
.menu-compte-nom { font-size: 14.5px; font-weight: 700; color: var(--ray-navy); overflow-wrap: anywhere; }
.menu-compte-profil { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: 12px; color: var(--ray-muted-2); overflow-wrap: anywhere; }
.menu-compte-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  height: 38px; padding: 0 10px; border: 0; border-radius: 8px;
  background: transparent; color: var(--ray-ink); text-decoration: none;
  font: inherit; font-size: 13px; font-weight: 600; text-align: left; cursor: pointer;
}
.menu-compte-item i { width: 16px; flex-shrink: 0; text-align: center; font-size: 13px; color: var(--ray-muted); }
.menu-compte-item:hover { background: var(--ray-accent-soft); color: var(--ray-accent); }
.menu-compte-item:hover i { color: inherit; }
.menu-compte-item.danger:hover { background: var(--ray-danger-soft); color: var(--ray-danger); }
.menu-compte-item:focus-visible { outline-offset: -2px; }
.menu-compte-item:disabled { opacity: .6; cursor: progress; }
@media (prefers-reduced-motion: no-preference) {
  .menu-compte:popover-open { animation: menu-compte-ouvre .14s ease-out; }
}
@keyframes menu-compte-ouvre { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* L'équivalent COMPACT du bloc, dans la barre mobile (« même bloc », décision du 28/09) : l'avatar
   et son repère, le NOM DU PROFIL, l'étiquette « admin » — le compte, lui, est dans l'en-tête du menu
   qu'il ouvre. Une cible de 44 px de haut (mains d'atelier). La PLACE se prend sur le titre
   (`.mobtop-title`, flex: 1, qui se tronque) ; le nom est borné et tronqué proprement, pour qu'un
   nom long ne mange pas toute la barre. Masqué avec sa barre au bureau. */
.mobtop-compte {
  display: flex; align-items: center; gap: 7px;
  flex: 0 1 auto; min-width: 0; height: 44px; padding: 0 8px 0 7px;
  border: 0; border-radius: 22px; background: transparent;
  color: inherit; font: inherit; cursor: pointer;
}
.mobtop-compte:hover { background: var(--ray-accent-soft); }
.mobtop-compte:focus-visible { outline-offset: 1px; }
.mobtop-compte-nom {
  min-width: 0; max-width: 104px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12.5px; font-weight: 600; color: var(--ray-navy);
}
body:has(.menu-compte:popover-open) .mobtop-compte { background: var(--ray-accent-soft); }

/* ============ SANS `popover` (navigateur trop ancien) ============
   L'attribut inconnu ne cache rien : le menu resterait affiché EN PERMANENCE, posé en `fixed`
   par-dessus la page. Il est donc masqué, et une déconnexion DIRECTE (`.deconnexion-directe`, un
   `[data-logout]` — le même gestionnaire délégué) apparaît au rail et dans la barre mobile. Masquée
   partout ailleurs : là, c'est le menu qui la porte. Sélecteurs à DEUX classes : `.mobtop-btn` pose
   `display: grid` dans le bloc mobile, plus bas, et l'emporterait à une classe près. */
.rail-item.deconnexion-directe, .mobtop-btn.deconnexion-directe { display: none; }
@supports not selector(:popover-open) {
  .menu-compte { display: none; }
  .rail-item.deconnexion-directe { display: flex; }
  .mobtop-btn.deconnexion-directe { display: grid; }
  .rail-user, .mobtop-compte { cursor: default; }
}

/* ============ EN-TÊTE DE MODULE ============
   La maquette déplace le titre et les actions du bandeau marine vers un en-tête blanc,
   au-dessus du contenu. C'est lui qui reçoit les slots `mid` et `actions` : quatorze pages
   y injectent leurs boutons, et les perdre aurait été une régression fonctionnelle
   déguisée en changement de style. */
.modhead {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  min-height: var(--modhead-h); padding: 6px 16px;
  background: #fff; border-bottom: 1px solid var(--ray-line);
  position: sticky; top: 0; z-index: 40;
}
.modhead-titles { display: flex; align-items: baseline; gap: 8px; min-width: 0; margin-right: auto; }
/* `min-width: 0` ne tronque rien tout seul : sans `overflow`/`text-overflow`, un titre long
   déborde au lieu de se couper, et pousse un défilement horizontal. Le motif est celui de
   `.mobtop-title`, plus bas. */
.modhead-titles h1, .modhead-titles p {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.modhead-titles h1 { font-size: 15px; font-weight: 600; color: var(--ray-navy); }
.modhead-titles p { font-size: 12px; color: var(--ray-muted); }

/* ============ BOUTONS D'EN-TÊTE ============
   `.tb-btn` et `.tb-chip` étaient dessinés POUR UN FOND MARINE : bordures et texte blancs.
   Sur l'en-tête blanc, ils devenaient invisibles. Ils sont redessinés ici plutôt que dans
   les pages — le nom de classe reste le contrat, son habillage suit la coquille.

   Recensé, plutôt que supposé : `.tb-btn` est employé par CINQ pages (clim-registre, clim,
   lettre-decharge, entretien/admin, entretien/index) et `.tb-chip` par AUCUNE — il n'existe
   que dans les feuilles. Les quatorze pages qui remplissent les slots y posent en fait six
   familles de classes, dont `.back-link`, `.settings-btn`, `.client-view-toggle` et
   `.session` : celles-là n'étaient marine que sous le sélecteur `.topbar …` de `compat.css`,
   qui ne s'applique plus faute de `.topbar`, et retrouvent donc seules leur habillage clair.
   La seule qui n'avait pas de version claire à retrouver est `.cx-tbbtn` (Caisse) — elle est
   corrigée dans sa propre page. */
.tb-btn {
  display: inline-flex; align-items: center; gap: 6px;
  height: 30px; padding: 0 10px; white-space: nowrap;
  border: 1px solid var(--ray-line); border-radius: 8px;
  background: #fff; color: var(--ray-muted-2);
  font-size: 12px; font-weight: 600;
  transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.tb-btn i { font-size: 11px; color: inherit; }
.tb-btn:hover { background: #fff; border-color: var(--ray-accent-2); color: var(--ray-accent); }
.tb-btn.solid { background: var(--ray-accent); border-color: var(--ray-accent); color: #fff; }
.tb-btn.solid i { color: #fff; }
.tb-btn.solid:hover { background: var(--ray-accent-2); border-color: var(--ray-accent-2); color: #fff; }
.tb-btn.danger:hover { background: var(--ray-danger-soft); border-color: #e0a49e; color: var(--ray-danger); }

.tb-chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 28px; padding: 0 10px; white-space: nowrap;
  border: 1px solid var(--ray-line); border-radius: 999px;
  background: #fff; color: var(--ray-muted-2);
  font-size: 11.5px; font-weight: 600;
}
.tb-chip .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.tb-chip.ok { background: var(--ray-ok-soft); border-color: #cfe7da; color: var(--ray-ok); }
.tb-chip.toggle:hover { border-color: var(--ray-accent-2); color: var(--ray-accent); }
.tb-chip.toggle.on { background: var(--ray-accent-soft); border-color: var(--ray-accent-soft); color: var(--ray-accent); }

/* ============ MOBILE ============
   Sous 760 px, la maquette remplace le rail par deux barres : un en-tête de 48 px en haut
   et des onglets de 60 px en bas. Le seuil est celui de la maquette (`width < 760`). */
.mobtop, .mobtabs { display: none; }

@media (max-width: 759px) {
  .shell { flex-direction: column; }
  .rail-slot { display: none; }

  .mobtop {
    display: flex; align-items: center; gap: 10px;
    position: sticky; top: 0; z-index: 50;
    height: var(--mobtop-h); padding: 0 12px;
    background: #fff; border-bottom: 1px solid var(--ray-line);
  }
  .mobtop .rail-mark { width: 26px; height: 26px; border-radius: 8px; }
  .mobtop .rail-mark::after { width: 9px; height: 9px; border-radius: 2px; }
  /* C'est le `h1` visible du téléphone — d'où la remise à plat des marges et de la taille
     par défaut d'un titre de niveau 1. */
  .mobtop-title { margin: 0; font-weight: 600; font-size: 14px; color: var(--ray-navy); flex: 1; min-width: 0;
                  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .mobtop-btn {
    width: 34px; height: 34px; flex-shrink: 0; border: 0; border-radius: 8px;
    background: transparent; color: var(--ray-muted); display: grid; place-items: center;
  }
  .mobtop-btn:hover { background: var(--ray-accent-soft); color: var(--ray-accent); }

  /* Le menu du compte descend de l'avatar de la barre du haut, calé à droite. Ses entrées passent à
     44 px de haut : ce sont des cibles au DOIGT (38 px au bureau, à la souris). */
  .menu-compte { inset: calc(var(--mobtop-h) + 6px) 8px auto auto; width: min(280px, calc(100vw - 16px)); }
  .menu-compte-item { height: 44px; }

  /* L'en-tête de module se colle SOUS la barre mobile, pas sous le haut de la fenêtre. */
  .modhead { top: var(--mobtop-h); }

  /* ⚠ `--topbar-h` DOIT suivre, et c'est le piège que la première version a laissé passer :
     au téléphone le bloc de tête ne fait plus 46 px mais 48 (`.mobtop`) + 46 (`.modhead`)
     = 94. Les panneaux `position: fixed` qui s'ancrent sur ce jeton — le tiroir comparatif
     de Devis Pneu, le panneau d'artéfact du Copilote — démarraient 48 px trop haut, donc
     par-dessus la barre mobile et par-dessus l'en-tête qu'ils sont censés laisser voir.
     La maquette portait exactement cette valeur : `headTop2: mobile ? '96px' : '48px'`. */
  :root { --topbar-h: calc(var(--mobtop-h) + var(--modhead-h)); }

  /* Le titre est déjà dans `.mobtop`. Les afficher tous les deux coûtait 94 px sur 812 pour
     écrire deux fois le même mot — et le faire annoncer deux fois. Les SLOTS restent : ce
     sont les commandes des pages, elles n'ont pas d'autre place. */
  .modhead-titles { display: none; }
  /* Sans commande de page (les slots sont vides), l'en-tête n'a plus rien à montrer : il laissait une
     bande blanche de 46 px sous la barre mobile (Gestion, Plateforme, Préférences, et aussi les
     accueils Comptabilité, Données, Documents et le rejeu Copilote). Il disparaît, et
     `--topbar-h` se ramène à la seule barre mobile pour les panneaux qui s'y ancrent. */
  .modhead:has(> .modhead-titles:only-child) { display: none; }
  :root:has(.modhead > .modhead-titles:only-child) { --topbar-h: var(--mobtop-h); }

  /* La barre d'onglets est en `fixed` : sans cette réserve, les dernières lignes de chaque
     page passeraient dessous et resteraient inatteignables. */
  .shell-main { padding-bottom: var(--mobtabs-h); }

  .mobtabs {
    display: flex; justify-content: space-around;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    height: var(--mobtabs-h); padding: 6px 4px 8px;
    background: #fff; border-top: 1px solid var(--ray-line);
  }
  .mobtab {
    flex: 1; min-width: 44px; border: 0; background: transparent; overflow: hidden;
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    color: var(--ray-muted); font-size: 10px; font-weight: 600;
  }
  /* Filet, en plus des libellés courts de `MODULES.short` : un module ajouté demain sans
     `short` tronquerait proprement au lieu d'écrire par-dessus l'onglet voisin. Le nom
     complet reste lisible — il est sur `aria-label`. */
  .mobtab-lab { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .mobtab .ico {
    width: 44px; height: 26px; border-radius: 8px;
    display: grid; place-items: center; font-size: 14px;
  }
  .mobtab.on { color: var(--ray-accent); }
  .mobtab.on .ico { background: var(--ray-accent-soft); }
}

/* `.tb-btn` est en `white-space: nowrap`, et rien ne raccourcissait ses libellés en petite
   largeur — contrairement aux pages qui emploient `.back-link`/`.settings-btn`, qui masquent
   leur `span` à 1100 px. Résultat : l'en-tête des cinq pages en `.tb-btn` passait sur trois
   rangs à 375 px, sous la barre mobile. La règle vit ICI, là où vit le nom de classe, plutôt
   que recopiée dans les cinq pages : le nom de classe est le contrat, son habillage suit la
   coquille. Le libellé reste dans l'arbre — c'est le nom accessible du bouton. */
@media (max-width: 900px) {
  .tb-btn span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .tb-btn { padding: 0 9px; }
}

@media (prefers-reduced-motion: reduce) {
  .rail, .rail-label { transition-duration: .001ms !important; }
}
