/* ============================================================
   ERP+ : Composants (CANONIQUE V1.3)

   Issu du split de brand.css par périmètre (DA15, socle 372, refs 364). Ce
   fichier porte les composants .erp-* (couche composant pure DA9, sur tokens).
   Les tokens sont dans erp-tokens.css ; la typo de base dans erp-typography.css.
   Ordre de chargement : tokens, typography, components.

   Composants atomiques V1.3 : btn, link, card, eyebrow, kpi, table (deja en
   prod) ; link, status, chip, alert, toast, field, footer (portes du kit V1.3,
   section "Composants atomiques V1.3" plus bas). Catalogue : docs/design/
   CATALOGUE_V1.3.md. Aucun composant n'est applique a une surface live au socle.
   ============================================================ */

/* Reset socle (DA16) : box-sizing global, lie au trio (charge par home, auth,
   legal). Les coquilles ne le re-declarent plus. admin.css (pages statiques hors
   trio) conserve le sien. Chaine Cerfa-PDF isolee (erp_template.html ne lie pas
   le trio, R-REG-D1/D2). box-sizing uniquement, pas de reset margin/padding. */
*, *::before, *::after { box-sizing: border-box; }

/* ============================================================
   Iconographie (RESTITUTION du kit, verdict 184, article R184.1)

   Le kit declare ce paragraphe en tete de docs/design/system-v1.3/system/
   system.css, dans la feuille meme qui porte .erp-alert__icon. L'eclatement de
   cette feuille unique en trois feuilles de socle (tokens, typography,
   components) ne l'a portee dans aucune des trois : la declaration existait au
   kit, la production ne l'a pas recue, et le defaut ne se voyait ni au kit, qui
   la porte, ni au catalogue, qui charge la feuille d'origine. Il ne se voyait
   que comme rendu casse sur les surfaces servies, dont une jamais rendue a
   personne.

   Les valeurs ne sont pas decidees ici, elles sont RECOPIEES du kit : 18 px de
   base, 14 px en --sm, 22 px en --lg, et le reste de la regle avec.

   Difference de portage assumee, et elle ne touche pas la regle : le kit
   commente un sprite (#i-NOM injecte par system/icons.js), que la production
   n'emploie pas. Les glyphes y sont des SVG Lucide inline, stroke=currentColor
   (DA19). Le commentaire est donc ecrit pour la production ; les quatre regles
   sont celles du kit, a l'identique.

   Rang : ce paragraphe est le premier du kit et le reste ici. Il precede
   .erp-icon-disc, qui dimensionne ses propres pictos par `.erp-icon-disc svg`
   (0,1,1) et l'emporte donc sur la classe seule (0,1,0), quel que soit l'ordre.

   PORTEE (verdict 185, amendement de R184.1). La regle est ecrite sur la CLASSE
   SEULE, aux trois niveaux, comme au kit. Ecrite `svg.erp-ic`, elle
   restreignait sa portee a un type d'element, et une declaration dont la portee
   n'atteint pas l'usage ne rend pas cet usage correct. L'elargissement ne
   change aucun rendu servi : la classe ne nomme plus qu'un glyphe, aux 47 sites
   de gabarit du depot. Ce qui la portait sans en etre un a ete corrige a l'acte
   trois, et c'est pourquoi l'elargissement passe apres lui et non avant.
   ============================================================ */
.erp-ic {
  width: 18px; height: 18px; flex: none; display: inline-block;
  vertical-align: -3px; fill: none; stroke: currentColor;
}
.erp-ic--sm { width: 14px; height: 14px; }
.erp-ic--lg { width: 22px; height: 22px; }
svg.erp-ic use { pointer-events: none; }

/* ============================================================
   Surfaces
   ============================================================ */

.erp-page          { background: var(--page-bg); color: var(--erp-fg-2); font-family: var(--erp-font-sans); }
.erp-surface-marine{ background: var(--erp-marine); color: var(--erp-fg-on-marine); }
.erp-surface-cream { background: var(--erp-cream);  color: var(--erp-fg-2); }
.erp-surface-white { background: var(--erp-white);  color: var(--erp-fg-2); }

/* ============================================================
   Eyebrow (marqueur identitaire)
   ============================================================ */

.erp-eyebrow {
  /* Marqueur identitaire inviolable : UPPERCASE, tracking 0.2em, terracotta,
     PAS de pilule de fond. Sur fond clair : terracotta-text (AA texte 12px). */
  font-family: var(--erp-font-sans); font-weight: 600;
  font-size: var(--t-eyebrow); line-height: 1;
  letter-spacing: var(--t-eyebrow-track); text-transform: uppercase;
  color: var(--erp-terracotta-text); margin: 0;
}
/* Sur fond marine : terracotta-lt (saumon) */
.erp-on-marine .erp-eyebrow,
.erp-eyebrow--on-marine { color: var(--erp-terracotta-lt); }

/* ============================================================
   KPI (chiffre serif terracotta)
   ============================================================ */

.erp-kpi   { font-family: var(--erp-font-serif); font-weight: 500; font-size: var(--t-kpi); line-height: 1; color: var(--erp-terracotta); letter-spacing: -0.01em; }

/* ============================================================
   Card (filet terracotta vertical 3x32 px à gauche)
   ============================================================ */

.erp-card {
  position: relative; background: var(--card-bg);
  border-radius: var(--card-radius);
  padding: var(--card-padding);
  box-shadow: var(--shadow-2);
  border: 1px solid color-mix(in srgb, var(--erp-marine) 6%, transparent);
}
.erp-card::before {
  content: ""; position: absolute; left: 0; top: var(--sp-6);
  width: var(--card-accent-w); height: var(--card-accent-h);
  background: var(--card-accent);
}
.erp-card--marine {
  background: var(--erp-marine); color: var(--erp-fg-on-marine);
  border-color: var(--erp-rule-marine); box-shadow: none;
}
.erp-card--marine::before { background: var(--erp-terracotta); }
/* Carte statique : aucune transition de transformation, aucune transformation au
   survol, aucune entree animee. L'effet d'elevation appartient aux cartes qui sont
   elles memes l'unique cible de clic, et sert alors a designer cette cible. Un
   assemblage composite, pleine largeur et porteur de plusieurs cibles, n'a pas de
   cible unique a designer : il ne se souleve pas et n'entre pas en echelle. La
   bande unitaire de la section Tarifs porte la meme classe.
   La neutralisation vaut aussi pour les enfants directs, l'entree animee des
   coquilles se posant en deux temps, le cadre puis son contenu.
   Les deux classes sont jointes a dessein : les feuilles de coquille se chargent
   apres ce socle et y reposent l'elevation a specificite egale, qu'un simple
   .erp-card--static perdrait par ordre de source.

   LIMITE DU MODIFICATEUR, a connaitre avant de s'y fier (portee au socle au lot
   E de #479, due depuis trois lots). La neutralisation du survol tient, sa paire
   .erp-card.erp-card--static:hover valant 0,3,0 contre 0,2,0 pour l'elevation de
   coquille. Celle de l'entree animee NE TIENT PAS de la meme facon : l'etat
   d'entree est pose par des selecteurs de descendance a trois classes, du type
   .has-reveal .reveal .erp-card > * de chrome-marketing.css, soit 0,3,0 contre
   0,2,0 pour .erp-card.erp-card--static > * ci-dessous. Le selecteur de
   descendance l'emporte. Conclusion a retenir telle quelle : si le porteur de
   .erp-card--static est lui aussi place sous un ancetre portant la classe
   d'entree animee, le modificateur ne neutralise que le survol. La parade n'est
   pas de surenchérir en specificite ici, c'est de ne pas poser la classe
   d'entree sur un assemblage composite, ce que les verdicts 42 et 37 imposent
   deja par ailleurs. */
.erp-card.erp-card--static,
.erp-card.erp-card--static:hover {
  transform: none;
  transition: none;
  animation: none;
}
.erp-card.erp-card--static > * {
  transform: none;
  transition: none;
  opacity: 1;
}

/* ============================================================
   Numbered badge (cercle plein terracotta)
   ============================================================ */

.erp-numbadge {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px;
  border-radius: 50%;  /* exception cercle déclarée */
  background: var(--erp-terracotta); color: var(--erp-white);
  font-family: var(--erp-font-sans); font-weight: 600; font-size: 14px; line-height: 1;
}
.erp-numbadge--lg { width: 40px; height: 40px; font-size: 18px; }

/* ============================================================
   Buttons (aplats nets)
   ============================================================ */

.erp-btn {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-family: var(--erp-font-sans); font-weight: 600;
  font-size: 15px; line-height: 1;
  padding: 14px 22px;
  border: 0; border-radius: var(--radius-2);
  cursor: pointer; transition: background-color 120ms ease;
  text-decoration: none;
}
.erp-btn--primary { background: var(--erp-terracotta); color: var(--erp-white); }
.erp-btn--primary:hover { background: var(--erp-terracotta-dk); }
.erp-btn--marine  { background: var(--erp-marine); color: var(--erp-cream); }
.erp-btn--marine:hover  { background: var(--erp-marine-soft); }
.erp-btn--ghost {
  background: transparent; color: var(--erp-marine);
  padding: 14px 0; border-bottom: 1px solid var(--erp-marine);
  border-radius: 0;
}
.erp-btn--ghost:hover { color: var(--erp-terracotta); border-bottom-color: var(--erp-terracotta); }

/* ============================================================
   PRIMITIVE DE FOCUS, verdict 92. Point unique de decision.
   Avant ce verdict il n'y avait pas de primitive : il y avait une FORME et
   vingt-six copies litterales de cette forme, reparties sur sept feuilles. Une
   forme copiee n'a pas de doctrine, elle a une habitude, et c'est ce qui rendait
   la question d'accessibilite impossible a instruire, faute d'un endroit unique
   ou poser la decision. Le registre paie une fois le prix de la constitution.
   L'encre se qualifie par FAMILLE DE FOND, verdict 90 : deux familles, deux
   encres, un seul dessin. La regle est portee par la SURFACE et non par le
   composant, un bouton ne sachant pas sur quel fond il est pose : c'est le
   mecanisme du verdict 82, reemploye tel quel.
   Le dessin n'est pas touche : 2 px, solid, decalage de 2 px. Le decalage
   negatif reste licite la ou il est deja employe, item de rail, jour de
   calendrier, onglet de code : il releve du sertissage et non de l'encre.

   RECETTE OPPOSABLE, verdict 92 amende par le verdict 96 :
   AUCUNE DECLARATION outline NE NOMME UNE ENCRE, QUELLE QU'ELLE SOIT. Seul
   var(--erp-focus-ring) y figure.
   La formulation precedente nommait un jeton, "toute occurrence litterale de
   terracotta clair", et elle laissait donc passer les deux regles en creme. Une
   recette qui nomme un jeton au lieu de nommer une propriete se contourne par
   n'importe quel autre jeton : c'est la quatrieme occurrence du meme defaut,
   apres les verdicts 84, 87 et 91, et la premiere dans une formule de recette.

   VERDICT 97 AMENDE PAR LE VERDICT 106, regle generale opposable : outline: 0 et
   outline: none ne sont licites que si LE MEME ELEMENT, DANS LE MEME ETAT, REND
   UN INDICATEUR DE FOCUS MESURABLE, ou que soit ecrite la declaration. Le test
   est le suivant, et il est le seul : on porte le focus sur l'element, on mesure
   ce qu'il rend. La localisation de la declaration n'entre pas dans le test ;
   l'etat, lui, y entre entierement. Un substitut porte par un DESCENDANT vaut
   substitut, des lors que l'element focalise est celui qui recoit le focus et que
   l'indicateur est visible a son niveau.
   La formulation precedente exigeait le substitut DANS LA MEME REGLE. Elle est
   RETIREE : elle decrivait ou le code est ecrit, non ce que l'element rend, et le
   releve a produit un cas de chaque cote. Elle condamnait .erp-toggle:focus-visible,
   conforme au rendu par son .erp-toggle__track ; elle sauvait a tort
   app-dashboard.css:161, dont le substitut couvre :focus quand l'etat supprime est
   :focus-visible. Un critere de localisation ecrit pour un defaut de rendu, parce
   que la localisation est facile a verifier en lisant.
   Une suppression sans substitution reste un defaut, quelle que soit sa date. Une
   primitive qu'une regle de composant peut neutraliser par specificite n'est pas
   une primitive, c'est une valeur par defaut.
   ============================================================ */
