/* Interface approuvée le 29/09/2026. Composition commune, palettes du compte
   et livrées héritées de themes.css. Les sélecteurs métier restent en place. */
body { --interface-soft:color-mix(in srgb,var(--accent) 8%,var(--ground-2)); }
/* Écrin (spec du 05/10/2026, 3.1) : une seule échelle de rayons, concentrique, et l'ombre des panneaux, tirée de l'encre du thème.
   Les jetons se recalculent sous chaque porteur de thème. En schéma sombre une ombre tirée de l'encre ferait un halo clair : chaque jeton d'ombre y vaut une couche transparente (jamais `none`, qui rendrait invalide une ombre composée avec le jeton) et le panneau garde un filet. Le voile du tiroir y tire vers le fond.
   La liste des thèmes sombres est tenue par test_le_filet_des_panneaux_est_transparent_en_clair_et_revient_en_sombre. */
:root,[data-theme] { --voile:color-mix(in srgb,var(--ink) 35%,transparent); --r-vif:3px; --r-etiquette:2px; --r-panneau:var(--r-vif); --r-contenu:var(--r-vif); --r-controle:var(--r-vif); --r-flottant:16px; --r-flottant-entree:12px; --ombre-flottant:0 1px 2px color-mix(in srgb,var(--ink) 4%,transparent),0 12px 32px -16px color-mix(in srgb,var(--ink) 18%,transparent); --ombre-tiroir:0 -12px 32px -16px color-mix(in srgb,var(--ink) 18%,transparent); --colonne-fond:var(--ground-2); --fond-doux:color-mix(in srgb,var(--ink) 6%,var(--ground-2)); --filet-tete:var(--hair-2); --filet-champ:color-mix(in srgb,var(--ink-2) 75%,var(--ground)); }
[data-theme="nuit-atelier"],[data-theme="weissach"] { --ombre-tiroir:0 0 transparent; --ombre-flottant:0 0 transparent; --voile:color-mix(in srgb,var(--ground) 72%,transparent); }
/* Composants (spec du 09/10/2026, section 1) : coins de 3 px au plus, 2 px pour une étiquette, aucune ombre portée. Deux jetons de rayon portent la règle : `--r-vif` (3 px) et `--r-etiquette` (2 px). `--r-panneau`, `--r-contenu` et `--r-controle`, l'échelle d'Écrin, restent en ALIAS de `--r-vif` : les règles et leurs gardes gardent leurs noms de jeton, la valeur ne s'écrit qu'une fois (ménage du lot D). `--ombre-panneau`, `--ombre-survol` et `--filet-panneau`, sans lecteur depuis le lot C, ont quitté la feuille. Les calques de la navigation de Maison (menu du compte, suggestions de la recherche, colonne déployée sous le pointeur) gardent leur forme par leurs propres jetons, `--r-flottant`, `--r-flottant-entree` et `--ombre-flottant`. */
/* Maison (spec du 08/10/2026, 3.1) : `--r-vif` est le coin de 3 px de la navigation (bouton d'ajout, entrées), hors de l'échelle concentrique des panneaux. `--colonne-fond` est le fond de la colonne : le cadre pour Maison, le papier des panneaux pour les neuf thèmes d'avant, dont le cadre est une teinte de bordure trop dense pour porter un libellé. La liste des thèmes sur le cadre est tenue par `COLONNE_SUR_CADRE` de garage/themes.py, qui mesure les libellés sur ce fond. `--filet-tete` est le filet qui ouvre « À venir » sur le tableau de bord : en laiton dans Maison (maquette validée, ocre discret), à l'encre des filets dans les neuf autres thèmes, où le laiton vaut l'accent du texte et ferait un trait de couleur sur un seul bord ; liste tenue par `FILET_DE_TETE_EN_LAITON`. */
[data-theme="maison"] { --colonne-fond:var(--frame); --filet-tete:var(--laiton); }
.dashboard-app,.cover { font-family:var(--sans); }
/* `--colonne-deployee` est la largeur de la colonne déployée, `--colonne` celle qu'elle occupe dans la page : la barre du haut et le contenu partent de son bord. Le bloc Maison, en fin de feuille, la réduit à 76 px en rail. */
.dashboard-app { --colonne:232px; }
@media (min-width:1600px) { .dashboard-app { --colonne:254px; } }
.dashboard-app { --colonne-deployee:232px; }
@media (min-width:1600px) { .dashboard-app { --colonne-deployee:254px; } }
.dashboard-app .content { max-width:1460px; padding:32px 36px 64px; margin:0 0 0 var(--colonne); width:calc(100% - var(--colonne)); }
.dashboard-app .content.court { max-width:900px; padding-top:36px; }
/* Écrin 3.2 : la barre est collée au bord gauche, de haut en bas (dashboard.css la fixe). Seule la liste défile quand l'écran est bas. Le retrait latéral du bloc laisse la place de l'anneau de focus des entrées. */
.dashboard-app .mast-defile { flex:1 1 auto; min-height:0; overflow-y:auto; overscroll-behavior:contain; scrollbar-width:thin; display:flex; flex-direction:column; margin-inline:-6px; padding-inline:6px; }
.navigation-plus { margin:0; padding:0; border:0; min-width:0; }
.navigation-plus > summary { display:none; }
.navigation-outils { display:flex; flex-direction:column; }
/* La liste coupée montre qu'elle continue : un dégradé du fond en bas tant qu'il reste des entrées dessous, en haut quand on a défilé. navigation.js nomme les bords dans `data-reste` ; sans script la liste défile sans indice. */
.dashboard-app .mast-defile::before,.dashboard-app .mast-defile::after { content:""; position:sticky; z-index:1; flex:none; height:28px; pointer-events:none; opacity:0; transition:opacity .15s; }
.dashboard-app .mast-defile::before { top:0; margin-bottom:-28px; background:linear-gradient(var(--colonne-fond),transparent); }
.dashboard-app .mast-defile::after { bottom:0; margin-top:-28px; background:linear-gradient(transparent,var(--colonne-fond)); }
.dashboard-app .mast-defile[data-reste~=haut]::before,.dashboard-app .mast-defile[data-reste~=bas]::after { opacity:1; }
@media (prefers-reduced-motion:reduce) { .dashboard-app .mast-defile::before,.dashboard-app .mast-defile::after { transition:none; } }
.dashboard-app .dashboard-concierge { margin-top:20px; }
.dashboard-app h1 { font-size:32px; font-weight:600; letter-spacing:-.035em; line-height:1.2; }
.dashboard-app h2 { font-weight:600; letter-spacing:-.02em; }
/* Composants (spec du 09/10/2026, pièce 8) : les boutons. 44 px, coins de 3 px, corps de 12 px en demi-gras, 10 px entre un pictogramme et son libellé. Le secondaire, forme de base : un filet sur fond transparent, le libellé à l'accent lisible (dashboard.css) ; au survol le fond doux et un filet à l'accent. Le principal et le danger sont pleins et foncent au survol. Le discret est un lien (« Annuler » au pied d'un formulaire, les gestes de la pagination). Le désactivé prend le fond doux et l'encre secondaire.
   `--fond-doux` est le fond des pièces discrètes (survol du secondaire, bouton désactivé, étiquette) : 6 % d'encre sur le papier des panneaux, dans les dix thèmes. Le cadre, que la planche emploie, ne porte ni l'accent lisible ni l'encre secondaire à 4,5 dans cinq thèmes (mesuré au lot B de Maison) ; dans Maison il se confond à 4 points près avec le fond adouci d'une échéance dépassée. */
/* Revue du lot A (spec section 6, décision 6) : `--filet-champ` est le filet d'un champ et d'un bouton secondaire, 75 % d'encre secondaire sur le fond de la page. Il tient 3 de contraste au moins avec le fond de la page et le papier des panneaux dans les dix thèmes (3,28 au plus bas, Maison), là où `hair-2` tenait 1,17 à 1,44. Les filets de simple séparation (rangées, en-têtes, pied d'un formulaire) restent en `hair-2`. */
.dashboard-app button,.dashboard-app .btn,.cover button,.cover .btn { min-height:44px; border-color:var(--filet-champ); border-radius:var(--r-vif); font-size:12px; font-weight:600; padding:11px 16px; gap:10px; }
/* Revue du lot A : le survol du secondaire ne vise que le secondaire. La règle pèse (0,4,0), devant `.dashboard-app .btn-primary:hover` et `.dashboard-app .btn-danger:hover` (0,3,0) : un principal ou un danger posé en lien (`a.btn.btn-primary`, « Activer » de la page Sécurité) y prenait le fond doux sous un libellé en `on-accent`, à 1,12 de contraste. Les deux pleins sont écartés dans `:where()`, qui ne pèse rien. */
.dashboard-app .btn:where(:not(.btn-primary,.btn-danger)):not(:where(.masthead,.ears,.installer,.ouverture,.prioritaire,.chiffres,.raccourcis,.journal,.accueil-garage) .btn):hover,.cover .btn:where(:not(.btn-primary,.btn-danger)):hover { background:var(--fond-doux); }
/* Section 4 de la spec : la navigation et le tableau de bord de Maison gardent leur forme. Dans leurs blocs un bouton lit la base d'avant le lot A, au poids et à la place de la règle ci-dessus (`:where()` ne pèse rien) : les règles propres à Maison passent devant elle comme avant. */
.dashboard-app :where(.masthead,.ears,.installer,.ouverture,.prioritaire,.chiffres,.raccourcis,.journal,.accueil-garage) button,.dashboard-app :where(.masthead,.ears,.installer,.ouverture,.prioritaire,.chiffres,.raccourcis,.journal,.accueil-garage) .btn { border-color:var(--hair-2); border-radius:999px; font-size:13px; font-weight:500; padding:10px 18px; gap:normal; }
/* La tuile d'entrée, bouton ou lien de plusieurs lignes, reste un bloc au rayon de contenu ; (0,2,1) passe devant `.dashboard-app button` et `.dashboard-app .btn`. La tuile-lien de l'écran « Ajouter un véhicule » prend la carrure de la tuile-bouton de la saisie (retours testeur du 01/10) ; les deux gardent le filet de séparation, que la tuile-bouton quittait pour le filet des champs. */
.dashboard-app a.entree,.dashboard-app button.entree { min-height:44px; border-color:var(--hair-2); border-radius:var(--r-contenu); background:transparent; color:var(--ink); font-size:13px; font-weight:500; padding:10px 16px; gap:8px; }
.dashboard-app a.entree:hover,.dashboard-app button.entree:hover { border-color:var(--accent); background:transparent; color:var(--accent-texte); }
.dashboard-app .btn-primary,.cover .btn-primary { background:var(--accent); border-color:var(--accent); color:var(--on-accent); }
.dashboard-app .btn-primary .icon { color:inherit; stroke:currentColor; }
.dashboard-app .btn-primary:hover,.cover .btn-primary:hover { background:color-mix(in srgb,var(--accent) 88%,var(--ink)); color:var(--on-accent); }
.dashboard-app button[type=submit]:not(.trait):not(.btn-danger):not(.chip):not(.micro),.cover button[type=submit] { background:var(--accent); color:var(--on-accent); border-color:var(--accent); }
.dashboard-app button[type=submit]:not(.trait):not(.btn-danger):not(.chip):not(.micro):hover,.cover button[type=submit]:hover { background:color-mix(in srgb,var(--accent) 88%,var(--ink)); border-color:color-mix(in srgb,var(--accent) 88%,var(--ink)); }
.dashboard-app .btn-primary:hover,.cover .btn-primary:hover { border-color:color-mix(in srgb,var(--accent) 88%,var(--ink)); }
.dashboard-app .btn-danger,.dashboard-app button.btn-danger { background:var(--danger); border-color:var(--danger); color:var(--on-accent); }
.dashboard-app .btn-danger.trait { background:transparent; color:var(--danger); border-color:color-mix(in srgb, var(--danger) 50%, transparent); }
/* Revue du lot A : au survol le danger au trait prend son fond adouci (dashboard.css) ; son libellé se compose avec l'encre, comme l'étiquette d'une échéance dépassée, pour tenir 4,5 sur ce fond dans les dix thèmes (4,31 à 4,37 dans quatre thèmes avec la teinte pure). (0,4,0), au poids de la règle de dashboard.css, devant elle par sa place. */
.dashboard-app .btn-danger.trait:hover { color:color-mix(in srgb,var(--danger) 82%,var(--ink)); }
/* Un seul bouton plein au pied d'un formulaire : l'envoi qui suit le principal (« Enregistrer et ajouter des photos », « Rejeter ») est un bouton secondaire. (0,8,1), devant la règle de l'envoi plein. */
.dashboard-app .form-actions>.btn-primary~button[type=submit]:not(.btn-primary):not(.btn-danger):not(.trait):not(.chip):not(.micro) { background:transparent; border-color:var(--filet-champ); color:var(--accent-texte); }
.dashboard-app .form-actions>.btn-primary~button[type=submit]:not(.btn-primary):not(.btn-danger):not(.trait):not(.chip):not(.micro):hover { background:var(--fond-doux); border-color:var(--accent); }
/* Le discret : « Annuler », lien qui ouvre la rangée d'actions d'un formulaire dont l'envoi est plein. Sans filet ni fond. Revue du lot A : il se confondait avec un secondaire et avec le texte courant ; il porte au repos un soulignement fin (1 px, écarté de 4 px), qui passe à 2 px au survol, le libellé à l'encre. Même signe partout où le discret sert : la pagination, les renvois d'un en-tête, les gestes discrets de la fiche (fiche.css). Qui ignore `:has()` le garde en bouton secondaire. */
.dashboard-app .form-actions:has(>button[type=submit]:is(.btn-primary,.btn-danger))>a.btn:first-child { padding-inline:0; border-color:transparent; background:none; text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:4px; }
.dashboard-app .form-actions:has(>button[type=submit]:is(.btn-primary,.btn-danger))>a.btn:first-child:hover { border-color:transparent; background:none; color:var(--ink); text-decoration:underline; text-decoration-thickness:2px; text-underline-offset:4px; }
/* Le pied d'un formulaire (planche, pièce 7) : sur un filet, à droite, « Annuler » puis l'envoi. Revue du lot A : le balisage suit la lecture (« Annuler » en tête, lien que la touche Entrée ignore), la rangée n'est plus inversée et la tabulation va de gauche à droite. Le principal ferme la rangée : un second envoi, qui le suit dans le balisage pour lui laisser la touche Entrée, se range avant lui. */
.dashboard-app .form-actions:has(>button[type=submit]:is(.btn-primary,.btn-danger)):has(>a.btn:first-child) { justify-content:flex-end; gap:12px 24px; margin-top:24px; padding-top:24px; border-top:1px solid var(--hair-2); }
.dashboard-app .form-actions:has(>a.btn:first-child)>.btn-primary { order:1; }
/* Le désactivé (un envoi en cours, base.html) : (0,6,1) et plus, devant la règle de l'envoi plein. */
.dashboard-app button:disabled,.dashboard-app button[type=submit]:not(.trait):not(.btn-danger):not(.chip):not(.micro):disabled,.dashboard-app button.btn-primary:disabled,.dashboard-app button.btn-danger:disabled,.dashboard-app button.btn-danger.trait:disabled,.cover button[type=submit]:disabled { background:var(--fond-doux); border-color:var(--hair-2); color:var(--ink-2); cursor:not-allowed; }
/* Composants (spec du 09/10/2026, pièce 7) : les champs. Cernés d'un filet de 1 px (`--filet-champ`) à coins de 3 px, 44 px ; corps de 13 px, 16 px au téléphone (en dessous iOS agrandit la page à la prise de focus). Le fond est plein, à la couleur de la page : le tracé de circuit du fond ne passe plus sous le texte saisi (revue du lot A, écart à la planche qui pose le champ sur fond transparent). Au survol le filet prend l'encre secondaire. */
.dashboard-app input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=range]):not([type=search]):not([disabled]),.dashboard-app select,.dashboard-app textarea,.cover input:not([type=checkbox]):not([type=hidden]) { min-height:44px; padding:10px 12px; border:1px solid var(--filet-champ); border-radius:var(--r-controle); background-color:var(--ground); color:var(--ink); font-family:var(--sans); font-size:13px; line-height:1.5; max-width:100%; }
/* Section 4 de la spec : dans les blocs de Maison un champ lit la base d'avant le lot A, au poids et à la place de la règle ci-dessus. */
.dashboard-app :where(.masthead,.ears,.installer,.ouverture,.prioritaire,.chiffres,.raccourcis,.journal,.accueil-garage) input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=range]):not([type=search]):not([disabled]),.dashboard-app :where(.masthead,.ears,.installer,.ouverture,.prioritaire,.chiffres,.raccourcis,.journal,.accueil-garage) select,.dashboard-app :where(.masthead,.ears,.installer,.ouverture,.prioritaire,.chiffres,.raccourcis,.journal,.accueil-garage) textarea { padding:11px 12px; border-color:var(--hair-2); background-color:var(--ground-2); font-size:16px; }
/* Le fond des champs s'écrit par `background-color` : le raccourci `background` effaçait le chevron que dashboard.css dessine sur les sélecteurs, et le raccourci `padding` ci-dessus sa place à droite. */
/* Un menu plus étroit que son option choisie la laisse passer à la ligne et grandit avec elle (« Organisateur d'événements » à 320 px, le circuit des préférences) : le navigateur la coupait sans le dire. Les menus à hauteur fixe (filtres de la collection) gardent la leur. */
.dashboard-app select { padding-right:30px; white-space:normal; height:auto; }
.dashboard-app input[type=search] { border-radius:var(--r-controle); min-height:44px; }
.dashboard-app input[type=file] { white-space:normal; overflow:hidden; }
/* Le choix de fichier est un bouton secondaire (planche, pièce 7). Sans script le champ natif se montre : son bouton prend la même forme, sans le cadre du champ ; (0,8,1), devant la règle des champs. */
.dashboard-app input[type=file]:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=range]):not([type=search]):not([disabled]) { padding:0; border:0; border-radius:0; }
.dashboard-app input[type=file]::file-selector-button { min-height:44px; margin-right:12px; padding:10px 16px; border:1px solid var(--filet-champ); border-radius:var(--r-vif); background:transparent; color:var(--accent-texte); font:inherit; font-size:12px; font-weight:600; letter-spacing:0; text-transform:none; cursor:pointer; }
.dashboard-app textarea { min-height:120px; resize:vertical; }
.dashboard-app input[type=checkbox],.dashboard-app input[type=radio],.cover input[type=checkbox] { accent-color:var(--accent); min-width:18px; min-height:18px; }
/* Le libellé se pose au-dessus de son champ, à l'encre et en demi-gras (planche : 12 px, 600). Le libellé d'une case ou d'un bouton radio, posé à côté d'elle, garde la graisse du texte, même quand un champ le suit sur la rangée (la date d'une première échéance, revue du lot A). Qui ignore `:has()` sert tous les libellés à la graisse du texte. */
.dashboard-app label,.dashboard-app .etiquette-lue { color:var(--ink); font-size:12px; line-height:1.6; }
.dashboard-app label:has(+ input:not([type=checkbox]):not([type=radio])):not(:is(input[type=checkbox],input[type=radio]) + label),.dashboard-app label:has(+ select),.dashboard-app label:has(+ textarea),.dashboard-app label:has(+ .fichier),.dashboard-app form p:not(:has(>input[type=checkbox],>input[type=radio]))>label:first-child:not(.chip):not(:has(>input[type=checkbox],>input[type=radio])) { font-weight:600; }
.dashboard-app .etiquette-lue { font-weight:600; }
/* À la connexion le libellé se tient à 8 px de son champ, hors du contour de focus (il le touchait). */
.cover label { display:block; margin-bottom:8px; color:var(--ink); font-size:12px; font-weight:600; line-height:1.6; }
/* Le libellé qui enveloppe son champ (le circuit des préférences) le pose dessous, à 8 px, à la graisse du texte ; celui d'un choix de fichier garde le même écart. */
.dashboard-app p>label>select,.dashboard-app p>label>input:not([type=checkbox]):not([type=radio]),.dashboard-app p>label>textarea { display:block; margin-top:8px; font-weight:400; }
.dashboard-app label:has(+ .fichier),.dashboard-app p>label:first-child:has(+ .periodicite) { margin-bottom:8px; }
.dashboard-app :where(.masthead,.ears,.installer,.ouverture,.prioritaire,.chiffres,.raccourcis,.journal,.accueil-garage) label { color:var(--ink-2); font-size:13px; line-height:inherit; }
.dashboard-app input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=range]):not([type=search]):not([disabled]):hover,.dashboard-app select:hover,.dashboard-app textarea:hover { border-color:var(--ink-2); }
/* Revue du lot A : au focus un seul signal, le contour de l'application (2 px à l'accent, écarté de 3 px, règle ci-dessous). Le filet du champ reste à sa teinte : passé à l'accent, il dessinait un second contour emboîté dans le premier. Un sélecteur ouvert à la souris, que `:focus-visible` ignore, reçoit le même contour. */
.dashboard-app select:focus { outline:2px solid var(--accent); outline-offset:3px; }
/* Revue du lot A : un champ désactivé ne se lit pas comme un champ à saisir. Fond doux, encre secondaire, filet de séparation en tirets, curseur d'interdiction ; le chevron d'un sélecteur s'éteint (40 % d'encre secondaire). Le sélecteur et la zone de texte gardaient la forme d'un champ actif (la voiture de « Modifier la sortie »). (0,4,1) pour le champ, au poids de la règle de dashboard.css, devant elle par sa place ; (0,2,1) pour les deux autres, devant la règle des champs. */
.dashboard-app input:disabled:not([type=checkbox]):not([type=radio]),.dashboard-app select:disabled,.dashboard-app textarea:disabled { border:1px dashed var(--hair-2); background-color:var(--fond-doux); color:var(--ink-2); opacity:1; cursor:not-allowed; }
.dashboard-app select:disabled { background-image:linear-gradient(to top right,transparent calc(50% - 1.1px),color-mix(in srgb,var(--ink-2) 40%,transparent) calc(50% - .3px),color-mix(in srgb,var(--ink-2) 40%,transparent) calc(50% + .3px),transparent calc(50% + 1.1px)),linear-gradient(to top left,transparent calc(50% - 1.1px),color-mix(in srgb,var(--ink-2) 40%,transparent) calc(50% - .3px),color-mix(in srgb,var(--ink-2) 40%,transparent) calc(50% + .3px),transparent calc(50% + 1.1px)); }
.dashboard-app select:disabled:hover,.dashboard-app textarea:disabled:hover { border-color:var(--hair-2); }
@media (max-width:720px) { .dashboard-app input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=range]):not([type=search]):not([disabled]),.dashboard-app select,.dashboard-app textarea,.cover input:not([type=checkbox]):not([type=hidden]) { font-size:16px; } }
.dashboard-app :focus-visible,.cover :focus-visible { outline:2px solid var(--accent); outline-offset:3px; }
/* L'aide sous le champ, en 11 px à l'encre secondaire. L'erreur se dit par la couleur d'alerte du message et du libellé du champ fautif (`aria-invalid`, posé par Django) : ni liseré, ni fond, ni puce. */
.dashboard-app .helptext,.dashboard-app .help,.dashboard-app .date-lue { color:var(--ink-2); font-size:11px; line-height:1.6; }
.dashboard-app .errorlist { margin:0; padding:0; list-style:none; color:var(--danger); font-size:11px; line-height:1.6; }
.dashboard-app p:has(>[aria-invalid=true])>label { color:var(--danger); }
/* Le rythme d'un formulaire posé sur la page : 22 px entre deux champs, le texte de ses lignes au corps des champs ; le message d'erreur se tient à 4 px au-dessus du libellé qu'il concerne. L'intitulé d'un groupe de cases parle comme un libellé. */
.dashboard-app main.content>form>p,.dashboard-app main.content>form>details>p,.dashboard-app main.content>form>fieldset { margin-block:22px; font-size:13px; }
.dashboard-app main.content>form>.errorlist { margin-top:22px; }
.dashboard-app main.content>form>.errorlist + p { margin-top:4px; }
.dashboard-app fieldset.cases-groupe>legend,.dashboard-app fieldset.pastilles>legend,.dashboard-app fieldset.themes-groupe>legend { margin-bottom:8px; color:var(--ink); font-size:12px; font-weight:600; line-height:1.6; letter-spacing:0; text-transform:none; }
.dashboard-app fieldset.pastilles>legend { margin-bottom:0; }
/* Revue du lot A : un groupe de boutons radio en erreur nomme son message (`aria-describedby`, sorties/formulaire.html) ; l'intitulé prend la couleur d'alerte et le message se tient sous lui, à 4 px de l'intitulé comme des choix. */
.dashboard-app fieldset.pastilles[aria-describedby]>legend { color:var(--danger); }
.dashboard-app fieldset.pastilles>.errorlist { margin-top:4px; }
.dashboard-app fieldset.pastilles>.errorlist+.pastilles-choix { margin-top:4px; }
/* Composants (spec du 09/10/2026, pièce 2) : les formulaires de filtre (collection, pièces, sorties, choix du client) quittent leur panneau. Des champs de la pièce 7 (filet de 1 px, 3 px de coin, 44 px), le libellé au-dessus, « Filtrer » à leur pied, au fer droit.
   La rangée reste celle d'avant le lot (`dashboard.css`), préférée à la grille à colonnes égales de la planche : un menu part de la largeur de son option la plus longue et la rangée passe à la ligne, pour qu'un nom de lieu se lise entier (spec Finitions 6 bis, point 6). La recherche prend 1,8 part de la place libre, un menu une part. De 721 à 1205 px la recherche de la collection tient sa rangée, ses trois menus la suivante avec « Filtrer » ; au téléphone chaque menu passe à la ligne dès qu'il manque de place.
   Un menu seul dans son formulaire (le choix du client) garde une largeur de menu, « Filtrer » à sa suite. */
