/* ============================================================================================
   APP — mise en page et composants.
   ============================================================================================
   ⚠️ AUCUNE COULEUR LITTÉRALE dans ce fichier. Pas un seul #hexa, pas un rgb().
      Tout passe par les variables de theme.css — c'est ce qui rend la marque blanche possible
      sans toucher au code, et bin/lint-ui.php le vérifie mécaniquement, au pré-commit.
      Une couleur écrite en dur ici serait invisible au distributeur : son thème s'appliquerait
      partout SAUF à cet endroit, et personne ne comprendrait pourquoi.
   ============================================================================================ */

*, *::before, *::after { box-sizing: border-box; }

html {
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--ink-0);
  color: var(--paper);
  font-family: var(--font-text);
  font-size: var(--text-base);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* ── Accessibilité ────────────────────────────────────────────────────────────────────────
   Le brief exige explicitement la navigation au clavier (tabulation garantie sur le formulaire
   d'achat). Un anneau de focus visible n'est donc pas une option de confort : c'est la seule
   façon de savoir où l'on est quand on ne se sert pas de la souris.                          */
:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: var(--space-2);
  padding: var(--space-2) var(--space-4);
  background: var(--ink-3);
  color: var(--paper);
  border-radius: var(--radius-sm);
  z-index: 100;
}
.skip-link:focus {
  left: var(--space-2);
}

/* ── Typographie ──────────────────────────────────────────────────────────────────────────── */
h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.2;
  margin: 0 0 var(--space-3);
}
h1 { font-size: var(--text-2xl); }
h2 { font-size: var(--text-xl); }
h3 { font-size: var(--text-lg); }

p { margin: 0 0 var(--space-4); }

a {
  color: var(--brand-accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

code, .mono, .ref, .amount {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

.muted    { color: var(--muted); }
.muted-2  { color: var(--muted-2); }
.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-2);
}

/* ── Structure : full width bord à bord ───────────────────────────────────────────────────
   Pas de largeur maximale, pas de contenu centré dans une colonne étroite : c'est une exigence
   explicite du brief, et les maquettes s'y tiennent sur 1280 px de large.                    */
/* ⚠️ `minmax(0, 1fr)` ET NON `1fr` — MESURÉ AU NAVIGATEUR LE 27/08/2026, ET C'EST LA MOITIÉ
      STRUCTURELLE DU CORRECTIF DE DÉBORDEMENT.

      `1fr` est un raccourci pour `minmax(auto, 1fr)`, et ce `auto` vaut le MIN-CONTENT de
      l'élément posé dans la colonne. La barre du haut étant une flexbox en `nowrap`, son
      min-content est la somme de ses enfants : quatorze entrées faisaient 1345,7 px, la colonne
      s'écartait d'autant, et TOUTE l'application défilait horizontalement sous 1346 px — sur
      chaque page, y compris celles dont le contenu tenait largement.

      Avec `minmax(0, 1fr)`, la colonne ne peut plus être écartée par son contenu : c'est au
      contenu de savoir rétrécir. La borne ne DISPENSE pas de le rendre souple (une barre dont
      les enfants ne rétrécissent pas déborderait alors de sa propre boîte, et un contenu qui
      dépasse compte encore dans le `scrollWidth` du document) — mais sans elle, aucun réglage
      sur la barre ne suffit : la grille reprend d'une main ce que la barre a lâché de l'autre.

      ⚠️ `ConventionChromeTest` tient cette ligne : la retirer rougit un banc. */
.page {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: var(--topbar-height) 1fr auto;
  grid-template-areas:
    "topbar"
    "content"
    "pied";
  min-height: 100vh;
}

/* ⚠️ `min-width: 0` sur la barre : l'autre moitié de la même mesure. Un élément de grille a un
      minimum automatique égal à son min-content ; sans cette ligne, la barre imposerait sa
      largeur minimale à la colonne même bornée par `minmax(0, 1fr)`. */
.topbar {
  grid-area: topbar;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  min-width: 0;
  padding: 0 var(--space-6);
  background: var(--ink-1);
  border-bottom: 1px solid var(--line);
}

.brand {
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.08em;
}
a.brand { color: var(--paper); text-decoration: none; }
.brand em {
  color: var(--brand-accent);
  font-style: normal;
  letter-spacing: 0.16em;
}

/* Navigation de la barre de marque.

   ⚠️ `margin-left: auto` la pousse à droite SANS conteneur intermédiaire : la barre est déjà une
      flexbox, et ajouter un `<div>` pour aligner reviendrait à décrire la mise en page dans le
      HTML — ce que la marque blanche ne pourra pas surcharger par le seul thème.                */
.topbar__nav {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  margin-left: auto;
}
.topbar__nav a { color: var(--muted); text-decoration: none; }
.topbar__nav a:hover { color: var(--paper); }

/* Le formulaire de déconnexion ne doit pas introduire de rythme vertical dans une barre dont la
   hauteur est fixée : il n'est là que pour porter le jeton CSRF. Depuis le 27/08/2026 il vit dans
   le menu profil, où `display: contents` fait du bouton un enfant direct de la colonne du menu —
   sans quoi il faudrait rendre le formulaire lui-même pleine largeur.                           */
.topbar__form { display: contents; }

/* ── LE MENU PROFIL ───────────────────────────────────────────────────────────────────────────
   Ce que le canon (12-transverse-ui:29) place dans la barre du haut : « Se déconnecter » dans le
   menu de l'avatar, jamais un bouton nu. Et ce qui a remplacé, le 27/08/2026, les douze liens
   d'administration qui faisaient déborder la page — ils sont désormais dans la barre latérale.

   ⚠️ UN `<details>`, DONC ZÉRO JAVASCRIPT : sous `script-src 'self'`, un menu écrit en JS
      demanderait un fichier de plus et une panne possible de plus, pour un comportement que le
      HTML fournit — clavier et annonce d'état compris.

   ⚠️ AUCUNE OMBRE PORTÉE, ET CE N'EST PAS UN OUBLI : une ombre s'écrit en `rgba()`, donc en
      couleur littérale, et `bin/lint-ui.php` les refuse hors de theme.css. Le détachement est
      obtenu par la bordure et le fond de barre, qui sont tous deux des jetons.                  */
.profil { position: relative; }

/* ⚠️ ON NE CHANGE PAS LE `display` DU RÉSUMÉ : `list-item` est celui que la feuille de l'agent
      utilisateur lui donne, et `list-style: none` est la voie prévue pour en retirer la puce. Un
      `display: flex` (première rédaction, le 27/08/2026) la retire aussi, mais il faut alors
      s'entendre avec chaque moteur sur le sort du marqueur — Safari ne connaît encore que
      `::-webkit-details-marker`. Le centrage vertical passe donc par le padding : 24 px de
      hauteur de ligne + 2 × 8 px = 40 px, soit exactement `--touch-min`, la cible tactile.

   ⚠️ CE QUI N'A PAS ÉTÉ MESURÉ, ET QU'IL FAUT DONC ALLER VOIR. Le rôle réellement annoncé pour ce
      menu (« bouton, replié ») n'est PAS vérifié : l'arbre d'accessibilité lu depuis l'outil de
      recette rend `generic` pour TOUT `<details>`/`<summary>` — y compris pour un témoin sans
      aucun style, ce qui a été éprouvé exprès le 27/08/2026. L'outil ne permet donc pas de
      comparer deux écritures, et l'affirmation contraire, qui figurait ici d'abord, était fausse.
      La vérification appartient à la recette clavier transverse (canon U11), avec un vrai lecteur
      d'écran.                                                                                    */
.profil__bouton {
  display: list-item;
  list-style: none;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--muted);
  cursor: pointer;
}
/* Le triangle de l'agent utilisateur est retiré des DEUX façons — la moderne (`list-style`,
   ci-dessus) et l'ancienne (WebKit) : Safari ne comprend encore que la seconde.                */
.profil__bouton::-webkit-details-marker { display: none; }
.profil__bouton::after { content: " ▾"; color: var(--muted-2); }
.profil__bouton:hover { color: var(--paper); background: var(--ink-2); }
.profil[open] .profil__bouton { color: var(--paper); }

.profil__menu {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 13rem;
  padding: var(--space-2);
  background: var(--ink-1);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

.profil__lien {
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--muted);
  text-decoration: none;
}
.profil__lien:hover { background: var(--ink-2); color: var(--paper); }

/* Le bouton de déconnexion aligné comme les liens du menu, sans perdre sa cible tactile. */
.profil__quitter { justify-content: flex-start; width: 100%; }

/* L'agent utilisateur est une chaîne de 150 caractères qui ferait exploser sa colonne. On la
   borne visuellement — jamais en la tronquant côté serveur : la valeur complète reste
   sélectionnable et copiable, ce dont on a besoin quand on cherche à identifier une session. */
/* La clé d'enrôlement du second facteur : elle se RECOPIE, donc elle doit se lire.

   ⚠️ Grande et espacée, à contre-courant du reste de l'interface. C'est délibéré : c'est la seule
      chaîne du produit qu'un humain doit transcrire caractère par caractère sur un autre appareil,
      et une erreur de recopie ne se manifeste que trente secondes plus tard, sous la forme d'un
      « code incorrect » qui ne dit pas où est la faute.                                          */
.cle-secrete {
  font-size: var(--text-lg);
  letter-spacing: 0.12em;
  word-break: break-all;
}

/* Les dix codes de secours — présentés pour être IMPRIMÉS ou recopiés.

   ⚠️ En grille et non en liste à puces : dix lignes à puces se relisent mal, et l'utilisateur qui
      coche mentalement ceux qu'il a notés perd sa place. Deux colonnes tiennent sur une demi-page
      imprimée.                                                                                   */
.codes-secours {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-2) var(--space-5);
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: var(--text-lg);
  letter-spacing: 0.06em;
}

/* Deux actions côte à côte, qui repassent l'une sous l'autre quand la place manque. */
.actions-2fa {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.agent {
  display: inline-block;
  max-width: 22rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}

.content {
  grid-area: content;
  padding: var(--space-6);
}

/* ── Carte ────────────────────────────────────────────────────────────────────────────────── */
.card {
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-5);
}

/* ── Citation ─ un texte qu'on RELIT, rendu au mot pres ───────────────────────────────────── */
/* ⚠️ LE TEXTE D'UNE MENTION LÉGALE EST CE QU'ON CERTIFIE : il doit se détacher de la prose
   de l'écran, sinon le relecteur ne sait plus où finit l'explication et où commence la loi. */
.citation {
  margin: var(--space-3) 0;
  padding: var(--space-3) var(--space-4);
  border-left: 3px solid var(--line);
  background: var(--ink-1);
  border-radius: var(--radius-sm);
}

/* ── Tuile d'indicateur ───────────────────────────────────────────────────────────────────── */
.tile {
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
}
.tile__label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-2);
  margin-bottom: var(--space-2);
}
.tile__value {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: 600;
}

/* ── Badge de statut ──────────────────────────────────────────────────────────────────────
   Les quatre seules variantes autorisées. Un écran qui aurait besoin d'une cinquième doit
   d'abord l'ajouter au kit — sinon la sémantique des couleurs se délite écran par écran.     */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  border: 1px solid currentColor;
}
.badge--pending { color: var(--status-pending); }
.badge--alert   { color: var(--status-alert); }
.badge--ok      { color: var(--status-ok); }
.badge--neutral { color: var(--status-neutral); }

/* ── Boutons ──────────────────────────────────────────────────────────────────────────────
   Le brief demande « au maximum des boutons et des cartes cliquables ». Ils doivent donc être
   généreux : la hauteur minimale est une cible tactile, pas une esthétique.                  */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--touch-min);
  padding: 0 var(--space-5);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--ink-3);
  color: var(--paper);
  font-family: inherit;
  font-size: var(--text-base);
  cursor: pointer;
}
.btn:hover { border-color: var(--brand-accent-dim); }
.btn--primary {
  background: var(--brand-accent);
  border-color: var(--brand-accent);
  color: var(--ink-0);
  font-weight: 600;
}

/* Bouton SECONDAIRE — l'action qu'on propose sans la recommander (fermer une session, annuler).

   ⚠️ Il reste un vrai bouton : même hauteur minimale, même surface tactile. Le rendre plus petit
      « parce qu'il est secondaire » est le réflexe qui produit les cibles de 24 px qu'on rate au
      pouce — et c'est précisément sur l'action de fermeture d'une session qu'un clic manqué est
      le plus agaçant.                                                                          */
.btn--ghost {
  background: transparent;
  color: var(--paper);
  padding: 0 var(--space-4);
}
.btn--ghost:hover { background: var(--ink-3); }

/* Liste de paires libellé/valeur — l'identité d'un compte, les caractéristiques d'un véhicule.

   ⚠️ Une GRILLE et non un tableau : ce sont des paires, pas des lignes comparables entre elles.
      Sous 34rem la colonne des libellés passe au-dessus, sinon les valeurs longues (une adresse
      e-mail, un ULID) débordent sur les petits écrans.                                         */
.paires {
  display: grid;
  grid-template-columns: minmax(9rem, max-content) 1fr;
  gap: var(--space-2) var(--space-5);
  margin: 0;
}
.paires dt { color: var(--muted); }
.paires dd { margin: 0; }

@media (max-width: 34rem) {
  .paires { grid-template-columns: 1fr; gap: 0; }
  .paires dt { margin-top: var(--space-3); }
}

/* Texte réservé aux technologies d'assistance.

   ⚠️ `display: none` NE CONVIENT PAS : il retire l'élément de l'arbre d'accessibilité, donc le
      lecteur d'écran ne l'annonce pas non plus — ce qui est exactement l'inverse du but. La
      recette ci-dessous est celle qui garde le texte annonçable en le sortant du rendu visuel. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── Rythme vertical ──────────────────────────────────────────────────────────────────────
   Quelques classes d'espacement, et pas davantage.

   ⚠️ Elles ne sont pas là par goût des classes utilitaires : la politique de sécurité de contenu
      impose style-src 'self', donc un attribut style= dans un gabarit est PUREMENT ET SIMPLEMENT
      IGNORÉ par le navigateur. Pas d'erreur visible, pas de message : la mise en page est juste
      fausse. Sans ces classes, le premier réflexe d'un développeur pressé produirait ce défaut
      silencieux — bin/lint-csp.php le refuse en pré-commit, mais mieux vaut offrir l'alternative
      que de se contenter d'interdire.                                                          */
.stack-sm > * + * { margin-top: var(--space-3); }
.stack    > * + * { margin-top: var(--space-5); }
.stack-lg > * + * { margin-top: var(--space-6); }

.badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* ── Indicateurs de requête HTMX ──────────────────────────────────────────────────────────
   ⚠️ CES RÈGLES SONT LA REPRISE EXACTE de ce qu'htmx injecte lui-même quand
      includeIndicatorStyles vaut true. On l'a désactivé (voir le <meta> de layout.php) parce
      que cette injection est un <style> en ligne, que style-src 'self' bloque.

      Si on les supprimait « parce qu'on ne s'en sert pas encore », le premier indicateur de
      chargement du lot L1 resterait affiché en permanence — sans erreur, sans message, juste
      un écran qui a l'air cassé. Elles précèdent volontairement leur premier usage.

   Reproduites au caractère près depuis htmx 2.0.10 ; à re-vérifier à chaque montée de version. */
.htmx-indicator {
  opacity: 0;
  visibility: hidden;
}
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
  opacity: 1;
  visibility: visible;
  transition: opacity 200ms ease-in;
}

/* ── État vide ────────────────────────────────────────────────────────────────────────────
   Un écran sans donnée doit DIRE quoi faire. « Aucun résultat » tout seul laisse l'utilisateur
   se demander s'il a mal cherché ou si le logiciel est cassé.                                */
.empty {
  text-align: center;
  padding: var(--space-8) var(--space-5);
  color: var(--muted);
}

/* ── Champs de formulaire ─────────────────────────────────────────────────────────────────
   Les premiers du produit. Écrits ici et pas dans l'écran de connexion : tout écran de saisie
   les reprendra, et deux définitions divergentes d'un champ de saisie, c'est deux apparences
   pour la même chose.

   ⚠️ AUCUNE COULEUR LITTÉRALE — bin/lint-ui.php refuse le commit qui en introduirait une hors
      de theme.css. Ce n'est pas une coquetterie : la marque blanche rebrande par les jetons,
      et une couleur écrite en dur ici resterait celle de LBO chez un distributeur.            */
.field {
  display: block;
}

.field__label {
  display: block;
  margin-bottom: var(--space-2);
  font-size: var(--text-sm);
  color: var(--muted);
}

.input {
  /* ⚠️ `width: 100%` AVEC `box-sizing: border-box` : sans le second, le rembourrage s'ajoute
        aux 100 % et le champ déborde de sa carte. Le reset global le pose déjà, mais un champ
        est précisément l'élément où l'oubli se voit — on le redit ici plutôt que de dépendre
        d'un réglage lointain. */
  box-sizing: border-box;
  width: 100%;
  min-height: var(--touch-min);
  padding: var(--space-3);
  background: var(--ink-3);
  color: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-family: var(--font-text);
  font-size: var(--text-base);
}

.input:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
  border-color: var(--brand-accent-dim);
}

/* ⚠️ `::placeholder` hérite d'une couleur trop pâle par défaut dans plusieurs navigateurs.
      On la fixe sur un jeton dont le contraste est mesuré (voir la note de theme.css). */
.input::placeholder {
  color: var(--muted-2);
}

/* Le remplissage automatique de Chrome force un fond blanc et un texte sombre — sur un thème
   sombre, le champ devient illisible dès que le gestionnaire de mots de passe intervient,
   c'est-à-dire au moment exact où l'utilisateur se connecte. L'ombre interne est le seul
   levier que le navigateur laisse pour repeindre ce fond. */
.input:-webkit-autofill,
.input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--paper);
  box-shadow: 0 0 0 1000px var(--ink-3) inset;
}

.form-error,
.form-avis,
.form-info {
  margin: 0;
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  border: 1px solid var(--line);
}

/* ⚠️ La couleur ne porte PAS l'information à elle seule : le message dit ce qui ne va pas, et
      le bloc est annoncé par `role="alert"`. Un daltonien, un lecteur d'écran et une
      impression en noir et blanc doivent tous comprendre. */
.form-error {
  color: var(--status-alert);
  border-color: var(--status-alert);
}

/* ══ L'AVERTISSEMENT — LE NIVEAU QUI MANQUAIT, ET SON ABSENCE A COÛTÉ UNE INSTALLATION ═══════
   🔴 Le bloc n'avait que DEUX niveaux : `form-error` (rouge d'alerte) et `form-info` (peint avec
      le jeton du SUCCÈS). Rien entre les deux. Un constat qui n'empêche rien devait donc choisir
      entre « échec » et « réussite » — deux mensonges.

      Le 28/08/2026 à 3 h du matin, sur la première installation réelle, l'exploitant s'est arrêté
      devant un cadre rouge qui disait, dans sa propre dernière phrase, que l'installation pouvait
      continuer. Il a lu le COSTUME, pas le texte, et il avait raison de le faire : c'est le rôle
      d'un costume.

   ⚠️ ET IL S'ANNONCE EN `role="status"`, JAMAIS `role="alert"`. `alert` est ASSERTIF : il coupe
      la parole au lecteur d'écran. L'employer pour un non-échec, c'est interrompre quelqu'un pour
      lui dire que tout va bien. */
.form-avis {
  color: var(--status-pending);
  border-color: var(--status-pending);
}

.form-info {
  color: var(--status-ok);
  border-color: var(--status-ok);
}

/* ── Écran de connexion ───────────────────────────────────────────────────────────────────
   Deux colonnes : la marque à gauche, le formulaire à droite (maquette 01). Sous 900 px, la
   colonne de marque disparaît — sur un téléphone, l'espace appartient au formulaire.        */
.auth {
  display: grid;
  grid-template-columns: 1fr;
  min-height: 100vh;
}

.auth__brand {
  display: none;
}

.auth__panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: var(--space-6) var(--space-4);
  gap: var(--space-5);
}

.auth__card {
  width: 100%;
  /* Une carte de connexion qui s'étire sur un écran large devient une ligne de saisie de
     1 500 px — illisible, et le regard perd le lien entre l'étiquette et le champ. */
  max-width: 26rem;
}

.auth__lede {
  margin-bottom: var(--space-5);
}

.auth__submit {
  width: 100%;
  margin-top: var(--space-2);
}

.auth__pied {
  font-size: var(--text-xs);
}

@media (min-width: 900px) {
  .auth {
    grid-template-columns: 1.1fr 1fr;
  }

  .auth__brand {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--space-5);
    padding: var(--space-8);
    background: var(--ink-1);
    border-right: 1px solid var(--line);
  }

  .auth__tagline {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    line-height: 1.25;
    color: var(--paper);
  }
}

/* ── Tableaux ─────────────────────────────────────────────────────────────────────────────
   Le premier du produit, écrit avec /admin/users. Il vit ici et pas dans l'écran : la
   prochaine liste — véhicules, factures, journal d'audit — doit hériter du même vocabulaire,
   sinon le produit aura autant de styles de tableau que d'écrans.

   ⚠️ LE DÉFILEMENT HORIZONTAL EST PORTÉ PAR L'ENVELOPPE, JAMAIS PAR LA PAGE. Un tableau à six
      colonnes sur un téléphone déborde ; si c'est le corps de page qui défile, toute la mise en
      page glisse sous le doigt et l'utilisateur perd la barre de navigation. `.tableau-defilant`
      confine le débordement au tableau lui-même.                                             */
.tableau-defilant {
  overflow-x: auto;
  /* Le trait rappelle qu'il y a quelque chose à droite : sans lui, sur un écran étroit, rien
     n'indique que la dernière colonne existe. */
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.tableau {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

.tableau th,
.tableau td {
  padding: var(--space-3);
  text-align: left;
  /* ⚠️ Filet SOUS chaque ligne, jamais autour de chaque cellule : une grille complète produit
        un damier illisible dès la quatrième colonne. */
  border-bottom: 1px solid var(--line-2);
  vertical-align: top;
}

.tableau thead th {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted-2);
  border-bottom-color: var(--line);
  /* L'en-tête reste visible quand la liste est longue et que la page défile. */
  position: sticky;
  top: 0;
  background: var(--ink-2);
}

/* La dernière ligne n'a pas besoin de filet : le bord de l'enveloppe le fait déjà. */
.tableau tbody tr:last-child th,
.tableau tbody tr:last-child td {
  border-bottom: none;
}

.tableau tbody tr:hover {
  background: var(--ink-3);
}

/* Les badges d'une cellule d'état s'alignent et vont à la ligne plutôt que d'élargir la colonne. */
.tableau .badges {
  margin: 0;
}


/* ── Textes juridiques ────────────────────────────────────────────────────────────────-----
   L ecran de consentement presente des textes longs. Deux contraintes s y opposent : la carte
   de connexion est etroite (26rem), et un texte juridique illisible n est pas un texte lu.     */
.auth__card--large {
  max-width: 46rem;
}

.legal {
  margin: var(--space-5) 0;
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--ink-1);
}

/* Le corps DEFILE dans son cadre plutot que d allonger la page a l infini : sur un texte de
   trois mille mots, les deux boutons se retrouveraient hors de portee, et l utilisateur
   conclurait qu il n y a pas d issue. */
.legal__corps {
  max-height: 22rem;
  overflow-y: auto;
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--muted);
}

/* ── Images ───────────────────────────────────────────────────────────────────────────
   🔴 AUCUNE REGLE DE CE PRODUIT NE TOUCHAIT UNE IMAGE, DANS AUCUNE DE SES QUATRE FEUILLES.
      Mesure du 13/09/2026 : `grep -rn "img|object-fit|aspect-ratio" public/assets/css/*.css`
      rendait une sortie VIDE. Un `<img>` que rien ne contraint est rendu a sa taille
      INTRINSEQUE : une photo d'appareil de 4000 px sortait a 4000 px, sur une fiche vehicule
      et sur l'atelier des photos. Rapporte par l'exploitant en production.

   🔑 ET LA DECISION QUI AVAIT FERME LE SUJET REPOSAIT SUR UNE PREMISSE FAUSSE.
      `modules/vehicles/FicheController.php` ecrivait, verbatim : « aucune vignette derivee n'est
      stockee — l'image d'origine est servie, LE NAVIGATEUR LA REDIMENSIONNE ». Aucun navigateur
      ne redimensionne un `<img>` que rien ne contraint. C'est cette phrase qui a classe le sujet
      comme une dette de VOLUME (« le jour ou le volume l'exigera ») au lieu d'un defaut
      d'AFFICHAGE — et deux autres commentaires deleguaient explicitement la mise en page a une
      feuille de style qui n'avait jamais rien recu.

   🔴 LE PLANCHER EST UN SELECTEUR D'ELEMENT, PAS UNE CLASSE, ET C'EST DELIBERE. Une classe
      ne protege que les endroits ou quelqu'un a pense a l'ecrire : un `<img>` ajoute demain par
      un autre ecran naitrait avec le meme defaut. Aucune porte n'exige qu'une balise PORTE une
      classe — `lint-ui` verifie qu'une classe EMPLOYEE est DEFINIE, jamais l'inverse.

   ⚠️ LE RISQUE DE REGRESSION EST NUL ET IL A ETE MESURE : le produit entier ne rend que DEUX
      balises `<img>` (fiche vehicule et atelier des photos). Aucune image existante ne peut
      casser.                                                                                  */
img {
  max-width: 100%;
  height: auto;
}

/* ── Galerie de vignettes ─────────────────────────────────────────────────────────────
   Les deux ecrans qui montrent des photos rendaient une PILE VERTICALE : `<ul class="stack-sm">`,
   dont la seule regle est une marge (`.stack-sm > * + *`). Chaque element occupait toute la
   largeur, et rien ne bornait l'image qu'il contenait.

   🔑 AUCUN NOMBRE DE VIGNETTES N'EST CODE ICI, et c'est une contrainte du depot, pas un gout :
      trois commentaires refusent d'arbitrer le « 4 vignettes + 4 » de la maquette 04 — « ce sont
      des constantes de DESSIN, et les coder en dur reproduirait une decision que personne n'a
      prise ». `auto-fill` + `minmax` laisse la feuille decider du nombre par ligne : c'est ce qui
      rend enfin VRAIE la phrase « c'est la feuille de style qui decide de la mise en page ».

   ⚠️ `aspect-ratio` PLUTOT QUE `width`/`height` SUR LA BALISE. Les deux suppriment le saut de
      mise en page, mais ce depot n'ecrit AUCUN attribut de dimension sur aucune balise — en
      ouvrir la pratique au detour d'un correctif serait une convention neuve non decidee.

   ⚠️ `object-fit: cover` RECADRE, il ne deforme pas. Une photo d'appareil est en 3:2 ou 4:3 et
      aucun des trois rapports de la maquette ne la contient sans recadrer ; `contain` laisserait
      des bandes vides sur une grille dont tout l'interet est le balayage de l'oeil.            */
.galerie {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
  gap: var(--space-3);
  margin: var(--space-4) 0;
  padding: 0;
  list-style: none;
}

/* ⚠️ L'ATELIER PORTE DES GESTES SOUS CHAQUE VIGNETTE — renommer, reordonner, couvrir, retirer.
      A 10 rem, ses boutons se chevauchent. Le modificateur elargit la maille SANS dupliquer la
      grille : une seconde grille serait une seconde verite a tenir d'accord.                   */
.galerie--atelier {
  grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
}

.galerie__vue {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--ink-1);
}

/* ── Cartes de la Synthese ───────────────────────────────────------------------------------
   Une carte par societe accessible. Elles sont ENTIEREMENT cliquables : une carte dont seuls
   trois mots reagissent se fait cliquer dans le vide neuf fois sur dix.                       */
.cartes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: var(--space-4);
  margin: var(--space-5) 0;
}

/* ── Couverture d'une carte de stock ────────────────────────────────────────────────────
   🔴 LA PLACE EST RESERVEE EN PERMANENCE, MEME SANS PHOTO — et c'est la grille qui l'impose,
      pas un gout. `.cartes` est un `grid` : dans une meme ligne, les elements s'alignent sur le
      plus haut. Une image qui n'apparaitrait QUE quand elle existe ferait danser le titre d'une
      carte a l'autre — l'un au ras du haut, l'autre 78 px plus bas — et le balayage de l'oeil,
      qui est tout ce que cet ecran offre, en serait detruit. La majorite des vehicules n'ont
      aucune photo : c'est un argument POUR reserver, pas contre.

   ⚠️ LE MEME SELECTEUR PORTE LES DEUX ETATS, et le modificateur ne change QUE le remplissage.
      Deux regles independantes divergeraient sur la hauteur au premier ajustement, et la grille
      redeviendrait irreguliere — exactement le defaut qu'on ferme ici.

   ⚠️ LE RAPPORT EST 16/9 DEPUIS LE 06/10/2026 — ECART VOLONTAIRE A LA MAQUETTE 03, consigne au
      00B § 44. La maquette posait un bandeau de 248 x 78 (~3,18/1) ; Anthony a juge meilleur le
      format de la carte client (« Mes vehicules », 16/9) et l'a demande pour le stock de l'Owner
      aussi : un bandeau plat coupait la voiture en haut et en bas. `--haute` (16/9 elle aussi)
      reste posee par les cartes du client, inoffensive.                                       */