:root { --erp-focus-ring: var(--erp-terracotta); }
/* VERDICT 101 : la liste est PEUPLEE de ce que la mesure etablit, jamais de ce
   qu'on suppose, et chaque selecteur porte son compte d'elements focalisables a
   la date du releve, etat 605c52d, huit surfaces visitees.
     .erp-on-marine      3 conteneurs,  1 element
     .sidenav            4 conteneurs, 20 elements
     .erp-footer         2 conteneurs, 24 elements
     .topnav--marine     2 conteneurs, 16 elements   AJOUTEE
     .atelier__header    2 conteneurs,  5 elements   AJOUTEE
   .topbar--marine est RETIREE : zero conteneur, zero element, sa seule
   occurrence dans le depot etait cette ligne meme. Un selecteur a zero element
   est un defaut de la liste, pas un vide anodin : il faisait passer la recette
   au vert sur un depot portant une surface hors dispositif.
   .proof-band n'est PAS ajoutee, et le motif est mesure : surface marine, mais
   zero element focalisable. Elle n'a rien a atteindre.
   Un composant qui peint son propre fond marine, .erp-btn--marine par exemple,
   n'est pas une surface : son anneau est pose a 2 px HORS de lui, donc sur la
   surface qui l'entoure, et c'est l'encre de cette surface qui doit s'appliquer.
   AUCUNE ENCRE N'ENTRE DANS CETTE CORRECTION. Le lien de la barre de navigation
   ne portait pas une encre fautive : il portait l'encre par defaut parce que la
   surcharge marine ne l'atteignait pas. */
.erp-on-marine,
.sidenav,
.erp-footer,
.topnav--marine,
.atelier__header { --erp-focus-ring: var(--erp-terracotta-lt); }
:focus-visible { outline: 2px solid var(--erp-focus-ring); outline-offset: 2px; }

/* Bouton de plein rang sur surface marine (#479 lot E, verdict 37 et son
   arbitrage du 29/07). Le socle n'offrait que --marine (plein marine, invisible
   sur marine), --ghost (texte et soulignement, trop faible face au plein d'en
   face) et le lien --on-marine, qui n'est pas un bouton. Ce modificateur ne crée
   aucun token : il recombine --erp-cream, --erp-cream-deep et --erp-marine.
   Repos transparent à filet crème, survol inversé en plein crème sur texte
   marine. Le survol est un changement de couleur PUR : aucune transformation,
   ni translation ni échelle, contrainte de report du verdict 37 reprise par le
   verdict 42. L'appui pousse le remplissage à --erp-cream-deep et garde le
   texte marine ; il ne revient jamais au transparent, un bouton qui se vide
   sous le doigt se lisant comme un relâchement. */
.erp-btn--on-marine {
  background: transparent;
  color: var(--erp-cream);
  border: 1px solid var(--erp-cream);
  transition: background-color 120ms ease, color 120ms ease;
}
.erp-btn--on-marine:hover {
  background: var(--erp-cream);
  color: var(--erp-marine);
}
.erp-btn--on-marine:active {
  background: var(--erp-cream-deep);
  color: var(--erp-marine);
}
/* Anneau de focus de la surface marine. L'outline est préféré à l'ombre que la
   feuille de jetons autorise ailleurs : une diffusion se délaye dans le marine.
   Le décalage de 3 px pose l'anneau HORS du filet de 1 px du bouton, séparé de
   lui par 3 px de marine, il se lit donc comme un anneau et non comme un
   épaississement du bord. Cette règle suit .erp-btn:focus-visible dans l'ordre
   de source, à spécificité égale : c'est elle qui prend sur cette surface.
   VERDICT 96 : l'encre creme tombe au profit du jeton. Le creme sur marine
   n'ouvrait pas une troisieme famille de fond, il posait une TROISIEME ENCRE sur
   une famille qui en a deja une, ce que le verdict 90 ferme. Le motif ecrit
   ci-dessus reste juste, mais c'est un motif de FORME arrive dans une
   declaration d'encre : un composant ne paie pas un probleme de forme avec une
   encre. Le sertissage est deja servi par le decalage de 3 px, qui pose l'anneau
   hors du filet, et cette separation est geometrique : elle n'a pas besoin d'une
   seconde encre pour se lire. LE DECALAGE DE 3 PX N'EST PAS TOUCHE. */
.erp-btn--on-marine:focus-visible {
  outline: 2px solid var(--erp-focus-ring);
  outline-offset: 3px;
}
/* Seul emploi de l'opacité admis par le socle. Ni filet ni remplissage ne
   changent : sur marine, le crème atténué reste au-dessus du seuil AA, la
   surface sombre travaillant en sa faveur. */
.erp-btn--on-marine:disabled,
.erp-btn--on-marine[aria-disabled="true"] {
  opacity: 0.6;
}

/* ============================================================
   Bandeaux pleins (claim uniques)
   ============================================================ */

.erp-bandeau {
  padding: var(--sp-7); font-family: var(--erp-font-serif); font-weight: 500;
}
.erp-bandeau--marine     { background: var(--erp-marine);     color: var(--erp-cream); }
.erp-bandeau--terracotta { background: var(--erp-terracotta); color: var(--erp-white); }

/* ============================================================
   Pagination presse "N / total"
   ============================================================ */

.erp-page-num {
  font-family: var(--erp-font-sans); font-size: 12px;
  letter-spacing: 0.06em; color: var(--erp-fg-4);
}

/* ============================================================
   Icon disc (cercle plein terracotta avec picto blanc Lucide)
   ============================================================ */

.erp-icon-disc {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  border-radius: 50%;  /* exception cercle déclarée */
  background: var(--erp-terracotta); color: var(--erp-white);
}
.erp-icon-disc svg { width: 20px; height: 20px; }
.erp-icon-disc--lg     { width: 56px; height: 56px; }
.erp-icon-disc--lg svg { width: 26px; height: 26px; }

/* ============================================================
   Tables (registre éditorial)
   ============================================================ */

.erp-table {
  width: 100%; border-collapse: collapse;
  font-family: var(--erp-font-sans); font-size: 14px;
}
.erp-table th {
  text-align: left; font-weight: 600; font-size: 12px;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--erp-fg-3); padding: 10px 12px;
  border-bottom: 1px solid var(--erp-rule-strong);
}
.erp-table td {
  padding: 12px; border-bottom: 1px solid var(--erp-rule); color: var(--erp-fg-2);
}

/* ============================================================
   Composants atomiques V1.3 (portes du kit docs/design/system-v1.3/,
   sur tokens). Aucun n'est applique a une surface live au socle 372 :
   ils sont disponibles pour les coquilles M2-M4.
   ============================================================ */

/* ---- Liens et fleches ---- */
/* DOMAINE : le chrome (navigation, pieds, cartes, appels a l'action).
   Verdict 273 : ce dispositif ne sert JAMAIS un lien pris dans un texte
   suivi ; la prose a son propre dispositif, .erp-text-link ci-dessous.
   Aucune classe ne porte les deux. */
.erp-link {
  font-family: var(--erp-font-sans); font-weight: 500; font-size: 15px;
  color: var(--erp-marine); text-decoration: none;
  border-bottom: 1px solid var(--erp-marine); padding-bottom: 2px;
  display: inline-flex; align-items: baseline; gap: 6px;
  transition: color 120ms ease, border-color 120ms ease;
}
.erp-link:hover { color: var(--erp-terracotta-dk); border-color: var(--erp-terracotta-dk); }
.erp-link .erp-arrow { font-family: var(--erp-font-serif); transition: transform 120ms ease; }
.erp-link:hover .erp-arrow { transform: translateX(3px); }
.erp-link--on-marine { color: var(--erp-terracotta-lt); border-color: var(--erp-terracotta-lt); }
.erp-link--on-marine:hover { color: var(--erp-fg-on-marine); border-color: var(--erp-fg-on-marine); }
/* Report du verdict 37 : le meme anneau que .erp-btn--on-marine, sur le lien qui
   n'en avait aucun. Une surface ne peut pas porter deux idiomes de focus, et
   cette definition depasse la bande unitaire : elle etablit l'idiome de focus de
   la surface marine pour tout le socle. Le primitif est partage, l'en-tete
   marketing le porte sur Connexion et sur Deconnexion. */
/* Verdict 96, meme motif qu'au bouton : l'encre passe au jeton, le decalage de
   3 px reste. */
.erp-link--on-marine:focus-visible {
  outline: 2px solid var(--erp-focus-ring);
  outline-offset: 3px;
}
.erp-link--quiet { color: var(--erp-fg-3); border-color: transparent; }
.erp-link--quiet:hover { color: var(--erp-terracotta-dk); border-color: transparent; }

/* ---- Lien de texte (dispositif de prose, verdicts 273 a 276) ----
   DOMAINE : le texte suivi. Un lien pris dans une phrase est un etat du
   texte, pas un objet : il herite le corps, la graisse, la famille,
   l'interligne et l'encre de son texte porteur, et ne declare que ce qui
   le signale (article R275.1). Ce dispositif n'est PAS une variante de
   .erp-link, qui garde le chrome : aucune classe ne porte les deux.
   Le soulignement est une decoration de texte, retrait 2 px : il suit la
   coupure de ligne, ce qu'un bord de boite ne sait pas faire (verdict
   274). La coupure a l'interieur d'un mot n'est permise qu'au mot que la
   colonne ne peut pas contenir (overflow-wrap: break-word, seule
   declaration non heritee du texte, due a la nature des libelles).
   L'encre au repos s'ecrit inherit, comme au precedent .erp-legal-strip a :
   sans elle un lien rend l'encre d'agent utilisateur, pas celle du texte.
   Le dispositif nait avec son anneau : idiome des verdicts 37 et 96,
   2 px au jeton --erp-focus-ring, decalage 3 px. */
.erp-text-link {
  color: inherit;
  text-decoration: underline; text-underline-offset: 2px;
  overflow-wrap: break-word;
}
.erp-text-link:hover { color: var(--erp-terracotta-dk); }
.erp-text-link:focus-visible { outline: 2px solid var(--erp-focus-ring); outline-offset: 3px; }

/* ---- Liste de texte (dispositif de texte suivi, verdicts 277 a 279) ----
   DOMAINE : le texte suivi, celui du lien de texte ci-dessus (R273.1,
   R277.1) : la colonne de prose de la surface publique et tout texte suivi
   a venir. Ce dispositif ne sert JAMAIS le chrome : une liste d'organe
   (.mirror-list, .sources-list, marqueur de .sidenav__item) tient son rendu
   de l'organe qui la porte et n'a pas de corps a heriter.
   L'element herite corps, graisse, famille, interligne et encre du texte
   porteur (verdict 275) ; le dispositif ne declare que son filet, ses deux
   blancs et son retrait (verdicts 278 et 279).
   Le filet est un pseudo-element, jamais un bord de boite (R274.1) : il ne
   parait que sur la premiere ligne de l'element. Son alignement est en em,
   seule grandeur qui doive trouver une ligne dont le corps est herite ; sa
   longueur et les blancs sont des crans de l'echelle (R278.1). Le retrait
   de 24 px vaut pour TOUTES les lignes de l'element (R279.1), et laisse la
   place a l'anneau de focus d'un lien de texte contenu (decalage 3 px).
   Aucun element de liste n'est atteignable au clavier : le dispositif n'a
   pas d'anneau propre a porter, et cette absence est arretee (releve
   d'office deux, note 277 a 280). */