.dashboard-app .collection-filters { margin:24px 0 0; padding:0; gap:18px; align-items:flex-end; background:none; }
/* Les champs gardent leur hauteur libre, 44 px au moins : un menu plus étroit que son option choisie la laisse passer à la ligne et grandit avec elle (lot A) ; au téléphone, au corps de 16 px, un champ fait 46 px et « Filtrer » le suit. */
.dashboard-app .collection-filters input,.dashboard-app .collection-filters select { height:auto; min-height:44px; }
.dashboard-app .collection-filters button { height:44px; min-height:44px; padding-block:0; }
.dashboard-app .collection-filters label { min-width:min(100%,150px); }
/* Sa propre règle : un sélecteur à `:has()` invalide la liste entière chez qui l'ignore. */
.dashboard-app .collection-filters label:has(input[type=search]) { flex-grow:1.8; }
.dashboard-app .collection-filters label:only-of-type { flex:0 1 max-content; min-width:min(100%,260px); }
.dashboard-app .collection-filters label:only-of-type+button { margin-left:0; }
/* Spec, décision 5 : la recherche d'une liste est cernée d'un filet comme les autres champs (celle de la barre du haut reste soulignée). */
.dashboard-app .collection-filters input[type=search] { padding:10px 12px; border:1px solid var(--filet-champ); border-radius:var(--r-vif); background-color:var(--ground); color:var(--ink); font-family:var(--sans); font-size:13px; line-height:1.5; }
.dashboard-app .collection-filters input[type=search]:hover { border-color:var(--ink-2); }
@media (max-width:720px) {
  .dashboard-app .collection-filters input[type=search] { font-size:16px; }
  .dashboard-app .collection-filters { gap:18px 14px; }
  .dashboard-app .collection-filters button { height:46px; }
}
/* Revue du lot A : plus aucune puce en capsule. Une puce est un geste (les sources d'une analyse, l'épingle d'une sortie, « Reporter », « + nouveau », les documents épinglés de la fiche) : elle prend la forme du bouton secondaire, filet des champs, coin de 3 px, 44 px, 12 px en demi-gras à l'accent lisible, sans capitales ; au survol et pressée, le fond doux et un filet à l'accent. La mention sans lien (une source sans adresse) garde la boîte, à l'encre secondaire, sans survol.
   Les choix d'un groupe prennent la forme d'un filtre : ceux d'une barre de filtres (lot B, plus bas) et les raccourcis qu'un formulaire pose au-dessus d'un champ (sorties.js : dates, pilote). La pastille d'un groupe de boutons radio (`label.chip`) garde sa forme du lot A.
   Dans les blocs de Maison (les suggestions de la recherche de la barre du haut) la puce garde sa forme d'avant, un rectangle au coin de 3 px en capitales espacées, par la règle en `:where()` qui suit. */
.dashboard-app .chip,.dashboard-app button.chip { min-height:44px; gap:10px; padding:11px 16px; border:1px solid var(--filet-champ); border-radius:var(--r-vif); background:transparent; color:var(--accent-texte); font-size:12px; font-weight:600; letter-spacing:0; text-transform:none; }
.dashboard-app :where(.masthead,.ears,.installer,.ouverture,.prioritaire,.chiffres,.raccourcis,.journal,.accueil-garage) .chip,.dashboard-app :where(.masthead,.ears,.installer,.ouverture,.prioritaire,.chiffres,.raccourcis,.journal,.accueil-garage) button.chip { min-height:40px; gap:6px; padding:8px 14px; border:1px solid var(--hair-2); color:var(--ink-2); font-weight:400; letter-spacing:.12em; text-transform:uppercase; }
/* (0,3,1) pour le lien, (0,4,1) et (0,3,1) pour le bouton : au poids des règles d'app.css, devant elles par leur place ; devant la règle de survol du secondaire, qui ne nomme que `.btn`. */
.dashboard-app a.chip:not(:where(.masthead,.ears,.installer,.ouverture,.prioritaire,.chiffres,.raccourcis,.journal,.accueil-garage) .chip):hover,.dashboard-app button.chip:hover:enabled,.dashboard-app button.chip[aria-pressed=true] { border-color:var(--accent); background:var(--fond-doux); color:var(--accent-texte); }
.dashboard-app span.chip { border-color:var(--hair-2); color:var(--ink-2); font-weight:400; }
/* Le bouton désactivé garde la forme commune (fond doux, encre secondaire) : l'encre pâle d'app.css tenait 4,14 à 4,27 sur ce fond en Atelier et Nuit d'atelier. (0,3,1), devant elle par sa place. */
.dashboard-app button.chip:disabled { border-color:var(--hair-2); background:var(--fond-doux); color:var(--ink-2); cursor:not-allowed; }
/* La pastille d'un groupe de boutons radio (Nature et Conditions d'une sortie, la voiture d'un rattachement) : sa forme du lot A, un rectangle au filet de séparation, en capitales espacées. (0,2,1) : devant la règle des puces, derrière le survol et la coche d'app.css. */
.dashboard-app label.chip { min-height:40px; gap:6px; padding:8px 14px; border:1px solid var(--hair-2); border-radius:var(--r-vif); background:none; color:var(--ink-2); font-size:12px; font-weight:400; letter-spacing:.12em; text-transform:uppercase; }
/* Les raccourcis d'un champ (sorties.js) : des choix, à la forme d'un filtre. Des libellés de 44 px sans filet ni fond, à l'encre secondaire ; celui qui vaut la valeur du champ (`aria-pressed`) à l'accent lisible et en gras. `form .raccourcis` : le bloc du tableau de bord de Maison porte le même nom de classe, hors de tout formulaire. */
/* Chaque raccourci porte 6 px de retrait de chaque côté de son texte, repris sur l'écart (10 px, soit 22 px d'un texte à l'autre) et sur le fer gauche de la rangée : un libellé court comme « sam. 10/10 » (53 px) dans une cible de 44 px de haut se lisait à la recette comme une colonne de lettres. Il tient sur une ligne. */
.dashboard-app form .raccourcis { gap:0 10px; margin:0 0 4px -6px; }
/* La règle écrit aussi la casse et l'approche : la règle des blocs de Maison, qui lit le nom `raccourcis`, les rendait à ces puces. */
.dashboard-app form .raccourcis button.chip { min-width:44px; min-height:44px; padding:8px 6px; border:0; border-radius:0; background:none; color:var(--ink-2); font-size:12px; font-weight:500; letter-spacing:0; text-transform:none; white-space:nowrap; }
.dashboard-app form .raccourcis button.chip:hover:enabled { background:none; color:var(--accent-texte); }
.dashboard-app form .raccourcis button.chip[aria-pressed=true] { background:none; color:var(--accent-texte); font-weight:700; }
.dashboard-app form .raccourcis button.chip:disabled { padding-inline:10px; border-radius:var(--r-vif); background:var(--fond-doux); color:var(--ink-2); }
/* Composants, lot C : les chiffres du bilan et de la fiche d'un intervenant, une bande entre deux filets (dashboard.css pose ses filets) : le libellé en petites capitales au laiton, la valeur en famille d'apparat à chiffres droits, à l'accent lisible, la sous-ligne en 11 px. */
.dashboard-app .dashboard-metrics { gap:0; }
.dashboard-app .metric { padding:20px 22px; }
.dashboard-app .metric>strong { margin:6px 0; font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:30px; font-weight:400; letter-spacing:0; line-height:1.3; color:var(--accent-texte); }
.dashboard-app .metric-label { font-size:11px; font-weight:600; line-height:1.5; letter-spacing:0; text-transform:uppercase; color:var(--laiton); }
.dashboard-app .metric small { font-size:11px; line-height:1.6; color:var(--ink-2); }
.dashboard-app .dashboard-section-head { margin-top:26px; margin-bottom:16px; }
/* Composants, lot C : sans panneau, c'est le titre qui tient un bloc. Le titre d'une rubrique (`.section-title`), d'un repère de section et d'un bloc posé à même le contenu se compose en famille d'apparat, à chiffres droits (planche, `.c-board h3`, 26 px au téléphone) ; son compte et ses gestes restent en famille de texte, au fer droit. La liste ou le tableau qui suit s'ouvre d'un filet. */
.dashboard-app .dashboard-section-head h2,.dashboard-app main.content>h2:not([class]),.dashboard-app main.content form h2:not([class]) { font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:26px; font-weight:500; letter-spacing:0; line-height:1.15; }
.dashboard-app main.content>h2:not([class]) { margin:32px 0 12px; }
/* Revue du lot D : le titre d'un bloc posé DANS un formulaire (« Lignes » et « Prochaines échéances d'entretien » d'une relecture, « Documents à joindre » d'un dossier de vente, « Propositions ») restait en Manrope : même forme, par la règle ci-dessus. */
.dashboard-app main.content form h2:not([class]) { margin:32px 0 12px; }
.dashboard-app .dashboard-section-head>a { min-height:32px; display:inline-flex; align-items:center; }
.dashboard-app .section-title { display:flex; align-items:baseline; justify-content:space-between; flex-wrap:wrap; gap:6px 20px; text-align:left; margin:32px 0 12px; padding:0; font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:26px; font-weight:500; line-height:1.15; border:0; text-transform:none; letter-spacing:0; }
.dashboard-app .section-title:before,.dashboard-app .section-title:after { display:none; }
.dashboard-app .section-title .compte { position:static; transform:none; max-width:100%; text-align:left; font-family:var(--sans); font-size:12px; font-weight:400; line-height:1.5; margin:0; }
.dashboard-app .section-title .compte a { display:inline-block; padding-block:6px; }
/* Composants (spec du 09/10/2026, pièce 4) : une liste est une suite de rangées sur des filets, posée sur la page, sans panneau. La feuille (`.feuille`), sans papier, sans marge et sans rayon, ouvre la liste d'un filet, sous le titre du bloc, et chaque rangée se ferme d'un filet de 1 px.
   `--debord` était le retrait latéral de la rangée dans sa feuille ; il vaut zéro : le texte d'une rangée part du fer du contenu, où part le titre de la page. Les rangées à gravure pendante d'app.css le lisent toujours pour poser leur retrait. */
:where(.dashboard-app) .filet-row { padding:14px var(--debord); }
.dashboard-app .filet-row { --debord:0px; border-bottom:1px solid var(--hair-2); }
.dashboard-app .filet-row.sans-filet { border-bottom:0; }
.dashboard-app .feuille,.dashboard-app .deadline-list { padding:0; border-top:1px solid var(--hair-2); }
/* Sous l'en-tête de page le filet de l'en-tête ouvre la liste, seul. Une feuille réduite à un état vide reste sans filet. */
.dashboard-app .bandeau-court+.feuille { border-top:0; }
/* Deux listes qui se suivent : le filet qui ferme la dernière rangée de la première ouvre la seconde, seul filet entre elles. */
.dashboard-app .feuille+.feuille { border-top:0; }
.dashboard-app .feuille:has(>.vide:only-child) { border-top:0; }
/* Composants (spec du 09/10/2026, pièce 4) : la rangée d'échéance (`garage/_echeance_rangee.html`) prend partout la forme du tableau de bord : le jour en famille d'apparat, à chiffres droits, son mois dessous, sans bloc de couleur ; le type en gras, sa gravure au laiton ; le porteur ; la note ; l'étiquette d'état ; le chevron ; sur un filet.
   La teinte d'une échéance dépassée (`echu`) ou proche vit sur le texte du jour et sur l'étiquette : sans bloc de date, ce sont eux qui disent l'urgence. Elle est réservée à « proche » et à « dépassée » : un accent de thème rouge (Porsche, Ferrari) ferait d'une échéance lointaine un danger. Le texte teinté se compose avec l'encre pour tenir 4,5 de contraste dans les dix thèmes.
   Le rond du porteur est retiré : le monogramme de la marque s'efface (le tableau de bord ne le montre pas), un lieu garde sa gravure devant son nom, sans laquelle il se lirait comme une voiture.
   L'intitulé (`.echeance-quoi`) se défait (`display:contents`) : le type, le dessous (porteur et note) et, dans la forme large, le porteur et la note eux-mêmes sont des cases de la grille de la rangée, que trois formes rangent selon la largeur de la feuille, conteneur que la rangée interroge.
   Les placements s'écrivent tous au même poids, sur `a.echeance>…` et ses descendants directs : une forme plus large, écrite plus bas, l'emporte par sa place. */