.carte__couverture {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--radius-sm);
  margin-bottom: var(--space-3);
}

/* ⚠️ UN APLAT NU, SANS PICTOGRAMME. La maquette 03 pose une silhouette de voiture dans chaque
      cadre vide, mais ce symbole est un actif de MAQUETTE : le produit n'a aucun jeu d'icones, et
      en inventer un au detour d'un correctif serait un sujet de socle deguise en detail.        */
.carte__couverture--vide {
  background: var(--ink-1);
  border: 1px solid var(--line);
}

.carte {
  display: block;
  padding: var(--space-4);
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  /* Le lien ne doit pas ressembler a un lien : c est une carte. La couleur du texte reprend
     celle du corps, et le soulignement disparait. */
  color: var(--paper);
  text-decoration: none;
}

.carte:hover {
  border-color: var(--brand-accent-dim);
  background: var(--ink-3);
}

/* Le focus CLAVIER reste visible : sans lui, une grille de cartes est intraversable au clavier,
   et rien a l ecran ne dit ou l on se trouve. */
.carte:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
}

.carte__titre {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-lg);
}

.carte__pied {
  margin: var(--space-3) 0 0;
  font-size: var(--text-xs);
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   LE KIT DE PARTIELS — L2/U4
   ══════════════════════════════════════════════════════════════════════════════════════════
   Cinq familles que le vocabulaire existant ne couvrait pas. Tout le reste du kit réutilise ce
   qui était déjà là : .card, .tuile, .tableau, .badge et ses quatre variantes, .btn, .input,
   .field, .form-error, .empty, .htmx-indicator.

   ⚠️ AUCUNE COULEUR LITTÉRALE ICI. `bin/lint-ui.php` la refuserait, et pour un motif de produit :
      l'installeur réécrit theme.css et TOUT doit suivre. Une couleur en dur serait invisible au
      distributeur — son thème s'appliquerait partout SAUF là.                                   */

/* ── Fil d'Ariane ─────────────────────────────────────────────────────────────────────────
   Le dernier segment n'est PAS un lien : il ne doit donc pas en avoir l'apparence non plus.    */
.fil-ariane {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--muted-2);
}

.fil-ariane__lien { color: var(--muted); }

.fil-ariane__ici { color: var(--paper); }

.fil-ariane__sep { color: var(--line); }

/* ── Pagination ───────────────────────────────────────────────────────────────────────────  */
.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
  font-size: var(--text-sm);
}

/* ── Barre de filtres ─────────────────────────────────────────────────────────────────────  */
.barre-filtres {
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: var(--ink-2);
}

.barre-filtres__compte { margin-left: var(--space-3); }

/* ── Aide de champ ────────────────────────────────────────────────────────────────────────
   Un `<details>` natif : cliquable ET focusable, jamais au survol seul. La cible fait au moins
   `--touch-min` — le brief vise un utilisateur qui « ne comprend pas grand-chose à
   l'informatique », et une pastille de 12 px ne se vise ni au doigt ni tremblant.              */
.aide-champ { display: inline-block; }

.aide-champ__declencheur {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--touch-min);
  min-height: var(--touch-min);
  border-radius: var(--radius-pill);
  color: var(--muted);
  cursor: pointer;
}

.aide-champ__corps {
  max-width: 42rem;
  margin-top: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-left: 2px solid var(--line);
  font-size: var(--text-sm);
}

/* ── Dialogue ─────────────────────────────────────────────────────────────────────────────
   `<dialog>` natif : le piège de focus, Échap et le retour du focus au déclencheur sont livrés
   par le navigateur. On ne style QUE l'apparence — toucher au comportement demanderait du
   JavaScript, que la CSP interdit en ligne et qu'aucune chaîne de build ne pourrait produire.   */
.dialogue {
  max-width: 42rem;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--ink-1);
  color: var(--paper);
}

.dialogue__corps {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5);
}

.dialogue__titre {
  font-family: var(--font-display);
  font-size: var(--text-lg);
}

/* ── Impression ───────────────────────────────────────────────────────────────────────────
   Une seule feuille, minimale : on retire le chrome et on repasse sur fond clair. Les vrais
   documents (contrats, factures) ne passent pas par ici — ils sont produits en PDF par le
   générateur, avec leur propre thème papier.

   🔴 IL Y AVAIT DEUX BLOCS `@media print`, ET CE COMMENTAIRE DISAIT DÉJÀ « une seule feuille ».
      Une prémisse tombée dans le fichier même qui la contredit — le défaut signature de ce dépôt,
      trouvé le 03/09/2026 en instruisant la Définition de fini de L0. Le canon exige une « feuille
      `@media print` unique » (`99-ROADMAP.md:144`) ; les deux blocs sont fusionnés ici.

   🔴 ET LE CHROME RESTAIT IMPRIMÉ. La règle ne masquait que `.topbar`, `.skip-link` et `.btn` :
      la barre latérale et le pied de page partaient à l'imprimante, alors que l'item « Ctrl+P sur
      la page d'accueil masque le chrome » (`99-ROADMAP.md:164`) est écrit dans la Définition de
      fini d'un lot DÉCLARÉ LIVRÉ. Un item mesurablement faux sur un lot clos.

   ⚠️ `.auth` EST MASQUÉ LUI AUSSI, ET POUR UNE RAISON PARTICULIÈRE : personne n'imprime un
      formulaire de connexion, et la règle générale masquerait son bouton sans masquer le reste —
      on obtiendrait un formulaire sans moyen de l'envoyer, c'est-à-dire une page qui ment.

   🔑 `ConventionChromeTest` GARDE CETTE FEUILLE depuis le 03/09 : un sélecteur de chrome retiré
      d'ici, ou un second bloc `@media print` rouvert, fait rougir la revue.                     */
@media print {
  .auth,
  .topbar,
  .skip-link,
  .sidebar,
  .pied,
  .btn { display: none !important; }

  body {
    background: var(--print-bg);
    color: var(--print-ink);
  }

  .card, .tile { border-color: var(--print-line); }
}

/* ── Matrice rôles × permissions (/admin/roles) ────────────────────────────────────────────
   Une grille de cases à cocher, dense par nature. Trois précautions, et chacune répond à une
   façon de se tromper de case :

   1. `accent-color` : sans elle, une case native se rend en bleu système sur fond sombre — la
      seule tache de couleur de l'application à échapper au thème, donc à la marque blanche.
      C'est le premier `accent-color` du produit ; s'il en apparaît d'autres, ils viendront ici.
   2. Les cases sont AGRANDIES et leur cellule est cliquable en entier (`<label>` étiré). Une
      case de 13 px au milieu d'un tableau se rate à la souris comme au doigt, et se rater ici
      veut dire retirer un droit à quelqu'un sans s'en apercevoir.
   3. La colonne des permissions est COLLANTE : sur une grille qui défilera à l'horizontale dès
      le deuxième module, une case cochée sans savoir de quelle ligne elle relève est pire
      qu'une case non cochée.                                                                 */
.matrice th[scope="row"] {
  position: sticky;
  left: 0;
  background: var(--ink-2);
  text-align: left;
  font-weight: 400;
}

.matrice__module th {
  font-family: var(--font-display);
  font-size: var(--text-sm);
  color: var(--paper);
  background: var(--ink-3);
}

.matrice__case {
  text-align: center;
  padding: 0;
}

.matrice__case label {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--touch-min);
  width: 100%;
  cursor: pointer;
}

.matrice__case input[type="checkbox"] {
  width: 1.15rem;
  height: 1.15rem;
  accent-color: var(--brand-accent);
  cursor: pointer;
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   S13 — LES DEUX TABLEAUX DE BORD (maquettes 02 et 05)
   ══════════════════════════════════════════════════════════════════════════════════════════════

   ⚠️ AUCUNE COULEUR LITTÉRALE ICI. `bin/lint-ui.php` les refuse hors de `theme.css` : une teinte
      écrite en dur survivrait au changement de charte d'un revendeur en marque blanche, et
      c'est exactement ce qu'on ne peut pas se permettre sur l'écran d'accueil du produit. */

/* ── LA PAGE À COLONNE LATÉRALE ───────────────────────────────────────────────────────────────
   La classe est posée par le gabarit, jamais devinée par un `:has()` que tous les navigateurs ne
   servent pas de la même façon.

   ⚠️ ELLE S'APPELLE `page--laterale` DEPUIS LE 27/08/2026, et non plus `page--societe` : elle ne
      décrit qu'une FORME — « il y a une colonne à gauche » — et depuis que les écrans d'instance
      ont eux aussi leur barre latérale, l'ancien nom aurait obligé une page d'administration à se
      déclarer « société » pour obtenir sa grille.

   ⚠️ `var(--sidebar-width)` PLUTÔT QUE `15rem` : le jeton valait 248 px, relevés dans les
      maquettes 05 et 06 (`JOURNAL-L0:112` — « 248 px, pas 260 »), et n'avait AUCUN consommateur ;
      la grille, elle, écrivait 240 px à la main. Deux vérités pour une largeur, dont la fausse
      était celle qui s'affichait.

   ⚠️ `minmax(0, 1fr)` sur la colonne de contenu, pour la même raison que sur `.page` : un tableau
      large ou une barre qui ne rétrécit pas ne doit pas pouvoir écarter la page entière. */
.page--laterale {
  grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
  grid-template-areas:
    "topbar  topbar"
    "sidebar content"
    "pied    pied";
}

.sidebar {
  grid-area: sidebar;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-5) var(--space-4);
  background: var(--ink-1);
  border-right: 1px solid var(--line);
}

/* L'en-tête de la colonne : le nom de la société et son code sous une société, « Administration »
   et le nom de l'instance sur les écrans d'instance. Les classes disent la FORME (en-tête, titre,
   mention) et non l'occasion : elles servent les deux barres, qui sont le même composant.        */
.sidebar__entete {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-bottom: var(--space-4);
}

.sidebar__titre { font-family: var(--font-display); font-size: var(--text-lg); }
.sidebar__mention { font-size: var(--text-xs); color: var(--muted-2); }

.sidebar__lien {
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--muted);
  text-decoration: none;
}

.sidebar__lien:hover { background: var(--ink-2); color: var(--paper); }

/* La page affichée. `aria-current` porte l'information pour le lecteur d'écran ; une classe n'en
   serait qu'une copie à tenir. */
.sidebar__lien[aria-current="page"] {
  background: var(--ink-2);
  color: var(--paper);
  box-shadow: inset 2px 0 0 var(--brand-accent);
}

/* ── LES RUBRIQUES DE LA BARRE DE SOCIÉTÉ — 30/09/2026 (00B § 31) ────────────────────────────
   Un `<details>` natif : le titre se lit comme un lien de même rang que « Tableau de bord »,
   avec un chevron qui tourne à l'ouverture ; les écrans de la rubrique sont en retrait, sous un
   filet, pour qu'on voie à quelle rubrique ils appartiennent sans relire le titre.            */
.sidebar__rubrique-titre {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--muted);
  cursor: pointer;
  list-style: none;
}

.sidebar__rubrique-titre::-webkit-details-marker { display: none; }

/* Décoratif : `<details>` annonce déjà replié/déplié. La seconde déclaration lui donne un texte
   alternatif VIDE ; un navigateur qui ne la comprend pas garde la première. */
.sidebar__rubrique-titre::after {
  content: "›";
  content: "›" / "";
  color: var(--muted-2);
}

.sidebar__rubrique[open] > .sidebar__rubrique-titre::after { transform: rotate(90deg); }

.sidebar__rubrique-titre:hover { background: var(--ink-2); color: var(--paper); }

.sidebar__rubrique-liens {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin: var(--space-1) 0 var(--space-2) var(--space-3);
  padding-left: var(--space-2);
  border-left: 1px solid var(--line);
}

.sidebar__retour {
  margin-top: var(--space-5);
  padding: var(--space-2) var(--space-3);
  color: var(--muted-2);
  font-size: var(--text-sm);
  text-decoration: none;
}

.sidebar__retour:hover { color: var(--paper); }

/* ── SOUS 900 px, LA COLONNE PASSE AU-DESSUS DU CONTENU ───────────────────────────────────────
   ⚠️ CE N'EST PAS UN CONFORT, C'EST UNE NÉCESSITÉ MESURÉE. À 390 px de large, une colonne de
      248 px ne laisse que 142 px au contenu, alors que `.tuiles` réclame 12 rem (192 px) par
      tuile et que `.content` prend 64 px de padding : la page déborderait de nouveau
      horizontalement — le défaut qu'on vient de corriger, déplacé d'un cran.

   ⚠️ LES LIENS PASSENT À LA LIGNE, ILS NE DÉFILENT PAS. Un `overflow-x: auto` sur une bande de
      liens cache des entrées sans le dire (mesuré : 275 px hors champ sur un portable) ; le
      passage à la ligne coûte de la hauteur, mais il ne cache RIEN. Pour un public qui « ne
      comprend pas beaucoup l'informatique », un lien invisible est un lien inexistant.

   ⚠️ 900 px ET NON 768 : à 900 px la colonne de contenu vaut encore 652 px — en dessous, deux
      tuiles ne tiennent plus côte à côte et la colonne latérale coûte plus qu'elle ne rend. La
      valeur fait écho au `min-width: 900px` de l'écran de connexion, plus haut dans ce fichier :
      une seule charnière pour toute l'application, pas une par composant.                       */
@media (max-width: 900px) {
  .page--laterale {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "topbar"
      "sidebar"
      "content"
      "pied";
  }

  .sidebar {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-right: 0;
    border-bottom: 1px solid var(--line);
  }

  /* L'en-tête reprend sa ligne entière : titre et mention côte à côte, les liens en dessous. */
  .sidebar__entete {
    flex-direction: row;
    align-items: baseline;
    gap: var(--space-2);
    width: 100%;
    margin-bottom: var(--space-1);
  }

  .sidebar__retour { margin-top: 0; }

  /* Une rubrique ouverte prend sa ligne entière, et ses écrans passent à la ligne comme le reste
     de la bande : rien ne défile, rien ne se cache. */
  .sidebar__rubrique[open] { flex-basis: 100%; }

  /* Le chevron reste collé au titre : étiré sur toute la ligne, il se perdrait à l'autre bord. */
  .sidebar__rubrique-titre { justify-content: flex-start; }

  .sidebar__rubrique-liens {
    flex-direction: row;
    flex-wrap: wrap;
    margin: 0 0 var(--space-1);
    padding-left: var(--space-3);
    border-left: 0;
  }
}

/* Le pied de page : la mention confidentielle à gauche, la version à droite. La version reste
   même quand la mention est vide — c'est le seul repère de la recette. */
.pied {
  grid-area: pied;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-6);
  border-top: 1px solid var(--line-2);
  color: var(--muted-2);
  font-size: var(--text-xs);
}

.pied__version { margin-left: auto; }