.erp-list { list-style: none; margin: var(--sp-4) 0; padding: 0; }
/* Jointure a un titre (verdict 293, precision de l'escalier) : contre un
   titre du domaine qui la precede immediatement, la liste recoit l'attache
   du titre, 12 px, et non son bord de 16 px. Le motif du bord, se
   distinguer d'un paragraphe voisin, n'existe pas contre un titre : c'est
   l'attache qui regit. Bord inferieur et blanc entre elements inchanges ;
   aucun barreau nouveau, l'escalier en compte toujours sept. */
.erp-h2 + .erp-list, .erp-h3 + .erp-list { margin-top: var(--sp-3); }
.erp-list li { position: relative; padding-left: var(--sp-5); }
.erp-list li + li { margin-top: var(--sp-3); }
.erp-list li::before {
  content: ""; position: absolute; left: 0; top: 0.7em;
  width: var(--sp-3); height: 1px; background: var(--erp-terracotta);
}

/* ---- Filet juridique (atome de socle, article R186.1, verdict 186).
        Une ligne, un filet de separation au dessus, quatre liens en une seule
        rangee souple, retour a la ligne autorise sur ecran etroit.

        Composition d'une ligne d'indication et non d'une navigation : le corps
        est celui de la ligne d'indication du socle (.erp-field__hint, sans
        13px). L'encre est --erp-fg-3. Le mot "tertiaire" du registre ne peut
        pas designer --erp-fg-4 : ce jeton porte l'interdiction propre du
        verdict 55 (plus de texte sur creme ni sur blanc) et le verdict 78 lui
        ajoute le seuil de 4,5:1, que #8A91A2 ne tient sur aucune des deux
        surfaces. --erp-fg-3 est la troisieme encre de l'echelle et la seule
        que le corpus admette ici.

        Aucune couleur nouvelle, aucun filet terracotta : le filet terracotta
        est la marque d'une carte, il ne descend pas ici. Le filet de
        separation prend --erp-rule, divider sur creme du socle.

        Le lien porte le soulignement editorial (text-decoration, decalage
        2px), et non l'idiome de bord bas de .erp-link : le filet est une ligne
        d'indication, ses liens ne sont pas des liens d'action.

        Separateur point median pose par la feuille sur chaque entree sauf la
        premiere. Ecrit dans le gabarit, il serait du contenu, donc lu a voix
        haute et traduit ; ici il est de la composition. ---- */
.erp-legal-strip {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: var(--sp-1) var(--sp-3);
  margin: 0; padding-top: var(--sp-4);
  border-top: 1px solid var(--erp-rule);
  font-family: var(--erp-font-sans); font-size: 13px; line-height: 1.5;
  color: var(--erp-fg-3);
}
/* display:inline-block n'est pas cosmetique : le separateur est un pseudo porte
   PAR le lien, et le soulignement d'un lien se propage a tout son contenu en
   ligne. Souligne, le point median se lit comme un deux-points (mesure au
   rendu, 1280x900). Une boite en ligne-bloc est atomique : la decoration de
   l'ancetre ne la traverse pas. */
.erp-legal-strip > * + *::before {
  content: "\00B7"; display: inline-block; margin-right: var(--sp-3);
}
.erp-legal-strip a {
  color: inherit; text-decoration: underline; text-underline-offset: 2px;
  transition: color 120ms ease;
}
.erp-legal-strip a:hover { color: var(--erp-terracotta-dk); }
.erp-legal-strip a:focus-visible { outline: 2px solid var(--erp-focus-ring); outline-offset: 3px; }
/* Page courante : sans lien, marquee par l'attribut et non par une classe. */
.erp-legal-strip [aria-current="page"] { color: var(--erp-fg-1); font-weight: 600; }

/* ---- Statuts (pastille = point 7px + libelle, JAMAIS une pilule, DA14 S7) ---- */
.erp-status {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--erp-font-sans); font-size: 13px; font-weight: 500; color: var(--erp-fg-2); white-space: nowrap;
}
.erp-status::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--dot, var(--erp-fg-4)); flex: none; }
.erp-status--emis,   .erp-status--termine { --dot: var(--erp-marine); }
.erp-status--encours, .erp-status--revue  { --dot: var(--erp-terracotta); }
.erp-status--file,   .erp-status--annule  { --dot: var(--erp-fg-4); }
.erp-status--erreur { --dot: var(--erp-terracotta-dk); color: var(--erp-terracotta-dk); font-weight: 600; }
/* Etats de paiement (registre admin, verdict b NOTE_VERDICTS_ADMIN_V1.3) : alias
   token-only sur les 4 godets --dot ci-dessus, mapping 1:1 sur les cles du
   contrat payment_status. Point 7px, jamais une pilule (DA14 S7). */
.erp-status--paid, .erp-status--manual { --dot: var(--erp-marine); }
.erp-status--pending, .erp-status--async { --dot: var(--erp-terracotta); }
.erp-status--expired { --dot: var(--erp-fg-4); }
.erp-status--failed { --dot: var(--erp-terracotta-dk); color: var(--erp-terracotta-dk); font-weight: 600; }
/* Etats de compte (page users) : meme principe, le nom suit le contrat,
   la couleur reste sur les godets socle (arbitrage Remy, Session 3). */
.erp-status--active { --dot: var(--erp-marine); }
.erp-status--inactive { --dot: var(--erp-fg-4); }
/* Etats de risque ERP (NOTE_VERDICTS_PDF_V1.3 verdict 5, refs #395) : alias
   token-only sur les 4 godets --dot ci-dessus, vocabulaire du contrat
   reglementaire. Inversion semantique assumee : la presence de risque recoit
   l'encre chaude emphatique, l'absence le marine calme (registre cabinet
   d'expertise). Zero creation de couleur. */
.erp-status--expose { --dot: var(--erp-terracotta-dk); color: var(--erp-terracotta-dk); font-weight: 600; }
.erp-status--commune { --dot: var(--erp-terracotta); }
.erp-status--non-concerne { --dot: var(--erp-marine); }
.erp-status--nd { --dot: var(--erp-fg-4); }
/* Etats guest /d/* (chrome-status, #422) : alias token-only sur les godets
   --dot ci-dessus, lexique visiteur (DECISION #422) : --attente = --encours,
   --indisponible = --erreur, --expire = --annule. Zero token cree. */
.erp-status--attente { --dot: var(--erp-terracotta); }
.erp-status--indisponible { --dot: var(--erp-terracotta-dk); color: var(--erp-terracotta-dk); font-weight: 600; }
.erp-status--expire { --dot: var(--erp-fg-4); }
.erp-on-marine .erp-status { color: var(--erp-fg-on-marine); }
.erp-on-marine .erp-status--emis { --dot: var(--erp-terracotta-lt); }
/* Deux statuts sur une meme cellule (verdict 177, lot C2 passe 2). REGLE DE
   COMPOSITION sous l'entree .erp-status, pas un atome nouveau : elle ne porte
   que la mise en ligne et le blanc, aucune couleur, aucune taille, aucun jeton.
   La separation des deux badges EST ce blanc : aucun glyphe, ni barre, ni point
   median, ni fleche. Le retour a la ligne ne change pas leur ordre, et l'ordre
   est celui du verdict : l'axe sur lequel on agit d'abord, l'axe que l'on
   constate ensuite. Deux badges au maximum. */
.erp-status-pair { display: flex; flex-wrap: wrap; gap: var(--sp-3); }

/* ---- Chips secondaires (refs cadastrales, codes postaux) : rectangulaire radius-0 ---- */
.erp-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--erp-font-sans); font-size: 11px; font-weight: 600; letter-spacing: 0.04em;
  padding: 4px 8px; border-radius: var(--radius-0); background: var(--erp-cream-warm); color: var(--erp-fg-2);
}
.erp-chip--mono { font-family: var(--erp-font-mono); font-weight: 500; letter-spacing: 0; }
.erp-chip--concerne { background: transparent; color: var(--erp-terracotta-text); border: 1px solid var(--erp-terracotta-text); }
.erp-chip--neutre   { background: transparent; color: var(--erp-fg-3); border: 1px solid var(--erp-rule-strong); }

/* ---- Alertes (note / attention / confirme) : marine et terracotta uniquement ---- */
.erp-alert {
  display: flex; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5);
  background: var(--erp-white); border: 1px solid var(--erp-rule-strong);
  border-left: 3px solid var(--accent, var(--erp-marine)); border-radius: var(--radius-1);
}
.erp-alert__icon { color: var(--accent, var(--erp-marine)); flex: none; margin-top: 1px; }
.erp-alert__title { font-family: var(--erp-font-sans); font-weight: 600; font-size: 14px; color: var(--erp-fg-1); }
.erp-alert__body  { font-family: var(--erp-font-sans); font-size: 14px; line-height: 1.5; color: var(--erp-fg-2); margin-top: 3px; }
.erp-alert--note      { --accent: var(--erp-marine); }
.erp-alert--attention { --accent: var(--erp-terracotta); }
.erp-alert--confirme  { --accent: var(--erp-marine); }

/* ---- Toasts : surface marine, filet terracotta, bouton close ---- */
.erp-toast {
  display: flex; align-items: flex-start; gap: var(--sp-3); max-width: 400px;
  background: var(--erp-marine); color: var(--erp-fg-on-marine);
  padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-1);
  border-left: 3px solid var(--erp-terracotta); box-shadow: var(--shadow-2);
}
.erp-toast__icon { color: var(--erp-terracotta-lt); flex: none; margin-top: 2px; }
.erp-toast__title { font-family: var(--erp-font-sans); font-weight: 600; font-size: 14px; }
.erp-toast__body { font-family: var(--erp-font-sans); font-size: 13px; opacity: 0.82; margin-top: 2px; }
.erp-toast__close { margin-left: auto; background: 0; border: 0; color: var(--erp-fg-on-marine); opacity: 0.6; cursor: pointer; }
.erp-toast__close:hover { opacity: 1; }

/* ---- Champ de formulaire (asterisque obligatoire .req, mention optionnel, DA14 S3) ---- */
.erp-field { display: flex; flex-direction: column; gap: var(--sp-2); }
.erp-field__label { font-family: var(--erp-font-sans); font-size: 13px; font-weight: 600; color: var(--erp-fg-2); display: flex; align-items: center; gap: 8px; }
.erp-field__label .req { color: var(--erp-terracotta-text); }
.erp-field__label .erp-field__opt-inline { margin-left: auto; font-family: var(--erp-font-sans); font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--erp-fg-4); }
.erp-input, .erp-select, .erp-textarea {
  font-family: var(--erp-font-sans); font-size: 16px; color: var(--erp-fg-1);
  background: var(--erp-white); border: 1px solid var(--erp-rule-strong);
  border-radius: var(--radius-1); padding: 11px 14px; width: 100%;
  transition: border-color 120ms ease;
}
.erp-input::placeholder { color: var(--erp-fg-4); }
/* VERDICT 111, LOT 1 SUR 4 DU DISPOSITIF DE FOCUS. La suppression nue est
   retiree : cette seule ligne portait `outline: none` et supprimait l'anneau sur
   130 elements de 12 surfaces, soit 33 des 36 elements du depot qui rendaient un
   focus sans anneau. La primitive de la ligne 216 reprend d'elle meme, aucune
   declaration de forme n'est posee ici : c'est ce qui rend ce lot arretable seul.
   LE CHANGEMENT DE border-color N'EST PAS DEFAIT, et ce n'est pas un oubli. Le
   verdict 111 le pose : il devient un signal SECOND et gratuit, et le verdict 105
   cesse de s'appliquer aux bordures des lors que l'anneau est pose. Le retirer
   couterait un signal sans rien rendre.
   Ce que la mesure avait etabli sur les temoins : contraste d'etat 2,59 sur les
   trois selecteurs de cette regle, variation non chromatique AUCUNE, anneau peint
   dans aucun des deux etats. Un champ peut rendre un contraste excellent et
   n'avoir aucun anneau ; c'est ce qui a ouvert le lot. */