.dashboard-app .feuille { container-type:inline-size; }
.dashboard-app a.echeance { --echeance-doux:var(--fond-doux); --echeance-encre:var(--ink-2); position:relative; display:grid; grid-template-columns:44px minmax(0,1fr) auto; column-gap:14px; align-items:center; padding:12px 0; border-bottom:1px solid var(--hair-2); color:inherit; text-decoration:none; }
/* Le survol : le type passe à l'accent lisible, souligné ; aucun fond. Le soulignement est écarté des rangées du tableau de bord, qui gardent le survol de Maison (l'étiquette neutre y passe au papier). */
.dashboard-app a.echeance:hover>.echeance-quoi>b { color:var(--accent-texte); }
.dashboard-app a.echeance:where(:not(.a-venir a)):is(:hover,:focus-visible)>.echeance-quoi>b { color:var(--accent-texte); text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:4px; }
.dashboard-app .a-venir a.echeance:hover>.echeance-etat { background:var(--ground-2); }
.dashboard-app .echeance-quoi,.dashboard-app .echeance-dessous { display:contents; }
/* Le jour et son mois partent du fer de la rangée, l'un sous l'autre. */
.dashboard-app .echeance-date { display:flex; flex-direction:column; align-items:flex-start; justify-content:center; color:var(--ink); line-height:1; text-align:left; }
.dashboard-app .echeance-date b { font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:30px; font-weight:500; letter-spacing:0; line-height:1; }
.dashboard-app .echeance-date i { margin-top:4px; font-style:normal; font-size:11px; letter-spacing:0; line-height:1.2; text-transform:none; white-space:nowrap; }
.dashboard-app .echeance-date i.an { white-space:normal; }
.dashboard-app .echeance-quoi>b { display:flex; align-items:center; gap:8px; min-width:0; font-size:13px; font-weight:700; line-height:1.4; }
.dashboard-app .echeance-quoi>b>.gravure { width:16px; height:16px; background:var(--laiton); }
/* Le nom du porteur se lit toujours entier, la note cède la place. Dans une liste elle tient en deux lignes (une quand elle partage la ligne du nom) ; le texte entier reste servi (lecture d'écran, écran de l'échéance). */
.dashboard-app .echeance-note { display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; overflow:hidden; min-width:0; margin-top:3px; font-size:11px; line-height:1.5; color:var(--ink-2); overflow-wrap:anywhere; }
.dashboard-app .echeance-vehicule { display:flex; align-items:center; gap:6px; min-width:0; font-size:12px; line-height:1.5; }
.dashboard-app .echeance-vehicule>.monogram.rond { display:none; }
.dashboard-app .echeance-vehicule>.rond { flex:none; width:16px; height:16px; }
.dashboard-app .echeance-vehicule>span.rond { display:grid; place-items:center; border:0; background:none; color:var(--echeance-encre); font-family:inherit; font-size:11px; font-weight:600; }
.dashboard-app .echeance-vehicule>.rond>.gravure { width:13px; height:13px; background:var(--ink-2); }
/* Le nom du véhicule ou du lieu se lit entier, à toute largeur : il passe à la ligne quand la place manque. */
.dashboard-app .echeance-vehicule>span:last-child { min-width:0; overflow-wrap:break-word; }
/* Composants (spec du 09/10/2026, pièce 12) : l'état d'une échéance est une étiquette, rectangle à coins de 2 px sur le fond doux. Les teintes restent celles des porteurs : l'encre secondaire, l'avertissement pour « proche », l'alerte sur son fond adouci pour « dépassée » ; « faite » parle à l'accent lisible. Dans les blocs de Maison elle garde la graisse d'avant (section 4 de la spec). */
.dashboard-app .echeance-etat { justify-self:end; padding:4px 7px; border-radius:var(--r-etiquette); background:var(--echeance-doux); color:var(--echeance-encre); font-size:11px; font-weight:600; line-height:1.4; white-space:nowrap; font-variant-numeric:tabular-nums; }
.dashboard-app :where(.masthead,.ears,.installer,.ouverture,.prioritaire,.chiffres,.raccourcis,.journal,.accueil-garage) .echeance-etat { font-weight:500; }
.dashboard-app a.echeance>.chev { display:none; width:16px; height:16px; justify-self:end; stroke:var(--ink-faint); }
.dashboard-app a.echeance.echu>.echeance-etat { background:color-mix(in srgb,var(--danger) 12%,var(--ground-2)); color:color-mix(in srgb,var(--danger) 82%,var(--ink)); }
.dashboard-app a.echeance.proche>.echeance-etat { background:color-mix(in srgb,var(--warn) 14%,var(--ground-2)); color:color-mix(in srgb,var(--warn) 55%,var(--ink)); }
.dashboard-app a.echeance.faite>.echeance-etat { background:var(--echeance-doux); color:var(--accent-texte); }
.dashboard-app a.echeance.echu>.echeance-date { color:color-mix(in srgb,var(--danger) 82%,var(--ink)); }
.dashboard-app a.echeance.proche>.echeance-date { color:color-mix(in srgb,var(--warn) 55%,var(--ink)); }
.dashboard-app a.echeance.faite>.echeance-date { color:var(--accent-texte); }
/* La forme servie par défaut est celle du TÉLÉPHONE, lisible à toute largeur : un navigateur qui ignore les requêtes de conteneur (Safari avant 16.0, Firefox avant 110) la sert partout. Les deux formes plus larges sont des améliorations, posées plus bas dans des requêtes à largeur minimale.
   Le type partage sa ligne avec la pastille ; dessous, la note (deux lignes au plus, une quand un porteur la suit), puis le porteur, son nom entier, chacun sur toute la largeur. Le chevron est retiré.
   Les variantes (sans dessous, faite) se lisent dans `:where()` : elles gardent le poids des placements, qu'une forme plus large recouvre par sa place. Chaque sélecteur à `:has()` a sa règle à lui : dans une liste, il ferait tomber la règle entière chez qui ne le connaît pas. */
.dashboard-app a.echeance>.echeance-date { width:44px; grid-area:1 / 1 / span 2 / auto; align-self:start; }
.dashboard-app a.echeance>.echeance-quoi>b { grid-area:1 / 2; align-self:center; min-height:28px; }
.dashboard-app a.echeance>.echeance-etat { grid-area:1 / 3; align-self:start; }
/* Sans note ni porteur la seconde rangée de la grille est vide : le type et l'étiquette couvrent les deux rangées du jour et se centrent face à lui. */
.dashboard-app a.echeance:where(:not(:has(.echeance-dessous)))>.echeance-quoi>b { grid-row:1 / span 2; }
.dashboard-app a.echeance:where(:not(:has(.echeance-dessous)))>.echeance-etat { grid-row:1 / span 2; align-self:center; }
/* La longue pastille « faite le » passe sous le reste : à côté du type elle l'écrasait. */
.dashboard-app a.echeance:where(.faite)>.echeance-quoi>b { grid-column:2 / -1; }
.dashboard-app a.echeance:where(.faite)>.echeance-etat { grid-area:3 / 2 / auto / -1; align-self:start; justify-self:start; margin-top:6px; }
.dashboard-app a.echeance>.echeance-quoi>.echeance-dessous { grid-area:2 / 2 / auto / -1; display:grid; gap:4px; margin:2px 0 0; font-size:12px; line-height:1.5; }
.dashboard-app a.echeance.avec-vehicule>.echeance-quoi>.echeance-dessous { align-self:start; align-items:flex-start; min-width:0; color:var(--ink-2); }
.dashboard-app a.echeance>.echeance-quoi>.echeance-dessous>.echeance-note { order:1; align-self:start; margin-top:0; }
.dashboard-app a.echeance.avec-vehicule>.echeance-quoi>.echeance-dessous>.echeance-note { position:relative; -webkit-line-clamp:1; }
.dashboard-app a.echeance.avec-vehicule>.echeance-quoi>.echeance-dessous>.echeance-vehicule { order:2; align-items:flex-start; gap:8px; font-size:inherit; line-height:inherit; }
.dashboard-app a.echeance.avec-vehicule>.echeance-quoi>.echeance-dessous>.echeance-vehicule>span:last-child { align-self:center; }
/* Revue du lot C : la virgule réservée à la lecture d'écran qui ferme chaque pièce lue de la rangée (date, type, porteur, note) se pose au coin de son bloc de référence, dans la rangée : laissée à la fin de son texte, elle sortait d'un pixel d'une rangée pleine. */
.dashboard-app a.echeance .sr-only { top:1px; left:1px; }
/* Revue du lot C : une seule règle de chevron. Toute rangée de liste qui est un lien porte son chevron à toute largeur : la forme étroite, celle du téléphone, lui ouvre une quatrième piste au bord droit, face à la rangée entière (planche, `.c-row` sous 600 px). Le type, le dessous et la longue étiquette « faite le » finissent avant elle. Les rangées du tableau de bord gardent la forme de Maison (spec, section 4). */
.dashboard-app a.echeance:where(:not(.a-venir a)) { grid-template-columns:44px minmax(0,1fr) auto 16px; }
.dashboard-app a.echeance:where(:not(.a-venir a))>.chev { display:block; grid-area:1 / 4 / span 3 / auto; align-self:center; }
.dashboard-app a.echeance:where(:not(.a-venir a))>.echeance-quoi>.echeance-dessous { grid-column-end:4; }
.dashboard-app a.echeance:where(.faite:not(.a-venir a))>.echeance-quoi>b { grid-column-end:4; }
.dashboard-app a.echeance:where(.faite:not(.a-venir a))>.echeance-etat { grid-column-end:4; }
/* Forme à deux lignes (feuille de plus de 440 px : la colonne « À venir » de l'accueil au PC, l'échéancier à la tablette et au demi-écran) : le jour et son mois, le type, l'étiquette et le chevron sur les deux lignes ; sous le type, le porteur (la gravure d'un lieu, puis son nom, entier) et la note sur une même ligne, séparés d'un point médian. Le dessous d'une rangée à porteur est une boîte en ligne, qui passe à la ligne ; sans porteur il se défait et la note se pose sous le type.
   La note prend la place qui reste, sur une ligne à points de suspension ; quand le nom ne lui laisse pas 9 rem elle passe dessous, toujours sur une ligne. Le nom, lui, prend deux lignes s'il le faut.
   Le point médian vit dans la marge gauche de la note, hors de la boîte rognée du dessous quand la note ouvre une ligne : il ne se montre qu'entre le nom et la note. Son texte de remplacement est vide (`/ ""`) : il n'entre pas dans le nom accessible du lien ; la première déclaration `content` sert le navigateur qui ne lit pas la seconde.
   Sans note, le type d'une rangée sans porteur tient les deux lignes de la grille et se centre face au jour ; avec une note, le type se pose en bas de sa ligne et la note en haut de la sienne, à 2 px. */
@container (width > 440px) {
  .dashboard-app a.echeance { grid-template-columns:44px minmax(0,1fr) auto 18px; column-gap:16px; }
  .dashboard-app a.echeance>.echeance-date { align-self:center; }
  .dashboard-app a.echeance>.echeance-quoi>b { grid-area:1 / 2; align-self:end; min-height:auto; }
  .dashboard-app a.echeance:where(:not(:has(.echeance-note)):not(.avec-vehicule))>.echeance-quoi>b { grid-area:1 / 2 / span 2 / auto; align-self:center; }
  .dashboard-app a.echeance>.echeance-etat { grid-area:1 / 3 / span 2 / auto; align-self:auto; justify-self:end; margin-top:0; }
  .dashboard-app a.echeance>.chev { display:block; grid-area:1 / 4 / span 2 / auto; }
  .dashboard-app a.echeance>.echeance-quoi>.echeance-dessous { display:contents; }
  .dashboard-app a.echeance.avec-vehicule>.echeance-quoi>.echeance-dessous { grid-area:2 / 2; display:flex; flex-wrap:wrap; gap:normal; margin:2px 0 0 -18px; clip-path:inset(0 0 0 18px); }
  .dashboard-app a.echeance>.echeance-quoi>.echeance-dessous>.echeance-note { grid-area:2 / 2; order:0; margin-top:2px; }
  .dashboard-app a.echeance.avec-vehicule>.echeance-quoi>.echeance-dessous>.echeance-note { display:block; flex:1 1 9rem; margin-top:0; padding-left:18px; white-space:nowrap; text-overflow:ellipsis; }
  .dashboard-app a.echeance.avec-vehicule>.echeance-quoi>.echeance-dessous>.echeance-vehicule + .echeance-note::before { content:"·"; content:"·" / ""; position:absolute; left:0; width:18px; text-align:center; }
  .dashboard-app a.echeance.avec-vehicule>.echeance-quoi>.echeance-dessous>.echeance-vehicule { order:0; gap:6px; max-width:calc(100% - 18px); margin-left:18px; }
  .dashboard-app a.echeance.avec-vehicule>.echeance-quoi>.echeance-dessous>.echeance-vehicule>span:last-child { align-self:auto; }
}
/* Forme large (feuille de plus de 786 px ; le seuil valait 820 px et tombait à 2 px de la feuille du demi-écran de 960 px, large de 818 px à côté du rail. Il se tient 16 px sous le plus bas des deux creux de la feuille, 802 px à 1100 px de fenêtre où la colonne se déploie et 829 px à 1151 px où les marges du contenu s'élargissent : une fois large, la rangée le reste) : le type et la note à gauche, le porteur dans sa colonne (son nom sur deux lignes quand elle est étroite), la pastille, le chevron. Le dessous se défait : le porteur et la note redeviennent des cases de la grille de la rangée. */
@container (width > 786px) {
  .dashboard-app a.echeance.avec-vehicule { grid-template-columns:44px minmax(0,1.25fr) minmax(0,1fr) minmax(7rem,auto) 18px; }
  .dashboard-app a.echeance:where(:not(:has(.echeance-note)))>.echeance-quoi>b { grid-area:1 / 2 / span 2 / auto; align-self:center; }
  .dashboard-app a.echeance.avec-vehicule>.echeance-etat { grid-area:1 / 4 / span 2 / auto; }
  .dashboard-app a.echeance.avec-vehicule>.chev { grid-area:1 / 5 / span 2 / auto; }
  .dashboard-app a.echeance.avec-vehicule>.echeance-quoi>.echeance-dessous { display:contents; color:inherit; }
  .dashboard-app a.echeance.avec-vehicule>.echeance-quoi>.echeance-dessous>.echeance-note { position:static; display:-webkit-box; -webkit-line-clamp:2; margin-top:2px; padding-left:0; white-space:normal; }
  .dashboard-app a.echeance.avec-vehicule>.echeance-quoi>.echeance-dessous>.echeance-vehicule + .echeance-note::before { content:none; }
  .dashboard-app a.echeance.avec-vehicule>.echeance-quoi>.echeance-dessous>.echeance-vehicule { grid-area:1 / 3 / span 2 / auto; align-items:center; max-width:none; margin-left:0; font-size:12px; line-height:1.5; }
}
/* Composants (spec du 09/10/2026, pièce 2) : la barre de filtres et le tri. Des libellés avec leur compte, sans capsule ni panneau ; le filtre courant se dit par la couleur d'accent lisible et la graisse, sans trait, sans fond (spec section 1).
   Revue du lot B (spec section 6, décision 8) : au-delà du téléphone la rangée passe à la ligne, tous les filtres se lisent, sans barre de défilement (elle défilait à toute largeur : à 960 px deux types étaient cachés). Au téléphone seul (bloc plus bas) elle tient sur une ligne et défile dans sa boîte, sa barre fine dessinée (planche, `.c-filter-bar`), à crans, chaque libellé s'arrêtant au fer gauche ; le libellé coupé net au bord dit qu'il y a une suite, sans masque ni dégradé (spec section 1). echeancier.js y amène le filtre courant.
   La rangée qui défile rogne ce qui en sort : 6 px de marge intérieure, repris en marge négative, logent le contour de focus d'un libellé (3 px, écarté de 3), et la même réserve au défilement l'amène entier quand il arrive au clavier.
   Le tri : une ligne discrète sous un filet, au fer droit, en 11 px (planche, `.c-sort`). */
.dashboard-app .filtrage { display:block; margin:8px 0 0; padding:0; background:none; }
.dashboard-app .filtrage .filtres { display:flex; flex-wrap:wrap; align-items:center; gap:0 22px; margin:0 -6px; padding:6px 6px 10px; }
@media (max-width:720px) { .dashboard-app .filtrage .filtres { flex-wrap:nowrap; scroll-padding-inline:6px; scroll-snap-type:x proximity; overflow-x:auto; overscroll-behavior-x:contain; scrollbar-width:thin; } }
.dashboard-app .filtrage .chip { scroll-snap-align:start; display:inline-flex; flex:none; align-items:center; justify-content:center; gap:8px; min-width:44px; min-height:44px; padding:8px 0; border:0; border-radius:0; background:none; color:var(--ink-2); font-size:12px; font-weight:500; letter-spacing:0; text-transform:none; white-space:nowrap; }
.dashboard-app .filtrage .chip .gravure { width:16px; height:16px; background:currentColor; }
.dashboard-app .filtrage .chip .num { font-size:11px; font-weight:inherit; font-variant-numeric:tabular-nums; }
.dashboard-app .filtrage .chip:hover { background:none; color:var(--accent-texte); }
.dashboard-app .filtrage .chip.on { color:var(--accent-texte); font-weight:700; }
/* Revue du lot B : en contrastes forcés la couleur d'accent cède à celle du système, et le filtre ou le tri courant ne se distinguait plus que par sa graisse. Dans ce mode seulement il est souligné. */
@media (forced-colors:active) { .dashboard-app .filtrage .chip.on { text-decoration:underline; text-decoration-thickness:2px; text-underline-offset:4px; } }
.dashboard-app .filtrage .tri-groupe { display:flex; flex-wrap:nowrap; align-items:center; justify-content:flex-end; gap:10px; margin:0; padding:0; border-top:1px solid var(--hair-2); color:var(--ink-2); font-size:11px; }
.dashboard-app .filtrage .tri-groupe>.micro { padding:0; color:var(--ink-2); font-size:11px; letter-spacing:0; text-transform:none; white-space:nowrap; }
/* Un choix de tri porte 10 px de retrait à gauche, qui s'ajoutent aux 10 px d'écart : 20 px entre deux libellés (planche), une cible plus large, et le dernier libellé reste au fer droit. */
.dashboard-app .filtrage .tri-groupe .chip { padding-left:10px; font-size:11px; }
/* Composants (spec du 09/10/2026, pièce 1) : l'en-tête de page des écrans de liste (`_bandeau_court.html`, dont il garde les classes). Le surtitre en petites capitales au laiton, le titre en famille d'apparat (chiffres droits), son mot en italique à l'accent lisible, une étiquette d'alerte à côté du titre, les comptes dessous ; à droite les gestes de tête, un principal plein et des secondaires au filet ; un filet sous le tout. Ni aplat, ni arc, ni panneau.
   Une grille : le surtitre, le titre et les comptes tiennent les trois premières rangées de la première colonne ; les gestes (`.bandeau-gestes`) et les renvois (`.bandeau-renvois`) ont chacun leur colonne, sur la rangée DU TITRE, centrés sur lui : d'un écran à l'autre ils gardent la même place face au titre, avec ou sans surtitre, avec ou sans compte. Une rangée vide ne pèse rien.
   Sous 1100 px de fenêtre (le seuil où la colonne de navigation se replie en rail) les gestes passent sous le titre.
   Revue du lot B : avec cinq gestes à sa droite le titre tombait à 74 px et se coupait lettre à lettre. La colonne du titre garde la largeur de son mot le plus long (`min-content` ; `overflow-wrap:break-word` ne coupe un mot que s'il dépasse seul la ligne, et laisse ce mot compter dans la largeur minimale, ce que `anywhere` ne fait pas), 12 rem au moins ; les colonnes des gestes cèdent, et leurs boutons passent à la ligne. */