/* Les tuiles : quatre sur la Synthèse, autant que de modules sur un tableau de bord. */
.tuiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--space-4);
  margin: var(--space-5) 0;
}

.tuile {
  display: block;
  padding: var(--space-4);
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  text-decoration: none;
  color: inherit;
}

a.tuile:hover { border-color: var(--brand-accent-dim); }

.tuile__titre {
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-2);
}

.tuile__valeur {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  margin: var(--space-2) 0 var(--space-1);
}

.tuile__legende { font-size: var(--text-xs); }

/* ⚠️ UNE TUILE VIDE RESTE VISIBLE, ELLE EST JUSTE EN RETRAIT. L'escamoter laisserait croire que
      la question ne se pose pas ; la mettre à zéro affirmerait une mesure qui n'a pas été faite. */
.tuile--vide .tuile__valeur { color: var(--muted-2); }

/* Les trois colonnes du tableau de bord de société : activité, à traiter, échéances. */
.colonnes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: var(--space-4);
  margin: var(--space-5) 0;
  align-items: start;
}

.flux { list-style: none; margin: 0; padding: 0; }

.flux__ligne {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--line-2);
}

.flux__ligne:last-child { border-bottom: 0; }
.flux__quand { color: var(--muted-2); font-size: var(--text-xs); white-space: nowrap; }
.flux__quoi { color: var(--paper); }

.liste-nue { list-style: none; margin: 0; padding: 0; }

.attente, .echeance {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-2) 0;
}

.attente__marque {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  flex: none;
  border-radius: 50%;
  background: var(--ink-3);
  color: var(--muted-2);
  font-size: var(--text-xs);
}

.attente--urgent .attente__marque { background: var(--status-alert); color: var(--ink-0); }
.echeance__quand { color: var(--muted-2); font-size: var(--text-xs); white-space: nowrap; }

/* La carte d'entité de la Synthèse porte ses chiffres PROPRES, ou son repli de nature. */
.carte__nature, .carte__repli { font-size: var(--text-sm); margin-top: var(--space-1); }

.carte__chiffres {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin: var(--space-3) 0;
}

.chiffre { display: flex; flex-direction: column; }
.chiffre__valeur { font-family: var(--font-display); font-size: var(--text-lg); }

.chiffre__quoi {
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-2);
}

.carte--transverse { border-color: var(--brand-accent-dim); }
.carte__action { color: var(--brand-accent); margin-top: var(--space-3); }

.section__titre {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  margin: var(--space-6) 0 var(--space-2);
}

.page__nature { color: var(--muted); margin-top: calc(-1 * var(--space-2)); }

/* Un module qui a échoué est ISOLÉ, mais son échec est DIT — voir `Dashboard\Collecteur`. */
.card--alerte { border-color: var(--status-alert); }

/* ── S16 — l'état du schéma ───────────────────────────────────────────────────────────────────
   Un repli natif `<details>`, jamais un script : la CSP interdit tout JS en ligne, et le repli du
   navigateur fonctionne sans JS, au clavier, et ne perd aucun état au rechargement. */
.carte-schema {
  margin: var(--space-3) 0;
  padding: var(--space-3) var(--space-4);
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.carte-schema > summary {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  cursor: pointer;
  font-size: var(--text-sm);
}

/* ⚠️ Le marqueur natif est conservé : le retirer priverait le lecteur du seul indice visuel
   qu'un bloc s'ouvre, et rien ne le remplacerait sans script. */
.carte-schema[open] > summary { margin-bottom: var(--space-3); }
/* ⚠️ `.tableau`, ET C'ÉTAIT `.table` — UNE RÈGLE QUI DÉSIGNAIT LE VIDE. Cinq gabarits écrivaient
   `class="table"`, une classe que cette feuille ne définit nulle part : ils rendaient un tableau
   NU. Le 26/08/2026 ils ont été passés à `.tableau` ; cette règle-ci, restée en arrière, aurait
   alors cessé de s'appliquer à son tour, et l'écran du schéma aurait perdu sa petite taille sans
   que rien ne le signale. Une correction qui laisse derrière elle une seconde panne est le même
   défaut, retourné. */
.carte-schema .tableau { font-size: var(--text-xs); }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   L'INSTALLEUR — huit classes que les gabarits employaient et que cette feuille n'avait JAMAIS
   définies.
   ══════════════════════════════════════════════════════════════════════════════════════════

   ⚠️ CE N'EST PAS UNE AMÉLIORATION, C'EST UNE PANNE RÉPARÉE. Mesuré le 26/08/2026 : quinze
      classes employées par les gabarits n'avaient de règle nulle part, et huit d'entre elles
      composaient l'ossature entière de l'installeur — `.install`, `.install__page`,
      `.install__entete`, `.install__rang`, `.install__contenu`, `.install__chemin`,
      `.install__geste`, `.install__lien`. L'installeur rendait donc un document NU : pas de
      cadre, pas de largeur de lecture, un en-tête empilé, des chemins de fichiers noyés dans
      le texte courant. C'est le premier écran qu'un client voit du produit.

   ⚠️ ET IL NE PEUT PAS EMPRUNTER L'OSSATURE DE L'APPLICATION. `.page` est une grille à barre
      latérale et barre haute, avec `grid-area` sur chacun de ses membres ; l'installeur n'a ni
      l'une ni l'autre — il n'y a pas encore de session, donc pas de navigation possible. D'où
      une ossature propre, volontairement minuscule : un cadre centré, un en-tête, un contenu.

   ⚠️ SOBRE ET NON DÉFINITIF. La révision de l'installeur est un chantier ouvert (parcours
      complet : compatibilité, base, mot de passe, connexion). Ces règles rendent l'existant
      LISIBLE ; elles ne préjugent pas de ce que ce parcours deviendra.                        */

.install {
  /* Le pied doit tomber en bas même sur un écran court : l'ossature est une colonne dont le
     contenu s'étire. `min-height: 100vh` est déjà posé sur `body`. */
  display: flex;
  flex-direction: column;
}

.install__page {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: var(--space-6);
  box-sizing: border-box;
  width: 100%;

  /* ⚠️ MÊME BORNE QUE `.auth__card`, ET POUR LA MÊME RAISON : au-delà, l'œil perd le lien entre
     une étiquette et son champ. L'installeur est plus large parce qu'il porte des tableaux de
     vérification — mais borné tout de même. */
  max-width: 48rem;
  margin: 0 auto;
  padding: var(--space-6) var(--space-5);
}

.install__entete {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--line-2);
}

/* « Étape 3 sur 6 » : un repère, pas un titre. Il ne doit jamais disputer la vedette à la marque. */
.install__rang {
  margin: 0;
  font-size: var(--text-sm);
}

.install__contenu {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: var(--space-5);
}

/* ⚠️ UN CHEMIN OU UNE COMMANDE EST FAIT POUR ÊTRE RECOPIÉ, souvent depuis un écran vers un
      terminal. Il lui faut donc un fond qui le détache du texte courant, et surtout
      `word-break` : une commande de 120 caractères sans coupure déborde de sa carte et la
      moitié droite devient illisible — c'est-à-dire irrecopiable. Même raison que
      `.cle-secrete`. */
.install__chemin,
.install__lien {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  background: var(--ink-1);
  color: var(--paper);
  font-size: var(--text-sm);
  line-height: 1.6;
  word-break: break-all;
}

/* Le geste à faire quand une vérification échoue : il court sous la ligne qu'il concerne, sur
   toute la largeur du tableau. Il se lit comme une note, pas comme une cellule de données. */
.install__geste {
  padding-top: 0;
  font-size: var(--text-xs);
  line-height: 1.6;
  white-space: normal;
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   Deux dernières classes orphelines, du même relevé.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

/* ⚠️ DEUX COLONNES QUI REDEVIENNENT UNE, ET LE SEUIL EST CELUI DE LA SAISIE. Deux champs côte à
      côte sous 34rem donnent deux champs trop étroits pour ce qu'ils portent — un DSN, un nom
      d'hôte. `auto-fit` le fait sans point de rupture à maintenir. */
.grille-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
  gap: var(--space-4);
}

/* La mention de gauche du pied. `min-width: 0` lui permet de céder la place à la version, qui
   ne doit jamais être poussée hors de l'écran : c'est le seul repère de la recette. */
.pied__mention {
  min-width: 0;
}

/* Un formulaire qui ne sert qu'à porter un bouton et un jeton CSRF — dans une cellule de tableau,
   à côté d'un autre geste.

   ⚠️ `display: contents` ET NON `display: inline`, ET C'EST LE MÊME ARBITRAGE QUE `.topbar__form`.
      Un `<form>` est un bloc : dans un `<td>`, il pousse son bouton sur sa propre ligne et ouvre
      un rythme vertical au milieu d'un tableau. `contents` fait disparaître SA boîte sans toucher
      à celle de ses enfants — le bouton se pose donc exactement où il se poserait sans
      formulaire, et l'envoi, lui, fonctionne comme avant.

   ⚠️ ELLE S'APPELAIT `.inline`, ET ELLE N'EXISTAIT PAS. Deux gabarits l'employaient — la liste des
      portefeuilles et celle des sites — via `form_open($action, ['class' => …])`. Trouvée le
      26/08/2026 en inspectant le DOM dans un navigateur, PAS par une porte : la première rédaction
      de `lint-ui` ne lisait que le balisage et ignorait les classes passées par un aide PHP. Elle
      lit désormais les deux.                                                                    */
.form-inline { display: contents; }

/* ── Fiche tiers — onglets, titre, actions de ligne, valeur révélée ───────────────────────────
   L3/T8. Quatre composants nés avec `templates/societe/fiche-tiers.php`, écrits ici parce que
   `bin/lint-ui.php` a refusé de les laisser passer sans règle : « ces écrans rendent SANS STYLE,
   et rien d'autre ne le signale ».

   ⚠️ Trois AUTRES classes de ce gabarit ont été RENOMMÉES plutôt que définies. La première
      rédaction inventait `.etiquette`, `.etiquette--eteinte`, `.etiquette--attention` et
      `.btn--discret` — alors que `.badge`, `.badge--neutral`, `.badge--alert` et `.btn--ghost`
      existaient déjà et disaient la même chose. C'est exactement ce que le message du lint
      suggère de vérifier en premier : « la feuille définit peut-être déjà la même chose sous une
      autre orthographe ». Un composant en double diverge toujours, et c'est le second qu'on
      oublie de corriger.                                                                        */

/* Le nom du tiers, en tête de fiche. Plus grand qu'un `.eyebrow`, moins qu'un titre de page :
   la page a déjà le sien, et deux h1 concurrents désorientent un lecteur d'écran.               */
.titre-fiche {
  font-size: var(--text-lg);
  font-weight: 600;
  margin: 0;
}

/* La barre d'onglets. Des LIENS, pas des boutons — voir l'en-tête du gabarit.

   ⚠️ `flex-wrap` n'est pas décoratif : il y a huit onglets, et sur un écran de portable ils ne
      tiennent pas sur une ligne. Sans lui, les derniers sortent du cadre — donc « RGPD » et
      « Interactions » deviennent inatteignables au doigt, en silence.                           */
.onglets {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.onglets__item {
  display: inline-block;
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--ink-3);
  border-radius: var(--radius-pill);
  color: var(--muted);
  text-decoration: none;
}

.onglets__item:hover {
  border-color: var(--brand-accent-dim);
  color: var(--paper);
}

/* ⚠️ L'onglet ouvert se distingue par la COULEUR ET par la bordure, pas par la couleur seule :
      un daltonisme rouge-vert ne verrait rien. `aria-current="page"` porte l'information pour
      un lecteur d'écran ; ces deux propriétés la portent pour un œil.                           */
.onglets__item--actif {
  border-color: var(--brand-accent);
  color: var(--paper);
  font-weight: 600;
}

/* Deux formulaires côte à côte dans une cellule de tableau (Afficher · Marquer vérifié).

   ⚠️ Les enfants directs sont des `<form class="form-inline">`, qui portent `display: contents` :
      ce sont donc les BOUTONS qui deviennent les éléments flex de cette ligne, pas les
      formulaires. Sans `display: contents` sur le formulaire, chaque bouton serait seul dans son
      bloc et la ligne ferait deux fois la hauteur.                                              */