.erp-input:focus, .erp-select:focus, .erp-textarea:focus { border-color: var(--erp-terracotta); }
/* Saisie monospace majuscule (code de parrainage B4 #452). Port de la primitive
   actee par Design (docs/design/system-v1.3/system/parrainage-v1.5.css), regle
   unique, var(--erp-*) only, zero token nouveau (DA3). */
.erp-input--mono { font-family: var(--erp-font-mono); letter-spacing: 0.08em; text-transform: uppercase; }
/* VERDICT 172, #513. `margin` DECLARE, ET A ZERO. L'element rendu est un <p> :
   sans cette ligne, la primitive herite la marge d'agent utilisateur, 1em soit
   13px haut et bas. Elle ne le faisait pas partout, et c'est precisement le
   defaut : `account.css` et `app-dashboard.css` portent chacune une remise a
   zero universelle, si bien que la meme primitive composait a marge nulle sur
   deux surfaces et a 26px d'ecart sur toutes les autres. Une primitive du kit ne
   peut pas dependre, pour composer, d'une remise a zero qu'elle ne charge pas.
   L'espacement du champ est gouverne par le `gap` du `.erp-field`, :429, qui est
   le poste prevu pour cela : la marge d'agent l'y doublait. */
.erp-field__hint { font-family: var(--erp-font-sans); font-size: 13px; color: var(--erp-fg-3); margin: 0; }
/* Ancre dans une ligne d'indication : soulignement editorial, meme idiome que
   .erp-legal-strip a. L'encre est celle du texte porteur (inherit), le
   terracotta n'apparait qu'au survol. Sans cette regle, l'ancre retombe sur le
   bleu et le violet du navigateur, hors palette. */
.erp-field__hint a {
  color: inherit; text-decoration: underline; text-underline-offset: 2px;
  transition: color 120ms ease;
}
.erp-field__hint a:hover { color: var(--erp-terracotta-dk); }
.erp-field__hint a:focus-visible { outline: 2px solid var(--erp-focus-ring); outline-offset: 3px; }
.erp-field--inline { position: relative; }
.erp-field--inline .erp-input { padding-right: 44px; }
.erp-field__addon { position: absolute; right: 12px; top: 50%; transform: translateY(-50%); color: var(--erp-fg-4); background: 0; border: 0; cursor: pointer; display: inline-flex; }

/* ---- Etat erreur de champ (.erp-field--erreur, verdict 3 fiche contact
        #436, famille formulaire). Doctrine couleur d'erreur V1.3 :
        terracotta-dk, jamais de rouge. Le MESSAGE porte le sens, la
        bordure le double (meme regle que la jauge de mot de passe). Le
        message occupe le slot hint existant, recolore par modificateur :
        zero element nouveau, zero token nouveau. Un champ en erreur
        n'affiche pas son hint courant : un seul message sous le champ
        a la fois. ---- */
.erp-field--erreur .erp-input,
.erp-field--erreur .erp-select,
.erp-field--erreur .erp-textarea { border-color: var(--erp-terracotta-dk); }
.erp-field__hint--erreur { color: var(--erp-terracotta-text); font-weight: 600; }

/* ---- Jauge de force de mot de passe (registre admin, verdict d
        NOTE_VERDICTS_ADMIN_V1.3, famille formulaire). 4 segments carres
        discrets (--radius-1), monochrome : vide cream-deep + filet
        rule-strong, rempli terracotta. Jamais un degrade rouge vers vert.
        Le MOT d'etat (Faible / Moyen / Bon / Fort) porte le sens, en
        terracotta-text ; les segments le doublent. Remplace les barres
        continues des brouillons chrome-card et account. ---- */
.erp-pwgauge { display: flex; flex-direction: column; gap: 6px; }
.erp-pwgauge__segs { display: flex; gap: 4px; }
.erp-pwgauge__seg {
  flex: 1; height: 5px; border-radius: var(--radius-1);
  background: var(--erp-cream-deep); border: 1px solid var(--erp-rule-strong);
  transition: background-color 120ms ease, border-color 120ms ease;
}
.erp-pwgauge__seg.is-filled { background: var(--erp-terracotta); border-color: var(--erp-terracotta); }
.erp-pwgauge__state {
  font-family: var(--erp-font-sans); font-size: 12px; font-weight: 600;
  color: var(--erp-terracotta-text); min-height: 16px;
}
.erp-pwgauge__state--empty { font-weight: 400; color: var(--erp-fg-3); }

/* ---- Interrupteur carre .erp-toggle (composite applicatif, famille formulaire).
        Verse depuis la fiche catalogue V1.3 (refs #292, refs #364). Controle on/off
        des preferences (alertes, options de compte). Doctrine rayon V1.3 : piste
        radius-1 (2px), pave radius-1 (2px), jamais 999px ni 8px et plus. 9 jetons,
        tous var(--erp-*), jamais vert ni rouge. Bouton a bascule portant aria-pressed
        (serialise en booleen pour le contrat alerts). Le mot d'etat reste toujours
        visible (.erp-toggle__state) : c'est le registre qui rend l'interrupteur
        de-pille lisible comme intentionnel, pas une pilule ratee. ---- */
.erp-toggle {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  background: transparent; border: 0; padding: 0; margin: 0; cursor: pointer;
  font-family: var(--erp-font-sans); font-size: 14px; font-weight: 600; line-height: 1;
  color: var(--erp-fg-3); -webkit-tap-highlight-color: transparent;
}
.erp-toggle__track {
  position: relative; flex: none; box-sizing: border-box;
  width: 44px; height: 24px;
  background: var(--erp-cream-deep);
  border: 1px solid var(--erp-rule-strong);
  border-radius: var(--radius-1);
  transition: background-color 120ms ease, border-color 120ms ease;
}
.erp-toggle__knob {
  position: absolute; top: 3px; left: 3px; box-sizing: border-box;
  width: 18px; height: 18px;
  background: var(--erp-white);
  border: 1px solid var(--erp-rule-strong);
  border-radius: var(--radius-1);
  transition: transform 120ms ease, border-color 120ms ease;
}
.erp-toggle__state { min-width: 70px; text-align: left; }
/* etat ON */
.erp-toggle[aria-pressed="true"] .erp-toggle__track { background: var(--erp-terracotta); border-color: var(--erp-terracotta); }
.erp-toggle[aria-pressed="true"] .erp-toggle__knob { transform: translateX(20px); border-color: var(--erp-terracotta); }
.erp-toggle[aria-pressed="true"] .erp-toggle__state { color: var(--erp-terracotta-text); }
/* hover : changement de couleur seul, 120ms, pas de transform */
.erp-toggle:hover .erp-toggle__track { border-color: var(--erp-marine); }
.erp-toggle[aria-pressed="true"]:hover .erp-toggle__track { background: var(--erp-terracotta-dk); border-color: var(--erp-terracotta-dk); }
/* focus clavier : anneau canonique V1.3 (terracotta-lt) sur la piste */
/* SUPPRESSION CONFORME, VERDICT 121. ANNEAU PORTE PAR : .erp-toggle__track
   Ce n'est pas une suppression, c'est un DEPLACEMENT : l'element focalise rend un
   anneau mesurable au niveau ou il recoit le focus, porte par son descendant, et
   le verdict 106 l'a declare conforme. Le retrait de `outline: 0` poserait DEUX
   anneaux la ou il y en a un, soit un defaut cree par l'application d'un verdict.
   Le verdict 111 disait "partout" parce qu'il ignorait que des suppressions
   intentionnelles existaient ; il est amende par le verdict 121 : le retrait vaut
   la ou il supprime un anneau, non la ou il en deplace un.
   La declaration ci-dessus n'est pas un ornement. Sans elle, la conformite de cet
   element n'est lisible que par une mesure, et une suppression non declaree est
   un defaut de forme MEME QUAND L'ELEMENT REND JUSTE. Le compte des suppressions
   conformes declarees entre dans la recette du dispositif, en regard du compte
   des elements sans anneau. */
.erp-toggle:focus-visible { outline: 0; }
.erp-toggle:focus-visible .erp-toggle__track { outline: 2px solid var(--erp-focus-ring); outline-offset: 2px; }
/* disabled : 60% d'opacite, doctrine */
.erp-toggle[disabled] { cursor: not-allowed; opacity: 0.6; }
.erp-toggle[disabled]:hover .erp-toggle__track { border-color: var(--erp-rule-strong); }
.erp-toggle[disabled][aria-pressed="true"]:hover .erp-toggle__track { background: var(--erp-terracotta); border-color: var(--erp-terracotta); }

/* ---- Segmented control (Vente / Location) : segments carres, jamais une pilule.
        Primitive de la famille formulaire, portee du kit avec .erp-field. ---- */
.erp-segment { display: inline-flex; border: 1px solid var(--erp-marine); border-radius: var(--radius-1); overflow: hidden; }
.erp-segment button {
  font-family: var(--erp-font-sans); font-size: 14px; font-weight: 600; padding: 9px 18px;
  border: 0; background: var(--erp-white); color: var(--erp-marine); cursor: pointer; transition: background-color 120ms ease, color 120ms ease;
}
.erp-segment button + button { border-left: 1px solid var(--erp-marine); }
.erp-segment button[aria-selected="true"] { background: var(--erp-marine); color: var(--erp-cream); }

/* ---- Stack : primitive de mise en page (flex colonne, gap tokenise).
        Pas un composant de marque : zero token de palette, aucune couleur,
        aucune bordure. Porte du kit pour composer les surfaces atelier (#389).
        Le gap par defaut est --sp-4 ; surcharger via --stack-gap en local. ---- */
.erp-stack { display: flex; flex-direction: column; gap: var(--stack-gap, var(--sp-4)); }
.erp-stack--tight { --stack-gap: var(--sp-2); }
.erp-stack--loose { --stack-gap: var(--sp-6); }

/* ---- Footer presse (cadence N / total) ---- */
.erp-footer { background: var(--erp-marine-deep); color: var(--erp-fg-on-marine); margin-top: auto; }
.erp-footer__inner { max-width: 1180px; margin: 0 auto; padding: var(--sp-8) var(--sp-8) var(--sp-6); }
.erp-footer__top { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: var(--sp-6); padding-bottom: var(--sp-7); border-bottom: 1px solid var(--erp-marine-line); }
@media (max-width: 760px) { .erp-footer__top { grid-template-columns: 1fr 1fr; } }
.erp-footer__desc { font-family: var(--erp-font-serif); font-style: italic; font-size: 15px; line-height: 1.5; color: var(--erp-fg-on-marine); opacity: 0.75; margin-top: var(--sp-4); max-width: 32ch; }
.erp-footer__col-label { font-family: var(--erp-font-sans); font-weight: 600; font-size: 11px; letter-spacing: var(--t-eyebrow-track); text-transform: uppercase; color: var(--erp-terracotta-lt); margin-bottom: var(--sp-4); }
.erp-footer__link { display: block; font-family: var(--erp-font-sans); font-size: 14px; color: var(--erp-fg-on-marine); opacity: 0.82; text-decoration: none; padding: 5px 0; }
.erp-footer__link:hover { opacity: 1; }
.erp-footer__cadence { display: flex; align-items: center; justify-content: space-between; padding: var(--sp-5) 0 0; gap: var(--sp-4); }
.erp-footer__cadence span { font-size: 12px; opacity: 0.55; }
.erp-footer__cadence .mid { font-family: var(--erp-font-sans); letter-spacing: 0.12em; }
.erp-footer__cadence .side { font-family: var(--erp-font-serif); font-style: italic; }