.dashboard-app .bandeau-court { display:grid; grid-template-columns:minmax(min-content,1fr) minmax(0,auto) minmax(0,auto); align-items:center; margin-bottom:24px; padding:0 0 24px; border-bottom:1px solid var(--hair-2); color:var(--ink); }
.dashboard-app .bandeau-court>* { grid-column:1; }
.dashboard-app .bandeau-surtitre { grid-row:1; margin:0 0 10px; max-width:none; color:var(--laiton); font-size:11px; font-weight:600; letter-spacing:.07em; line-height:1.4; text-transform:uppercase; }
.dashboard-app .bandeau-surtitre a { display:inline-flex; align-items:center; min-height:44px; margin-block:-15px; color:inherit; text-decoration:none; }
.dashboard-app .bandeau-surtitre a:hover { text-decoration:underline; text-underline-offset:4px; }
/* Ménage du lot D : ce que le titre d'un en-tête de liste et celui de la fiche partagent s'écrit une fois ; chaque sélecteur garde son poids. */
.dashboard-app .bandeau-court h1,.dashboard-app header.bandeau-arc h1 { margin:0; color:var(--ink); font-family:var(--apparat); font-variant-numeric:lining-nums; font-weight:500; line-height:1.1; letter-spacing:0; overflow-wrap:break-word; }
.dashboard-app .bandeau-court h1 { grid-row:2; font-size:46px; min-width:12rem; }
.dashboard-app :is(.bandeau-court,.bandeau-arc) h1 em { color:var(--accent-texte); font-style:italic; font-weight:400; }
.dashboard-app .bandeau-pastille { display:inline-block; vertical-align:middle; margin-left:2px; padding:4px 7px; border-radius:var(--r-etiquette); background:color-mix(in srgb,var(--danger) 12%,var(--ground-2)); color:color-mix(in srgb,var(--danger) 82%,var(--ink)); font-family:var(--sans); font-size:11px; font-weight:600; letter-spacing:0; line-height:1.4; white-space:nowrap; }
.dashboard-app .bandeau-sous { grid-row:3; margin:14px 0 0; max-width:none; color:var(--ink-2); font-size:12px; line-height:1.5; }
.dashboard-app .bandeau-sous .num { color:inherit; }
.dashboard-app .bandeau-sous a { display:inline-flex; align-items:center; min-height:44px; margin-block:-13px; border-radius:var(--r-vif); color:var(--accent-texte); font-weight:600; text-decoration:none; }
.dashboard-app .bandeau-sous a:hover { color:var(--ink); text-decoration:underline; text-underline-offset:4px; }
.dashboard-app .bandeau-gestes,.dashboard-app .bandeau-renvois { grid-row:2; display:flex; flex-wrap:wrap; align-items:center; justify-content:flex-end; gap:10px; margin:0 0 0 24px; }
.dashboard-app .bandeau-gestes { grid-column:2; }
.dashboard-app .bandeau-renvois { grid-column:3; gap:10px 20px; }
.dashboard-app .bandeau-gestes .btn { white-space:nowrap; }
/* Le geste principal : plein, à l'accent (pièce 8). Les autres gardent la forme de base d'un bouton, le secondaire au filet. */
.dashboard-app .bandeau-gestes .btn.premier,.dashboard-app .bandeau-renvois a:first-child { border-color:var(--accent); background:var(--accent); color:var(--on-accent); }
.dashboard-app .bandeau-gestes .btn.premier:hover,.dashboard-app .bandeau-renvois a:first-child:hover { border-color:color-mix(in srgb,var(--accent) 88%,var(--ink)); background:color-mix(in srgb,var(--accent) 88%,var(--ink)); color:var(--on-accent); text-decoration:none; }
/* Les renvois (planche, premier en-tête) : le premier plein, les suivants en liens discrets, leur chevron au bout. */
.dashboard-app .bandeau-renvois a { display:inline-flex; align-items:center; gap:10px; min-height:44px; padding:11px 0; border:1px solid transparent; border-radius:var(--r-vif); color:var(--accent-texte); font-size:12px; font-weight:600; text-decoration:none; white-space:nowrap; }
.dashboard-app .bandeau-renvois a:not(:first-child) { text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:4px; }
.dashboard-app .bandeau-renvois a:first-child { padding-inline:16px; }
.dashboard-app .bandeau-renvois a:hover { color:var(--ink); text-decoration:underline; text-decoration-thickness:2px; text-underline-offset:4px; }
.dashboard-app .bandeau-renvois a>.chev { width:14px; height:14px; stroke:currentColor; }
.dashboard-app .bandeau-court+.feuille,.dashboard-app .bandeau-court+.vide,.dashboard-app .filtrage+.vide,.dashboard-app :is(.filtrage,.collection-filters)+.feuille { margin-top:16px; }
/* Composants, pièce 1 : l'en-tête de la fiche d'une voiture (planche, `.c-vehicle-header`). Le titre et ses repères à gauche, la vue à droite dans son cadre ; deux colonnes centrées l'une sur l'autre. Le contenu de chaque colonne vit dans fiche.css.
   Revue du lot B (spec section 6, décision 7) : les deux colonnes tiennent côte à côte au-delà du téléphone, où le contenu fait 605 px au moins ; à côté du rail (721 à 1099 px) la photo cède de la largeur au texte. Au téléphone elles s'empilent, la photo plafonnée en hauteur (fiche.css).
   `header.bandeau-arc h1` pèse (0,2,2) : devant `.dashboard-app h1` (28 px au téléphone, dashboard.css), écrite plus bas. */
.dashboard-app .bandeau-arc { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,.85fr); gap:30px; align-items:center; color:var(--ink); }
.dashboard-app .bandeau-texte { min-width:0; }
.dashboard-app .bandeau-photo { min-width:0; }
.dashboard-app header.bandeau-arc h1 { font-size:42px; }
@media (max-width:1099px) {
  .dashboard-app .bandeau-court { grid-template-columns:minmax(0,1fr); }
  .dashboard-app .bandeau-court h1 { min-width:0; }
  .dashboard-app .bandeau-gestes,.dashboard-app .bandeau-renvois { grid-column:1; grid-row:4; justify-content:flex-start; margin:18px 0 0; }
  .dashboard-app .bandeau-renvois { grid-row:5; }
  .dashboard-app .bandeau-arc { grid-template-columns:minmax(0,1.35fr) minmax(0,1fr); gap:24px; }
}
@media (max-width:720px) {
  .dashboard-app .bandeau-arc { grid-template-columns:minmax(0,1fr); gap:16px; }
  .dashboard-app .bandeau-court { padding-bottom:22px; }
  .dashboard-app .bandeau-court h1,.dashboard-app header.bandeau-arc h1 { font-size:35px; }
}
/* Composants (spec du 09/10/2026, pièce 4) : la réglette « La voiture en bref » de la fiche est une bande entre deux filets, comme la bande des quatre chiffres du tableau de bord : le libellé en petites capitales au laiton, la valeur en famille d'apparat à chiffres droits, à l'encre (un lien parmi les valeurs s'en distingue par l'accent, sans soulignement), la sous-ligne en 11 px (le libellé est celui des chiffres du bilan, `.metric-label`, plus haut), des filets verticaux entre les cases, aucun pictogramme dans un rond (le rond reste dans le gabarit, retiré de l'affichage).
   Autant de cases par rangée que la réglette en porte (`--cases`, quatre) tant que sa largeur de contenu atteint `--seuil-cases` (728 px), deux en dessous (trois ne se présente à aucune largeur) : sous le seuil le plancher d'une piste saute à 50 % de la réglette.
   Chaque case reprend les lignes de sa rangée (libellé, valeur, sous-ligne) : d'une case à l'autre elles partent des mêmes ordonnées.
   La réglette est un conteneur interrogé : le corps des valeurs suit SA largeur, et les filets des cases se posent selon le nombre de cases qu'elle range (bloc plus bas, et fiche.css pour ses seuils propres). Par défaut, pour qui ignore les requêtes de conteneur, deux cases par rangée : la case impaire part du fer et porte le filet vertical, les rangées se séparent d'un filet. */
.dashboard-app .reglette { position:relative; display:grid; grid-template-columns:repeat(auto-fit,minmax(clamp(100% / var(--cases,4),(var(--seuil-cases,728px) - 100%) * 999,50%),1fr)); gap:0; margin:28px 0 0; padding:0; border-top:1px solid var(--hair-2); border-bottom:1px solid var(--hair-2); container:reglette / inline-size; }
.dashboard-app .chiffre { display:grid; grid-template-columns:minmax(0,1fr); grid-template-rows:subgrid; grid-row:span 3; row-gap:0; align-content:start; align-items:start; min-width:0; padding:18px 14px; }
.dashboard-app .chiffre>div { display:contents; }
.dashboard-app .chiffre:nth-child(odd) { padding-left:0; border-right:1px solid var(--hair-2); }
.dashboard-app .chiffre:nth-child(even) { padding-right:0; }
.dashboard-app .chiffre:nth-child(n+3) { border-top:1px solid var(--hair-2); }
.dashboard-app .chiffre:last-child:nth-child(odd) { border-right:0; }
.dashboard-app .chiffre strong { display:block; margin:4px 0 2px; font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:24px; font-size:clamp(20px,7cqi,26px); font-weight:500; letter-spacing:0; line-height:1.25; color:var(--ink); }
.dashboard-app .chiffre small { display:block; font-size:11px; line-height:1.5; color:var(--ink-2); }
.dashboard-app .chiffre small a { color:var(--accent-texte); }
/* Au téléphone les cases se resserrent : la réglette, sur deux rangées, laisse les onglets dans le premier écran (revue du lot B). */
@media (max-width:720px) {
  .dashboard-app .reglette { margin-top:20px; }
  .dashboard-app .chiffre { padding-block:10px; }
  .dashboard-app .chiffre strong { margin:2px 0 0; }
}
/* Sous 360 px « À renseigner » dépasse la ligne d'une demi-réglette : les chiffres s'empilent, chacun sur son filet. */
@media (max-width:359px) {
  .dashboard-app .reglette { grid-template-columns:minmax(0,1fr); }
  .dashboard-app .reglette .chiffre { padding-inline:0; border-right:0; }
  .dashboard-app .reglette .chiffre + .chiffre { border-top:1px solid var(--hair-2); }
}
/* Composants (spec du 09/10/2026, pièce 4) : les groupes de l'échéancier. Le titre de groupe (« Dépassées », « Octobre 2026 », un véhicule ou un lieu au tri par véhicule) se compose en famille d'apparat, à chiffres droits ; son compte suit, en 11 px au laiton ; la liste s'ouvre d'un filet, dessous (planche, `.c-group`). « Dépassées » garde la teinte d'alerte de son texte. Un lieu garde sa gravure devant son nom ; le monogramme d'une voiture se retire, comme dans les rangées. */
.dashboard-app .groupe { margin-top:28px; container:groupe / inline-size; }
.dashboard-app .groupe-titre { display:flex; align-items:center; gap:12px; margin:0 0 10px; color:var(--ink); font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:29px; font-weight:500; letter-spacing:0; line-height:1.15; text-transform:none; }
.dashboard-app .groupe-titre>.num { color:var(--laiton); font-family:var(--sans); font-size:11px; font-weight:600; letter-spacing:0; }
.dashboard-app .groupe-titre.alerte>span:not(.num) { color:color-mix(in srgb,var(--danger) 82%,var(--ink)); }
.dashboard-app .groupe-titre>.monogram.rond { display:none; }
.dashboard-app .groupe-titre>.rond { width:22px; height:22px; flex:none; }
.dashboard-app .groupe-titre>span.rond { display:grid; place-items:center; border:0; background:none; }
.dashboard-app .groupe-titre>.rond>.gravure { width:20px; height:20px; background:var(--ink-2); }
.dashboard-app .groupe-titre>span:not(.num):not(.rond) { min-width:0; overflow-wrap:anywhere; }
/* Pour la conciergerie, le client du porteur : deux clients au même modèle donnent deux groupes au même nom.
   Par défaut (le téléphone, la tablette à côté de la barre latérale, et tout navigateur qui ignore les requêtes de conteneur) le client se lit SOUS le nom du véhicule, dans sa colonne : à sa suite, sans céder, il écrasait le nom (0 px de large pour un nom complet de 43 caractères à 320 px). Le rond tient la gauche, le compte la droite de la première ligne ; les deux noms se lisent entiers.
   Qui ignore aussi `:has()` garde l'intitulé en ligne : le client suit le nom après son point médian, et cède. */
.dashboard-app .groupe-titre>.groupe-client { grid-area:2 / 2; min-width:0; color:var(--ink-2); font-family:var(--sans); font-size:12px; font-weight:400; line-height:1.4; overflow-wrap:anywhere; }
.dashboard-app .groupe-titre>.groupe-client::before { content:"·"; margin-right:10px; }
.dashboard-app .groupe-titre:has(>.groupe-client) { display:grid; grid-template-columns:auto minmax(0,1fr) auto; gap:2px 0; align-items:center; }
.dashboard-app .groupe-titre:has(>.groupe-client)>.rond:not(.monogram) { margin-right:10px; }
.dashboard-app .groupe-titre:has(>.groupe-client)>.num { margin-left:12px; }
.dashboard-app .groupe-titre:has(>.groupe-client)>.rond { grid-area:1 / 1; }
.dashboard-app .groupe-titre:has(>.groupe-client)>span:not(.num):not(.rond):not(.groupe-client) { grid-area:1 / 2; }
.dashboard-app .groupe-titre:has(>.groupe-client)>.num { grid-area:1 / 3; }
.dashboard-app .groupe-titre:has(>.groupe-client)>.groupe-client::before { content:none; }
/* Dans un groupe de plus de 640 px le client suit le nom du véhicule sur sa ligne, après un point médian, sans céder. */
@container groupe (width > 640px) {
  .dashboard-app .groupe-titre:has(>.groupe-client) { display:flex; gap:12px; }
  .dashboard-app .groupe-titre:has(>.groupe-client)>.rond:not(.monogram) { margin-right:0; }
  .dashboard-app .groupe-titre:has(>.groupe-client)>.num { margin-left:0; }
  .dashboard-app .groupe-titre>.groupe-client { flex:none; min-width:auto; overflow-wrap:normal; }
  .dashboard-app .groupe-titre:has(>.groupe-client)>.groupe-client::before { content:"·"; }
}
/* Composants (spec du 09/10/2026, pièce 13) : la pagination. Une ligne d'un bord à l'autre de la liste : le geste précédent au fer gauche, la position en chiffres tabulaires, le geste suivant au fer droit. Les gestes sont des liens discrets de 44 px, soulignés au survol ; le geste absent reste en place, à l'encre secondaire. */
.dashboard-app .pagination { justify-content:space-between; gap:12px 24px; margin-top:24px; padding:0; font-size:12px; font-variant-numeric:lining-nums tabular-nums; }
.dashboard-app .pagination .btn { min-width:64px; padding-inline:0; border-color:transparent; background:none; box-shadow:none; text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:4px; }
.dashboard-app .pagination .btn:last-child { justify-content:flex-end; }
.dashboard-app .pagination .btn:hover { border-color:transparent; background:none; color:var(--ink); text-decoration:underline; text-decoration-thickness:2px; text-underline-offset:4px; }
.dashboard-app .pagination .btn[aria-disabled=true] { color:var(--ink-2); text-decoration:none; }
.dashboard-app .pagination .num { font-size:12px; font-variant-numeric:lining-nums tabular-nums; }
@media (min-width:721px) { .dashboard-app .rangee-hivernage > .deadline-kind.titre { flex:1 1 12rem; min-width:0; } }
/* Le titre d'une rangée en gras (planche, `.c-row-body h3`) ; le survol d'une rangée cliquable souligne ce titre (app.css), sans aplat. */
.dashboard-app .filet-row .titre { font-weight:600; }
.dashboard-app .filet-row .sub { line-height:1.6; }
.dashboard-app .filet-row .gravure { opacity:.75; }
.dashboard-app .lot { gap:24px; grid-template-columns:minmax(0,1fr) minmax(240px,300px); }
.dashboard-app .lot-head { border:0; background:transparent; padding:0; margin:0 0 18px; }
/* Composants, lot C : le titre d'une fiche à lot (lieu, intervenant, pièce, sortie, hivernage) prend la famille des titres de ses rubriques. */
.dashboard-app .lot-head .vname { color:var(--ink); font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:42px; font-weight:500; letter-spacing:0; line-height:1.1; }
.dashboard-app .lot-head .vsub { color:var(--ink-2); line-height:1.7; margin-top:10px; }
.dashboard-app .lot-tools { display:flex; flex-wrap:wrap; gap:9px; padding:0; border:0; margin-bottom:24px; }
/* Composants, lot C : la marge d'une fiche (lieu, intervenant, pièce, sortie) n'est plus un panneau. Ses groupes se séparent d'un filet, ses cases partent du fer de la colonne. */
.dashboard-app .lot-aside { padding:0; }
.dashboard-app .aside-groupe { padding-block:18px; }
.dashboard-app .aside-groupe:first-child { padding-top:0; }
.dashboard-app .lot-aside .fig { padding-block:12px; }
/* Revue du lot A : dans une case de la marge chaque enfant est un bloc (app.css) ; deux boutons qui s'y suivent s'empilaient bord à bord (« Modifier ce lieu », « Supprimer ce lieu »). Tout empilement de boutons garde 8 px. */
.dashboard-app .fig>:is(.btn,button)+:is(.btn,button) { margin-top:8px; }
/* Composants (spec du 09/10/2026, pièce 3) : les onglets de la fiche. Des libellés sans fond ni capsule ; le courant en famille d'apparat, italique, 21 px, à l'accent lisible, sans trait (son compte suit, à chiffres droits). Un filet neutre sépare la barre du contenu. La barre passe à la ligne dès que ses dix onglets dépassent une rangée, à toute largeur (décision du 25/09) : elle reste sans défilement, chaque onglet en vue.
   Revue du lot B (spec section 6, décision 10) : chaque onglet réserve la largeur de sa forme courante, pour qu'aucun ne bouge quand le courant change (ils se décalaient de 7 à 42 px, et sur tablette un onglet changeait de rangée). Le gabarit redit le libellé dans `data-courant` ; un pseudo-élément de hauteur nulle, caché (`visibility:hidden` : il ne se peint pas et ne se lit pas), le compose dans la forme courante et donne sa largeur à la boîte. L'onglet est un bloc à une ligne de 28 px dans une cible de 44 px, aux deux formes : la rangée garde sa hauteur. Le libellé et son compte se suivent en texte, séparés par l'espace du gabarit, comme sur la planche ; le compte de l'onglet courant prend la famille du libellé (il restait en Manrope, penché par synthèse, à côté d'un libellé en Cormorant), et le pseudo-élément a la largeur de la forme courante, plus 1 px qui couvre l'arrondi de la jointure du compte (0,02 px mesuré : assez pour faire changer de rangée un onglet posé au bord). */