.actions-ligne {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* L'IBAN complet, après le geste tracé qui le révèle.

   ⚠️ `user-select: all` sélectionne la valeur entière d'un seul clic. C'est ce qui remplace le
      bouton « Copier » que la CSP interdit — et qui ferait entrer le numéro dans le
      presse-papiers du poste, où il resterait jusqu'à la copie suivante.                        */
.valeur-revelee {
  font-size: var(--text-lg);
  letter-spacing: 0.08em;
  user-select: all;
  word-break: break-all;
}

/* ══ COMBOBOX D'AUTO-COMPLÉTION (L3/T13) ═════════════════════════════════════════════════════

   Le composant vit dans `assets/js/modules/combobox.js` ; ces classes sont les SEULES qu'il pose.
   Aucune valeur de couleur littérale ici — `bin/lint-ui.php` le refuserait, et à raison : la
   marque blanche tient à ce que `theme.css` reste la source unique.                              */
.suggest {
  position: relative;
}

/* ⚠️ `position: absolute` ET NON un flux normal : la liste doit RECOUVRIR ce qui suit, sinon
      chaque ouverture pousse le reste du formulaire vers le bas et le champ suivant fuit sous le
      curseur. C'est le défaut qui rend un combobox pénible sans qu'on sache dire pourquoi.

   ⚠️ `max-height` + `overflow-y` : la porte rend au plus 20 résultats, mais 20 lignes suffisent
      déjà à dépasser un petit écran. C'est cette hauteur bornée que `scrollIntoView({block:
      'nearest'})` exploite côté JS.                                                             */
.suggest__liste {
  position: absolute;
  z-index: 20;
  left: 0;
  right: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  max-height: 16rem;
  overflow-y: auto;
  /* 🔴 0.96.95 (00B § 47) : `--ink-2` (le fond des cartes), et NON `--paper` — `--paper` est la couleur du TEXTE
        (`theme.css`) : depuis L3/T13, le libellé de chaque proposition s'écrivait en blanc cassé sur du blanc cassé,
        invisible (vu au navigateur sur le vendeur déjà connu ; le combobox de l'annuaire avait le même défaut). */
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

.suggest__option {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-2) var(--space-3);
  cursor: pointer;

  /* ⚠️ La cible tactile minimale du référentiel, pas une valeur choisie ici : une liste de
        propositions se touche au doigt autant qu'elle se parcourt au clavier.                   */
  min-height: var(--touch-min);
}

/* ⚠️ UNE SEULE RÈGLE POUR LE SURVOL ET POUR L'ACTIF CLAVIER, et c'est délibéré : la classe est
      posée par le JS sur l'option `aria-selected`, donc l'utilisateur au clavier voit exactement
      ce que voit l'utilisateur à la souris. Deux apparences distinctes feraient croire à deux
      états.                                                                                     */
.suggest__option:hover,
.suggest__option--actif {
  background: var(--line-2);
}

.suggest__detail {
  font-size: var(--text-xs);
  color: var(--muted);
}

.suggest__vide {
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  color: var(--muted);
}

/* ⚠️ L'ANNONCE EST LUE, PAS VUE. Elle porte `aria-live="polite"` et sert aux lecteurs d'écran :
      « 3 résultats ». La masquer par `display: none` la retirerait de l'arbre d'accessibilité —
      donc la rendrait muette. C'est le piège classique de cette technique.                      */
.suggest__annonce {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   LE CALENDRIER — L9/A8, maquette 10.

   🔴 UNE GRILLE CSS, PAS UN `<table>`. `bin/lint-ui.php` refuse `<table` dans une vue de module —
      le kit rend les tableaux — et la règle sert ici : un calendrier n'est pas un tableau de
      données, c'est une mise en page. Sept colonnes de largeur égale, autant de rangées que le
      mois en demande.

   ⚠️ `minmax(0, 1fr)` ET NON `1fr` : la valeur par défaut d'une piste de grille est `auto`, qui
      refuse de descendre sous la taille de son contenu. Un titre d'événement long élargirait alors
      sa colonne et les sept cesseraient d'être égales.                                          */
.calendrier {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

.calendrier__jour-nom {
  padding: var(--space-2);
  background: var(--ink-1);
  color: var(--muted);
  font-size: var(--text-xs);
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.calendrier__case {
  min-height: 6rem;
  padding: var(--space-2);
  background: var(--ink-0);
}

/* ⚠️ « Hors période » se distingue par l'ATTÉNUATION du fond ET du texte. Les jours de bord d'un
      mois restent lisibles — ils portent parfois un rendez-vous — mais ne doivent pas se lire
      comme faisant partie du mois affiché.                                                      */
.calendrier__case--hors {
  background: var(--ink-1);
  color: var(--muted-2);
}

/* ⚠️ AUJOURD'HUI SE MARQUE PAR UNE BORDURE, PAS PAR UNE COULEUR SEULE : un daltonisme
      rouge-vert ne verrait rien. Même doctrine que `.onglets__item--actif`.                     */
.calendrier__case--aujourdhui {
  box-shadow: inset 0 0 0 2px var(--brand-accent);
}

.calendrier__quantieme {
  margin: 0 0 var(--space-2);
  font-size: var(--text-sm);
  font-weight: 600;
}

.calendrier__evenements {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.calendrier__evenement {
  padding: var(--space-1) var(--space-2);
  border-left: 3px solid var(--brand-accent);
  border-radius: var(--radius-sm);
  background: var(--ink-1);
  font-size: var(--text-xs);
  line-height: 1.35;
}

/* Une échéance n'est pas un rendez-vous : elle alimente « À traiter » et les rappels.           */
.calendrier__evenement--echeance {
  border-left-color: var(--status-pending);
}

/* ⚠️ CLOS SE VOIT, MAIS NE DISPARAÎT PAS. La règle 6 du canon interdit d'effacer un événement :
      la vue doit donc pouvoir montrer ce qui a été annulé, sans quoi un créneau devenu vide
      laisserait la question sans réponse.                                                       */
.calendrier__evenement--clos {
  border-left-color: var(--muted-2);
  color: var(--muted-2);
  text-decoration: line-through;
}

.calendrier__heure {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* La barre de période : ‹ juillet 2026 › d'un côté, les trois vues de l'autre.                  */
.agenda-barre {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.agenda-barre__periode {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
  font-size: var(--text-lg);
}

/* Le calendrier et le panneau À VENIR. Une seule colonne sous 900 px : le panneau passe dessous
   plutôt que de se comprimer, une case de calendrier ne survivant pas à moins de 4 rem.         */
.agenda-colonnes {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(14rem, 1fr);
  gap: var(--space-4);
  align-items: start;
}

@media (max-width: 900px) {
  .agenda-colonnes {
    grid-template-columns: minmax(0, 1fr);
  }
}

.a-venir__ligne {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-top: 1px solid var(--line-2);
}

.a-venir__quand {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
}

.a-venir__quoi {
  margin: 0;
  min-width: 0;
}

/* Un rattachement d'événement : le véhicule, le document ou le tiers que l'événement désigne.

   ⚠️ La CIBLE DISPARUE reste LISIBLE, barrée. Le canon l'exige (`10-agenda.md:34`) : un événement
      passé doit rester compréhensible même quand son objet a été fusionné ou purgé. Effacer la
      mention laisserait « un rendez-vous avec quelque chose » dont personne ne saurait plus quoi. */
.rattachement {
  display: inline-block;
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--ink-1);
  color: var(--muted);
  font-size: var(--text-xs);
  text-decoration: none;
}

a.rattachement:hover {
  color: var(--paper);
  border-color: var(--brand-accent-dim);
}

.rattachement--perdue {
  text-decoration: line-through;
  color: var(--muted-2);
}

/* ══ LA FICHE D'ENREGISTREMENT — 0.96.84 (proposition C de la recette du 03/10/2026) ══════════════════════════════
   En-tête (titre, puces, étapes, actions), bande de chiffres clés, onglets, panneau, et le FIL à droite. Écrite pour
   la demande d'achat de l'Owner, taillée pour les fiches véhicule, tiers et facture : préfixe `fiche`, partiels
   `templates/partials/fiche-*.php` et `vignette.php`, îlot `public/assets/js/modules/fiche.js`.

   ⚠️ ÉCARTS ASSUMÉS À LA MAQUETTE : base 16 px et cibles de 40 px (le produit, pas les 13 px / 24 px du dessin) ; pas de
      rail d'icônes (la barre latérale est celle du produit) ; le fil d'Ariane reste en tête du corps ; un PDF s'ouvre
      dans un onglet, jamais dans la fenêtre (CSP verrouillée) ; la page défile au niveau du document — aucune
      hauteur fixe qui cacherait du contenu, seul le fil défile dans sa colonne.
   ⚠️ SOUS 1100 PX, UNE SEULE COLONNE : le fil passe sous le panneau.                                                */
.fiche {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 19rem;
  grid-template-areas:
    "entete entete"
    "chiffres chiffres"
    "corps fil";
  gap: var(--space-2) var(--space-5);
  align-items: start;
}

.fiche [hidden] { display: none; }

/* Un lien qui a l'habit d'un bouton n'est pas souligné : c'est un geste, pas une phrase. */
.fiche a.btn { text-decoration: none; }

.fiche-entete {
  grid-area: entete;
  display: grid;
  gap: var(--space-2);
  min-width: 0;
}

.fiche-entete__ligne {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.fiche-entete__titre {
  margin: 0;
  font-size: var(--text-lg);
  line-height: 1.2;
}

.fiche-entete__ligne--titre { align-items: baseline; gap: var(--space-2) var(--space-5); }
.fiche-entete__ligne--titre > p { margin: 0; }

.fiche-entete__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.fiche-entete__droite {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;
}

/* La barre d'étapes : une flèche par étape (`clip-path`, aucune couleur). La faite porte une coche, la courante le fond
   d'accent ET `aria-current="step"` : jamais la couleur seule.                                                       */
.fiche-etapes {
  display: flex;
  flex-wrap: wrap;
  margin: 0 0 0 auto;
  padding: 0;
  list-style: none;
}

.fiche-etapes__pas {
  margin-left: -4px;
  padding: var(--space-1) var(--space-3) var(--space-1) var(--space-4);
  background: var(--ink-3);
  color: var(--muted-2);
  font-size: var(--text-sm);
  clip-path: polygon(0 0, calc(100% - 9px) 0, 100% 50%, calc(100% - 9px) 100%, 0 100%, 9px 50%);
}

.fiche-etapes__pas:first-child {
  margin-left: 0;
  padding-left: var(--space-4);
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  clip-path: polygon(0 0, calc(100% - 9px) 0, 100% 50%, calc(100% - 9px) 100%, 0 100%);
}

.fiche-etapes__pas--fait { color: var(--muted); }
.fiche-etapes__pas--fait::before { content: "✓ "; }

.fiche-etapes__pas--courant {
  background: var(--brand-accent);
  color: var(--ink-0);
  font-weight: 600;
}

/* Le geste qui refuse : lisible comme tel sans être une alarme. */
.btn--danger {
  background: transparent;
  color: var(--status-alert);
  border-color: var(--status-alert);
}

/* Le menu « ⋯ » : un `<details>`, comme le menu du profil. */
.fiche-plus { position: relative; }
.fiche-plus__bouton { list-style: none; }
.fiche-plus__bouton::-webkit-details-marker { display: none; }

.fiche-plus__menu {
  position: absolute;
  top: calc(100% + var(--space-1));
  right: 0;
  z-index: 20;
  display: grid;
  gap: var(--space-1);
  min-width: 17rem;
  padding: var(--space-2);
  background: var(--ink-1);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

.fiche-plus__item {
  justify-content: flex-start;
  width: 100%;
  text-align: left;
}

/* La liste de contrôle, dite près des actions : ce qui manque avant le prochain geste. */
.fiche-controles {
  padding: var(--space-1) var(--space-3);
  background: var(--ink-1);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
}

.fiche-controles__titre { margin: 0; color: var(--muted); }

.fiche-controles__liste {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
  margin: var(--space-1) 0 0;
  padding: 0;
  list-style: none;
}

.fiche-controles__item--ok { color: var(--status-ok); }
.fiche-controles__item--manque { color: var(--status-alert); }

/* La bande des chiffres clés. */
.fiche-chiffres {
  grid-area: chiffres;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  gap: 1px;
  margin: 0;
  background: var(--line-2);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  overflow: hidden;
}

.fiche-chiffres__cellule {
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  background: var(--ink-1);
}

.fiche-chiffres__quoi {
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-2);
}

.fiche-chiffres__valeur {
  margin: 0;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.fiche-chiffres__valeur--conforme { color: var(--status-ok); }
.fiche-chiffres__valeur--alerte   { color: var(--status-alert); }
.fiche-chiffres__valeur--attente  { color: var(--status-pending); }

.fiche-chiffres__detail {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--muted-2);
}

/* Le corps : les onglets, puis le panneau ouvert. */
.fiche__corps {
  grid-area: corps;
  display: grid;
  gap: var(--space-3);
  align-content: start;
  min-width: 0;
}

/* Les onglets — 0.96.116 (00B § 68, Notion 149) : la fiche tiers en porte NEUF ; ils passaient à la ligne à 1 280 px
   (1 004 px demandés pour 951 disponibles, barre de défilement comprise — mesuré le 15/10/2026 en Segoe UI, la police
   que Windows affiche tant qu'Inter n'est pas livrée). Deux gestes, pour toutes les barres :
   1. ils se resserrent (le rembourrage `space-2` est le seul écart, aucun `gap`) : 876 px pour les neuf, 920 avec un
      compte sur chacun — une ligne dès 1 263 px ;
   2. une barre qui se replie quand même reste LISIBLE : chaque onglet porte son trait (un fond de 1 px posé dans la
      boîte de BORDURE — sans `border-box`, il flotterait 2 px plus haut et doublerait celui de la barre), donc chaque
      rangée a le sien, et l'onglet ouvert est souligné sur SA rangée.
   ⚠️ `flex-wrap: wrap` reste et aucun `overflow` : un onglet ne sort jamais du cadre (rien ne disparaît d'un écran). */
.fiche-onglets {
  display: flex;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--line-2);
}

.fiche-onglets__item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: var(--touch-min);
  margin-bottom: -1px;
  padding: 0 var(--space-2);
  border-bottom: 2px solid transparent;
  background: linear-gradient(var(--line-2), var(--line-2)) left bottom / 100% 1px no-repeat border-box;
  color: var(--muted);
  text-decoration: none;
}

.fiche-onglets__item:hover { color: var(--paper); }

.fiche-onglets__item[aria-current="page"] {
  border-bottom-color: var(--brand-accent);
  color: var(--paper);
  font-weight: 600;
}

.fiche-onglets__compte {
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--ink-3);
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: 400;
}

.fiche__panneau {
  display: grid;
  gap: var(--space-3);
  min-width: 0;
}

/* Dans une fiche, les cartes des partiels partagés (contrat, dépôt-vente) se resserrent : titre de section en petite
   capitale, comme les sections de la synthèse. Hors d'une fiche — l'écran du client —, rien ne change.               */
.fiche .card { padding: var(--space-4); }

.fiche .section__titre {
  margin: 0 0 var(--space-2);
  font-family: var(--font-text);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-2);
}

/* La synthèse : des sections côte à côte, séparées par des filets. */
.fiche-cadre {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 1px;
  background: var(--line-2);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  overflow: hidden;
}

.fiche-cadre__section {
  min-width: 0;
  padding: var(--space-2) var(--space-4);
  background: var(--ink-2);
}

/* Un geste dans une section (« Vérifier auprès de VIES ») tient sur une ligne : la colonne est étroite. */
.fiche-cadre .btn {
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
}

/* ⚠️ LE LIBELLÉ AU-DESSUS DE SA VALEUR : à trois sections sur la largeur d'un portable, une colonne de libellés
      (« Première mise en circulation ») laissait à la valeur quelques pixels, et le châssis se lisait lettre à lettre. */
.fiche-cadre .paires {
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
  line-height: 1.35;
}

.fiche-cadre .paires dt {
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--muted-2);
}

.fiche-cadre .paires dt:first-child { margin-top: 0; }

.fiche-cadre .paires dd {
  font-size: var(--text-sm);
  overflow-wrap: anywhere;
}

/* Le mode correction : le formulaire existant, ses blocs côte à côte, et la barre Enregistrer / Annuler. */
.fiche-correction__barre {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.fiche-correction__boutons {
  display: flex;
  gap: var(--space-2);
  margin-left: auto;
}

.fiche-correction__grille {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: var(--space-3);
  align-items: start;
}

/* Les textes d'aide du formulaire partagé se resserrent en correction ; les champs gardent leurs 40 px. */
.fiche-correction__grille .muted-2 { font-size: var(--text-sm); }

/* Les pièces : une tuile par type, ses vignettes, son dépôt. */
.fiche-pieces {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(12.5rem, 1fr));
  gap: var(--space-3);
}

.fiche-piece {
  display: grid;
  gap: var(--space-2);
  align-content: start;
  min-width: 0;
  padding: var(--space-3);
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
}

.fiche-piece__titre { margin: 0; font-size: var(--text-sm); }

.fiche-vignettes {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.fiche-vignette {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
  padding: var(--space-2);
  background: var(--ink-1);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  color: var(--paper);
  text-decoration: none;
}

a.fiche-vignette:hover { border-color: var(--brand-accent-dim); }

.fiche-vignette--vide {
  border-style: dashed;
  color: var(--muted-2);
}

/* La feuille d'un document : du papier réglé, aux jetons du document imprimé. */
.fiche-vignette__feuille {
  display: block;
  height: 4.5rem;
  padding: var(--space-3) var(--space-4);
  border-radius: 3px;
  background-color: var(--doc-paper);
  background-image: repeating-linear-gradient(to bottom, transparent 0, transparent 9px, var(--doc-line) 9px, var(--doc-line) 10px);
  background-clip: content-box;
  overflow: hidden;
}

.fiche-vignette__feuille--image {
  padding: 0;
  background: var(--ink-0);
}

.fiche-vignette__feuille--vide {
  display: grid;
  place-items: center;
  background: transparent;
  border: 1px dashed var(--line);
  color: var(--muted-2);
  font-size: var(--text-lg);
}

.fiche-vignette__image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.fiche-vignette__titre {
  font-size: var(--text-sm);
  font-weight: 600;
  overflow-wrap: anywhere;
}

.fiche-vignette__meta {
  font-size: var(--text-xs);
  color: var(--muted-2);
}

.fiche-depot > summary { list-style: none; }
.fiche-depot > summary::-webkit-details-marker { display: none; }
.fiche-depot[open] > summary { margin-bottom: var(--space-2); }

/* L'aperçu d'une pièce dans sa fenêtre : l'image entière, ou la feuille et le lien qui ouvre le document. */
.fiche-apercu {
  display: grid;
  place-items: center;
  gap: var(--space-3);
  min-height: 12rem;
  padding: var(--space-3);
  background: var(--ink-0);
  border-radius: var(--radius-sm);
}

.fiche-apercu__image {
  max-width: 100%;
  max-height: 60vh;
  object-fit: contain;
}

.fiche-apercu__feuille {
  width: min(16rem, 100%);
  height: 12rem;
}

/* Le fil, à droite. Sa liste défile dans sa colonne : la page tient en un écran même quand le journal est long. */
.fiche-fil {
  grid-area: fil;
  display: grid;
  gap: var(--space-3);
  align-content: start;
  min-width: 0;
  padding: var(--space-3) var(--space-4);
  background: var(--ink-1);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
}

.fiche-fil__titre {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin: 0;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-2);
}

/* La composition se replie dans un `<details>` : ouverte, elle prendrait la colonne entière. */
.fiche-fil__ecrire > summary { list-style: none; width: 100%; }
.fiche-fil__ecrire > summary::-webkit-details-marker { display: none; }
.fiche-fil__ecrire[open] > summary { margin-bottom: var(--space-2); }

.fiche-fil__composer {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

.fiche-fil__composer .input { min-height: 4.5rem; resize: vertical; }

/* ⚠️ LA HAUTEUR SUIT L'ÉCRAN : 14 rem sur un portable (la page tient en 800 px), davantage sur un grand écran. */
.fiche-fil__liste {
  display: grid;
  max-height: max(14rem, calc(100vh - 36rem));
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-y: auto;
}

.fiche-fil__liste:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }

.fiche-fil__evt {
  display: grid;
  grid-template-columns: 1.5rem minmax(0, 1fr);
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-top: 1px solid var(--line-2);
  font-size: var(--text-sm);
}

.fiche-fil__evt:first-child { border-top: 0; }

.fiche-fil__marque {
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--ink-3);
  color: var(--muted-2);
  font-size: var(--text-xs);
}

.fiche-fil__marque--message { color: var(--brand-accent); }

.fiche-fil__texte { display: grid; min-width: 0; }
.fiche-fil__quoi { overflow-wrap: anywhere; }
.fiche-fil__detail { color: var(--muted); overflow-wrap: anywhere; }

.fiche-fil__quand {
  color: var(--muted-2);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
}

/* Le dialogue large (aperçu d'une pièce, gestes d'en-tête), son fond, son pied — et son repli SANS JavaScript : le lien
   `#id` du déclencheur le cible, et il s'affiche à sa place dans la page au lieu de rester caché.                    */
.dialogue--large {
  width: min(56rem, calc(100% - 2rem));
  max-width: none;
  max-height: calc(100vh - 2rem);
}

.dialogue::backdrop { background: color-mix(in srgb, var(--ink-0) 72%, transparent); }

.dialogue__tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.dialogue__titre { margin: 0; }

.dialogue__pied {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-2) var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line-2);
}