/* ============================================================
   Navigation unifiee .sidenav (DA13) : UN composant marine, deux jeux de
   liens (console, doc) et deux dispositions passes EN DONNEES par le partial
   templates/public/partials/components/sidenav.hbs. Construit au socle 372,
   PAS applique aux surfaces live (application = coquilles M2-M4).

   Couche de theming locale --nav-* (defaut marine). Toutes les references aux
   surfaces themables passent par var(--nav-*). Le modificateur .sidenav--cream
   remappe sur creme : echafaudage INGENIERIE DORMANT, non applique, a realigner
   Claude Design (direction visuelle creme de la nav non validee design).
   ============================================================ */

.sidenav {
  /* theming local : defaut marine */
  --nav-bg:      var(--erp-marine);
  --nav-fg:      var(--erp-fg-on-marine);
  --nav-line:    var(--erp-marine-line);
  --nav-hover:   var(--erp-marine-soft);
  --nav-accent:  var(--erp-terracotta);
  --nav-eyebrow: var(--erp-terracotta-lt);

  position: sticky; top: 0; align-self: start;
  height: 100vh; background: var(--nav-bg); color: var(--nav-fg);
  display: flex; flex-direction: column; padding: 0 0 var(--sp-6);
  border-right: 1px solid var(--nav-line);
}

/* Zone de tete de rail (#416) : marque + env regroupees sur une bande de meme
   hauteur que la topbar (var(--sp-10)). La marque reste calee en haut, l'env
   glisse au bas via margin-top:auto (cf .sidenav__env). .sidenav__nav demarre
   alors exactement au filet bas de la topbar : un seul datum, sp-10, partage
   par le rail et le contenu. La bande absorbe l'ancien padding-top du rail. */
.sidenav__head {
  min-height: var(--sp-10); display: flex; flex-direction: column;
  padding-top: var(--sp-6);
}

/* Modificateur creme DORMANT (non applique, a realigner Claude Design). */
.sidenav--cream {
  --nav-bg:      var(--erp-cream);
  --nav-fg:      var(--erp-fg-2);
  --nav-line:    var(--erp-rule);
  --nav-hover:   var(--erp-cream-warm);
  --nav-accent:  var(--erp-terracotta);
  --nav-eyebrow: var(--erp-terracotta-text);
}

.sidenav__brand { padding: 0 var(--sp-6) var(--sp-1); }
.sidenav__logo {
  font-family: var(--erp-font-serif); font-weight: 500; font-size: 22px; line-height: 1;
  letter-spacing: 0.02em; text-decoration: none; color: var(--nav-fg);
}
.sidenav__logo .erp-plus { color: var(--nav-eyebrow); font-weight: 600; }
.sidenav__env {
  font-family: var(--erp-font-sans); font-weight: 600; font-size: 11px;
  letter-spacing: var(--t-eyebrow-track); text-transform: uppercase;
  color: var(--nav-eyebrow); padding: var(--sp-2) var(--sp-6) var(--sp-5);
  margin-top: auto;
}
.sidenav__nav { display: flex; flex-direction: column; gap: var(--sp-1); padding: 0 var(--sp-3); }
.sidenav__group-label {
  font-family: var(--erp-font-sans); font-weight: 600; font-size: 10px; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--nav-fg); opacity: 0.45;
  padding: var(--sp-4) var(--sp-3) var(--sp-2);
}
/* Le rang tient sa hauteur de lui meme, jamais de la boite de ligne d'un
   enfant (verdict 185, meme ecriture qu'au kit). Avant cette ligne, les 41 px
   du rang etaient 41 = 20 de padding + 21, et ces 21 etaient la boite de ligne
   de l'enveloppe du glyphe : un remplace de 18 px pose sur la ligne de base,
   plus la descente du strut. Le libelle, lui, ne fait que 16. La hauteur du
   rang venait donc d'un enfant, et deux lots consecutifs qui ne visaient pas ce
   rang l'ont deplace en touchant ce qui vit dedans.

   La valeur n'est pas decidee : elle est LUE sur ce qui est servi, 41 px,
   constants sur les quatre surfaces qui portent une nav laterale et sur les
   sept echelles de la matrice. box-sizing est border-box (reset socle en tete
   de cette feuille) : 41 est bien la boite de bordure. */
.sidenav__item {
  display: flex; align-items: center; gap: 12px;
  min-height: 41px;
  padding: 10px 13px; border-radius: var(--radius-1);
  font-family: var(--erp-font-sans); font-weight: 500; font-size: 14px;
  color: var(--nav-fg); text-decoration: none;
  position: relative; opacity: 0.8; transition: background-color 100ms ease, opacity 100ms ease;
}
.sidenav__item .erp-ic { opacity: 0.85; }
.sidenav__item:hover { background: var(--nav-hover); opacity: 1; }
.sidenav__item[aria-current="page"] { background: var(--nav-hover); opacity: 1; }
.sidenav__item[aria-current="page"]::before {
  content: ""; position: absolute; left: -3px; top: 50%; transform: translateY(-50%);
  width: 2px; height: 20px; background: var(--nav-accent);
}
.sidenav__item:focus-visible { outline: 2px solid var(--erp-focus-ring); outline-offset: -2px; }
.sidenav__spacer { flex: 1; }
.sidenav__user {
  margin: var(--sp-5) var(--sp-5) 0; padding-top: var(--sp-5);
  border-top: 1px solid var(--nav-line);
  display: flex; flex-direction: column;
}
.sidenav__user-id { display: flex; align-items: center; gap: 10px; }
.sidenav__avatar {
  width: 32px; height: 32px; border-radius: 50%; flex: none;
  background: var(--erp-terracotta); color: var(--erp-white);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--erp-font-sans); font-weight: 600; font-size: 12px;
}
.sidenav__cabinet { font-family: var(--erp-font-sans); font-size: 13px; font-weight: 600; color: var(--nav-fg); }
.sidenav__email { font-family: var(--erp-font-sans); font-size: 11px; color: var(--nav-fg); opacity: 0.6; margin-top: 2px; }
.sidenav__credits {
  margin-top: var(--sp-4); display: flex; align-items: baseline; justify-content: space-between;
  font-family: var(--erp-font-sans); font-size: 12px; color: var(--nav-fg); opacity: 0.7;
}
.sidenav__credits strong { font-family: var(--erp-font-mono); font-weight: 500; opacity: 1; color: var(--nav-eyebrow); }
.sidenav__logout {
  margin-top: var(--sp-4); display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--erp-font-sans); font-size: 13px; color: var(--nav-fg);
  opacity: 0.7; text-decoration: none; transition: opacity 100ms ease;
}
.sidenav__logout:hover { opacity: 1; }
.sidenav__build {
  font-family: var(--erp-font-mono); font-size: 11px; letter-spacing: 0.12em;
  color: var(--nav-eyebrow); opacity: 0.6; padding: var(--sp-5) var(--sp-6) 0;
}
.sidenav__close { display: none; }

/* Scrim mobile du tiroir : marine-deep 45% via color-mix (ex rgba marine-deep a
   0.45), sans nouveau token. Le controle d'ouverture (.app-nav-toggle) et le
   hamburger sont fournis par la coquille app-shell (issue 393). */
.sidenav-scrim { display: none; }
@media (max-width: 900px) {
  .sidenav {
    position: fixed; inset: 0 auto 0 0; width: 264px; height: 100vh; z-index: 60;
    transform: translateX(-100%); transition: transform 160ms ease;
  }
  .app-nav-toggle:checked ~ .sidenav { transform: translateX(0); }
  .app-nav-toggle:checked ~ .sidenav-scrim { display: block; }
  .sidenav-scrim {
    display: none; position: fixed; inset: 0; z-index: 55;
    background: color-mix(in srgb, var(--erp-marine-deep) 45%, transparent);
  }
}

/* ============================================================
   Coquille app-shell (#403, refs #364) : grille [nav verticale marine
   | zone applicative]. Fondue au socle, comme l'attendait l'echafaudage
   sidenav #372 (le controle .app-nav-toggle et le scrim mobile vivent
   deja plus haut, NON redeclares ici). Source : maquette V1.3
   system.css ; hex residuel deja tokenise (var(--erp-*) seulement).
   Slot unique pour /app et futures surfaces applicatives authentifiees.
   ============================================================ */
.app-shell { display: grid; grid-template-columns: 240px minmax(0, 1fr); min-height: 100vh; }
.app-main { min-width: 0; background: var(--erp-cream-soft); }
/* Filet juridique au pied de la zone servie (article R186.1). La gouttiere
   reprend celle du corps applicatif (.app-body, var(--sp-7)) pour que le filet
   s'aligne sur le contenu qu'il suit et non sur le bord de la coquille. Le
   filet est dans le flux : il descend avec la page, il n'est pas epingle. */
.app-main > .erp-legal-strip { margin: 0 var(--sp-7) var(--sp-7); }
.app-topbar {
  display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-5);
  flex-wrap: wrap; row-gap: var(--sp-4); min-height: var(--sp-10);
  padding: var(--sp-6) var(--sp-7) var(--sp-5); border-bottom: 1px solid var(--erp-rule-strong);
  background: var(--erp-cream-soft);
}
.app-topbar__lead { display: flex; align-items: flex-end; gap: var(--sp-4); min-width: 0; }
.app-topbar__crumb {
  display: flex; gap: 8px; align-items: center; margin-bottom: 10px;
  font-family: var(--erp-font-sans); font-size: 12px; color: var(--erp-fg-3);
}
.app-topbar__crumb .sep { color: var(--erp-rule-strong); }
.app-topbar__crumb .cur { color: var(--erp-fg-1); font-weight: 600; white-space: nowrap; }
.app-topbar__title {
  font-family: var(--erp-font-serif); font-weight: 500; font-size: var(--t-h1); line-height: 1.1;
  color: var(--erp-fg-1); margin: 0; letter-spacing: -0.01em;
}
/* Salutation (#407) : le prenom passe en terracotta italique. Fold app-kit.css. */
.app-topbar__title em { color: var(--erp-terracotta); font-style: italic; }
.app-topbar__actions { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }

/* Champ de recherche topbar (#407). Fold system.css : tokens seuls, l'input
   conserve son id="searchInput" (lecture JS inchangee). */