.dashboard-app .tabs { display:flex; flex-wrap:wrap; align-items:center; gap:0 16px; overflow:visible; margin:20px 0 0; padding:0; border-bottom:1px solid var(--hair-2); background:none; }
.dashboard-app .tabs a { display:block; box-sizing:border-box; min-width:44px; height:44px; min-height:44px; padding:8px 0; border:0; border-radius:0; background:none; color:var(--ink-2); font-size:12px; line-height:28px; white-space:nowrap; }
.dashboard-app .tabs a::after { content:attr(data-courant); content:attr(data-courant) / ""; display:block; height:0; overflow:hidden; visibility:hidden; font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:21px; font-style:italic; font-weight:600; white-space:nowrap; padding-right:1px; pointer-events:none; }
.dashboard-app .tabs a .num { font-size:11px; color:inherit; font-variant-numeric:lining-nums tabular-nums; }
.dashboard-app .tabs a:hover { color:var(--accent-texte); }
.dashboard-app .tabs a[aria-current=true] { color:var(--accent-texte); font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:21px; font-style:italic; font-weight:600; }
.dashboard-app .tabs a[aria-current=true] .num { font-family:inherit; font-size:inherit; font-variant-numeric:inherit; }
/* Composants (spec du 09/10/2026, pièce 5) : la collection en cartes prend la carte du garage du tableau de bord. La photo dans un cadre 3 / 2, recadrée (la planche et la silhouette entières, sur le fond de planche) ; le nom en famille d'apparat, à chiffres droits, sur trois lignes au plus (revue du lot C : un nom de 74 signes était coupé à deux ; le texte entier reste dans le lien et dans le `title` du nom) ; l'année et le kilométrage ; l'étiquette de statut ; la prochaine échéance ; puis le pied, calé en bas de la carte : le lieu, « Acquis » et la valeur au fer droit. Sans panneau : un filet ferme la carte, et les cartes d'une rangée, étirées par la grille, posent leur filet au même niveau. */
.dashboard-app .entries[data-presentation=cartes] { gap:30px 24px; }
.dashboard-app .entries .entry { border:0; border-bottom:1px solid var(--hair-2); border-radius:0; background:none; overflow:visible; padding:0; }
.dashboard-app .entries .entry:hover { border-color:var(--hair-2); box-shadow:none; }
.dashboard-app .entries .entry:is(:hover,:focus-visible) .entry-name { color:var(--accent-texte); text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:4px; }
.dashboard-app .entries .entry-media { height:auto; min-height:0; aspect-ratio:3 / 2; border-radius:var(--r-vif); overflow:hidden; }
.dashboard-app .entries .entry-media img.car-blueprint { box-sizing:border-box; padding:4% 6%; }
.dashboard-app .entry-name { display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:3; line-clamp:3; overflow:hidden; font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:24px; font-weight:500; letter-spacing:0; line-height:1.1; overflow-wrap:break-word; }
.dashboard-app .entries[data-presentation=cartes] .entry .entry-body { flex:1 1 auto; padding:14px 0 0; }
.dashboard-app .entries .entry-spec { margin-top:7px; font-size:11px; line-height:1.6; color:var(--ink-2); }
.dashboard-app .entries .entry-spec .num { font-variant-numeric:lining-nums; }
.dashboard-app .entries .entry-spec .num.danger { color:color-mix(in srgb,var(--danger) 82%,var(--ink)); }
.dashboard-app .entries[data-presentation=cartes] .entry-figures { flex:none; gap:2px 12px; margin:0; padding:12px 0 16px; border-top:0; }
.dashboard-app .entries .entry-figures .micro { font-size:11px; line-height:1.6; color:var(--ink-2); }
.dashboard-app .entries .entry-figures .num { margin-left:auto; font-size:13px; font-weight:700; font-variant-numeric:lining-nums tabular-nums; white-space:nowrap; color:var(--ink); }
/* Les vignettes de photos d'une fiche (pièce, sortie, prêt, sinistre) : la photo et sa légende, sans carte. Celles du garage du tableau de bord ont leur forme dans accueil.css. */
.dashboard-app .vignettes { gap:20px; }
.dashboard-app .vignette { background:none; overflow:hidden; padding:0 0 12px; }
.dashboard-app .vignette .plate { border:0; border-radius:var(--r-vif); }
.dashboard-app .vignette-nom { padding:10px 0 0; }
.dashboard-app .vignette-spec { padding:6px 0 0; }
/* La bande de synthèse (la valeur du parc sur la collection, le coût du gardiennage d'un lieu) : entre deux filets, sans aplat. */
.dashboard-app .valeur.synthese,.dashboard-app .synthese { padding:14px 0; border:0; border-top:1px solid var(--hair-2); border-bottom:1px solid var(--hair-2); border-radius:0; background:none; }
/* Sous l'en-tête de page la bande suit le filet de l'en-tête et n'en ouvre pas un second. */
.dashboard-app .bandeau-court+.synthese { padding-top:0; border-top:0; }
/* Composants (spec du 09/10/2026, pièce 14) : le bloc repliable. Le titre à gauche et le chevron au fer droit, sur une ligne de 44 px, en 14 px à l'accent lisible ; le chevron tourne à l'ouverture (app.css). Le contenu garde ses lignes à filets. */
.dashboard-app .repli { border-color:var(--hair-2); }
.dashboard-app details.repli>summary { display:flex; justify-content:space-between; gap:12px; min-height:44px; padding-block:12px; color:var(--accent-texte); font-size:14px; line-height:1.4; }
.dashboard-app details.repli>summary>.micro { color:inherit; font-size:inherit; letter-spacing:0; text-transform:none; }
.dashboard-app details.repli>summary>.micro .num { color:inherit; }
.dashboard-app details.repli>summary .chev { flex:none; width:15px; height:15px; stroke:currentColor; }
.dashboard-app details.repli>summary:hover { color:var(--ink); }
/* Composants (spec du 09/10/2026, pièce 6) : le tableau de chiffres. Sur la page, sans cadre ni aplat ; les en-têtes en petites capitales au laiton ; des filets horizontaux seuls ; les colonnes de nombres (`.nombre`, en-tête compris) au fer droit, en chiffres tabulaires et droits ; la ligne de total (`tr.total`, `tfoot`) en gras, son nombre en famille d'apparat. La première cellule part du fer, la dernière y finit. Le tableau défile dans son cadre quand l'écran est plus étroit que lui ; ceux qui s'empilent au téléphone (`tableau-empile`, dashboard.css) gardent leur empilement. */
.dashboard-app .table-scroll { border:0; border-radius:0; background:none; }
.dashboard-app table { background:none; }
.dashboard-app table th,.dashboard-app table td { padding:14px 16px 14px 0; border-color:var(--hair-2); font-size:12px; line-height:1.6; }
.dashboard-app table :is(th,td):last-child { padding-right:0; }
.dashboard-app table th { background:none; color:var(--laiton); font-size:11px; font-weight:600; letter-spacing:0; text-transform:uppercase; }
.dashboard-app :is(th,td).nombre,.dashboard-app td.nombre .num { font-variant-numeric:lining-nums tabular-nums; }
.dashboard-app td.nombre { white-space:nowrap; }
/* Une colonne de nombres au fer droit s'écarte de la colonne de texte qui la suit. */
.dashboard-app :is(th,td).nombre:not(:last-child) { padding-right:32px; }
.dashboard-app :is(tr.total,tfoot tr)>:is(th,td) { padding-block:18px; font-weight:700; color:var(--accent-texte); }
.dashboard-app :is(tr.total,tfoot tr)>td.nombre { font-family:var(--apparat); font-variant-numeric:lining-nums tabular-nums; font-size:22px; font-weight:500; line-height:1.2; }
.dashboard-app :is(tr.total,tfoot tr)>td.nombre .num { font-family:inherit; }
.dashboard-app .tableau-empile td { vertical-align:top; }
/* Le registre des vendus : le signe du P&L se dit par la couleur du montant, la teinte de l'état mêlée à l'encre pour tenir 4,5 (il vivait sur un liseré au bord gauche de la ligne). */
.dashboard-app .registre tr.plus>td:last-child { color:color-mix(in srgb,var(--ok) 55%,var(--ink)); font-weight:600; }
.dashboard-app .registre tr.moins>td:last-child { color:color-mix(in srgb,var(--danger) 82%,var(--ink)); font-weight:600; }
.dashboard-app .leaflet-container { border-radius:var(--r-contenu); }
/* Les plans de Leaflet portent des z-index de 400 à 1000 : isolée, la carte les garde chez elle et reste sous la barre, le dock, le tiroir et le voile. */
.dashboard-app .carte,.dashboard-app .leaflet-container { isolation:isolate; }
.dashboard-app .leaflet-container button,.dashboard-app .leaflet-control a { min-height:30px; padding:0; }
.dashboard-app .carte-gestes { margin:14px 0; gap:10px; }
.dashboard-app .depot-traces { flex-wrap:wrap; gap:12px; }
.dashboard-app .compte-menu { border-radius:var(--r-flottant); padding:10px; border-color:var(--hair-2); }
.dashboard-app .compte-menu a { min-height:40px; padding:10px 12px; border-radius:var(--r-flottant-entree); }
.dashboard-app .compte-menu a:hover { background:var(--interface-soft); }
.dashboard-app .compte-menu button { width:100%; text-align:left; background:none!important; color:var(--ink)!important; border:0!important; }
.dashboard-app .visionneuse { border-radius:var(--r-panneau) 0 0 var(--r-panneau); }
.cover { background:var(--ground); color:var(--ink); }
.cover form,.cover .verrou { padding:26px; background:var(--ground-2); text-align:left; }
.cover form h1 { font-size:26px; letter-spacing:-.03em; }
.cover form button[type=submit] { width:100%; }
/* Composants, lot C : le contenu d'un `.panel` (un encart d'analyse, un tour d'échange, un formulaire de dépôt) se pose sur la page. Deux blocs qui se suivent se séparent d'un filet. */
.dashboard-app .panel { padding:0; border:0; border-radius:0; background:none; }
.dashboard-app .panel + .panel { padding-top:20px; border-top:1px solid var(--hair-2); }
/* Composants (spec du 09/10/2026, pièce 9) : la confirmation de suppression, écran court dont le formulaire ne porte qu'un envoi de danger. La question en famille d'apparat, à chiffres droits ; ce qui sera perdu en 14 px ; une colonne de 680 px au plus ; « Annuler » et le bouton danger au pied, sans panneau. Qui ignore `:has()` garde le titre des autres écrans. */
.dashboard-app main.content.court:has(>form>.form-actions>button.btn-danger:not(.trait))>h1 { margin:0 0 18px; font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:29px; font-weight:500; line-height:1.15; letter-spacing:0; }
.dashboard-app main.content.court:has(>form>.form-actions>button.btn-danger:not(.trait))>:is(h1,p,form) { max-width:680px; }
.dashboard-app main.content.court:has(>form>.form-actions>button.btn-danger:not(.trait))>p { font-size:14px; line-height:1.6; }
@media (max-width:720px) { .dashboard-app main.content.court:has(>form>.form-actions>button.btn-danger:not(.trait))>h1 { font-size:26px; } }
/* Composants, pièce 7 : le formulaire d'un écran court se pose sur la page, sans panneau. Deux formulaires qui se suivent gardent un écart. */
.dashboard-app main.content.court>form + form { margin-top:32px; }
/* Passe finale : dans un échange avec l'assistant la réponse, la réponse suivante et la question de suite sont des panneaux qui se suivent ; ils gardent le même écart. */
.dashboard-app .rapport>.panel + .panel { margin-top:20px; }
/* Le panneau d'un geste qui suit une liste de faits (une échéance faite et son « Rouvrir ») s'en écarte : de nuit son filet haut se lisait collé sous la dernière valeur. */
.dashboard-app main.content.court>div:has(>.situation-facts) + form { margin-top:24px; }
/* Lot E : hors du téléphone le chevron d'une rangée de sortie quitte le flux et se pose au bord droit, face au milieu de la rangée : quand la rangée plie (une mention d'inscription, un record), il ne passe plus seul à la ligne. La rangée lui réserve sa place ; les réserves d'app.css, qui ne valaient que derrière la ligne de voiture, sont levées.
   Passe finale : même règle pour les rangées qui la demandent par leur classe `chevron-au-bord`, celles d'une analyse et de la provenance. À 768 px une analyse dont le texte pliait renvoyait son chevron seul, à gauche, sous « Relire ». Les autres rangées-liens gardent leur chevron dans le flux : leurs mentions de droite ne bougent pas. */
@media (min-width:721px) {
  .dashboard-app .rangee-sortie:has(>.chev),.dashboard-app .chevron-au-bord:has(>.chev) { position:relative; padding-right:calc(var(--debord) + 30px); }
  .dashboard-app .rangee-sortie>.chev,.dashboard-app .chevron-au-bord>.chev { position:absolute; right:var(--debord); top:50%; margin:-9px 0 0; }
  .dashboard-app .rangee-sortie>.sub.grow:not(:empty):has(+ .chev) { margin-right:0; }
}
/* Lot E : une feuille ne touche pas ce qui la suit (pagination, repli, autre feuille). La rangée prioritaire de l'accueil et la fiche véhicule règlent leur propre rythme. */
.dashboard-app .feuille:not(:is(.fiche-corps,.a-venir,.groupe) .feuille):has(+ *) { margin-bottom:16px; }
.dashboard-app main>section:has(>.feuille:last-child)+details.repli { margin-top:16px; }
/* Lot E : dans le registre des vendus le nom de la voiture garde de quoi se lire ; le tableau défile dans son cadre quand l'écran est plus étroit que lui. */
.dashboard-app .registre tbody th { min-width:11rem; }
/* L'aperçu d'une pièce déposée au rayon de contenu. */
.dashboard-app .apercu { border-radius:var(--r-contenu); }
/* La tuile d'un thème au rayon de contenu, ses teintes au coin de l'étiquette. Composants, pièce 7 : le choix de fichier habillé par le script de base.html perd son cadre en tirets, son bouton est un bouton secondaire de 44 px, le nom du fichier choisi le suit. */
.dashboard-app .theme-papier { border-radius:var(--r-contenu); }
.dashboard-app .theme-teintes .t { border-radius:var(--r-etiquette); }
.dashboard-app .fichier { flex-wrap:wrap; gap:8px 16px; min-height:44px; padding:0; border:0; border-radius:0; }
/* Sur l'écran « Ajouter » les tuiles ouvrent le sélecteur : le bouton y reste masqué à l'œil (app.css) et ne revient qu'au focus clavier. */
.dashboard-app .fichier-bouton:not(.fichier-tuiles .fichier-bouton),.dashboard-app .fichier-tuiles input[type=file]:focus-visible + .fichier-bouton { display:inline-flex; align-items:center; min-height:44px; padding:10px 16px; border:1px solid var(--filet-champ); border-radius:var(--r-vif); color:var(--accent-texte); font-size:12px; font-weight:600; letter-spacing:0; text-transform:none; }
.dashboard-app .fichier-bouton:not(.fichier-tuiles .fichier-bouton):hover { border-color:var(--accent); background:var(--fond-doux); }
.dashboard-app .fichier input[type=file]:focus-visible + .fichier-bouton { outline:2px solid var(--accent); outline-offset:3px; }
.dashboard-app .fichier-etat { color:var(--ink-2); font-size:12px; }
/* Un bouton est une boîte flexible : les espaces entre son texte et un nombre posé dedans ne se rendent pas (« Reporter4 kmaux kilomètres »). Le bouton qui porte un nombre écarte ses morceaux d'une espace. */
.dashboard-app button:has(>.num) { column-gap:.28em; }
/* L'invitation à installer l'application, au téléphone : un encart servi sur le tableau de bord, qui garde le rayon que Maison lui a livré (spec Composants, section 4). */
.dashboard-app .installer { border-radius:var(--r-flottant); }
/* La recherche documentaire. Le champ sur la page ; chaque groupe de résultats sous son titre, sans puces, une rangée par document sur son filet (le titre, puis le type et la date au fer droit) ; le compte et les tailles de page sur leur ligne. */
.dashboard-app form.recherche-page.panel { margin-bottom:20px; }
.dashboard-app ul.feuille.resultats { margin:0 0 20px; list-style:none; }
.dashboard-app ul.feuille.resultats>li { display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between; gap:2px 16px; margin:0; padding:12px 0; border-bottom:1px solid var(--hair-2); }
.dashboard-app ul.feuille.resultats>li a:is(:hover,:focus-visible) { text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:4px; }
.dashboard-app .filtrage .filtres.resultats-tete { flex-wrap:wrap; gap:0 22px; margin:0; padding:0; overflow:visible; }
/* Composants (spec du 09/10/2026, pièce 5) : la collection en liste. Une voiture par rangée, sur un filet : la vignette au rapport 3 / 2, le nom en famille d'apparat, les repères et l'étiquette, le lieu dans sa colonne, « Acquis » et la valeur au fer droit (planche, `.c-car-row`). */
.dashboard-app .entries[data-presentation=liste] { gap:0; border-top:1px solid var(--hair-2); }
.dashboard-app .entries[data-presentation=liste]:not(:has(>.entry)) { border-top:0; }
.dashboard-app .entries[data-presentation=liste] .entry { grid-template-columns:130px minmax(0,1.5fr) minmax(0,1fr); column-gap:24px; padding:18px 0; }
.dashboard-app .entries[data-presentation=liste] .entry-media { width:100%; }
.dashboard-app .entries[data-presentation=liste] .entry-body { padding:0; }
.dashboard-app .entries[data-presentation=liste] .entry-figures { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:2px 24px; align-items:center; margin:0; padding:0; border:0; }
.dashboard-app .entries[data-presentation=liste] .entry-figures>.micro:first-child { grid-row:1 / span 2; }
.dashboard-app .entries[data-presentation=liste] .entry-figures>.micro:nth-child(2) { grid-column:2; text-align:right; }
.dashboard-app .entries[data-presentation=liste] .entry-figures>.num { grid-column:2; }
/* À côté du rail et au téléphone (planche, `.c-car-row` sous 1050 px) : la vignette, puis le nom et ses repères ; le lieu, « Acquis » et la valeur passent sous eux, la valeur au fer droit. */
@media (max-width:900px) {
  .dashboard-app .entries[data-presentation=liste] .entry { grid-template-columns:110px minmax(0,1fr); column-gap:16px; align-items:start; }
  .dashboard-app .entries[data-presentation=liste] .entry-media { grid-row:1 / span 2; }
  .dashboard-app .entries[data-presentation=liste] .entry-figures { grid-column:2; display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between; gap:2px 12px; margin-top:8px; }
  .dashboard-app .entries[data-presentation=liste] .entry-figures>.micro:first-child { flex-basis:100%; }
}
@media (max-width:600px) {
  .dashboard-app .entries[data-presentation=liste] .entry { grid-template-columns:84px minmax(0,1fr); column-gap:12px; }
  .dashboard-app .entries[data-presentation=liste] .entry-name { font-size:22px; }
}
/* Fenêtre large et très basse (téléphone couché, fenêtre réduite) : la tête et le pied fixes ne laisseraient qu'une centaine de pixels à la liste. Sous 540 px de haut la barre entière défile ; au-dessus, la liste garde au moins six entrées en vue (mesuré : 267 px à 541 px). */
@media (min-width:721px) and (max-height:540px) {
  .dashboard-app .masthead { overflow-y:auto; overscroll-behavior:contain; scrollbar-width:thin; }
  .dashboard-app .mast-defile { flex:none; overflow:visible; }
  .dashboard-app .mast-defile::before,.dashboard-app .mast-defile::after { content:none; }
}
/* Fenêtre très large : le contenu, borné à 1460 px, se centre dans l'espace que la colonne laisse. La barre du haut garde son filet d'un bord à l'autre et rentre son contenu aux fers du contenu de la page. */
@media (min-width:1800px) {
  .dashboard-app .content { margin-left:max(var(--colonne),calc((100vw + var(--colonne) - 1460px) / 2)); }
  .dashboard-app .ears { padding-left:calc(36px + max(0px,(100vw - var(--colonne) - 1460px) / 2)); padding-right:calc(36px + 100% - 1460px - max(var(--colonne),(100vw + var(--colonne) - 1460px) / 2)); }
}
@media (max-width:1150px) {
  .dashboard-app .content { padding:28px 24px 60px; }
  .dashboard-app .ears { padding-inline:24px; }
  .dashboard-app .lot { grid-template-columns:minmax(0,1fr); }
  .dashboard-app .lot-aside { margin-top:0; }
  .dashboard-app .lot-aside .aside-groupe { min-width:0; }
}
@media (max-width:900px) {
  .dashboard-app .content { padding-inline:20px; }
  .dashboard-app .ears { padding-inline:20px; }
}
@media (max-width:720px) {
  /* Écrin 3.3 : le contenu réserve la hauteur du dock (67 px) et de l'encoche basse. */
  .dashboard-app .content,.dashboard-app .content.court { width:100%; margin:0; padding:24px 16px calc(96px + env(safe-area-inset-bottom)); }
  .dashboard-app .ears { width:100%; margin:0; padding:10px 16px; min-height:68px; }
  .dashboard-app h1 { font-size:28px; }
  .dashboard-app .dashboard-metrics { grid-template-columns:repeat(2,minmax(0,1fr)); }
  .dashboard-app .metric { padding:16px 14px 16px 22px; }
  .dashboard-app .metric>strong { font-size:24px; overflow-wrap:anywhere; }
  .dashboard-app .lot-head .vname { font-size:35px; }
  .dashboard-app .groupe-titre { font-size:26px; }
  /* Un groupe qui nomme son porteur (tri par véhicule) porte un nom long : en 22 px il tient deux lignes à 320 px. Qui ignore `:has()` le sert en 26 px, sur trois. */
  .dashboard-app .groupe-titre:has(>.rond) { font-size:22px; }
  .dashboard-app .section-title { margin:28px 0 10px; font-size:24px; }
  .dashboard-app .dashboard-section-head h2,.dashboard-app main.content>h2:not([class]) { font-size:24px; }
  .dashboard-app .section-title .compte { position:static; display:block; width:auto; line-height:1.7; padding:0; }
  .dashboard-app .lot-tools { gap:8px; margin-bottom:20px; }
  .dashboard-app .lot-tools .btn { font-size:12px; padding:10px 12px; }
  .dashboard-app .collection-filters label { min-width:min(100%,120px); }
  .dashboard-app .vignettes { gap:16px; }
  .dashboard-app .tableau-empile td { padding:12px 0; }
  .dashboard-app .tableau-empile td:before { color:var(--ink-2); }
    .dashboard-app .chip,.dashboard-app button.chip,.dashboard-app .pastilles label.chip { min-height:44px; }
  /* Revue du lot A : au doigt tout danger au trait offre 44 px, sur toute rangée (« Libérer » d'un lieu restait à 30 px ; seul celui qui portait `btn-tactile` passait à 44). (0,3,0), au poids de la règle compacte de dashboard.css, devant elle par sa place. */
  .dashboard-app .btn-danger.trait { min-width:44px; min-height:44px; }
  .dashboard-app .visionneuse { border-radius:var(--r-panneau) var(--r-panneau) 0 0; }
}
@media (max-width:359px) {
  .dashboard-app .dashboard-metrics { grid-template-columns:1fr; }
}
/* Maison (spec du 08/10/2026, section 3) : l'habit de la navigation, d'après la maquette validée (docs/maquettes/2026-10-08-maison). Le bloc vit en fin de feuille : il passe devant les règles des contrôles (capsules) et des champs, de même poids.
   La colonne : le logo long centré, le bouton d'ajout plein aux coins de 3 px, les surtitres de groupe en laiton, des entrées de 44 px au moins.
   L'entrée allumée se dit par la typographie seule : son libellé en famille d'apparat, italique, 17 px, à l'or de texte. Aucun fond, aucune bordure, aucune ombre, aucun trait de couleur sur un bord (arbitrage de Vincent, spec 1.3) ; une garde lit chaque règle qui la vise. */