.dialogue:target:not([open]) {
  display: block;
  position: static;
  margin: var(--space-4) 0;
}

@media (max-width: 1100px) {
  .fiche {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "entete"
      "chiffres"
      "corps"
      "fil";
  }

  .fiche-etapes { margin-left: 0; }
}

/* ══ LE GABARIT ÉTENDU — 0.96.87 : listes, paramétrage, tableaux de bord ══════════════════════════════════════════════
   Le gabarit de la fiche (0.96.84) devient celui de TOUS les écrans : même en-tête (`fiche-entete`, fil d'Ariane
   facultatif), même bande de chiffres (`fiche-chiffres`, cellules qui mènent quelque part), mêmes onglets. Ce bloc ajoute
   la page SANS fil (liste, paramétrage, tableau de bord), la barre d'outils de liste (`liste-outils`), la section de
   paramétrage lue puis « Modifier » (`fiche-section`), les colonnes d'un tableau de bord et ses raccourcis.

   🔴 BLOC COMMUN : les écrans alignés n'y touchent pas. Ce qui leur manque s'ajoute dans un bloc délimité À LEUR NOM en
      fin de feuille (voir `GUIDE.md` du chantier), jamais ici.                                                       */

/* La page sans fil : en-tête, chiffres, corps, sur toute la largeur. */
.fiche--sans-fil {
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    "entete"
    "chiffres"
    "corps";
}

/* Le `hidden` d'un panneau, d'une section, d'un « Modifier » gagne sur le `display` d'un bouton, partout dans le gabarit. */
.fiche-section [hidden] { display: none; }

/* Hors d'un `.fiche`, l'en-tête garde sa grille ; dans une liste, il respire un peu plus au-dessus du tableau. */
.fiche--sans-fil .fiche__corps { gap: var(--space-4); }

/* Une cellule de chiffres qui mène quelque part : toute la cellule reçoit le clic, un seul arrêt de tabulation. */
.fiche-chiffres__cellule { position: relative; }

.fiche-chiffres__lien {
  color: inherit;
  text-decoration: none;
}

.fiche-chiffres__lien::after {
  content: "";
  position: absolute;
  inset: 0;
}

.fiche-chiffres__lien:hover { text-decoration: underline; }

.fiche-chiffres__lien:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
}

/* La barre d'outils d'une liste : les filtres à gauche, le compteur et « Nouveau … » à droite. */
.liste-outils {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-2) var(--space-3);
  background: var(--ink-1);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
}

.liste-outils__filtres {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-2) var(--space-3);
  min-width: 0;
}

.liste-outils__champ {
  display: grid;
  min-width: 11rem;
  margin: 0;
}

.liste-outils__champ--recherche { min-width: 16rem; }
.liste-outils__champ .field__label { margin-bottom: var(--space-1); font-size: var(--text-xs); }

.liste-outils__case {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--touch-min);
  margin: 0;
  font-size: var(--text-sm);
  color: var(--muted);
}

.liste-outils__envoi {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
}

.liste-outils__actifs { font-size: var(--text-sm); color: var(--status-pending); }

.liste-outils__droite {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin-left: auto;
}

.liste-outils__compteur {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.liste-outils a.btn { text-decoration: none; }

/* Un groupe d'une liste (le pays, puis le lieu, dans le stock) : un intertitre en petite capitale et son compte. */
.liste-groupe {
  display: grid;
  gap: var(--space-2);
  min-width: 0;
}

.liste-groupe__titre {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  margin: 0;
  font-family: var(--font-text);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.liste-groupe__titre--sous { font-size: var(--text-xs); color: var(--muted-2); }

.liste-groupe__compte {
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted-2);
}

.fiche .cartes { margin: 0; }

/* La pagination d'une liste, sous le tableau : le rang à gauche, les deux pas à droite. */
.liste-pied {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  color: var(--muted-2);
}

.liste-pied__pas { display: flex; gap: var(--space-2); margin-left: auto; }

/* La section de paramétrage : titre et « Modifier » sur une ligne, l'aide, la lecture ou le formulaire. */
.fiche-section {
  display: grid;
  gap: var(--space-2);
  align-content: start;
  min-width: 0;
  padding: var(--space-3) var(--space-4);
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
}

.fiche-section__tete {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.fiche-section__titre {
  margin: 0;
  font-family: var(--font-text);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-2);
}

.fiche-section__aide { margin: 0; font-size: var(--text-sm); color: var(--muted-2); }
.fiche-section__lecture, .fiche-section__correction { display: grid; gap: var(--space-2); min-width: 0; }
.fiche-section__annuler { margin: 0; }
.fiche-section a.btn { text-decoration: none; }

/* Les sections côte à côte quand la largeur le permet (paramétrage en colonnes), l'une sous l'autre sinon. */
.fiche-sections {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(24rem, 100%), 1fr));
  gap: var(--space-3);
  align-items: start;
}

/* Le tableau de bord : ses colonnes (activité, à traiter, échéances) dans le corps du gabarit. */
.fiche .colonnes { margin: 0; }

/* Les raccourcis de gestion : un titre, une phrase, un geste — en grille, sans rien perdre des textes des cartes. */
.fiche-raccourcis {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(17rem, 100%), 1fr));
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.fiche-raccourci {
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: var(--space-2);
  min-width: 0;
  padding: var(--space-3) var(--space-4);
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
}

.fiche-raccourci__titre {
  margin: 0;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-2);
}

.fiche-raccourci__texte { margin: 0; font-size: var(--text-sm); color: var(--muted); }
.fiche-raccourci__geste { margin: 0; }

/* La tête d'un panneau d'onglet : son titre et son geste (« Gérer les photos »), sur une ligne. */
.fiche-panneau__tete {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-3);
}

.fiche-panneau__tete > * { margin: 0; }

/* Les gestes d'une section de synthèse (plaque, châssis, relevés…) : des boutons compacts qui vont à la ligne. */
.fiche-gestes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0;
}

/* Des vignettes de fichiers EN GRILLE (les documents d'un véhicule), et non plus en colonne dans une tuile de pièce. */
.fiche-vignettes--grille { grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); }

/* Un bandeau d'état en tête du corps (véhicule sorti du stock, fiche fusionnée) : il se lit avant les onglets. */
.fiche-bandeau {
  display: grid;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-4);
  background: var(--ink-1);
  border: 1px solid var(--line-2);
  border-left: 3px solid var(--status-pending);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
}

.fiche-bandeau--alerte { border-left-color: var(--status-alert); }
.fiche-bandeau > * { margin: 0; }

.fiche-bandeau__titre {
  font-weight: 600;
  color: var(--paper);
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   LA PILE DESSINÉE — 0.96.86, partiel `@financing/_pile-dessinee` (Owner ET client)
   ══════════════════════════════════════════════════════════════════════════════════════════
   Le simulateur d'Anthony (`docs/reference/simulateur-pile-financement.html`) transposé sur les
   jetons EXISTANTS du thème — aucune couleur littérale, aucun jeton neuf. La pile monte du bas vers
   le haut (`column-reverse` : la brique n° 1 est au sol), la graduation à gauche porte le cumul
   engagé au sommet de chaque brique.

   ⚠️ LES LARGEURS SONT DES PALIERS DE CLASSE, PAS DES `style=` : la CSP les ignorerait
      (`style-src 'self'`). `--l0` … `--l10` vont de 40 % à 100 % — une brique garde la place de son
      montant et de son taux. La barre de marge va de 0 à 100 %. */
.pile { margin: 0; }

.pile__etages {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column-reverse;
  gap: var(--space-2);
}

.pile__etage {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr);
  gap: var(--space-3);
  align-items: stretch;
}

.pile__cumul {
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
  padding-right: var(--space-2);
  border-right: 1px dashed var(--line);
  font-size: var(--text-xs);
  color: var(--muted-2);
  white-space: nowrap;
}

/* ⚠️ `min-width` : un étage garde la place de son véhicule, de son montant et de son taux même quand son palier
      de largeur le voudrait plus étroit que son texte — sinon le taux sort de l'étage, mesuré au rendu à 1000 px.
      La proportion se lit au-dessus de ce plancher. */
.pile__bloc {
  position: relative;
  display: flex;
  align-items: stretch;
  min-width: min(100%, 22rem);
  min-height: 3.9rem;
  overflow: hidden;
  background: var(--ink-3);
  border: 1px solid var(--line);
  border-left: 5px solid var(--brand-accent);
  border-radius: var(--radius-sm);
  color: var(--paper);
  text-decoration: none;
}

a.pile__bloc:hover { border-color: var(--brand-accent-dim); border-left-color: var(--brand-accent); }

a.pile__bloc:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
}

.pile__bloc--l0 { width: 40%; }
.pile__bloc--l1 { width: 46%; }
.pile__bloc--l2 { width: 52%; }
.pile__bloc--l3 { width: 58%; }
.pile__bloc--l4 { width: 64%; }
.pile__bloc--l5 { width: 70%; }
.pile__bloc--l6 { width: 76%; }
.pile__bloc--l7 { width: 82%; }
.pile__bloc--l8 { width: 88%; }
.pile__bloc--l9 { width: 94%; }
.pile__bloc--l10 { width: 100%; }

.pile__rang {
  flex: 0 0 2.4rem;
  display: grid;
  place-items: center;
  border-right: 1px solid var(--line);
  font-family: var(--font-display);
  font-size: var(--text-lg);
  color: var(--brand-accent);
}

.pile__corps {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  padding: var(--space-2) var(--space-3);
}

.pile__vehicule {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--text-xs);
  color: var(--muted);
}

.pile__montant { font-weight: 600; }

.pile__droite {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  gap: 2px;
  padding: var(--space-2) var(--space-3);
}

.pile__taux {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  line-height: 1;
  color: var(--brand-accent);
}

.pile__sous {
  font-size: var(--text-xs);
  color: var(--muted-2);
  white-space: nowrap;
}

.pile__marge {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 3px;
  background: var(--brand-accent-dim);
}

.pile__marge--l0 { width: 0; }
.pile__marge--l1 { width: 10%; }
.pile__marge--l2 { width: 20%; }
.pile__marge--l3 { width: 30%; }
.pile__marge--l4 { width: 40%; }
.pile__marge--l5 { width: 50%; }
.pile__marge--l6 { width: 60%; }
.pile__marge--l7 { width: 70%; }
.pile__marge--l8 { width: 80%; }
.pile__marge--l9 { width: 90%; }
.pile__marge--l10 { width: 100%; }