.app-search {
  display: flex; align-items: center; gap: 10px; background: var(--erp-white);
  border: 1px solid var(--erp-rule-strong); border-radius: var(--radius-1); padding: 9px 13px; width: 320px;
}
/* VERDICT 97, AMENDE PAR LE VERDICT 106. La suppression nue est retiree : le
   test est que l'element focalise rende un indicateur mesurable, ou que soit
   ecrite la declaration. Ici il n'en rendait aucun, et la specificite de ce
   selecteur, une classe plus un type, l'emportait sur la primitive : le champ
   rendait 0px none meme au focus clavier.
   Le substitut ci-dessous vit dans une regle DISTINCTE, et c'est licite : le
   verdict 106 a retire l'exigence de meme regle, qui aurait condamne ce correctif
   au moment meme ou il rendait l'anneau.
   Le retrait de l'etat non focalise est conserve, il sert le dessin du champ. Le
   focus clavier retrouve l'anneau de la primitive, que le jeton resout seul.
   CORRECTION D'UNE PHRASE FAUSSE de ce meme commentaire : elle disait "le rail
   est marine, donc --erp-terracotta-lt par le verdict 90". Ce champ n'est pas
   sur le rail, il est dans .app-topbar, dont le fond est --erp-cream-soft, une
   surface CLAIRE. Le jeton y resout --erp-terracotta, et la mesure le rend :
   focus clavier, 2px solid rgb(179,90,58). La phrase expliquait un rendu correct
   par une surface qui n'est pas la sienne.
   Premier dividende du verdict 92 : la constitution n'a pas cree ce defaut, elle
   l'a rendu lisible, un point unique de decision transformant chaque
   contournement local en ecart visible. */
/* SUPPRESSION CONFORME, VERDICT 121. ANNEAU PORTE PAR : .app-search input
   L'anneau est porte par l'element lui meme, a la regle suivante : le retrait de
   l'etat non focalise sert le dessin du champ, et le focus clavier retrouve
   l'anneau de la primitive. Deplacement et non suppression, au sens du verdict
   106, et le verdict 121 en tire que le lot 4 ne part pas.
   Mesure : focus clavier, 2px solid rgb(179,90,58), le jeton resolvant
   --erp-terracotta, .app-topbar etant une surface CLAIRE au sens du verdict 107.
   Une suppression non declaree est un defaut de forme meme quand l'element rend
   juste : c'est cette declaration, et non le rendu, qui manquait. */
.app-search input { border: 0; outline: 0; background: transparent; flex: 1; font-family: var(--erp-font-sans); font-size: 14px; color: var(--erp-fg-1); }
.app-search input:focus-visible { outline: 2px solid var(--erp-focus-ring); outline-offset: 2px; }
.app-search input::placeholder { color: var(--erp-fg-4); }
.app-search .erp-ic { color: var(--erp-fg-4); }

/* Pastille d'environnement honnete (#407, resout #403). Fold system.css :
   libelle config-driven, point marine, masquee sous 760px. */
.env-pill {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--erp-font-sans); font-size: 12px; font-weight: 600;
  letter-spacing: 0.04em; color: var(--erp-fg-2);
  border: 1px solid var(--erp-rule-strong); border-radius: var(--radius-1);
  padding: 7px 11px; white-space: nowrap;
}
.env-pill__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--erp-marine); flex: none; }
@media (max-width: 760px) { .env-pill { display: none; } }

.app-body { padding: var(--sp-7); }
.app-hamburger { display: none; }

@media (max-width: 900px) {
  .app-shell { grid-template-columns: 1fr; }
  .app-hamburger {
    display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px;
    border: 1px solid var(--erp-rule-strong); border-radius: var(--radius-1); background: var(--erp-white);
    color: var(--erp-marine); cursor: pointer;
  }
  .app-search { width: auto; flex: 1; }
}

/* ============================================================
   Entete de section doctrine (#407, #408). .section-head est le motif
   d'entete partage (eyebrow terracotta + titre Newsreader, segment ou
   action a droite), deja utilise par la home marketing (chrome-marketing.css,
   meme valeurs) ; fondu ici au socle car /app charge erp-components.css mais
   pas chrome-marketing.css. var(--erp-*) seuls.
   Section ACTIVITE de /app : le wrapper .activity-section porte id="filterBar"
   (toggle JS display:flex/none selon allJobs.length, logique inchangee) et
   empile l'entete (titre + segment) puis la rangee meta (date-range + compteur).
   ============================================================ */
.section-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-5); margin-bottom: var(--sp-7); }
.activity-section { flex-direction: column; }
.activity-section .section-head { margin-bottom: var(--sp-4); flex-wrap: wrap; row-gap: var(--sp-4); }
/* Rangee meta (#413) : groupe gauche (plage + compteur) a gauche, pager du haut a
   droite (justify-content: space-between). Sur une seule page, le pager du haut est
   masque (JS) : la droite reste vide. */
.activity-meta { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-5); }
.activity-meta__lead { display: inline-flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.activity-meta .result-count { font-family: var(--erp-font-sans); font-size: 12px; font-weight: 500; color: var(--erp-fg-3); white-space: nowrap; }

/* ============================================================
   Ligne de job enrichie (#390, refs #364). Fondue au socle depuis
   l'archive system-v1.3/system/app-kit.css (deja 0 hex brut, color-mix
   sur tokens). Gabarit stable partage par les 4 etats (queued,
   processing dont palier finalisation, completed, failed) : aucun saut
   de layout pendant le polling 3s. Les classes de FAUX contenu de la
   maquette (.doc-mini, .preview-page, .error-trace) ne sont PAS portees :
   /app rend le vrai thumbnail, le vrai PDF.js et le message mapError.
   ============================================================ */
.jobline {
  display: flex; align-items: center; gap: var(--sp-5);
  background: var(--erp-white);
  border: 1px solid var(--erp-rule-strong);
  border-radius: var(--radius-1);
  padding: var(--sp-4) var(--sp-5);
}
.jobline + .jobline { margin-top: var(--sp-3); }
/* surbrillance apres redirection depuis /new (?job= / ?batch=) */
.jobline.is-highlight { border-color: var(--erp-terracotta); }

/* Widget de previsualisation (dimensions figees, porteur visuel de l'etat) */
.jobprev {
  position: relative; width: 64px; height: 88px; flex: none; align-self: center;
  border-radius: var(--radius-1); overflow: hidden;
  background: var(--erp-marine); border: 1px solid var(--erp-rule-marine);
  display: flex; align-items: center; justify-content: center; text-align: center;
}
.jobprev__label {
  position: relative; font-family: var(--erp-font-sans); font-size: 9px; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--erp-fg-on-marine);
  opacity: 0.72; padding: 0 4px;
}
.jobprev__pct {
  position: relative; font-family: var(--erp-font-mono); font-size: 14px;
  color: var(--erp-fg-on-marine); font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}