/* La marque de la colonne porte deux images dans le même lien : le logo long, et le monogramme PC que le rail montre à sa place (le logo long rogné à 48 px y était illisible). (0,4,0) : devant `.dashboard-app .masthead .wordmark img` de dashboard.css, qui les pose en bloc. L'inversion des thèmes de nuit (dashboard.css) vise toute image de la marque. */
.dashboard-app .masthead .wordmark .marque-pc { display:none; width:40px; height:40px; }
.dashboard-app .masthead .wordmark .marque-pc.marque-maison { object-fit:contain; }
/* Une maison sans logo : son nom en tête de colonne, sur deux lignes au besoin. */
.dashboard-app .masthead .wordmark .ears-marque { letter-spacing:0; white-space:normal; text-align:center; padding-inline:8px; }
.dashboard-app .dashboard-ajouter { min-height:44px; gap:9px; padding:10px; border-radius:var(--r-vif); font-size:12px; }
.dashboard-app .dashboard-nav-label { display:block; margin:24px 12px 8px; padding:0; font-size:11px; font-weight:600; line-height:1.5; letter-spacing:0; color:var(--laiton); }
.dashboard-app .dashboard-concierge .dashboard-nav-label { margin:0 0 4px; }
.dashboard-app .mast-nav { gap:0; }
.dashboard-app .mast-nav a { position:relative; display:flex; align-items:center; gap:12px; flex:none; min-height:44px; margin:0; padding:9px 12px; border:0; border-radius:var(--r-vif); background:none; color:var(--ink-2); font-size:12px; line-height:1.4; letter-spacing:0; text-transform:none; }
.dashboard-app .mast-nav a>span:not([id]) { min-width:0; }
.dashboard-app .mast-nav .icon { width:18px; height:18px; flex-shrink:0; stroke:currentColor; stroke-width:1.5; }
.dashboard-app .mast-nav a[aria-current=page] { color:var(--accent-texte); }
@media (min-width:721px) {
  .dashboard-app .mast-nav a[aria-current=page]>span:not([id]) { font-family:var(--apparat); font-variant-numeric:lining-nums; font-style:italic; font-weight:500; font-size:17px; line-height:1.15; }
}
/* Survol et focus clavier (spec Finitions 3.3) : l'encre pleine et un fond teinté de 5 % d'encre sur le fond de la colonne, sans graisse ni retrait qui feraient bouger le libellé. L'entrée allumée en est exclue. Le survol est réservé aux pointeurs qui survolent : au doigt il restait collé à l'onglet quitté. */
.dashboard-app .mast-nav a:not([aria-current=page]):focus-visible { color:var(--ink); background:color-mix(in srgb,var(--ink) 5%,var(--colonne-fond)); }
@media (hover:hover) { .dashboard-app .mast-nav a:not([aria-current=page]):hover { color:var(--ink); background:color-mix(in srgb,var(--ink) 5%,var(--colonne-fond)); } }
/* Le compte à relire : un rond au filet, au bord droit de son entrée. Il garde la famille de texte dans une entrée allumée. */
.dashboard-app .mast-nav #badge-a-relire,.dashboard-app .mast-nav #badge-demandes { display:flex; margin-left:auto; }
.dashboard-app .mast-nav .badge { display:grid; place-items:center; box-sizing:border-box; min-width:20px; height:20px; padding:0 5px; border:1px solid var(--hair-2); border-radius:999px; background:none; color:var(--accent-texte); font:600 11px/1 var(--sans); letter-spacing:0; }
/* Le pied du compte : un filet, le monogramme rond et plein, le nom, les préférences. Le panneau « Plus » du téléphone porte le même (`.navigation-compte`), servi caché ailleurs. */
.dashboard-app .dashboard-sidebar-foot,.dashboard-app .navigation-compte { align-items:center; gap:10px; padding-top:15px; border-top:1px solid var(--hair-2); }
.dashboard-app .dashboard-sidebar-foot { display:flex; flex:none; margin-top:10px; }
.dashboard-app .navigation-compte,.dashboard-app .navigation-fermer { display:none; }
.dashboard-app .dashboard-sidebar-foot>div,.dashboard-app .navigation-compte>div { min-width:0; }
.dashboard-app .dashboard-sidebar-foot .monogram,.dashboard-app .navigation-compte .monogram,.dashboard-app .compte>summary .monogram { width:36px; height:36px; border:0; border-radius:50%; background:var(--accent); color:var(--on-accent); box-shadow:none; font:600 11px var(--sans); letter-spacing:0; }
.dashboard-app .dashboard-sidebar-foot strong,.dashboard-app .navigation-compte strong { display:block; font-size:11px; font-weight:700; line-height:1.4; overflow-wrap:anywhere; }
.dashboard-app .dashboard-sidebar-foot a,.dashboard-app .navigation-compte a { display:flex; align-items:center; min-height:44px; margin:0; padding:5px 0; font-size:11px; font-weight:400; color:var(--ink-2); }
/* La barre du haut : à gauche le bouton qui replie la colonne et la marque composée en famille d'apparat ; la date ; la recherche, soulignée d'un filet, sans cadre ; le monogramme du compte, dont le nom se lit dans l'intitulé du bouton. */
.dashboard-app .ears-identite { display:flex; align-items:center; gap:14px; flex:1 0 auto; }
.dashboard-app .ears-marque,.cover .ears-marque { font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:22px; line-height:1.2; white-space:nowrap; color:var(--ink); }
.dashboard-app .ears-marque em,.cover .ears-marque em { font-style:italic; }
.dashboard-app .ears-date { color:var(--ink-2); }
.dashboard-app .colonne-repli { display:none; }
.dashboard-app .ears .search input { width:100%; max-width:none; min-width:0; height:44px; min-height:44px; padding:0; border:0; border-bottom:1px solid var(--hair-2); border-radius:0; background:transparent; box-shadow:none; font-size:12px; color:var(--ink); }
.dashboard-app .ears .search input:focus { border-bottom-color:var(--accent); }
.dashboard-app .ears .search input::placeholder { color:var(--ink-2); opacity:1; }
/* La loupe ouvre le champ, au fer du filet ; le texte commence après elle. (0,5,1) : devant la règle commune de la loupe de dashboard.css. */
.dashboard-app .ears .champ-loupe .loupe { left:0; }
.dashboard-app .ears .search .champ-loupe input[type=search] { padding-left:28px; }
/* La cible du compte fait 44 px autour d'un monogramme de 36 : elle déborde de 4 px, pour que le monogramme finisse au fer droit du contenu de la page. Même réglage pour le bouton de repli, dont le pictogramme de 18 px part du fer gauche. */
.dashboard-app .ears .compte { margin-right:-4px; }
.dashboard-app .ears .compte>summary { justify-content:center; min-width:44px; min-height:44px; }
.dashboard-app .ears .compte-menu { top:calc(100% + 6px); }
/* Le concierge du client en tête du menu du compte (revue du lot B) : dans le rail et au téléphone la colonne ne montre pas son bloc « Votre concierge », le menu le reprend, surtitre en laiton et nom, sans lien. Il se retire au-delà de 1099 px tant que la colonne est déployée (bloc du rail choisi, plus bas). */
.dashboard-app .compte-concierge { align-self:stretch; margin:0 0 6px; padding:6px 12px 12px; border-bottom:1px solid var(--hair-2); line-height:1.4; letter-spacing:0; cursor:default; }
.dashboard-app .compte-concierge>span { display:block; margin-bottom:4px; font-size:11px; font-weight:600; text-transform:uppercase; color:var(--laiton); }
.dashboard-app .compte-concierge>strong { display:block; font-size:12px; overflow-wrap:anywhere; }
@media (max-width:1099px) { .dashboard-app .ears-marque { font-size:19px; } }
/* La colonne tient sans défiler sur un ordinateur portable (revue du lot B). Aux mesures de la maquette (entrées de 44 px) la liste du client avec concierge demande 1 039 px de haut et celle du compte d'équipe 1 189 : en dessous elle défilait.
   Au pointeur fin qui survole (souris, pavé tactile), et sous une hauteur de fenêtre, la colonne se resserre en deux paliers : entrées de 36 px puis de 32 px, marges des surtitres, du bloc du concierge et du pied réduites. Sur tout appareil tactile, et dans une fenêtre assez haute, la cible de 44 px et les mesures de la maquette restent entières.
   Les règles lisent des jetons dont le repli est la mesure de la maquette : sans jeton posé, rien ne bouge. Les quatre requêtes qui suivent posent les jetons du palier. Le compte d'équipe (seize entrées, quatre surtitres), reconnu à son repère d'espace (le nom de sa maison), franchit chaque palier plus haut que le client ; le navigateur qui ignore `:has()` lui sert les paliers du client.
   Les seuils sont mesurés (tableau des écarts du plan) : test_la_colonne_tient_a_toute_hauteur_au_dela_de_son_plancher balaie les hauteurs. */
@media (hover:hover) and (pointer:fine) and (min-width:721px) and (max-height:1199px) {
  .dashboard-app .masthead { padding-block:var(--nav-tete,18px) var(--nav-fond,14px); }
  .dashboard-app .masthead .wordmark { margin-bottom:var(--nav-logo-marge,12px); }
  .dashboard-app .dashboard-workspace { padding-block:var(--nav-repere,13px); }
  .dashboard-app .dashboard-nav-label { margin-block:var(--nav-surtitre-haut,24px) var(--nav-surtitre-bas,8px); }
  .dashboard-app .mast-nav a { min-height:var(--nav-entree,44px); padding-block:var(--nav-entree-marge,9px); }
  .dashboard-app .dashboard-concierge { margin-top:var(--nav-concierge-ecart,20px); padding-block:var(--nav-concierge-haut,24px) var(--nav-concierge-bas,18px); }
  .dashboard-app .dashboard-sidebar-foot { margin-top:var(--nav-pied-ecart,10px); padding-top:var(--nav-pied-haut,15px); }
  .dashboard-app .dashboard-sidebar-foot a { min-height:var(--nav-entree,44px); }
  .dashboard-app .masthead:has(.dashboard-workspace) { --nav-entree:36px; --nav-entree-marge:8px; --nav-surtitre-haut:14px; --nav-surtitre-bas:4px; --nav-tete:14px; --nav-fond:12px; --nav-repere:10px; --nav-concierge-ecart:12px; --nav-concierge-haut:14px; --nav-concierge-bas:10px; --nav-pied-ecart:8px; --nav-pied-haut:12px; }
}
@media (hover:hover) and (pointer:fine) and (min-width:721px) and (max-height:1049px) {
  .dashboard-app .masthead { --nav-entree:36px; --nav-entree-marge:8px; --nav-surtitre-haut:14px; --nav-surtitre-bas:4px; --nav-tete:14px; --nav-fond:12px; --nav-repere:10px; --nav-concierge-ecart:12px; --nav-concierge-haut:14px; --nav-concierge-bas:10px; --nav-pied-ecart:8px; --nav-pied-haut:12px; }
}
@media (hover:hover) and (pointer:fine) and (min-width:721px) and (max-height:989px) {
  .dashboard-app .masthead:has(.dashboard-workspace) { --nav-entree:32px; --nav-entree-marge:6px; --nav-surtitre-haut:12px; --nav-surtitre-bas:4px; --nav-tete:12px; --nav-fond:10px; --nav-logo-marge:8px; --nav-repere:8px; --nav-concierge-ecart:8px; --nav-concierge-haut:10px; --nav-concierge-bas:6px; --nav-pied-ecart:6px; --nav-pied-haut:10px; }
}
@media (hover:hover) and (pointer:fine) and (min-width:721px) and (max-height:869px) {
  .dashboard-app .masthead { --nav-entree:32px; --nav-entree-marge:6px; --nav-surtitre-haut:12px; --nav-surtitre-bas:4px; --nav-tete:12px; --nav-fond:10px; --nav-logo-marge:8px; --nav-repere:8px; --nav-concierge-ecart:8px; --nav-concierge-haut:10px; --nav-concierge-bas:6px; --nav-pied-ecart:6px; --nav-pied-haut:10px; }
}
/* Le rail (spec Maison 3.2) : 76 px, le monogramme PC en tête dans un lien de 44 px, les pictogrammes seuls. Les libellés sont rognés à un pixel et restent dans leur lien, pour la lecture d'écran ; l'infobulle (`title`) les rend au pointeur. Le compte à relire monte au coin de son pictogramme.
   Entre 721 et 1099 px la largeur l'impose. Au-delà, la classe `colonne-reduite` de la racine le demande (bouton de la barre du haut, choix gardé dans le navigateur). Les deux blocs portent les mêmes règles, à leur préfixe près : test_le_rail_impose_et_le_rail_choisi_sont_le_meme_rail les compare.
   Le seuil est dérivé du bandeau à la photo : à 1100 px de fenêtre la colonne déployée (232 px) et les marges du contenu (deux fois 24 px) laissent au bandeau 820 px, la largeur de sa forme « cadre », que le rail lui donne déjà depuis 944 px. Avec un seuil plus bas le bandeau retombait en bande au moment où la colonne se déployait. */