/* Le sol : la pile s'y pose, sous la colonne des briques (pas sous la graduation). */
.pile__sol {
  height: 3px;
  margin: var(--space-1) 0 0 calc(7.5rem + var(--space-3));
  background: var(--muted-2);
}

.pile__legende {
  margin-top: var(--space-3);
  font-size: var(--text-xs);
}

@media (max-width: 40rem) {
  .pile__etage { grid-template-columns: 4.5rem minmax(0, 1fr); }
  .pile__sol { margin-left: calc(4.5rem + var(--space-3)); }
  .pile__bloc--l0, .pile__bloc--l1, .pile__bloc--l2, .pile__bloc--l3,
  .pile__bloc--l4, .pile__bloc--l5 { width: 100%; }
}

/* Deux volets : la pile à gauche, la situation à droite — la grille du simulateur. */
.deux-volets {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
}

/* Sous 1200 px, les volets s'empilent : la pile garde toute la largeur, c'est elle qui se lit en premier. */
@media (max-width: 1200px) {
  .deux-volets { grid-template-columns: minmax(0, 1fr); }
}

/* ── « Mes véhicules » : les cartes du client — 0.96.86 ─────────────────────────────────────
   Plus larges que celles du stock (elles portent la brique), et les mesures en deux colonnes.
   ⚠️ 06/10/2026 (00B § 44) : la carte est devenue un LIEN vers la fiche du client
   (/c/{code}/mes-vehicules/{vehicule}) ; la règle qui neutralisait son survol (une `<div>` à
   l'époque) est retirée — elle réagit désormais comme toute `.carte`. */
.cartes--larges { grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)); }

.carte__couverture--haute { aspect-ratio: 16 / 9; }

.carte__mesures {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2) var(--space-4);
  margin: var(--space-3) 0;
}

.carte__mesures dt {
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-2);
}

.carte__mesures dd {
  margin: 0;
  font-family: var(--font-mono);
}

.carte__taux { color: var(--brand-accent); }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   LE GRAPHIQUE DU KIT — 0.96.102, partiel `graphique` (00B § 54)
   ══════════════════════════════════════════════════════════════════════════════════════════
   Un dessin SVG rendu par le serveur : la géométrie est en ATTRIBUTS (la CSP refuse `style=`),
   l'apparence ici. Les marques portent la couleur de leur série (`--graphique-1`, `--graphique-2`,
   theme.css) ; les TEXTES jamais — valeurs, graduations, légende restent dans l'encre du texte, la
   pastille à côté porte l'identité. Grille et axe en filets d'un pixel, pleins, discrets.
   🔑 Les marques dessinées APRÈS les cibles de survol (aire, ligne, repère, textes) ne captent pas
   la souris : sans `pointer-events: none`, l'aire de la courbe couvrirait les infobulles des mois.
   🔴 0.96.103 (00B § 55) — LE TEXTE NE GROSSIT PLUS AVEC LA CARTE. Le dessin n'a plus de `viewBox` :
   une unité = un pixel CSS, la hauteur est son attribut `height`, la largeur celle de la carte. Les
   tailles du texte sont donc celles de l'échelle du kit (`--text-xs` pour les axes, comme la légende ;
   `--text-sm` pour la valeur du bout, comme le résumé), à 375 px comme à 2000 px. */
.graphique {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-3) var(--space-4);
  background: var(--ink-1);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  min-width: 0;
  container-type: inline-size;
}

.graphique__titre {
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--paper);
}

.graphique__resume,
.graphique__vide {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--muted);
}

/* ⚠️ AUCUNE `height` ICI : c'est l'attribut du dessin qui la donne, en pixels, et les ordonnées du partiel
   sont calculées dessus. `overflow: visible` laisse une étiquette du bord déborder dans la marge de la
   carte plutôt que d'être rognée ; les SVG intérieurs laissent de même passer le trait de la courbe et
   la moitié gauche d'une colonne (posée au milieu de sa bande, elle s'étend de part et d'autre). */
.graphique__dessin {
  display: block;
  width: 100%;
  overflow: visible;
}

.graphique__trace,
.graphique__colonne { overflow: visible; }

.graphique__grille { stroke: var(--line-2); stroke-width: 1; shape-rendering: crispEdges; }
.graphique__axe { stroke: var(--line); stroke-width: 1; shape-rendering: crispEdges; }
.graphique__texte { fill: var(--muted-2); font-size: var(--text-xs); font-variant-numeric: tabular-nums; }
.graphique__valeur { fill: var(--paper); font-size: var(--text-sm); font-weight: 600; }

/* Un liseré à la couleur du fond, SOUS la lettre (`paint-order`) : une graduation posée au-dessus de sa
   ligne reste lisible quand une colonne ou la courbe passe derrière elle. */
.graphique__texte,
.graphique__valeur {
  paint-order: stroke;
  stroke: var(--ink-1);
  stroke-width: 3px;
  stroke-linejoin: round;
}

/* Plus de six mois sur une carte étroite (un téléphone) : un mois sur deux se tait, le dernier reste
   écrit (le partiel pose `graphique__texte--alterne`). Le seuil garde de l'air : douze étiquettes de
   `--text-xs` se touchent vers 280 px de dessin (« janv. » 24,8 px et « févr. » 21,3 px côte à côte,
   mesuré le 09/10/2026) ; à 23rem, les plus serrées restent à ~7 px l'une de l'autre, et la largeur d'une
   étiquette dépend de la police que le poste a installée. */
@container (max-width: 23rem) {
  .graphique__texte--alterne { display: none; }
}

.graphique__serie--1 { fill: var(--graphique-1); }
.graphique__serie--2 { fill: var(--graphique-2); }
.graphique__ligne { fill: none; stroke: var(--graphique-1); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.graphique__aire { fill: var(--graphique-1); fill-opacity: 0.1; }
.graphique__repere { fill: var(--graphique-1); stroke: var(--ink-1); stroke-width: 2; }

.graphique__grille,
.graphique__axe,
.graphique__texte,
.graphique__valeur,
.graphique__ligne,
.graphique__aire,
.graphique__repere { pointer-events: none; }

.graphique__cible { fill: transparent; }
.graphique__point:hover .graphique__cible { fill: var(--ink-2); }

.graphique__legende {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-xs);
  color: var(--muted);
}

.graphique__legende li {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

.graphique__cle {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 2px;
}

.graphique__cle--1 { background: var(--graphique-1); }
.graphique__cle--2 { background: var(--graphique-2); }

/* ════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
   LES BLOCS DE FAMILLE DU CHANTIER « TOUS LES ÉCRANS » — 0.96.87
   ════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
   Huit blocs, un par famille d'écrans, POSÉS D'AVANCE et vides (sauf les véhicules) : chaque famille n'écrit QUE dans
   le sien, entre ses deux bornes, ce qui manque au bloc commun « LE GABARIT ÉTENDU » — jamais dans le bloc commun, jamais
   dans le bloc d'une autre famille. Les bornes séparent les écritures de familles qui travaillent en parallèle : deux
   insertions dans deux blocs différents se fusionnent sans conflit. Couleurs par jetons du thème seulement (`lint-ui`).
   ════════════════════════════════════════════════════════════════════════════════════════════════════════════════════ */

/* ══ BLOC DE FAMILLE « vehicules » — VÉHICULES (stock, fiche, sous-écrans de geste, « Mes véhicules ») — DÉBUT ══ */

/* La synthèse du véhicule : l'identité sur deux parts, ses paires EN LIGNE (libellé | valeur) — douze lignes libellé
   au-dessus faisaient défiler la fiche sur deux écrans ; le financier et la localisation sur une part chacun. */
.fiche-cadre--vehicule { grid-template-columns: minmax(0, 2fr) repeat(2, minmax(0, 1fr)); }
.fiche-cadre--vehicule-sans-prix { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }

.fiche-identite .paires {
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  gap: var(--space-1) var(--space-3);
}

.fiche-identite .paires dt,
.fiche-identite .paires dt:first-child { margin-top: 0; }

@media (max-width: 1100px) {
  .fiche-cadre--vehicule,
  .fiche-cadre--vehicule-sans-prix { grid-template-columns: minmax(0, 1fr); }
}

/* La vignette d'une photo est le lien qui ouvre sa fenêtre : un bloc, pour que toute l'image reçoive le clic. */
.galerie__lien { display: block; border-radius: var(--radius-sm); }
.galerie__lien:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }

/* 0.96.88 — l'aperçu d'une fusion : « ce qui serait déplacé » et « ce qui resterait » CÔTE À CÔTE (deux colonnes qui se
   comparent), l'une sous l'autre quand la largeur manque. */
.vehicule-moities {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
  gap: var(--space-2) var(--space-5);
  align-items: start;
}
/* 0.96.90 (06/10/2026, 00B § 44) — le code couleur DISCRET des cartes d'un client : un liseré à gauche, trois familles
   (« stock propre » = le stock de SA société, « confié », « acheté pour vous »). Posé ici parce que la carte est une carte
   de véhicule (« Mes véhicules » et l'aperçu de l'espace client l'emploient tous deux). Jetons du thème seulement ; la
   couleur ne porte JAMAIS seule l'information : chaque carte dit sa famille en toutes lettres. */
.carte--propre { border-left: 3px solid var(--status-pending); }
.carte--confie { border-left: 3px solid var(--status-ok); }
.carte--achete { border-left: 3px solid var(--status-neutral); }

/* 07/10/2026 (00B § 51) — l'offre aux clients : le formulaire en une colonne, et la liste des clients cochés en grille
   (une case par client, plusieurs colonnes quand la largeur le permet). */
.offre-saisie { display: grid; gap: var(--space-3); max-width: 60rem; }
.offre-audience {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr));
  gap: var(--space-1) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  margin: 0;
}
.offre-audience__client { margin: 0; }
.offre-audience__aide { grid-column: 1 / -1; }

/* 07/10/2026 (00B § 51) — « Véhicules proposés » de l'Owner : les demandes d'achat À TRAITER, une carte chacune, en grille
   pleine largeur (deux ou trois de front sur un écran de bureau, une seule sous 1100 px). */
.offres-a-traiter {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(26rem, 100%), 1fr));
  gap: var(--space-3);
}
/* ══ BLOC DE FAMILLE « vehicules » — FIN ══ */

/* ══ BLOC DE FAMILLE « facturation » — FACTURATION ET PAIEMENTS (invoicing, finance) — DÉBUT ══ */

/* La synthèse d'une pièce (facture client, facture fournisseur) : ses paires EN LIGNE (libellé | valeur) — quatre à six
   lignes, là où le libellé au-dessus de sa valeur en faisait le double et poussait les lignes de la pièce sous le pli. */
.facture-etat .paires {
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  gap: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
}

.facture-etat .paires dd { overflow-wrap: anywhere; }

/* Trois sections côte à côte quand la largeur le permet (les trois types de pièce de la numérotation). */
.facture-trois { grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr)); }

.facture-etat .paires dt,
.facture-etat .paires dt:first-child { margin-top: 0; }

/* Un formulaire de saisie à plusieurs champs (facture reçue, mouvement bancaire, ventilation) : deux colonnes, pour qu'il
   tienne dans sa fenêtre ou sa section sans défiler ; les champs larges, les notes et le bouton prennent toute la ligne. */
.facture-saisie {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2) var(--space-4);
  align-items: start;
}

.facture-saisie > * { margin: 0; }
.facture-saisie__large { grid-column: 1 / -1; }

/* La période d'un export : journal, du, au et le bouton sur une ligne, au-dessus des totaux ; la phrase d'aide dessous. */
.facture-periode {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-2) var(--space-4);
}

.facture-periode > * { margin: 0; }
.facture-periode__aide { flex-basis: 100%; }

/* La fiche d'une pièce (facture client, facture fournisseur) : le fil du journal un peu plus étroit que celui de la
   demande d'achat — il n'y a pas de zone de composition, et les huit colonnes des lignes ont besoin de la largeur.
   ⚠️ Sous 1100 px, une seule colonne, comme toute fiche : la règle est REDITE ici parce que ce sélecteur, plus précis,
      l'emporterait sinon sur celle du bloc commun. */
.fiche.facture-fiche { grid-template-columns: minmax(0, 1fr) 15rem; }

@media (max-width: 1100px) {
  .fiche.facture-fiche { grid-template-columns: minmax(0, 1fr); }
}

/* Les lignes d'une pièce : les nombres ne se coupent pas — un montant sur deux lignes se relit mal —, seul le libellé
   (deuxième colonne) va à la ligne. Les gestes au-dessus du tableau se resserrent pour tenir sur une rangée. */
.facture-lignes .tableau th,
.facture-lignes .tableau td { padding: var(--space-2); }

.facture-lignes .tableau td:not(:nth-child(2)) { white-space: nowrap; }
.facture-lignes .tableau td:nth-child(2) { min-width: 9rem; }

/* L'empreinte SHA-256 d'un PDF archivé : soixante-quatre caractères sans espace, qui se coupent plutôt que d'élargir la
   section qui les porte. */
.facture-empreinte { overflow-wrap: anywhere; }

.facture-gestes .btn {
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
}

@media (max-width: 40rem) {
  .facture-saisie { grid-template-columns: minmax(0, 1fr); }
}

/* 0.96.93 (00B § 45) — la saisie d'une facture reçue : « + Nouveau fournisseur » à côté de la liste, et la TVA calculée.
   ⚠️ Les fenêtres sont rendues HORS de `.fiche` : la règle commune `.fiche [hidden]` ne les atteint pas, et `.field` comme
      `.btn` posent un `display` qui l'emporterait sur `hidden`. D'où la règle redite pour ces deux formulaires. */
.facture-saisie [hidden],
.facture-nouveau-tiers [hidden] { display: none; }