.jobprev__fill {
  position: absolute; left: 0; right: 0; bottom: 0; height: 0;
  background: color-mix(in srgb, var(--erp-terracotta-lt) 34%, transparent);
  border-top: 1px solid var(--erp-terracotta-lt);
  transition: height 600ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.jobprev--finalising .jobprev__fill {
  background: color-mix(in srgb, var(--erp-terracotta-lt) 30%, transparent);
  border-top-color: var(--erp-terracotta-lt);
  animation: jobprev-shimmer 1.3s ease-in-out infinite;
}
@keyframes jobprev-shimmer { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
.jobprev--error { background: color-mix(in srgb, var(--erp-terracotta-dk) 26%, var(--erp-marine)); }
.jobprev--error .erp-ic { color: var(--erp-terracotta-lt); width: 20px; height: 20px; }
/* completed : cadre doctrine accueillant le vrai thumbnail page 1 (img), cliquable */
.jobprev--doc {
  background: var(--erp-cream-soft); border-color: var(--erp-rule-strong);
  cursor: pointer; padding: 0; transition: border-color 120ms ease;
}
.jobprev--doc:hover { border-color: var(--erp-terracotta); }
.jobprev--doc img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Colonne principale : reference, adresse, chips, jauge */
.jobline__main { flex: 1 1 auto; min-width: 0; align-self: center; display: flex; flex-direction: column; gap: 7px; }
.jobline__top { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.jobline__ref {
  font-family: var(--erp-font-mono); font-weight: 500; font-size: 12px;
  color: var(--erp-fg-on-marine); background: var(--erp-marine);
  padding: 4px 9px; border-radius: var(--radius-1); white-space: nowrap; flex: none;
}
.jobline__addr { font-family: var(--erp-font-serif); font-size: 17px; color: var(--erp-fg-1); min-width: 0; }
.jobline__chips { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.jobline__chips .erp-chip { white-space: nowrap; }

/* Parties (Vendeur / Acquereur) : meta secondaire sous l'adresse (4.2b, #390 refs #364).
   Micro-label fg-4 (PAS terracotta : l'eyebrow reste l'unique marqueur d'identite),
   separateur point median, filet vertical entre parties. Une partie absente : span
   omis cote template (jamais de "n/a" fabrique). Branche sur vendeur / acquereur de
   /api/v1/erp/list. */
.jobline__parties {
  display: flex; align-items: baseline; flex-wrap: wrap;
  gap: 5px var(--sp-3); min-width: 0;
  font-family: var(--erp-font-sans); font-size: 13px; line-height: 1.35;
}
.jobline__party { display: inline-flex; align-items: baseline; gap: 7px; min-width: 0; }
.jobline__party + .jobline__party { padding-left: var(--sp-3); border-left: 1px solid var(--erp-rule); }
.jobline__party-role {
  flex: none; font-size: 11px; font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--erp-fg-4);
}
.jobline__party-sep { flex: none; color: var(--erp-fg-4); }
.jobline__party-name {
  min-width: 0; max-width: 30ch; color: var(--erp-fg-2); font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.jobline__progress { min-height: 20px; display: flex; align-items: center; gap: var(--sp-4); }
.jobline__progress--done {
  font-family: var(--erp-font-sans); font-size: 13px; color: var(--erp-fg-3);
  display: inline-flex; align-items: center; gap: 8px;
}
.jobline__progress--error {
  font-family: var(--erp-font-sans); font-size: 13px; font-weight: 600; color: var(--erp-terracotta-dk);
}

/* ============================================================
   .gauge : QUATORZIEME ATOME DU CATALOGUE (verdict 176, lot C2 passe 2).
   Jauge deterministe 9 segments plus etape nommee, cablee sur le vrai progress.

   Elle n'est plus un fragment de la ligne de job : elle est employee sur DEUX
   surfaces, le tableau de bord /app et l'atelier visiteur /buy. Le second emploi
   n'a pas cree l'obligation de la cataloguer, il a revele ce que l'objet etait
   deja. Regle generale rendue par le meme verdict, et elle vaut au dela de ce
   lot : un objet visuel employe sur une seule surface est un fragment de cette
   surface ; employe sur deux, il est une primitive du kit.

   ELLE ENTRE A L'IDENTIQUE. Aucune de ses declarations n'a bouge d'une ligne,
   aucune n'a ete renommee, aucun jeton n'a ete cree : un objet qui change en
   entrant au catalogue n'est pas catalogue, il est refait. Seul ce commentaire
   a change, et un commentaire n'est pas une declaration.

   .jobprev reste sous .jobline ci-dessus : c'est une vue de la jauge dans le
   composite, pas la jauge.

   Catalogue : docs/design/CATALOGUE_V1.3.md section 2.
   ============================================================ */
.gauge { display: flex; align-items: center; gap: var(--sp-4); min-width: 0; }
.gauge__segs { display: flex; gap: 3px; flex: none; }
.gauge__seg {
  width: 16px; height: 4px; background: var(--erp-rule-strong);
  border-radius: 1px;
}
.gauge__seg--done    { background: var(--erp-marine); }
.gauge__seg--current { background: var(--erp-terracotta); animation: gauge-pulse 1.4s ease-in-out infinite; }
/* finalisation (palier 100%) : terracotta clair pulse, sans degrade (doctrine plat) */
.gauge__seg--shimmer { background: var(--erp-terracotta-lt); animation: gauge-pulse 0.9s ease-in-out infinite; }
@keyframes gauge-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
.gauge__step { font-family: var(--erp-font-sans); font-size: 13px; color: var(--erp-fg-2); white-space: nowrap; }
.gauge__step strong { color: var(--erp-fg-1); font-weight: 600; }
.gauge__pct {
  font-family: var(--erp-font-mono); font-size: 12px; color: var(--erp-fg-3);
  font-variant-numeric: tabular-nums; flex: none;
}
/* queued : segment 0 indetermine, PAS de barre vide trompeuse */
.gauge--queued { gap: 10px; }
/* indetermine (queued) : barre pleine fg-4 qui pulse, sans degrade (doctrine plat) */
.gauge__indet {
  width: 56px; height: 4px; flex: none;
  border-radius: 1px;
  background: var(--erp-fg-4);
  animation: gauge-pulse 1.6s ease-in-out infinite;
}

/* La jauge sur surface marine (lot C2 passe 2). CORRECTION AU KIT, faite UNE
   FOIS et ici : le verdict 176 interdit de poser quoi que ce soit de la jauge
   dans une feuille d'atelier, et pose que si l'accueil sur une nouvelle surface
   exige une declaration locale, c'est la primitive qui est en cause, pas la
   surface d'accueil.

   Elle l'etait. Les encres de la jauge sont toutes calculees pour un fond clair :
   sur la barre de paiement marine de /buy, les segments franchis rendaient du
   marine sur du marine, les segments a venir rendaient un beige plus clair que
   les segments franchis (donc l'inverse du sens voulu), et l'etape comme le
   pourcentage rendaient un texte sombre. Rien de tout cela n'etait lisible.

   Le dispositif employe est celui que le socle avait deja pour .erp-status :
   le contexte se declare par .erp-on-marine sur la surface, le socle rend
   l'encre. Aucun jeton cree, aucune valeur nouvelle : les quatre inversions
   recombinent --erp-marine-line, --erp-fg-on-marine et --erp-terracotta-lt.
   Le calme et le chaud s'echangent comme partout ailleurs sur marine.

   TROIS SOUS-ELEMENTS N'Y FIGURENT PAS, et chacun pour un motif mesure :

   .gauge__seg--shimmer porte deja --erp-terracotta-lt, qui est l'encre chaude de
   la surface marine : le declarer serait une declaration inerte (verdict 169).

   .gauge__indet n'est pas admise sur l'atelier visiteur (verdict 176) : aucun
   element a atteindre.

   .gauge__step et son `strong` ONT ETE RETIRES au verdict 178, qui fait cesser
   l'emission de l'etape nommee sur cette surface. Ils y avaient ete declares au
   tour precedent, quand elle y etait encore rendue, et le releve les a comptes a
   ZERO element des la pose du 178. Le lot qui les a tuees emporte ces deux
   regles : les differer aurait fait de cette inertie une dette que personne
   n'aurait reprise. Aucune autre surface marine du depot ne rend de __step. */
.erp-on-marine .gauge__seg          { background: var(--erp-marine-line); }
.erp-on-marine .gauge__seg--done    { background: var(--erp-fg-on-marine); }
.erp-on-marine .gauge__seg--current { background: var(--erp-terracotta-lt); }
.erp-on-marine .gauge__pct          { color: var(--erp-terracotta-lt); }

/* Aside : statut + heure + actions (largeur reservee, gabarit stable) */
.jobline__aside { display: flex; align-items: center; gap: var(--sp-5); align-self: center; flex: none; }
.jobline__statcol { display: flex; flex-direction: column; align-items: flex-end; gap: 7px; min-width: 86px; }
.jobline__time { font-family: var(--erp-font-mono); font-size: 12px; color: var(--erp-fg-4); font-variant-numeric: tabular-nums; }
.jobline__actions { display: flex; align-items: center; gap: var(--sp-3); min-width: 158px; justify-content: flex-end; }
.jobline__actions .erp-btn { padding: 9px 15px; font-size: 14px; }
.jobline__actions .erp-btn--ghost { padding: 9px 0; }
.jobline__actions--empty { color: var(--erp-fg-4); font-family: var(--erp-font-sans); font-size: 12px; font-style: italic; }

@media (max-width: 1024px) {
  .jobline { flex-wrap: wrap; }
  .jobprev { order: 0; }
  .jobline__main { flex: 1 1 240px; order: 1; }
  .jobline__parties { gap: 3px 0; }
  .jobline__party + .jobline__party { padding-left: 0; border-left: 0; }
  .jobline__aside { order: 2; width: 100%; justify-content: space-between; gap: var(--sp-4); margin-top: 4px; padding-top: var(--sp-3); border-top: 1px solid var(--erp-rule); }
  .jobline__statcol { flex-direction: row; align-items: baseline; gap: var(--sp-4); min-width: 0; }
  .jobline__actions { min-width: 0; }
}
@media (max-width: 560px) {
  .jobline__aside { flex-wrap: wrap; }
}

/* Menu d'actions (trois points) compose sur tokens. L'impersonation est geree
   par omission au rendu (arbitrage C) : la regle declarative .impersonation-hidden
   du kit n'est PAS portee. */
.jobmenu { position: relative; flex: none; }
.jobmenu__trigger {
  width: 34px; height: 34px; border-radius: var(--radius-1);
  border: 1px solid var(--erp-rule-strong); background: var(--erp-white);
  color: var(--erp-fg-3); display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}
.jobmenu__trigger:hover { background: var(--erp-cream); color: var(--erp-fg-1); }
.jobmenu.is-open .jobmenu__trigger { background: var(--erp-cream); color: var(--erp-fg-1); border-color: var(--erp-rule-strong); }
.jobmenu__panel {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 50; min-width: 244px;
  background: var(--erp-white); border: 1px solid var(--erp-rule-strong);
  border-radius: var(--radius-1); box-shadow: var(--shadow-2); padding: var(--sp-2); display: none;
}
.jobmenu.is-open .jobmenu__panel { display: block; }
.jobmenu__item {
  display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
  padding: 9px 10px; border-radius: var(--radius-1); background: transparent; border: 0; cursor: pointer;
  font-family: var(--erp-font-sans); font-size: 14px; color: var(--erp-fg-2); text-decoration: none;
}
.jobmenu__item:hover { background: var(--erp-cream); color: var(--erp-fg-1); }
.jobmenu__item .erp-ic { color: var(--erp-fg-4); flex: none; }
.jobmenu__item:hover .erp-ic { color: var(--erp-fg-2); }
.jobmenu__item .meta { margin-left: auto; font-family: var(--erp-font-mono); font-size: 11px; color: var(--erp-fg-4); }
.jobmenu__sep { height: 1px; background: var(--erp-rule); margin: var(--sp-2) 6px; border: 0; }
.jobmenu__item--danger { color: var(--erp-terracotta-dk); }
.jobmenu__item--danger .erp-ic { color: var(--erp-terracotta-dk); }
.jobmenu__item--danger:hover { background: color-mix(in srgb, var(--erp-terracotta-dk) 9%, var(--erp-white)); color: var(--erp-terracotta-dk); }

/* Liste de resume (modale #summaryModal) : dt/dd + .erp-status par alea */
.summary-list { display: flex; flex-direction: column; gap: 0; margin-top: var(--sp-2); }
.summary-list__row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); padding: 11px 0; border-top: 1px solid var(--erp-rule); }
.summary-list__row:first-child { border-top: 0; }
.summary-list__row dt { font-family: var(--erp-font-sans); font-size: 14px; color: var(--erp-fg-2); margin: 0; }
.summary-list__row dd { margin: 0; }

/* ============================================================
   Pagination doctrine (#412, refs #409, refs #364) : variante "cadence
   presse" (specimen kit erp-pagination.css, bloc A). Remplace la grille
   numerotee plus doubles chevrons livree en #409 (glyphes unicode + vocabulaire
   B2C, reference negative de la marque) : compteur a gauche, "Page n / total"
   mono plus Precedent/Suivant ghost en chevrons Lucide SVG a droite, select
   compact blanc. La logique (slice client, math des pages, anti-verrou) reste
   cote app-dashboard.js, gelee.
   Chevrons en SVG inline + currentColor : jamais de glyphe unicode, jamais de
   data-uri avec hex (cf. leçon glyphes + chevron de select). La variante numeros
   cliquables reste en reserve au kit (ecran fort volume), NON fondue ici : pas de
   CSS mort dans le socle gate. var(--erp-*) seuls.
   ============================================================ */
.erp-pagination {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-5); flex-wrap: wrap;
  margin-top: var(--sp-6); padding: var(--sp-4) 0;
  font-family: var(--erp-font-sans);
}
/* Resume (gauche), T en mono */
.erp-pagination__count { font-size: 14px; color: var(--erp-fg-3); white-space: nowrap; }
.erp-pagination__count b { font-family: var(--erp-font-mono); font-weight: 500; color: var(--erp-fg-1); }

/* Groupe droit : "Page n / total" + steps + selecteur de volume */
.erp-pagination__nav { display: flex; align-items: center; gap: var(--sp-5); flex-wrap: wrap; }
.erp-pagination__navgroup { display: inline-flex; align-items: center; gap: var(--sp-5); }

.erp-pagination__pageinfo {
  font-family: var(--erp-font-sans); font-size: 13px; letter-spacing: 0.04em;
  color: var(--erp-fg-3); white-space: nowrap;
}
.erp-pagination__pageinfo b { font-family: var(--erp-font-mono); font-weight: 500; color: var(--erp-fg-1); letter-spacing: 0; }

/* Precedent / Suivant : ghost, bordure basse marine, chevron Lucide */
.erp-pagination__steps { display: inline-flex; align-items: center; gap: var(--sp-4); }
.erp-pagination__step {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-family: var(--erp-font-sans); font-size: 14px; font-weight: 600;
  color: var(--erp-marine); background: transparent;
  border: 0; border-bottom: 1px solid var(--erp-marine); border-radius: 0;
  padding: 6px 0; cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease;
}
.erp-pagination__step:hover { color: var(--erp-terracotta-dk); border-bottom-color: var(--erp-terracotta-dk); }
.erp-pagination__step svg { width: 16px; height: 16px; }
.erp-pagination__step[disabled] { color: var(--erp-fg-4); border-bottom-color: transparent; cursor: default; opacity: 0.6; }
.erp-pagination__step[disabled]:hover { color: var(--erp-fg-4); }

/* Selecteur de volume par page : .erp-select compact blanc + chevron Lucide en
   SVG inline overlay (currentColor). PAS de data-uri (le gate flague le hex %23). */
.erp-pagination__perpage { display: inline-flex; align-items: center; gap: var(--sp-2); }
.erp-pagination__perpage label { font-size: 13px; color: var(--erp-fg-3); white-space: nowrap; }
/* Select habille generalise (registre admin lot B, admin-kit.css bloc 5, DA19) :
   tout .erp-select place sous .erp-select-wrap est de-pille (appearance none) et
   recoit le caret Lucide inline currentColor en overlay. Generalisation du
   pattern ne du pager #412 ; jamais de chevron data-uri (le gate flague %23hex). */
.erp-select-wrap { position: relative; display: inline-flex; align-items: center; }
.erp-select-wrap .erp-select { appearance: none; -webkit-appearance: none; -moz-appearance: none; padding-right: 38px; }
.erp-select--compact {
  width: auto; padding: 7px 32px 7px 11px; font-size: 14px;
  -webkit-appearance: none; -moz-appearance: none; appearance: none;
  background: var(--erp-white); cursor: pointer;
}
.erp-select__caret {
  position: absolute; right: 11px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--erp-marine); pointer-events: none;
}