@media (min-width:721px) and (max-width:1099px) {
  .dashboard-app { --colonne:76px; }
  html:not(.colonne-survol) .dashboard-app .masthead { padding-inline:12px; }
  html:not(.colonne-survol) .dashboard-app .masthead .wordmark { width:44px; height:44px; margin-inline:auto; }
  html:not(.colonne-survol) .dashboard-app .masthead .wordmark .marque-long,html:not(.colonne-survol) .dashboard-app .masthead .wordmark .ears-marque { display:none; }
  html:not(.colonne-survol) .dashboard-app .masthead .wordmark .marque-pc { display:block; }
  html:not(.colonne-survol) .dashboard-app .dashboard-ajouter,html:not(.colonne-survol) .dashboard-app .dashboard-workspace { justify-content:center; padding-inline:0; }
  html:not(.colonne-survol) .dashboard-app .dashboard-ajouter>span,html:not(.colonne-survol) .dashboard-app .dashboard-workspace>div,html:not(.colonne-survol) .dashboard-app .mast-nav a>span:not([id]) { position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }
  html:not(.colonne-survol) .dashboard-app .dashboard-nav-label,html:not(.colonne-survol) .dashboard-app .dashboard-concierge,html:not(.colonne-survol) .dashboard-app .dashboard-sidebar-foot>div { display:none; }
  html:not(.colonne-survol) .dashboard-app .mast-defile { margin-top:16px; }
  html:not(.colonne-survol) .dashboard-app .mast-nav a { justify-content:center; padding-inline:0; }
  html:not(.colonne-survol) .dashboard-app .mast-nav #badge-a-relire,html:not(.colonne-survol) .dashboard-app .mast-nav #badge-demandes { position:absolute; top:2px; right:4px; margin:0; }
  html:not(.colonne-survol) .dashboard-app .mast-nav .badge { min-width:16px; height:16px; padding:0 3px; background:var(--colonne-fond); }
  html:not(.colonne-survol) .dashboard-app .dashboard-sidebar-foot { justify-content:center; }
}
@media (min-width:1100px) {
  html.js .dashboard-app .colonne-repli { display:grid; place-items:center; flex:none; min-width:44px; min-height:44px; margin-left:-13px; padding:0; border:0; border-radius:50%; background:none; color:var(--accent-texte); }
  .dashboard-app .colonne-repli .icon { stroke:currentColor; }
  .dashboard-app .colonne-repli .volet-deployer,html.colonne-reduite .dashboard-app .colonne-repli .volet-reduire { display:none; }
  html.colonne-reduite .dashboard-app .colonne-repli .volet-deployer { display:block; }
  html:not(.colonne-reduite) .dashboard-app .compte-concierge { display:none; }
  html.colonne-reduite .dashboard-app { --colonne:76px; }
  html.colonne-reduite:not(.colonne-survol) .dashboard-app .masthead { padding-inline:12px; }
  html.colonne-reduite:not(.colonne-survol) .dashboard-app .masthead .wordmark { width:44px; height:44px; margin-inline:auto; }
  html.colonne-reduite:not(.colonne-survol) .dashboard-app .masthead .wordmark .marque-long,html.colonne-reduite:not(.colonne-survol) .dashboard-app .masthead .wordmark .ears-marque { display:none; }
  html.colonne-reduite:not(.colonne-survol) .dashboard-app .masthead .wordmark .marque-pc { display:block; }
  html.colonne-reduite:not(.colonne-survol) .dashboard-app .dashboard-ajouter,html.colonne-reduite:not(.colonne-survol) .dashboard-app .dashboard-workspace { justify-content:center; padding-inline:0; }
  html.colonne-reduite:not(.colonne-survol) .dashboard-app .dashboard-ajouter>span,html.colonne-reduite:not(.colonne-survol) .dashboard-app .dashboard-workspace>div,html.colonne-reduite:not(.colonne-survol) .dashboard-app .mast-nav a>span:not([id]) { position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }
  html.colonne-reduite:not(.colonne-survol) .dashboard-app .dashboard-nav-label,html.colonne-reduite:not(.colonne-survol) .dashboard-app .dashboard-concierge,html.colonne-reduite:not(.colonne-survol) .dashboard-app .dashboard-sidebar-foot>div { display:none; }
  html.colonne-reduite:not(.colonne-survol) .dashboard-app .mast-defile { margin-top:16px; }
  html.colonne-reduite:not(.colonne-survol) .dashboard-app .mast-nav a { justify-content:center; padding-inline:0; }
  html.colonne-reduite:not(.colonne-survol) .dashboard-app .mast-nav #badge-a-relire,html.colonne-reduite:not(.colonne-survol) .dashboard-app .mast-nav #badge-demandes { position:absolute; top:2px; right:4px; margin:0; }
  html.colonne-reduite:not(.colonne-survol) .dashboard-app .mast-nav .badge { min-width:16px; height:16px; padding:0 3px; background:var(--colonne-fond); }
  html.colonne-reduite:not(.colonne-survol) .dashboard-app .dashboard-sidebar-foot { justify-content:center; }
}
/* Le rail sous le pointeur (demande de Vincent du 09/10). `colonne-survol`, posée sur la racine par navigation.js tant qu'un pointeur fin est sur le rail, lève les règles du rail : la colonne reprend sa largeur déployée PAR-DESSUS la page, dont `--colonne` (76 px) tient toujours la place. Les largeurs glissent en 0,22 s, au survol comme au clic du bouton de repli, le temps que navigation.js tient `colonne-glisse` sur la racine : une fenêtre qu'on redimensionne change de forme d'un coup. Sous mouvement réduit le changement est immédiat. */
@media (min-width:721px) {
  .dashboard-app .masthead { overflow-x:clip; }
  html.colonne-glisse .dashboard-app .masthead { transition:width .22s ease,padding-left .22s ease,padding-right .22s ease,box-shadow .22s ease; }
  html.colonne-glisse .dashboard-app .content,html.colonne-glisse .dashboard-app .ears { transition:margin-left .22s ease,width .22s ease,padding-left .22s ease,padding-right .22s ease; }
  .dashboard-app .mast-nav a>span,.dashboard-app .dashboard-ajouter>span { white-space:nowrap; }
  html.colonne-survol .dashboard-app .masthead { width:var(--colonne-deployee); z-index:40; box-shadow:var(--ombre-flottant); }
  html.colonne-survol .dashboard-app .masthead>* { animation:colonne-fondu .22s ease; }
}
@keyframes colonne-fondu { from { opacity:0; } }
@media (prefers-reduced-motion:reduce) {
  html.colonne-glisse .dashboard-app .masthead,html.colonne-glisse .dashboard-app .content,html.colonne-glisse .dashboard-app .ears { transition:none; }
  html.colonne-survol .dashboard-app .masthead>* { animation:none; }
}
/* Le téléphone (spec Maison 3.3, seuil de l'application). La barre du haut : la recherche et le monogramme, sans marque. La barre du bas : cinq entrées sur le fond du thème, un filet au-dessus ; l'entrée allumée en accent et en gras, sans trait.
   Écrin 3.3 reste : la barre du bas est fixée au bord sur toute la largeur, sans marge ni rayon ni ombre ; son fond est porté par la navigation, pour que le voile du panneau (z-index -1 dans la barre) passe DESSOUS elle et au-dessus de la page.
   « Plus » ouvre le panneau des autres rubriques, posé au-dessus de la barre du bas : deux colonnes de rangées, le surtitre et le bouton de fermeture en tête, le pied du compte en fin. */
@media (max-width:720px) {
  .dashboard-app .ears-identite { display:none; }
  .dashboard-app .ears .search input { font-size:16px; }
  .dashboard-app .compte>summary .monogram { width:30px; height:30px; }
  .dashboard-app .ears .compte { margin-right:-7px; }
  .dashboard-app .masthead { --colonne-fond:var(--ground); width:100%; padding:0; overflow:visible; border:0; background:transparent; box-shadow:none; }
  .dashboard-app .mast-defile { display:contents; }
  .dashboard-app .mast-defile::before,.dashboard-app .mast-defile::after { content:none; }
  .dashboard-app .mast-defile>.dashboard-nav-label,.dashboard-app .dashboard-sidebar-foot { display:none; }
  .dashboard-app .mast-nav { flex-direction:row; align-items:stretch; background:var(--ground); border-top:1px solid var(--hair-2); padding:6px 4px calc(6px + env(safe-area-inset-bottom)); }
  .dashboard-app .mast-nav>a { flex:1 1 0; min-width:0; min-height:54px; padding:8px 0 6px; flex-direction:column; justify-content:center; gap:5px; border-radius:0; font-size:11px; line-height:1.2; }
  .dashboard-app .navigation-plus { flex:1 1 0; min-width:0; }
  .navigation-plus>summary { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:5px; min-height:54px; padding:8px 0 6px; font-size:11px; line-height:1.2; cursor:pointer; color:var(--ink-2); }
  .dashboard-app .mast-nav a[aria-current=page],.navigation-plus[open]>summary,.navigation-plus>.navigation-plus-active { color:var(--accent-texte); font-weight:700; }
  .navigation-outils { position:absolute; bottom:calc(100% + 12px); left:12px; right:12px; max-height:min(70vh,600px); max-height:min(70dvh,600px); overflow:auto; overscroll-behavior:contain; padding:10px 18px 14px; border:1px solid var(--hair-2); background:var(--ground); box-shadow:var(--ombre-tiroir); display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); column-gap:8px; align-items:center; }
  /* Le panneau fermé est retiré de l'affichage : le contenu d'un `details` fermé garde des boîtes de 0 px de large, que la recette lit comme un texte écrasé. */
  .navigation-plus:not([open])>.navigation-outils { display:none; }
  .dashboard-app .navigation-outils a { min-height:44px; padding:9px 5px; gap:8px; }
  .dashboard-app .navigation-outils .dashboard-nav-label { grid-column:1/-1; margin:14px 5px 4px; }
  .dashboard-app .navigation-outils>.dashboard-nav-label:first-child { margin-block:0; }
  /* Le bouton ferme par le script : il paraît avec lui seulement, et le surtitre lui laisse alors la seconde colonne. */
  html.js .dashboard-app .navigation-outils>.dashboard-nav-label:first-child { grid-column:1; }
  html.js .dashboard-app .navigation-fermer { display:grid; place-items:center; grid-column:2; justify-self:end; min-width:44px; min-height:44px; margin-right:-10px; padding:0; border:0; border-radius:50%; background:none; color:var(--accent-texte); }
  .dashboard-app .navigation-fermer .icon { stroke:currentColor; }
  .dashboard-app .navigation-compte { display:flex; grid-column:1/-1; margin-top:10px; }
  /* (0,3,1) : devant la règle des rangées du panneau, pour que « Préférences du compte » parte du fer du nom. */
  .dashboard-app .navigation-outils .navigation-compte a { padding:5px 0; }
  /* Panneau ouvert, la page derrière ne défile pas (classe posée par navigation.js, qui rend aussi la page inerte). */
  html.tiroir-ouvert,html.tiroir-ouvert body { overflow:hidden; }
  /* Le voile appartient au bouton « Plus » : un appui dessus referme le panneau par le geste natif. Sans script le panneau est servi ouvert, donc sans voile. */
  html.js .navigation-plus[open]>summary::before { content:""; position:fixed; inset:0; z-index:-1; background:var(--voile); cursor:default; }
}
/* À l'impression un navigateur laisse les fonds en blanc (réglage par défaut) : l'en-tête s'écrit à l'encre, surtitre, mot en italique et étiquette compris (le laiton et l'accent d'un thème de nuit ne se lisent pas sur le papier), son geste plein devient un contour, la photo décorative de l'accueil se retire (la galerie de la fiche, qui montre la voiture, reste, sans sa navette). Les panneaux sont sans ombre, leurs jetons éteints comme en schéma sombre.
   `body.dashboard-app` : la règle passe devant celles de fiche.css, chargée après. */
@media print {
  .dashboard-app .content { margin:0; width:100%; max-width:none; padding:0; }
  .navigation-plus { display:none; }
  html[data-theme],body.dashboard-app { --ombre-tiroir:0 0 transparent; --ombre-flottant:0 0 transparent; }
  body.dashboard-app .bandeau-court { padding:0 0 8px; }
  body.dashboard-app .fiche-navette { display:none; }
  body.dashboard-app :is(.bandeau-gestes .btn,.bandeau-gestes .btn.premier,.bandeau-sous a,.bandeau-renvois a,.bandeau-renvois a:first-child,.fiche-gestes .btn,.fiche-gestes .btn.premier,.fiche-legende>span) { border-color:var(--hair-2); background:none; color:var(--ink); }
  body.dashboard-app :is(.bandeau-surtitre,.fiche-fil,.bandeau-court h1 em,.bandeau-arc h1 em,.fiche-bandeau .vsub .etat) { background:none; color:var(--ink); }
}
/* Composants, lot D : le titre de TOUTE page se compose dans la famille d'apparat, son terme porteur en italique à l'accent lisible (filtre `titre_de_page`, balise `em`). Un formulaire, un écran d'attente ou de relecture prend le titre de la planche (pièce 7 : 29 px, sa ligne de rappel dessous en 12 px) et un filet le sépare de ses champs, comme l'en-tête d'une liste ; la confirmation de suppression (pièce 9) garde sa colonne sans filet. Le titre d'un rapport (`rapport-titre`, une phrase) garde son corps. */
.dashboard-app main.content>h1,.dashboard-app main.content .rapport-titre { font-family:var(--apparat); font-variant-numeric:lining-nums; font-weight:500; letter-spacing:0; }
.dashboard-app main.content>h1:not(.rapport-titre) { margin:0; font-size:29px; line-height:1.15; overflow-wrap:break-word; }
.dashboard-app main.content>h1 em { color:var(--accent-texte); font-style:italic; font-weight:400; }
.dashboard-app main.content>h1+p.muted { margin:6px 0 0; font-size:12px; line-height:1.6; color:var(--ink-2); }
.dashboard-app main.content:not(:has(>form>.form-actions>button.btn-danger:not(.trait)))>:is(h1:not(.rapport-titre):not(:has(+p.muted)),h1+p.muted) { padding-bottom:16px; margin-bottom:22px; border-bottom:1px solid var(--hair-2); }
.dashboard-app main.content.court>header.bandeau-court { max-width:820px; }
@media (max-width:720px) { .dashboard-app main.content>h1:not(.rapport-titre) { font-size:26px; } }
/* Composants, lot D : le pied d'un formulaire sans « Annuler » (« Analyser », « Demander », « Enregistrer » et « Plus tard », « Activer », « Définir ») prend la forme du pied commun dès qu'il FERME le formulaire : sur un filet, à droite, le principal en bout de rangée. Une rangée d'actions posée ailleurs reste à gauche, sans filet. */
.dashboard-app main.content form>:is(.form-actions,p):last-child:has(>button[type=submit].btn-primary:first-child) { display:flex; flex-wrap:wrap; align-items:center; justify-content:flex-end; gap:12px 24px; margin-top:24px; margin-bottom:0; padding-top:24px; border-top:1px solid var(--hair-2); }
.dashboard-app main.content form>:is(.form-actions,p):last-child:has(>button[type=submit].btn-primary:first-child)>.btn-primary { order:1; }
/* Composants, lot D : le choix d'un groupe de boutons radio (Nature et Conditions d'une sortie, la voiture d'un rattachement) prend la forme d'un choix de la planche, celle d'un filtre : un libellé de 44 px sans filet ni fond ni capitales, à l'encre secondaire ; le choix coché à l'accent lisible et en gras. En contrastes forcés, où l'accent cède à la couleur du système, le choix coché est souligné (spec 6, décision 11). (0,3,1) et plus : devant la pastille du lot A et les règles d'app.css. */
/* Chaque choix porte 8 px de retrait de chaque côté de son texte, repris sur l'écart (6 px, soit 22 px d'un texte à l'autre) et sur le fer gauche de la rangée, comme les raccourcis d'un champ : un libellé court (« Variable », 45 px) dans une cible de 44 px de haut se lisait à la recette comme une colonne de lettres. */
.dashboard-app .pastilles .pastilles-choix { gap:0 6px; margin:0 0 0 -8px; }
.dashboard-app .pastilles label.chip { min-height:44px; padding:8px; border:0; border-radius:0; background:none; color:var(--ink-2); font-size:12px; font-weight:500; letter-spacing:0; text-transform:none; }
.dashboard-app .pastilles label.chip:hover { border:0; color:var(--accent-texte); }
.dashboard-app .pastilles label.chip:has(input:checked) { border:0; color:var(--accent-texte); font-weight:700; }
@media (forced-colors:active) { .dashboard-app .pastilles label.chip:has(input:checked) { text-decoration:underline; text-decoration-thickness:2px; text-underline-offset:4px; } }
/* Composants, revue d'ensemble : UNE forme pour tout groupe de boutons radio, quel que soit son balisage (les pastilles d'une sortie et d'un rattachement, le rendu de Django pour « Nature » et « Portée » du coffre, qui montrait les radios du système). Un libellé cliquable de 44 px à l'encre secondaire, le bouton du système masqué à l'œil et gardé au clavier ; devant chaque libellé un cercle vide au filet des champs, devant le retenu un point plein, à l'accent lisible et en gras. Le signe est dessiné par son seul BORD (1 px, puis 7 px qui couvrent la boîte de 14 px) : il tient à sa géométrie, se lit en niveaux de gris, et reste peint en contrastes forcés, où un fond s'efface ; le retenu y est aussi souligné (spec 6, décision 11). Sans valeur cochée, la rangée de cercles vides dit qu'un choix attend. Les tuiles de thème des préférences, aperçus peints, gardent leur forme. Chaque sélecteur à `:has()` a sa règle ; qui l'ignore garde les radios du système (coffre) ou les libellés du lot D (sorties). (0,3,3) et plus : devant les règles des pastilles. */
.dashboard-app main.content label:has(>input[type=radio]):where(:not(.theme)) { position:relative; display:inline-flex; align-items:center; gap:8px; min-height:44px; margin:0; padding:8px; border:0; border-radius:0; background:none; color:var(--ink-2); font-size:12px; font-weight:500; line-height:1.6; letter-spacing:0; text-transform:none; cursor:pointer; }
.dashboard-app main.content label:has(>input[type=radio]):where(:not(.theme))>input[type=radio] { position:absolute; width:1px; height:1px; min-width:0; min-height:0; margin:-1px; padding:0; border:0; overflow:hidden; clip-path:inset(50%); opacity:0; }
.dashboard-app main.content label:has(>input[type=radio]):where(:not(.theme))::before { content:""; flex:none; box-sizing:border-box; width:14px; height:14px; border:1px solid var(--filet-champ); border-radius:50%; }
.dashboard-app main.content label:has(>input[type=radio]):where(:not(.theme)):hover { border:0; color:var(--accent-texte); }
.dashboard-app main.content label:has(>input[type=radio]):where(:not(.theme)):has(>input:checked) { border:0; color:var(--accent-texte); font-weight:700; }
.dashboard-app main.content label:has(>input[type=radio]):where(:not(.theme)):has(>input:checked)::before { border:7px solid currentColor; }
.dashboard-app main.content label:has(>input[type=radio]):where(:not(.theme)):has(>input:focus-visible) { outline:2px solid var(--accent); outline-offset:2px; }
@media (forced-colors:active) { .dashboard-app main.content label:has(>input[type=radio]):where(:not(.theme)):has(>input:checked) { text-decoration:underline; text-decoration-thickness:2px; text-underline-offset:4px; } }
/* Le groupe rendu par Django (une `div` par choix) se range comme les pastilles : une rangée qui passe à la ligne, le premier cercle au fer du libellé du groupe. */
.dashboard-app main.content div:has(>div>label>input[type=radio]) { display:flex; flex-wrap:wrap; gap:0 6px; margin:0 0 0 -8px; }
/* Composants, lot D : un seul bouton plein par groupe d'actions. L'envoi nu d'une rangée de liste ou d'une cellule (« Fait », « Détacher », « Révéler », « Enregistrer » d'un rattachement, « Clôturer », « Analyser » d'un document, « Couper l'IA »), répété à chaque rangée, est un bouton secondaire ; le plein reste au geste principal de l'écran. Revue du lot D : l'envoi posé à la suite d'une rangée, dans sa feuille (« Détacher cet entretien » d'un sinistre), et l'envoi d'un groupe de la marge d'une fiche (« Rouvrir le sinistre ») suivent la même règle ; « Enregistrer » du suivi IA quitte la classe du principal. L'envoi d'une feuille de texte (« Analyse IA des coûts », « Analyser le modèle ») reste plein : seul le formulaire qui SUIT une rangée est visé. (0,10,1) : devant la règle de l'envoi plein, le désactivé gardant la sienne. */
.dashboard-app :is(.filet-row,td,.rangee-piece,.rangee-frais,.rangee-montage,.feuille>.filet-row+form,.aside-groupe>form,.ajout-de-liste) button[type=submit]:not(.btn-primary):not(.btn-danger):not(.trait):not(.chip):not(.micro):enabled { background:transparent; border-color:var(--filet-champ); color:var(--accent-texte); }
.dashboard-app :is(.filet-row,td,.rangee-piece,.rangee-frais,.rangee-montage,.feuille>.filet-row+form,.aside-groupe>form,.ajout-de-liste) button[type=submit]:not(.btn-primary):not(.btn-danger):not(.trait):not(.chip):not(.micro):enabled:hover { background:var(--fond-doux); border-color:var(--accent); color:var(--accent-texte); }
/* Composants, lot D : l'état d'une rangée se dit par une étiquette (pièce 12 : rectangle au coin de 2 px, fond doux ou alerte adoucie, 11 px en demi-gras). Le libellé entier d'un geste d'hivernage dépassé passait au rouge, et un intervenant « à confirmer » ne se distinguait que par la teinte de son nom : la rangée qui porte une étiquette garde son titre et ses gestes à l'encre. */
.dashboard-app .etiquette { display:inline-block; padding:4px 7px; border-radius:var(--r-etiquette); background:var(--fond-doux); color:var(--ink-2); font-family:var(--sans); font-size:11px; font-weight:600; line-height:1.4; letter-spacing:0; text-transform:none; white-space:nowrap; vertical-align:middle; }
.dashboard-app .etiquette.proche { color:color-mix(in srgb,var(--warn) 55%,var(--ink)); }
.dashboard-app .etiquette.echu { background:color-mix(in srgb,var(--danger) 12%,var(--ground-2)); color:color-mix(in srgb,var(--danger) 82%,var(--ink)); }
.dashboard-app .filet-row:is(.echu,.proche):has(.etiquette)>.titre,.dashboard-app a.filet-row.row:is(.echu,.proche):has(.etiquette):hover>.titre { color:var(--ink); }
.dashboard-app .filet-row:is(.echu,.proche):has(.etiquette)>.end { color:inherit; }
/* Dans le titre d'une rangée l'étiquette tient dans la hauteur de la ligne : ses marges hautes et basses rendent sa marge intérieure (une liste de trente rangées garde sa longueur). */
.dashboard-app .filet-row .titre>.etiquette { margin:-4px 0 -4px 8px; }
.dashboard-app .rangee-hivernage .sub.end>.etiquette { margin-right:8px; }
/* Revue du lot D : « dépassée » se dit par la même étiquette sur la liste des voitures en hivernage et dans la rubrique de la fiche (un texte rouge nu jusque-là), à 8 px de la date du geste, sans grandir la ligne. */
.dashboard-app .filet-row .end>.etiquette { margin:-4px 0 -4px 8px; }
/* « Fait », répété à chaque geste dû de la routine, suit la règle des envois de rangée : secondaire. */
.dashboard-app .filet-row button[type=submit].btn-fait:not(.btn-danger):not(.trait):not(.chip):not(.micro):enabled { background:transparent; border-color:var(--filet-champ); color:var(--accent-texte); }
.dashboard-app .filet-row button[type=submit].btn-fait:not(.btn-danger):not(.trait):not(.chip):not(.micro):enabled:hover { background:var(--fond-doux); border-color:var(--accent); color:var(--accent-texte); }
/* Composants, lot D : le monogramme rond d'une voiture dans une rangée (les voitures présentes d'un lieu) est l'initiale de la marque, que le nom redit aussitôt : il se retire, comme celui des rangées d'échéance (lot C), et la rangée repart du fer. */
.dashboard-app .lot-main .filet-row>.monogram:first-child { display:none; }
.dashboard-app .lot-main .filet-row:has(>.monogram:first-child) { padding-left:var(--debord,0px); }
/* Composants, lot D : la relecture d'une analyse. Le titre d'un point (bloc `.panel`) se compose en famille d'apparat, comme le titre d'une rubrique ; le titre du rapport prend le corps d'un titre de page (29 px, 26 au téléphone).
   Les sources : douze boutons de 44 px au pied d'une analyse des coûts se lisaient comme douze gestes. Une liste de liens discrets sur des filets (deux colonnes au-delà du téléphone, une au téléphone), chacun dans une cible de 44 px, souligné fin ; la source sans adresse reste une ligne à l'encre secondaire.
   Les en-têtes des postes : petites capitales au laiton (pièce 6). Le repli des postes restants : la forme du bloc repliable, sans capitales espacées. */