.facture-saisie__fournisseur {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

.facture-saisie__fournisseur .input { flex: 1 1 auto; min-width: 0; }
.facture-saisie__fournisseur .btn { flex: 0 0 auto; white-space: nowrap; }

.facture-tva > * { margin: 0 0 var(--space-1); }

/* 0.96.94 (00B § 46) — une charge générale de la Configuration (`charges-generales.php`) : libellé, position et
   « Enregistrer » sur une ligne, « Retirer » à côté ; le libellé prend la place, la position reste étroite. */
.facture-charge { flex: 1 1 32rem; }
.facture-charge__libelle { flex: 1 1 16rem; }
.facture-charge__position { flex: 0 0 7rem; }

/* 0.96.98 (00B § 50) — « Vendre » : la liste des acheteurs et « + Nouveau client » sur une ligne, comme le fournisseur
   d'une facture reçue. Sur un téléphone, le bouton passe SOUS la liste (sinon le nom de l'acheteur est rogné). */
.facture-saisie__acheteur {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

.facture-saisie__acheteur .input { flex: 1 1 12rem; min-width: 0; }
.facture-saisie__acheteur .btn { flex: 0 0 auto; white-space: nowrap; }

/* ══ BLOC DE FAMILLE « facturation » — FIN ══ */

/* ══ BLOC DE FAMILLE « financement » — FINANCEMENT (encours, piles, briques, simulateur, barème, « Mon financement ») — DÉBUT ══ */
/* La bande des chiffres de l'encours (sept cellules : l'alerte puis les six tuiles d'avant) et du simulateur (les huit
   indicateurs du canon, dans son ordre) : des cellules plus étroites, pour qu'elle tienne sur UNE ligne à 1280 px. */
.encours-bande > .fiche-chiffres,
.simulateur-bande > .fiche-chiffres { grid-template-columns: repeat(auto-fit, minmax(7.25rem, 1fr)); }

/* Le relevé d'une brique : la brique (ses paires) à gauche, le relevé de paliers — huit colonnes — à droite. */
.brique-releve {
  display: grid;
  grid-template-columns: minmax(15rem, 1fr) minmax(0, 3fr);
  gap: var(--space-3);
  align-items: start;
}

/* Ses paires sont enveloppées d'un `<div>` chacune (le banc relit `<dt>Valeur ajustée</dt><dd>`) : une paire par ligne,
   le libellé à gauche, la valeur à droite — deux paires par ligne se chevauchaient dans la colonne étroite. */
.brique-releve .paires {
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-1);
}

.brique-releve .paires > div {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0 var(--space-3);
}

/* Le simulateur : le cadre sur toute la largeur, puis la pose | l'enregistrement (dans l'ordre de l'arbre, qui est une
   garde) ; les champs d'une section se rangent côte à côte, le bouton aligné sur leur pied. */
.simulateur-champs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: var(--space-2) var(--space-3);
  align-items: end;
}

.simulateur-champs > * { margin: 0; }

/* Les textes d'aide d'une section du simulateur : la grille de la section fait l'écart, pas leurs marges. */
.simulateur-bande .fiche-section > p,
.simulateur-bande .fiche-section > ul { margin: 0; }

/* La phrase du plafond de la passe, À CÔTÉ des pas de temps qu'elle explique, dans l'en-tête. */
.simulateur-plafond {
  flex: 1 1 18rem;
  margin: 0;
  font-size: var(--text-sm);
}

@media (max-width: 1100px) {
  .brique-releve { grid-template-columns: minmax(0, 1fr); }
}

/* 0.96.102 (00B § 54) — la JAUGE de surveillance du calcul de la marge, toujours rendue sous les chiffres du stock confié :
   un liseré à la couleur de l'état (règle 16 seule : à jour, en retard, rien à calculer), le badge, la phrase chiffrée,
   une mini-mesure « N voitures sur M » et le dernier passage de la nuit. La largeur du plein est un ATTRIBUT du svg. */
.encours-jauge {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-2) var(--space-4);
  background: var(--ink-1);
  border: 1px solid var(--line-2);
  border-left: 3px solid var(--status-ok);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
}

.encours-jauge--alerte { border-left-color: var(--status-alert); }
.encours-jauge--neutre { border-left-color: var(--status-neutral); }
.encours-jauge > p { margin: 0; }
.encours-jauge__etat { font-weight: 600; color: var(--paper); }
.encours-jauge__passage { color: var(--muted); }
.encours-jauge__mesure { width: 8rem; height: 6px; flex: 0 0 auto; }
.encours-jauge__piste { fill: var(--line); }
.encours-jauge__plein { fill: var(--status-ok); }
.encours-jauge__plein--alerte { fill: var(--status-alert); }

/* L'évolution : les deux graphiques côte à côte (une colonne sous 1100 px), puis leurs valeurs, repliées. */
.encours-evolution { display: grid; gap: var(--space-2); }

.encours-evolution__graphiques {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
}

.encours-evolution__valeurs > summary {
  cursor: pointer;
  color: var(--muted);
  font-size: var(--text-sm);
}

.encours-evolution__valeurs[open] > summary { margin-bottom: var(--space-2); }

@media (max-width: 1100px) {
  .encours-evolution__graphiques { grid-template-columns: minmax(0, 1fr); }
}

/* ══ BLOC DE FAMILLE « financement » — FIN ══ */

/* ══ BLOC DE FAMILLE « documents » — DOCGEN, GED ET REGISTRE (générateur, modèles, documents générés, GED, livre de police) — DÉBUT ══ */
/* L'éditeur d'une copie de modèle (`docgen/modele.php`) : le texte à gauche, le catalogue des jetons À CÔTÉ — un clic y
   insère le jeton au curseur, il doit donc rester sous les yeux pendant l'écriture. Une colonne sous 1100 px. */
.modele-editeur {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(16rem, 1fr);
  gap: var(--space-4);
  align-items: start;
}

.modele-editeur__liste {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
  margin: 0;
}

.modele-editeur__liste .btn { font-size: var(--text-xs); }

/* Le texte tient dans l'écran avec l'en-tête et la bande au-dessus ; il s'agrandit à la main (poignée). */
.modele-editeur textarea { height: 26rem; resize: vertical; }

@media (max-width: 1100px) {
  .modele-editeur { grid-template-columns: minmax(0, 1fr); }
}

/* La fiche d'un document généré (`docgen/document-genere.php`) : le document, ses signatures, et le dépôt du scan — le
   formulaire — sur la part la plus large. Une colonne sous 1100 px. */
.fiche-cadre--document-genere { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.6fr); }

@media (max-width: 1100px) {
  .fiche-cadre--document-genere { grid-template-columns: minmax(0, 1fr); }
}

/* Les cartes du générateur (`docgen/generateur.php`) : les quatre types sur une ligne à 1280 px. */
.generateur-cartes { grid-template-columns: repeat(auto-fill, minmax(min(13rem, 100%), 1fr)); }

/* L'export du registre (`docgen/registre.php`) : la période et ses deux gestes sur une ligne. */
.registre-export {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
}

.registre-export .field__label { margin: 0; }
.registre-export .input { width: auto; }

/* La fiche d'un document de la GED (`documents/fiche-document.php`) : identité, péremption et partages sur une ligne. */
.document-sections { grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr)); }

/* Une catégorie de la société et sa bascule (`documents/categories.php`), sur une ligne. */
.categorie-ligne {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* Un document de la file « À classer » (`documents/a-classer.php`) : son nom en clair, son formulaire serré. */
.classement__titre {
  margin: 0;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.classement__geste { display: grid; gap: var(--space-2); }
.classement__geste > p { margin: 0; }

/* ══ BLOC DE FAMILLE « documents » — FIN ══ */

/* ══ BLOC DE FAMILLE « achats » — ACHATS, CLIENTS ET AGENDA (purchase, clients, agenda) — DÉBUT ══ */

/* Les demandes d'achat : les HUIT états sont la bande des chiffres (zéro compris) — des cellules plus étroites, pour
   qu'ils tiennent sur une ligne à 1280 px plutôt que de passer à la ligne à six.                                       */
.achats-demandes .fiche-chiffres { grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr)); }

/* Les types d'événement de l'agenda : le catalogue en cartes côte à côte (`fiche-cadre`), une liste sans puces. */
.agenda-types {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* 0.96.111 (00B § 62) — « Déposer les fichiers choisis » : la barre sous la grille des pièces (`_depot_groupe.php`), montrée
   par l'îlot `depot-groupe.js` dès qu'un fichier est choisi. L'état prend la place, le bouton reste à droite ; le refus passe
   sur sa propre ligne. `hidden` gagne par la règle commune `.fiche [hidden]`.                                              */
.fiche-depot-groupe {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-top: var(--space-3);
  padding: var(--space-3);
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
}

.fiche-depot-groupe__etat { flex: 1 1 18rem; margin: 0; }

.fiche-depot-groupe__refus { flex: 1 1 100%; margin: 0; }

/* ══ BLOC DE FAMILLE « achats » — FIN ══ */

/* ══ BLOC DE FAMILLE « societe » — SOCIÉTÉ ET TIERS (templates/societe/*, historique, modules de la société) — DÉBUT ══ */

/* ══ BLOC DE FAMILLE « societe » — FIN ══ */

/* ══ BLOC DE FAMILLE « administration » — ADMINISTRATION (templates/admin/*) — DÉBUT ══ */

/* Un formulaire d'administration sur deux colonnes (créer une société, régler un pays) : chaque colonne empile ses
   libellés et ses champs, le bouton d'envoi les suit sur toute la largeur. L'ordre du document reste celui des champs. */
.admin-formulaire {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3) var(--space-5);
  align-items: start;
}

.admin-formulaire__colonne {
  display: grid;
  gap: var(--space-2);
  align-content: start;
  min-width: 0;
}

.admin-formulaire__colonne > * { margin: 0; }

.admin-formulaire__envoi {
  grid-column: 1 / -1;
  margin: 0;
}

/* Le filtre du journal d'audit : six champs, dont deux dates, que la barre `liste-outils` ne porte pas — gardés tels
   quels, posés en ligne sur toute la largeur, dans le même cadre que la barre d'outils d'une liste. */
.admin-filtres {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-2) var(--space-3);
  background: var(--ink-1);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
}

.admin-filtres__champs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-2) var(--space-3);
  flex: 1 1 40rem;
  min-width: 0;
}

.admin-filtres__champs > * { margin: 0; }

.admin-filtres__envoi {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

@media (max-width: 1100px) {
  .admin-formulaire { grid-template-columns: minmax(0, 1fr); }
}
/* ══ BLOC DE FAMILLE « administration » — FIN ══ */

/* ══ BLOC DE FAMILLE « tableaux » — TABLEAUX DE BORD ET PROFIL (synthèse, tableau de bord de société, profil) — DÉBUT ══ */

/* ── les alertes ── 0.96.113 (00B § 64) : la cloche « Alertes » de la barre du haut (à côté de « Mon compte ») et la
   pastille du nombre de non lues — sur la cloche, sur une entrée de la barre latérale, sur le titre d'une rubrique. Le
   texte porte l'information (le nombre, et « non lue(s) » pour un lecteur d'écran) ; la couleur n'est qu'un renfort. */
.alertes-cloche {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.alertes-cloche__icone {
  width: 1.1rem;
  height: 1.1rem;
  fill: currentColor;
}

.alertes-pastille {
  display: inline-block;
  min-width: 1.5em;
  margin-left: var(--space-1);
  padding: 0 var(--space-1);
  border-radius: var(--radius-pill);
  background: var(--status-alert);
  color: var(--ink-0);
  font-size: var(--text-xs);
  font-weight: 600;
  line-height: 1.5;
  text-align: center;
}

/* Dans le titre d'une rubrique (flex, `space-between`), la pastille se range à droite, contre le chevron. Une rubrique
   OUVERTE montre les pastilles de ses entrées : la somme du titre se retire, pour ne pas compter deux fois. */
.sidebar__rubrique-titre .alertes-pastille { margin-left: auto; }
.sidebar__rubrique[open] > .sidebar__rubrique-titre .alertes-pastille { display: none; }

/* « Vos alertes » : un tableau par société, aux MÊMES colonnes d'un groupe à l'autre, espacés comme le corps de la fiche. */
.alertes-liste { display: grid; gap: var(--space-3); min-width: 0; }
.alertes-liste .tableau { table-layout: fixed; }
.alertes-liste .tableau thead th:nth-child(2) { width: 11rem; }
.alertes-liste .tableau thead th:nth-child(3) { width: 7rem; }

/* ── gabarit : pages ── 0.96.88 : synthèse, historique, modules (et son panneau d'installation), profil.
   Ce que le bloc commun n'a pas, préfixé par l'écran, jetons du thème seulement. */

/* Les modules d'une société en grille de cartes : le code, la date, les dépendances serrés sous le libellé, et le geste
   (ou le refus nominatif qui le remplace) en petit texte — huit modules tiennent en trois rangées au lieu d'une colonne. */
.modules-grille .fiche-raccourci__texte {
  display: grid;
  gap: var(--space-1);
  align-content: start;
}

.modules-grille .fiche-raccourci__texte > *,
.modules-grille .fiche-raccourci__geste > * { margin: 0; }

.modules-grille .fiche-raccourci__geste { font-size: var(--text-sm); }

.modules-grille .fiche-raccourci__geste form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* Les paires du profil : la valeur peut se replier (un identifiant de 26 caractères, une adresse longue) au lieu de
   sortir de sa section quand trois sections partagent la largeur. */
.profil-paires { grid-template-columns: minmax(9rem, max-content) minmax(0, 1fr); }
.profil-paires dd { min-width: 0; overflow-wrap: anywhere; }

/* Sous 34rem, les paires repassent sur une colonne, comme `.paires` (le libellé au-dessus de la valeur). */
@media (max-width: 34rem) {
  .profil-paires { grid-template-columns: minmax(0, 1fr); }
}

/* ── L'espace client — `/app` d'un compte client (0.96.90, 06/10/2026, 00B § 44) ──────────────────────────────────
   La légende du code couleur des véhicules (les liserés `.carte--propre|confie|achete` vivent au bloc « vehicules »),
   et « Mes sociétés » relégué en bas. Jetons du thème seulement. */
.espace-legende {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-sm);
  color: var(--muted);
}

.espace-legende__item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.espace-pastille {
  display: inline-block;
  width: 0.625rem;
  height: 0.625rem;
  border-radius: var(--radius-pill);
}

.espace-pastille--propre { background: var(--status-pending); }
.espace-pastille--confie { background: var(--status-ok); }
.espace-pastille--achete { background: var(--status-neutral); }

/* « Mes sociétés », en bas et EN RETRAIT : un filet au-dessus, des cartes sans fond. */
.espace-societes {
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.espace-societes .carte { background: transparent; }

/* ── La carte d’entité de la Synthèse (0.96.112, 00B § 63) — LIEN ÉTIRÉ : le lien du nom couvre toute la carte et entre
   dans la société ; un chiffre qui porte un lien (« 2 · Demandes d’achat à traiter ») passe au-dessus et mène à son écran.
   Un `<a>` ne s’emboîte pas dans un `<a>` : la carte est un `<article>`, l’apparence de `.carte` ne change pas. ── */
.synthese-carte { position: relative; }

.synthese-carte__entrer {
  color: inherit;
  text-decoration: none;
}

.synthese-carte__entrer::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
}

/* Le focus CLAVIER dessine la carte entière (le lien la couvre) ; l'anneau du nom reste, jamais retiré. */
.synthese-carte__entrer:focus-visible::after {
  outline: var(--focus-ring);
  outline-offset: 2px;
}

.synthese-carte__lien {
  position: relative;
  z-index: 1;
  color: inherit;
  text-decoration: none;
}

.synthese-carte__lien:hover .chiffre__quoi {
  color: var(--brand-accent);
  text-decoration: underline;
}

.synthese-carte__lien:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
}

/* ══ BLOC DE FAMILLE « tableaux » — FIN ══ */