/* Pager en ligne du haut de liste (#413, refs #364). Fold du specimen bloc C
   (erp-pagination.css) : integre a la rangee meta, allege : uniquement "Page n /
   total" + Precedent/Suivant, pas de compteur (rangee meta), pas de select (unique,
   en bas). Chevrons a libelle masque (.vh) pour rester compacts sans perdre
   l'accessibilite. Reutilise .erp-pagination__step / __pageinfo. var(--erp-*) seuls. */
.erp-pagination__inline { display: inline-flex; align-items: center; gap: var(--sp-4); }
.erp-pagination__inline .erp-pagination__step { font-size: 13px; padding: 4px 0; }
.erp-pagination__step .vh {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (max-width: 640px) {
  .erp-pagination { gap: var(--sp-4); }
  .erp-pagination__nav { gap: var(--sp-4); width: 100%; justify-content: space-between; }
}

/* ============================================================
   Selecteur de plage de dates doctrine (#411, refs #364). Fold du specimen kit
   erp-datepicker.css (.erp-daterange + .erp-cal) au socle. var(--erp-*) seuls :
   la bordure du panneau passe du rgba brut du specimen au pattern .erp-card reel
   (color-mix marine 6%). Icones Lucide SVG inline (calendrier, chevrons, X),
   jamais de glyphe. La legende de kit (.erp-cal-legend*) n'est PAS fondue (doc
   hors produit). Le clear-X est un bouton FRERE absolu (pas imbrique dans le
   bouton declencheur : HTML valide), revele par data-active. La logique de
   filtre/plage/presets reste cote app-dashboard.js, gelee.
   ============================================================ */
.erp-daterange { position: relative; display: inline-block; font-family: var(--erp-font-sans); }

/* Declencheur (ferme) : surface blanche, hairline, dates en mono */
.erp-daterange__trigger {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  height: 40px; padding: 0 34px 0 var(--sp-3);
  background: var(--erp-white); color: var(--erp-fg-2);
  border: 1px solid var(--erp-rule-strong); border-radius: var(--radius-1);
  font-family: var(--erp-font-sans); font-size: 14px; font-weight: 500;
  cursor: pointer; transition: border-color 120ms ease, color 120ms ease;
}
.erp-daterange__trigger:hover { border-color: var(--erp-marine); }
.erp-daterange__trigger-ic { display: inline-flex; color: var(--erp-fg-3); flex: none; }
.erp-daterange__trigger-ic svg { width: 17px; height: 17px; }
.erp-daterange__trigger-label { white-space: nowrap; }
.erp-daterange__trigger-label .erp-daterange__date { font-family: var(--erp-font-mono); font-weight: 500; }
.erp-daterange__trigger-caret {
  position: absolute; right: 11px; top: 50%; transform: translateY(-50%);
  display: inline-flex; color: var(--erp-fg-4); pointer-events: none;
}
.erp-daterange__trigger-caret svg { width: 15px; height: 15px; }

/* Plage active : encre fg-1, bordure marine, ic terracotta, caret remplace par le clear-X */
.erp-daterange[data-active="true"] .erp-daterange__trigger { color: var(--erp-fg-1); border-color: var(--erp-marine); }
.erp-daterange[data-active="true"] .erp-daterange__trigger-ic { color: var(--erp-terracotta-text); }
.erp-daterange[data-active="true"] .erp-daterange__trigger-caret { display: none; }

.erp-daterange__trigger-clear {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  display: none; align-items: center; justify-content: center;
  width: 22px; height: 22px;
  background: transparent; border: 0; border-radius: var(--radius-1);
  color: var(--erp-fg-4); cursor: pointer; transition: background-color 120ms ease, color 120ms ease;
}
.erp-daterange[data-active="true"] .erp-daterange__trigger-clear { display: inline-flex; }
.erp-daterange__trigger-clear:hover { background: var(--erp-cream-warm); color: var(--erp-fg-1); }
.erp-daterange__trigger-clear svg { width: 13px; height: 13px; }

/* Panneau (popover) : anatomie .erp-card, bordure color-mix marine 6% (pas de rgba brut) */
.erp-daterange__panel {
  position: absolute; top: calc(100% + var(--sp-2)); left: 0; z-index: 40;
  background: var(--erp-white);
  border: 1px solid color-mix(in srgb, var(--erp-marine) 6%, transparent); border-radius: var(--radius-2);
  box-shadow: var(--shadow-2);
  padding: var(--sp-5);
}
.erp-daterange__panel::before {
  content: ""; position: absolute; top: var(--sp-5); left: 0;
  width: var(--card-accent-w); height: var(--card-accent-h);
  background: var(--erp-terracotta);
}
.erp-daterange__layout { display: flex; align-items: stretch; gap: var(--sp-5); }

/* Rail de presets */
.erp-daterange__presets {
  display: flex; flex-direction: column; gap: 2px;
  min-width: 158px; padding-right: var(--sp-5);
  border-right: 1px solid var(--erp-rule);
}
.erp-daterange__preset {
  text-align: left; font-family: var(--erp-font-sans); font-size: 14px; font-weight: 500;
  color: var(--erp-fg-2); background: transparent; border: 0;
  padding: 8px var(--sp-3); border-radius: var(--radius-1); cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}
.erp-daterange__preset:hover { background: var(--erp-cream-warm); color: var(--erp-fg-1); }
.erp-daterange__preset[aria-pressed="true"] { background: var(--erp-marine); color: var(--erp-cream); }

/* Calendriers (deux mois) */
.erp-daterange__cals { display: flex; gap: var(--sp-5); }
.erp-cal + .erp-cal { padding-left: var(--sp-5); border-left: 1px solid var(--erp-rule); }
.erp-cal__head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: var(--sp-3); padding: 0 4px;
}
.erp-cal__title {
  font-family: var(--erp-font-serif); font-weight: 500; font-size: 17px;
  color: var(--erp-fg-1); letter-spacing: -0.005em;
}
.erp-cal__title .erp-cal__year { font-family: var(--erp-font-mono); font-weight: 500; font-size: 15px; color: var(--erp-fg-3); margin-left: 6px; }
.erp-cal__nav {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border: 0; border-radius: var(--radius-1);
  background: transparent; color: var(--erp-marine); cursor: pointer;
  transition: background-color 120ms ease;
}
.erp-cal__nav:hover { background: var(--erp-cream-warm); }
.erp-cal__nav svg { width: 17px; height: 17px; }
.erp-cal__nav[disabled] { opacity: 0.6; cursor: default; }
.erp-cal__nav--ghost { visibility: hidden; }
.erp-cal__grid { display: grid; grid-template-columns: repeat(7, 38px); }
.erp-cal__dow {
  height: 28px; display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--erp-font-sans); font-size: 11px; font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--erp-fg-4);
}
.erp-cal__day {
  position: relative; height: 36px;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--erp-font-mono); font-size: 13px; font-weight: 400;
  color: var(--erp-fg-2); background: transparent;
  border: 1px solid transparent; border-radius: var(--radius-1);
  cursor: pointer; transition: background-color 120ms ease, color 120ms ease;
}
.erp-cal__day:hover,
.erp-cal__day.is-hover { background: var(--erp-cream-warm); color: var(--erp-fg-1); }
.erp-cal__day:focus-visible { outline: 2px solid var(--erp-focus-ring); outline-offset: -2px; z-index: 2; }
.erp-cal__day--empty { visibility: hidden; cursor: default; }
.erp-cal__day--in-range { background: var(--erp-cream-warm); color: var(--erp-fg-1); border-radius: var(--radius-0); }
.erp-cal__day--in-range:hover { background: var(--erp-cream-warm); }
.erp-cal__day--start,
.erp-cal__day--end {
  background: var(--erp-marine); color: var(--erp-cream); font-weight: 500;
  border-radius: var(--radius-0);
}
.erp-cal__day--start:hover,
.erp-cal__day--end:hover { background: var(--erp-marine); color: var(--erp-cream); }
.erp-cal__day--start { border-top-left-radius: var(--radius-1); border-bottom-left-radius: var(--radius-1); }
.erp-cal__day--end   { border-top-right-radius: var(--radius-1); border-bottom-right-radius: var(--radius-1); }
.erp-cal__day--single { border-radius: var(--radius-1); }
.erp-cal__day--today { border-color: var(--erp-terracotta); }
.erp-cal__day[disabled],
.erp-cal__day--disabled {
  color: var(--erp-fg-4); opacity: 0.6; cursor: default; background: transparent;
}
.erp-cal__day[disabled]:hover,
.erp-cal__day--disabled:hover { background: transparent; color: var(--erp-fg-4); }

/* Pied : resume de la selection + actions */
.erp-daterange__foot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px solid var(--erp-rule);
}
.erp-daterange__summary { font-family: var(--erp-font-sans); font-size: 13px; color: var(--erp-fg-3); }
.erp-daterange__summary .erp-daterange__date { font-family: var(--erp-font-mono); font-weight: 500; color: var(--erp-fg-1); }
.erp-daterange__summary--empty { color: var(--erp-fg-4); }
.erp-daterange__actions { display: flex; align-items: center; gap: var(--sp-4); }
.erp-daterange__actions .erp-btn--primary { padding: 11px 18px; font-size: 14px; }
.erp-daterange__actions .erp-btn--ghost   { padding: 11px 0; font-size: 14px; }

@media (max-width: 720px) {
  .erp-daterange__layout { flex-direction: column; gap: var(--sp-4); }
  .erp-daterange__presets {
    flex-direction: row; flex-wrap: wrap; min-width: 0; gap: 4px;
    padding-right: 0; padding-bottom: var(--sp-4);
    border-right: 0; border-bottom: 1px solid var(--erp-rule);
  }
  .erp-cal + .erp-cal { display: none; }
}

/* ---------------------------------------------------------------
   Etiquette de consentement (.erp-check-block) et notice associee
   (.erp-notice-block)

   ENTREE AU CATALOGUE AU TITRE DU VERDICT 176. Les deux objets ont vecu dans
   public/css/atelier.css tant que l'ecran de commande sans compte etait leur
   seule surface : ils y etaient des fragments de cette surface. Le lot de
   consentement a l'inscription les emploie sur une seconde surface, servie par
   une autre coquille (layout-chrome-card), et le verdict les fait passer
   primitives du kit. A L'IDENTIQUE : les declarations ci dessous sont celles
   d'atelier.css au caractere pres, seul le nom porte desormais le prefixe du
   kit. Recopier pour eviter l'entree est refuse.

   Ce que ces objets NE sont pas : une case a cocher generique. Ils composent
   une etiquette de CONSENTEMENT, c'est a dire une case dont le libelle est un
   engagement et porte les liens du texte engage. Une case de preference
   (recevoir une copie, se souvenir de moi) n'a pas ce registre.
   --------------------------------------------------------------- */
.erp-check-block {
  display: flex; gap: var(--sp-2); margin: var(--sp-4) 0 var(--sp-2);
  font-family: var(--erp-font-sans); font-size: 12px; color: var(--erp-fg-2); line-height: 1.5;
}
.erp-check-block input[type="checkbox"] { margin-top: 3px; flex-shrink: 0; accent-color: var(--erp-marine); }
.erp-check-block a { color: var(--erp-marine); font-weight: 600; text-decoration: underline; }

/* LA NOTICE NE SE CONSENT PAS (verdict 193, article R193.1). Elle informe au
   lieu de la collecte, et rien ne s'y engage : elle ne doit se lire ni comme
   une case de plus, ni comme l'appendice de la derniere. Le filet est celui de
   la ligne d'indication du socle (.erp-legal-strip), pose sur le meme jeton
   --erp-rule : la notice change de registre, pas de grammaire. Aucun filet
   terracotta, qui est la marque d'une carte. */
.erp-notice-block {
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--erp-rule);
}