.dashboard-app main.content .panel>h2:not([class]) { font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:22px; font-weight:500; letter-spacing:0; line-height:1.2; }
.dashboard-app main.content .rapport-titre { font-size:29px; line-height:1.15; }
.dashboard-app .rapport-sources { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:0 30px; padding-top:0; margin-top:10px; }
.dashboard-app .rapport-sources .chip { justify-content:flex-start; min-width:0; min-height:44px; padding:10px 0; border:0; border-bottom:1px solid var(--hair-2); border-radius:0; background:none; font-weight:500; text-align:left; overflow-wrap:anywhere; }
.dashboard-app .rapport-sources a.chip { text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:4px; }
.dashboard-app .rapport-sources a.chip:hover { border-color:var(--hair-2); background:none; color:var(--ink); text-decoration-thickness:2px; }
.dashboard-app .rapport-postes>.tete { color:var(--laiton); font-size:11px; font-weight:600; letter-spacing:.07em; text-transform:uppercase; border-bottom-color:var(--hair-2); }
.dashboard-app .rapport-suite summary { font-size:14px; letter-spacing:0; text-transform:none; }
@media (max-width:720px) {
  .dashboard-app main.content .rapport-titre { font-size:26px; }
  .dashboard-app .rapport-sources { grid-template-columns:minmax(0,1fr); }
}
/* Composants, lot D : la page de connexion, la vérification du second facteur et le verrou (pages hors session qui étendent l'habit commun, spec 6, décision 2) prennent les pièces de la planche. Plus de panneau : le formulaire se pose sur la page, sous le filet qui le sépare de la couronne. Le titre en famille d'apparat (29 px, son terme en italique à l'accent lisible), la devise en surtitre au laiton de 11 px, le champ cerné du filet des champs, l'envoi à sa largeur, au fer droit, sur le filet du pied. Une erreur se dit dans la forme des erreurs de champ. */
.cover form,.cover .verrou { padding:24px 0 0; border-top:1px solid var(--hair-2); background:none; }
.cover form + form { margin-top:16px; padding-top:0; border-top:0; }
.cover :is(form,.verrou) h1 { margin:0 0 18px; font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:29px; font-weight:500; line-height:1.15; letter-spacing:0; }
.cover h1 em { color:var(--accent-texte); font-style:italic; font-weight:400; }
.cover .devise { color:var(--laiton); font-size:11px; font-weight:600; letter-spacing:.07em; line-height:1.5; text-transform:uppercase; }
.cover form button[type=submit] { width:auto; }
.cover .form-actions { display:flex; justify-content:flex-end; margin-top:24px; padding-top:24px; border-top:1px solid var(--hair-2); }
.cover form + form { display:flex; justify-content:flex-end; }
.cover form + form button[type=submit] { background:transparent; border-color:var(--filet-champ); color:var(--accent-texte); }
.cover form + form button[type=submit]:hover { background:var(--fond-doux); border-color:var(--accent); }
.cover .errorlist { margin:0 0 4px; padding:0; list-style:none; color:var(--danger); font-size:11px; line-height:1.6; }
.cover form:has([aria-invalid=true]) label { color:var(--danger); }
/* Composants, lot D : la bande des chiffres du bilan et de la fiche d'un intervenant ne rogne plus rien. Elle débordait de 23 px à gauche et rognait ce débord (`clip-path`) pour sortir de la vue le filet de la première case de chaque rangée : un contour de focus y aurait été rogné avec lui. La bande reste au fer. Une case part du fer, sans filet à sa gauche ; le filet vertical se pose sur les cases qui suivent la première de leur rangée : les cases paires sur deux colonnes (fenêtre de 360 à 1 150 px, impression ; au-delà, bande de 480 px), toutes sauf la première sur une rangée (bande de 720 px). Qui ignore les requêtes de conteneur lit la bande sans filets verticaux. */
.dashboard-app .dashboard-metrics { margin-left:0; clip-path:none; container:chiffres / inline-size; }
.dashboard-app .dashboard-card.metric { padding-left:0; border-left:0; }
@media (min-width:1151px) {
  @container chiffres (min-width:480px) { .dashboard-app .dashboard-card.metric:nth-child(even) { padding-left:22px; border-left:1px solid var(--hair-2); } }
  @container chiffres (min-width:720px) { .dashboard-app .dashboard-card.metric:not(:first-child) { padding-left:22px; border-left:1px solid var(--hair-2); } }
}
@media (min-width:360px) and (max-width:1150px),print { .dashboard-app .dashboard-card.metric:nth-child(even) { padding-left:22px; border-left:1px solid var(--hair-2); } }
/* Un tableau empilé au téléphone (bilan, lecture des sorties) range chaque valeur au fer droit de sa ligne : la réserve de 32 px qui écarte deux colonnes de nombres n'y a plus d'emploi, et trois valeurs s'arrêtaient en retrait des autres. */
@media (max-width:600px) { .dashboard-app .tableau-empile :is(th,td).nombre:not(:last-child) { padding-right:0; } }
/* Le journal des accès range sa liste dans un bloc : sous l'en-tête de page elle suit le filet de l'en-tête, comme toute liste, sans en tracer un second. */
.dashboard-app .bandeau-court+.analyses>.feuille:first-child { border-top:0; }
/* Un message de page posé au-dessus d'un en-tête : son filet ne touche plus le surtitre. */
.dashboard-app main.content>.flash+:is(header.bandeau-court,h1) { margin-top:22px; }
/* La fiche : son surtitre est une cible de 44 px remontée de 15 px ; 16 px suffisent à le détacher du filet, et le premier écran du téléphone garde ses gestes au-dessus de la barre du bas (revue du lot B). */
.dashboard-app main.content>.flash+header.bandeau-arc { margin-top:16px; }
/* La carte des sorties (feuille tierce Leaflet, vendor/leaflet) : l'épingle sans ombre, le contrôle de zoom au coin de 3 px, la bulle et l'infobulle cernées d'un filet, sans ombre ni grand rayon. */
.dashboard-app .carte .epingle span { box-shadow:none; }
.dashboard-app .carte.leaflet-container .leaflet-bar { border-radius:var(--r-vif); }
.dashboard-app .carte .leaflet-bar a:first-child { border-top-left-radius:var(--r-etiquette); border-top-right-radius:var(--r-etiquette); }
.dashboard-app .carte .leaflet-bar a:last-child { border-bottom-left-radius:var(--r-etiquette); border-bottom-right-radius:var(--r-etiquette); }
.dashboard-app .carte :is(.leaflet-popup-content-wrapper,.leaflet-tooltip) { border:1px solid var(--hair-2); border-radius:var(--r-vif); box-shadow:none; }
.dashboard-app .carte .leaflet-popup-tip { box-shadow:none; }
/* À l'impression un geste discret de la fiche reste un lien souligné, sans la boîte que la règle d'impression rend aux boutons. */
@media print { body.dashboard-app .fiche-gestes .btn:nth-child(n+3) { border-color:transparent; } }
/* Composants, lot D : finitions de la tournée.
   Le lien d'un titre de rubrique (« + ajouter », « + rattacher ») et le lien de fin d'une rangée (« Télécharger ») se lisent à l'accent, comme sur la fiche d'une voiture : à l'encre ils se confondaient avec le texte.
   Le titre d'un groupe de la marge d'un dossier (« Dossier », « Inscription », « Sommes enregistrées ») et le libellé d'une rangée de clôture de « Ajouter » sont des surtitres : petites capitales au laiton, 11 px. */
.dashboard-app .section-title .compte a,.dashboard-app .filet-row .sub.end>a:not(.btn):not(.micro) { color:var(--accent-texte); }
.dashboard-app .ajouter-rangee>.micro { color:var(--laiton); font-family:var(--sans); font-size:11px; font-weight:600; letter-spacing:.07em; line-height:1.5; text-transform:uppercase; }
/* Sous l'en-tête de page la bande des chiffres ouvre par ses propres filets, que l'en-tête traçait une seconde fois 25 px au-dessus : la bande remonte sur le filet de l'en-tête, les deux se confondent. */
.dashboard-app .bandeau-court:has(+.dashboard-metrics) { margin-bottom:0; }
.dashboard-app .bandeau-court+.dashboard-metrics { margin-top:-1px; }
/* Les mentions légales, page publique de l'habit commun : ses titres en famille d'apparat (ils tombaient dans la serif du système), le terme du titre en italique à l'accent lisible, le retour en lien discret. */
.plaque-legal h1,.plaque-legal h2 { font-family:var(--apparat); font-variant-numeric:lining-nums; font-weight:500; letter-spacing:0; }
.plaque-legal h1 { margin:0 0 6px; font-size:29px; line-height:1.15; }
.plaque-legal h1 em { color:var(--accent-texte); font-style:italic; font-weight:400; }
.plaque-legal h2 { font-size:22px; line-height:1.2; }
.plaque-legal .plaque-pied.micro { font-size:12px; letter-spacing:0; text-transform:none; }
.plaque-legal .plaque-pied a { display:inline-flex; align-items:center; min-height:44px; color:var(--accent-texte); font-weight:600; text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:4px; }
@media (max-width:720px) { .plaque-legal h1 { font-size:26px; } }
/* Le rattachement d'un entretien à son intervenant (onglet Entretien de la fiche), répété à chaque rangée : son envoi est secondaire, comme tout envoi de rangée. */
.dashboard-app .ligne-rattachement button[type=submit]:not(.btn-primary):not(.btn-danger):not(.trait):not(.chip):not(.micro):enabled { background:transparent; border-color:var(--filet-champ); color:var(--accent-texte); }
.dashboard-app .ligne-rattachement button[type=submit]:not(.btn-primary):not(.btn-danger):not(.trait):not(.chip):not(.micro):enabled:hover { background:var(--fond-doux); border-color:var(--accent); color:var(--accent-texte); }
/* Composants, revue du lot C. */
/* Le tableau de chiffres : la première cellule d'une rangée en est l'en-tête (`th scope="row"` : la voiture du registre des vendus, le compte du suivi IA). Elle garde la forme d'une cellule de texte, à l'encre, en demi-gras léger (planche, `.c-table tbody th`). */
.dashboard-app table tbody th { color:var(--ink); font-size:12px; font-weight:500; letter-spacing:0; text-align:left; text-transform:none; }
/* Le registre des vendus défile dans son cadre (spec, pièce 6 ; planche, `min-width: 680px`) : au téléphone il serrait ses colonnes dans la largeur de l'écran, le nom d'une voiture sur trois lignes et un montant dans 54 px. À 680 px le nom tient une ligne ou deux et chaque nombre la sienne ; la colonne du nom tient 46 % du tableau (planche : 30 %) : un nom de 70 signes y tient en deux lignes, et la date de vente s'amorce au bord du premier écran du téléphone, signe que le tableau continue. */
.dashboard-app .registre table { min-width:680px; }
.dashboard-app .registre :is(thead th:first-child,tbody th) { width:46%; }
/* La collection en cartes : quatre par rangée au-delà de 1600 px de fenêtre (à 1920 px trois cartes de 540 px allongeaient la page de 19 %), trois jusque-là. */
@media (min-width:1601px) { .dashboard-app .entries[data-presentation=cartes] { grid-template-columns:repeat(4,minmax(0,1fr)); } }
/* Les résultats de la recherche : le lien du titre s'étend à sa rangée entière (lien étiré), sans rien peindre ; la mention de droite reste du texte. */
.dashboard-app ul.feuille.resultats>li { position:relative; }
.dashboard-app ul.feuille.resultats>li>a::after { content:""; position:absolute; inset:0; }
/* Le titre d'un bloc de la marge d'une fiche (« Inscription » d'une sortie, « Dossier » d'un sinistre, « Assurance » d'un prêt) : un titre de bloc, dans la forme des blocs de la marge de la fiche d'une voiture (famille d'apparat à chiffres droits, 21 px, à l'encre, sur un filet). */
.dashboard-app .lot-aside h2.micro { margin:0; padding:0 0 10px; border-bottom:1px solid var(--hair-2); color:var(--ink); font-family:var(--apparat); font-variant-numeric:lining-nums; font-size:21px; font-weight:500; letter-spacing:0; line-height:1.15; text-transform:none; }
/* Un bloc vide d'une fiche est compact (spec, pièce 10 : le dessin au trait centré est réservé à l'état vide d'une PAGE, la liste principale sous son en-tête). Dans le corps d'une fiche (`.lot`) : le titre du bloc, puis la phrase d'état à l'encre secondaire, au fer du titre, à 12 px sous lui (la marge du titre), sans dessin, à la forme des phrases d'état d'une sortie (`_vide.html`, `ligne`, que la routine d'hivernage emploie pour chacun de ses blocs). Un lieu vide alignait six dessins sur 1 996 px. */
.dashboard-app .lot .vide { flex-direction:row; flex-wrap:wrap; align-items:baseline; justify-content:flex-start; gap:0 6px; margin:0 0 1em; padding:0; font-size:.85rem; text-align:left; }
.dashboard-app .lot .vide>.gravure { display:none; }
.dashboard-app .lot td>.vide { margin:0; }
/* La phrase d'état écrite en clair dans sa feuille (« Aucun sinistre ouvert. ») prend la même forme : sans filet entre le titre et elle. Sa propre règle : un sélecteur à `:has()` invalide la liste entière chez qui l'ignore. */
.dashboard-app .lot .feuille:has(>p.muted:only-child) { border-top:0; }
.dashboard-app .lot .feuille>p.muted:only-child { margin-top:0; }
/* Composants, revue du lot D : les pieds d'un même écran. Le bouton qui FERME un formulaire ou un écran est à droite, sur son filet ; le bouton d'ajout d'une liste (« Ajouter » un pilote, « Ajouter des traces » : formulaire `ajout-de-liste`) est secondaire, au fer gauche de sa liste, par la règle des envois de rangée. Le geste plein qui ferme un écran sans formulaire (« Activer » de Sécurité, « Continuer » des codes de secours : un lien-bouton seul dans son paragraphe, à même le contenu) prend la forme du pied. Sa propre règle : un sélecteur à `:has()` invalide la liste entière chez qui l'ignore, et le bouton reste alors à gauche. */
.dashboard-app main.content>p:has(>a.btn.btn-primary:only-child) { display:flex; justify-content:flex-end; max-width:none; margin-top:24px; margin-bottom:0; padding-top:24px; border-top:1px solid var(--hair-2); }
/* Composants, revue du lot D : l'envoi d'un groupe de la marge (« Rouvrir le sinistre ») prend la carrure de son voisin, le bouton d'une case de la marge (« Modifier », un bloc de toute la largeur, app.css), à 8 px de lui. */
.dashboard-app .lot-aside .aside-groupe>form>button[type=submit] { display:block; width:100%; margin-top:8px; text-align:left; }
/* Composants, revue du lot D : l'état vide d'une page (pièce 10) se centre dans le contenu, sur tous les écrans. Posé à même le contenu, il prenait la borne de lecture d'un paragraphe (78 caractères, app.css) et se centrait à 130 px de l'axe des états vides portés par une feuille (analyses, sorties, coffre). */
.dashboard-app main.content>p.vide { max-width:none; }
/* Composants, revue du lot D : le lien discret a sa classe. Tout lien d'action d'un écran connecté qui n'est ni un bouton, ni une rangée, ni un lien dans une phrase (« + ajouter une observation », « Modifier » du carnet, « Retour à la fiche véhicule », « Retour au lieu », le nom d'un intervenant ou d'un lieu dans la marge d'une fiche) se lisait à l'encre, sans soulignement, comme du texte. Forme du discret du lot A : à l'accent lisible, souligné fin au repos (1 px, écarté de 4 px), 2 px et l'encre au survol. Il garde le corps et la graisse du texte qui le porte. (0,2,1) au repos, au poids de `.dashboard-app a`, devant elle par sa place ; (0,3,1) au survol. */
.dashboard-app a.lien-discret,.cover a.lien-discret { color:var(--accent-texte); text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:4px; }
.dashboard-app a.lien-discret:hover,.cover a.lien-discret:hover { color:var(--ink); text-decoration-thickness:2px; }
/* À l'impression les gestes se retirent : les boutons d'un en-tête et de la fiche, les renvois, le formulaire de filtre, les choix inactifs d'une barre de filtres (le filtre et le tri courants restent : ils disent ce que la page imprimée contient), la pagination. */
@media print { body.dashboard-app :is(.bandeau-gestes,.bandeau-renvois,.fiche-gestes,.fiche-navette,.collection-filters,nav.pagination,.filtrage a:not([aria-current])) { display:none; } }
/* Revue du lot D : la fiche imprimait encore sa barre d'onglets et les liens d'ajout de ses titres de bloc (`ajout` : le lien et le point médian qui le suit), la collection son renvoi vers l'échéancier. Le compte d'un titre de bloc reste. */
@media print { body.dashboard-app :is(nav.tabs,.section-title .compte .ajout,.dashboard-section-head>a) { display:none; } }
