/* ============================================================================
   NEXORA — habillage du service.

   Deux directions, arrêtées sur maquettes et validées :

   — **l'ouverture de session** est éditoriale : un panneau marine porte la
     marque, la saisie occupe une page blanche à côté. On l'ouvre deux fois par
     jour, elle peut se permettre une image ;

   — **les écrans du magasin** sont un poste de travail : rail sombre, densité
     assumée, fiche du certificat à droite de la saisie. On y passe la journée.

   Ce qui les relie n'est pas une mise en page commune mais un vocabulaire : le
   marine du logo en fond de marque, l'or réservé à ce qui est **calculé** ou
   **retenu** — jamais décoratif —, et les mêmes familles typographiques.

   Les couleurs sont échantillonnées sur le logo, pas choisies : l'hexagone
   donne les marines, le monogramme les ors.
   ========================================================================== */

:root {
  color-scheme: light;

  --marine-950: #060f22;
  --marine-900: #0a1a34;
  --marine-800: #0e2549;
  --marine-700: #143563;
  --marine-600: #17408a;
  --marine-500: #0b4ea8;
  --marine-300: #7fa3d8;
  --marine-100: #dbe5f3;

  --or-700: #8c6314;
  --or-600: #a8781c;
  --or-500: #c8961f;
  --or-400: #e1a430;
  --or-100: #f6ecd6;

  --encre: #14181f;
  --encre-moyenne: #414855;
  --encre-douce: #6b7280;
  --trait: #e3e0d8;
  --trait-froid: #e2e6ec;
  --papier: #ffffff;
  --ivoire: #f7f5f0;
  --plan: #eff1f5;

  --valide: #10603c;
  --valide-fond: #e9f4ee;
  --attention: #8a5a00;
  --attention-fond: #fdf3e0;
  --refus: #99231f;
  --refus-fond: #fcedec;
  /* La teinte du refus **appuyée**, pour le survol d'un bouton qui la porte en
     fond. Un jeton et non un littéral : une teinte d'état se déplace d'un seul
     endroit, comme `--marine-800` est le survol de `--marine-900`. */
  --refus-appuye: #7d1c19;

  /* Familles système : le service est servi hors de tout réseau public et ne
     charge aucune fonte distante. Le rendu est fidèle sur les postes Apple,
     substitué ailleurs — les replis sont ordonnés par ressemblance, pas par
     disponibilité. */
  --ui: 'Avenir Next', 'Avenir', 'Segoe UI', 'Helvetica Neue', system-ui, sans-serif;
  --didone: Didot, 'Bodoni 72', 'Bodoni MT', 'Times New Roman', Georgia, serif;
  --chiffres: 'SF Mono', ui-monospace, 'JetBrains Mono', Menlo, Consolas, monospace;
}

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

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

body {
  margin: 0;
  font-family: var(--ui);
  color: var(--encre);
  line-height: 1.5;
  background: var(--plan);
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
p,
figure,
fieldset,
legend,
dl,
dd {
  margin: 0;
  padding: 0;
}

fieldset {
  border: 0;
  min-inline-size: 0;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

button,
input,
select {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
}

img {
  display: block;
  max-width: 100%;
}

a {
  color: var(--marine-700);
  text-underline-offset: 3px;
}

:focus-visible {
  outline: 2px solid var(--focus, var(--marine-500));
  outline-offset: 2px;
}

.tabulaire {
  font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ═══ Ouverture de session ══════════════════════════════════════════════════
   Partagée par la connexion et la reprise après verrouillage : ce sont les
   deux écrans où personne n'est encore au travail. */

.ouverture {
  min-height: 100vh;
  display: grid;
  grid-template-columns: minmax(0, 47fr) minmax(0, 53fr);
  background: var(--papier);
}

.panneau {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: clamp(2.5rem, 4.5vw, 4rem);
  overflow: hidden;
  color: rgba(255, 255, 255, 0.72);
  background: var(--marine-950);
  isolation: isolate;
}

/* Lueur froide décentrée. Elle n'est pas un ornement : sans elle, un aplat
   #060f22 sur près de la moitié de l'écran se lit comme un trou noir. */
.panneau::before {
  content: '';
  position: absolute;
  z-index: -2;
  inset: -30% -40% auto -55%;
  aspect-ratio: 1;
  background: radial-gradient(
    circle at 50% 50%,
    rgba(23, 64, 138, 0.5) 0%,
    rgba(11, 78, 168, 0.14) 38%,
    rgba(6, 15, 34, 0) 68%
  );
}

/* L'hexagone du logo, redessiné en trait et débordant du cadre : la marque
   habite le fond sans que le logo y soit répété. */
.filigrane {
  position: absolute;
  z-index: -1;
  right: -16%;
  bottom: -22%;
  width: 78%;
  pointer-events: none;
}

.filigrane path {
  fill: none;
  stroke: rgba(255, 255, 255, 0.07);
  stroke-width: 1.1;
}

.filigrane path.or {
  stroke: rgba(225, 164, 48, 0.16);
}

/* La signature de l'outil composée de ses deux pièces — monogramme et mot —, comme
   au rail du poste. La signature d'un seul tenant a été retirée : elle porte une
   enseigne dans ses pixels, et un écran du personnel ne nomme que celle de
   l'acteur. Composée, elle ne dépend plus d'un actif à recouper. */
.panneau__marque {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}

/* La hauteur mène, la largeur suit : le monogramme est plus haut que large, et le
   borner en largeur le laisserait déborder le mot qu'il accompagne. 62 px de
   monogramme pour la ligne capitale de 1.5rem, soit à peu près l'encombrement de
   la signature d'un seul tenant qu'il remplace — la colonne du panneau ne se
   redessine pas. */
.panneau__marque img {
  width: auto;
  height: 62px;
}

.panneau__mot {
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: 0.3em;
  color: #fff;
}

.manchette {
  max-width: 22ch;
  margin: auto 0 0;
  font-family: var(--didone);
  font-size: clamp(2rem, 3.4vw, 3.05rem);
  font-weight: 400;
  line-height: 1.14;
  letter-spacing: -0.015em;
  color: #fff;
}

.manchette em {
  display: block;
  font-style: normal;
  color: var(--or-400);
}

.panneau__propos {
  max-width: 34ch;
  margin-top: 1.6rem;
  font-size: 0.9375rem;
  line-height: 1.75;
  color: rgba(255, 255, 255, 0.6);
}

.assertions {
  display: grid;
  margin-top: 3rem;
  border-top: 1px solid rgba(255, 255, 255, 0.11);
}

.assertions li {
  display: grid;
  grid-template-columns: 2.4rem 1fr;
  align-items: baseline;
  padding: 0.85rem 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  border-bottom: 1px solid rgba(255, 255, 255, 0.11);
}

.assertions b {
  font-family: var(--chiffres);
  font-size: 0.6875rem;
  font-weight: 500;
  color: var(--or-400);
}

.page {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(2.5rem, 5vw, 5rem) clamp(1.5rem, 6vw, 6rem);
}

.page__entete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 2.75rem;
  font-size: 0.6875rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--encre-douce);
}

.page h1 {
  max-width: 16ch;
  font-family: var(--didone);
  font-size: clamp(2.1rem, 3vw, 2.75rem);
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.page .intro {
  max-width: 42ch;
  margin-top: 1rem;
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--encre-douce);
}

.page form {
  max-width: 26rem;
  margin-top: 2.5rem;
}

.page .champ {
  margin-bottom: 1.15rem;
}

/* Le champ de saisie de l'ouverture : plus grand qu'ailleurs, encadré, et
   éclairci à la prise de focus. On y frappe deux fois par jour, pas trente. */
.boite {
  display: flex;
  align-items: center;
  background: #fbfaf8;
  border: 1px solid var(--trait);
  border-radius: 10px;
  transition: border-color 0.2s, background 0.2s, box-shadow 0.2s;
}

.boite:focus-within {
  background: var(--papier);
  border-color: var(--marine-600);
  box-shadow: 0 0 0 3px rgba(23, 64, 138, 0.12);
}

.boite input {
  flex: 1;
  min-width: 0;
  padding: 0.85rem 1rem;
  font-size: 1rem;
  background: transparent;
  border: 0;
}

.boite input:focus {
  outline: none;
}

.boite--code input {
  font-family: var(--chiffres);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.champ[data-refuse='oui'] .boite {
  border-color: var(--refus);
  background: var(--refus-fond);
}

.devoiler {
  align-self: stretch;
  padding: 0 1rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--encre-douce);
  background: none;
  border: 0;
  border-left: 1px solid var(--trait);
}

.devoiler:hover {
  color: var(--marine-600);
}

.barre {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  margin-top: 1.75rem;
}

/* ═══ Rail du poste ═════════════════════════════════════════════════════════
   Il nomme le vendeur dont la session est ouverte et le magasin émetteur :
   c'est ce que le certificat gèlera, et cela doit être lisible avant
   l'émission, non découvert sur le document imprimé. */

.rail {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 0.55rem clamp(0.75rem, 2vw, 1.25rem);
  color: rgba(255, 255, 255, 0.6);
  background: var(--marine-950);
}

.rail img {
  height: 24px;
  width: auto;
}

.rail__mot {
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  color: #fff;
}

/* Les deux destinations du poste, permanentes. La courante n'est pas un lien : elle
   est marquée d'un aplat discret et d'`aria-current`, de sorte que la distinction ne
   repose pas sur la seule couleur. */
.rail__fil {
  display: flex;
  gap: 0.35rem;
  padding-left: 0.8rem;
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  border-left: 1px solid rgba(255, 255, 255, 0.15);
}

.rail__fil a,
.rail__fil span {
  padding: 0.2rem 0.5rem;
  color: inherit;
  text-decoration: none;
  border-radius: 5px;
}

.rail__fil a:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.1);
}

.rail__fil [aria-current='page'] {
  font-weight: 600;
  color: #fff;
  background: rgba(255, 255, 255, 0.12);
}

.rail__droite {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-left: auto;
  font-size: 0.75rem;
}

.rail__magasin {
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--or-400);
}

.rail__acteur {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.25rem 0.7rem;
  background: rgba(255, 255, 255, 0.07);
  border-radius: 999px;
}

.rail__acteur b {
  font-weight: 600;
  color: #fff;
}

/* La pastille du compte est devenue un lien — elle mène à ses propres secrets. Elle garde
   l'apparence qu'elle avait : c'est le même objet, il conduit désormais quelque part. Seconde
   règle ajoutée depuis la reprise du témoin, après `.refus__motif`. */
a.rail__acteur {
  color: inherit;
  text-decoration: none;
}

a.rail__acteur:hover {
  background: rgba(255, 255, 255, 0.14);
}

.rail__action {
  padding: 0.3rem 0.6rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.6);
  background: none;
  border: 0;
  border-radius: 5px;
}

.rail__action:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.1);
}

/* Le décompte d'inactivité et son bouton forment **un groupe** : c'est le même formulaire,
   celui que la minuterie soumet à échéance, et le décompte annonce précisément ce que le
   bouton fait à la main. Le formulaire est donc une rangée, non une boîte de bloc. */
.rail__minuterie {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

/* La géométrie de la pastille est portée **en permanence**, ground compris : elle n'apparaît
   pas avec l'alerte. Une pastille qui naîtrait au franchissement élargirait le décompte d'une
   douzaine de pixels et pousserait le bouton de côté — un déplacement de cible au moment
   précis où l'on demande au vendeur de la viser.

   Le libellé, lui, **peut se replier**, et c'est mesuré. Posé en `nowrap`, il porte le rail du
   poste à 534 px pour 480 offerts — une largeur où il tient aujourd'hui — et le rail
   d'administration de 1 120 à 1 191 px à 1 024. La règle du rail est que ce qui manque de
   largeur gagne de la hauteur ; le libellé la suit au lieu de s'en excepter. Aux deux largeurs
   du poste (1 366 et 1 024 px) la rangée ne comprime rien, et il tient donc sur une ligne. */
.rail__decompte {
  display: flex;
  gap: 0.3rem;
  align-items: baseline;
  padding: 0.25rem 0.55rem;
  border-radius: 999px;
}

/* La valeur est le seul mot qui bouge, et le seul en blanc plein : au repos, le décompte est
   une mention du rail, non une alarme. `tabular-nums` sans quoi `0:47` et `0:11` ne font pas la
   même largeur et la phrase tressaute à chaque seconde.

   `nowrap` ici, et pas sur le libellé : une durée coupée entre deux lignes — `15` puis `min` —
   ne se lit plus, là où un libellé replié se lit encore. Elle ne coûte rien, et c'est relevé :
   aux sept largeurs du tableau d'adaptation et sur les deux rails, aucun élément ne déborde de
   sa boîte avec elle en place, et le rail d'administration est 16 px plus bas sous 1 024 px
   qu'il ne l'est sans. */
.rail__decompte b {
  font-weight: 600;
  color: #fff;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Sous soixante secondes. `--refus` est la **seule urgence que la feuille déclare**, et le rail
   n'en porte aucun autre usage : il n'y a donc pas d'ambiguïté à lui emprunter son rouge. L'or
   aurait été le candidat voisin, et c'eût été un défaut — il nomme déjà le magasin dans ce même
   rail, et il y dit « calculé ou retenu », non « imminent ».

   Le blanc plein sur ce fond tient 7:1, là où le décompte au repos vit à 0,6 d'opacité : le
   contraste **monte** avec l'urgence, et l'état ne repose donc pas sur la seule couleur. */
.rail__decompte--alerte {
  font-weight: 600;
  color: #fff;
  background: var(--refus);
}

/* L'annonce polie est **dans** le document, jamais retirée : `display: none` la sortirait de
   l'arbre d'accessibilité, et il n'y aurait plus rien à annoncer. Même masquage que le contrôle
   des cartes de durée, pour la même raison. */
.rail__annonce {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ═══ Plan de travail ══════════════════════════════════════════════════════ */

/* Les respirations haute et basse sont fixes et courtes. Les 4 rem de pied venaient d'une
   page qu'on lisait en défilant ; l'écran de suite se lit d'un coup d'œil entre deux clients,
   et cette réserve y coûtait la moitié de ce qui manquait au poste de caisse. */
.plan {
  max-width: 64rem;
  margin: 0 auto;
  padding: 1.25rem clamp(1rem, 3vw, 2rem) 0.6rem;
}

/* Le plan **propre à l'archive** (ADR-0033). 64 rem est la mesure d'une colonne de
   lecture, et l'archive y loge un tableau de neuf colonnes qui n'y tient pas : mesuré
   sur le poste de caisse, il faisait 1 125 px dans un plan qui en offre 960.

   `96vw` avant `84rem` : sur une dalle plus étroite que le plafond, le plan garde ses
   marges au lieu de venir toucher les bords. La dérogation est accordée au tableau,
   non à l'écran : un futur écran qui la demanderait devra montrer la même chose. */
.plan--archive {
  max-width: min(96vw, 84rem);
}

.plan h1 {
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.plan .chapeau {
  max-width: 70ch;
  margin-top: 0.4rem;
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--encre-douce);
}

/* Deux colonnes : la saisie, et la fiche du certificat qui se remplit à la
   frappe. La fiche n'est **pas** le document imprimé — celui-ci est produit par
   le gabarit, seule source du PDF (ADR-0005). Elle en reprend l'ordre des
   informations pour qu'aucune ne surprenne au tirage. */
.travail {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 24rem;
  gap: 1px;
  min-height: calc(100vh - 44px);
  background: var(--trait-froid);
  padding-bottom: 68px;
}

.saisie {
  padding: 1.15rem clamp(0.9rem, 2vw, 1.6rem) 1.5rem;
  background: var(--papier);
}

/* La colonne de saisie ne s'étire pas indéfiniment : au-delà d'une cinquantaine
   de caractères, l'œil perd la ligne entre un libellé et son champ. */
.saisie > * {
  max-width: 52rem;
}

.saisie__entete {
  margin-bottom: 1.25rem;
}

.saisie__entete h1 {
  font-size: 1.25rem;
  font-weight: 600;
}

.saisie__entete p {
  max-width: 68ch;
  margin-top: 0.35rem;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--encre-douce);
}

/* ═══ Rubriques et champs ══════════════════════════════════════════════════ */

.rubrique + .rubrique {
  margin-top: 1.15rem;
  padding-top: 1.15rem;
  border-top: 1px solid var(--trait-froid);
}

.rubrique__titre {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.75rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--marine-700);
}

.rubrique__titre::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--trait-froid);
}

.rubrique__titre .apposition {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--encre-douce);
}

.grille {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 0.7rem 0.85rem;
}

.champ {
  grid-column: span 6;
}

.champ--plein {
  grid-column: span 12;
}

.champ--cinq {
  grid-column: span 5;
}

.champ--sept {
  grid-column: span 7;
}

.champ label,
.champ .intitule {
  display: block;
  margin-bottom: 0.25rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--encre-moyenne);
}

.page .champ label {
  margin-bottom: 0.4rem;
  font-size: 0.8125rem;
}

.facultatif {
  font-weight: 400;
  color: var(--encre-douce);
}

/* Le contrôle de saisie, sous les deux dispositions que le service emploie : le champ
   empilé — libellé, boîte, note — des écrans du poste, et la **rangée** de registre de
   l'écran de la Diffusion, où la note passe à côté de la valeur. Une seule écriture pour
   les deux : ce sont les mêmes contrôles, et deux blocs auraient fini par diverger sur la
   hauteur de frappe. Ce qui diffère — la laisse de largeur — est dit plus bas, au registre. */
/* `select` n'est de la liste qu'au registre, et pour un seul contrôle : le mode de
   renouvellement de la Diffusion. Les listes des autres écrans — enseigne, magasin, nature —
   vivent hors d'une rangée de registre et gardent l'apparence native ; celui-ci voisine trois
   boîtes de saisie dans la même carte, et un contrôle natif y aurait signalé une différence
   qui n'existe pas. */
.champ input,
.registre__valeur input,
.registre__valeur select {
  width: 100%;
  height: 40px;
  padding: 0 0.7rem;
  font-size: 0.9375rem;
  background: #fafbfc;
  border: 1px solid var(--trait-froid);
  border-radius: 6px;
  transition: border-color 0.14s, background 0.14s, box-shadow 0.14s;
}

.champ input:focus,
.registre__valeur input:focus,
.registre__valeur select:focus {
  outline: none;
  background: var(--papier);
  border-color: var(--marine-500);
  box-shadow: 0 0 0 3px rgba(11, 78, 168, 0.13);
}

/* Un champ figé n'est pas désactivé : la saisie commune, une fois gelée sur un
   certificat émis, doit continuer d'accompagner les lignes qui restent — un
   champ désactivé n'est pas posté. */
.champ input[readonly] {
  color: var(--encre-douce);
  background: #f0f1f4;
  border-style: dashed;
}

.champ input[aria-invalid='true'] {
  border-color: var(--refus);
  background: var(--refus-fond);
}

.note {
  margin-top: 0.25rem;
  font-size: 0.6875rem;
  line-height: 1.5;
  color: var(--encre-douce);
}

.erreur {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.75rem;
  color: var(--refus);
}

.page .erreur {
  font-size: 0.8125rem;
}

.refus {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin-bottom: 1.15rem;
  padding: 0.8rem 0.95rem;
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--refus);
  background: var(--refus-fond);
  border-radius: 8px;
}

/* Les deux seules règles que cette feuille ait reçues depuis sa reprise octet pour octet du témoin.
   Elle vivait en ligne dans `src/app/emission/refus-de-sortie.ts`, page que le cadre
   TypeScript rendait à la main : une route de ressource ne traversait ni la mise en page
   racine ni la feuille empaquetée. La contrainte n'existe pas ici — la page de refus est un
   gabarit comme les autres —, mais la règle est partie avec le module. Valeurs recopiées de
   l'étiquette `typescript-avant-bascule`, sans rien y ajouter.

   Le numéro de certificat est composé de segments tirettés : sans `hyphens: none`, le
   navigateur le coupe en fin de ligne, et le vendeur lit un numéro sur deux lignes là où il
   cherche à le relever. */
/* Même composition qu'au panneau, sur fond clair : le monogramme plein et le mot
   à l'encre marine.

   La signature d'un seul tenant est partie avec la mention d'enseigne et de groupe
   qu'elle portait en petites capitales — la règle précédente la disait déjà, et
   c'est précisément ce qu'un écran du personnel ne nomme plus. */
.refus__marque {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  margin-bottom: 1.75rem;
}

.refus__marque img {
  width: auto;
  height: 46px;
}

.refus__marque span {
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: 0.28em;
  color: var(--marine-900);
}

.refus__motif {
  margin-top: 0.9rem;
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--encre-moyenne);
  text-wrap: pretty;
  hyphens: none;
}

.case {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  grid-column: span 12;
  font-size: 0.8125rem;
  color: var(--encre-moyenne);
}

.case input {
  width: 16px;
  height: 16px;
  flex: none;
  accent-color: var(--marine-700);
}

.case label {
  margin: 0;
  font-size: inherit;
  font-weight: 400;
}

.case .erreur {
  flex-basis: 100%;
}

/* ═══ Durée de garantie ════════════════════════════════════════════════════
   La durée est ce que le vendeur cherche : elle titre les groupes. La nature du
   produit est ce qui, au barème, la justifie : elle est le choix (ADR-0017).
   Un seul groupe de boutons radio pour les six natures — la présentation est en
   trois blocs, la valeur postée reste la catégorie, et le clavier parcourt les
   six options sans qu'aucune ne soit masquée. */

.garantie {
  grid-column: span 12;
}

.garantie > .intitule {
  display: block;
  margin-bottom: 0.45rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--encre-moyenne);
}

.durees {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.5rem;
}

.duree {
  display: block;
  padding: 0.85rem 0.75rem 0.9rem;
  background: #fafbfc;
  border: 1px solid var(--trait-froid);
  border-radius: 8px;
  cursor: pointer;
  text-align: center;
}

.duree:hover {
  background: rgba(20, 53, 99, 0.05);
}

/* Le contrôle est **dans** le document, jamais retiré : `sr-only` plutôt que
   `display: none`, qui le sortirait du parcours clavier et le rendrait muet aux
   lecteurs d'écran. La carte entière est le `<label>` : toute sa surface coche. */
.duree input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* La carte choisie se distingue : c'est la ligne du barème que le document mettra
   en avant. */
.duree:has(input:checked) {
  background: linear-gradient(180deg, rgba(225, 164, 48, 0.1), rgba(225, 164, 48, 0));
  border-color: var(--or-500);
}

/* Le focus est porté par la carte, le contrôle étant invisible : sans cela, un
   vendeur au clavier ne saurait pas où il se trouve dans le groupe. */
.duree:has(input:focus-visible) {
  outline: 2px solid var(--or-600);
  outline-offset: 2px;
}

.duree__valeur {
  display: block;
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--marine-900);
}

.duree:has(input:checked) .duree__valeur {
  color: var(--or-700);
}

.garantie[data-refuse='oui'] .duree {
  border-color: var(--refus);
}

/* ═══ Signalements ═════════════════════════════════════════════════════════ */

/* Le doublon **avertit**, il n'interdit pas : le doublon légitime existe. La
   confirmation n'apparaît qu'après le signalement — offerte d'emblée, elle
   serait cochée par habitude et la trace ne vaudrait plus rien. */
.doublon {
  grid-column: span 12;
  padding: 0.7rem 0.85rem;
  font-size: 0.75rem;
  line-height: 1.55;
  color: var(--attention);
  background: var(--attention-fond);
  border: 1px solid rgba(138, 90, 0, 0.22);
  border-radius: 6px;
}

.doublon b {
  display: block;
}

.doublon .case {
  grid-column: auto;
  margin-top: 0.4rem;
  font-size: 0.75rem;
  color: var(--attention);
}

.doublon .case input {
  accent-color: var(--attention);
}

.derogation {
  grid-column: span 12;
  padding: 0.7rem 0.85rem;
  background: #f5f8fd;
  border: 1px dashed var(--marine-300);
  border-radius: 6px;
}

.derogation__titre {
  margin-bottom: 0.55rem;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--marine-800);
}

.derogation__titre em {
  font-style: normal;
  font-weight: 400;
  color: var(--encre-douce);
}

.avis {
  display: flex;
  gap: 0.6rem;
  padding: 0.85rem 1rem;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--marine-800);
  background: #f2f6fc;
  border-radius: 8px;
}

/* Le gras d'un avis est **celui d'un avertissement** : les cinq écrans qui portent un
   `.avis` sans état — l'envoi qui ne remet pas, l'annulation sans retour, l'absence de
   version en vigueur — ouvrent tous sur une phrase que l'ambre souligne.

   Il n'a jamais rien eu à dire de l'essai de la Diffusion, dont l'avis porte un état et
   non un avertissement : le mot « Essai servi » — le succès — s'y peignait dans la couleur
   de l'alerte (D11). Le correctif est au gabarit et non ici : cet avis-là n'a plus de
   gras, et son mot en clair est celui du libellé lui-même. */
.avis b {
  color: var(--attention);
}

/* ── Les trois apparences de l'avis d'essai (D10) ──────────────────────────
   Six issues, trois apparences, et c'est le partage que font déjà les codes de retour de
   la commande — `3` l'action humaine, `4` l'absence momentanée. L'écran dit ce que
   journald dit ; un découpage propre à l'écran aurait fait diverger les deux lectures du
   même fait. Le classement est **au serveur** (`transport.py`, `LIBELLES_DE_L_ESSAI`), sur
   l'idiome de `LIBELLES_REMISE` : la feuille ne porte que les aplats.

   Les modificateurs sont **ceux de `.avis`**, et non ceux de `.statut` ou d'`.etiquette`
   dont ils reprennent pourtant les couleurs : emprunter `statut--neutre` à un autre bloc
   aurait accolé à `avis` un modificateur orphelin, et le premier réglage de `.statut` se
   serait propagé ici sans que rien ne l'annonce. C'est la décision déjà écrite au bloc
   `.etiquette`, tenue une troisième fois.

   **Trois et non quatre** : l'état d'attente que l'îlot pose pendant l'appel reprend
   `avis--neutre`. Les deux disent la même chose à qui regarde — il n'y a rien à corriger,
   il y a à attendre —, et une quatrième teinte aurait introduit une couleur qui ne
   nomme aucun fait. La couleur, de toute façon, ne porte jamais l'état seule : chaque
   libellé ouvre sur son mot (D11, WCAG 1.4.1). */
.avis--servi {
  color: var(--valide);
  background: var(--valide-fond);
}

.avis--refus {
  color: var(--refus);
  background: var(--refus-fond);
}

.avis--neutre {
  color: var(--encre-moyenne);
  background: #eef0f3;
}

/* ═══ Onglets des produits garantis ════════════════════════════════════════
   Un certificat par onglet : la profondeur de la page ne dépend plus du nombre
   de produits. Les lignes inactives restent dans le document — masquées, elles
   sont toujours postées, et une saisie qui disparaîtrait du formulaire
   disparaîtrait de la série. */

.onglets {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  margin-bottom: 1rem;
  border-bottom: 1px solid var(--trait-froid);
}

.onglet {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.5rem 0.8rem;
  margin-bottom: -1px;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--encre-douce);
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
}

/* Sans quoi l'onglet ne descend pas sous la largeur de son libellé : un élément
   de rangée `flex` a pour largeur minimale celle de son contenu, et c'est ce
   plancher qui reportait la troncature sur le repli du texte.

   Porté par les onglets **de produit** seuls, et non par `.onglet` : le bouton
   d'ajout partage la classe sans porter de libellé tronquable — il n'a pas de
   `<span>` —, et l'autoriser à passer sous sa largeur de contenu ne lui laisse
   que le repli. */
.onglets__groupe .onglet {
  min-width: 0;
}

/* Le libellé est tronqué, jamais replié. La barre est une rangée sans repli :
   un libellé qui passe à la ligne fait grandir toute la rubrique, et pousse la
   saisie vers le bas. À quatre produits — le ticket d'une livraison —, les
   quatre désignations se repliaient déjà, et l'ouverture de la confirmation,
   qui demande sa place à la même rangée, portait la barre de 57 à 96 px. La
   désignation entière reste lisible sur la ligne du produit et sur la fiche,
   et le texte reste entier au document pour qui lit l'écran autrement. */
.onglet span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.onglet[aria-selected='true'] {
  color: var(--marine-900);
  border-bottom-color: var(--marine-800);
}

.onglet em {
  font-style: normal;
  font-size: 0.6875rem;
  font-weight: 500;
  color: var(--or-600);
}

.onglet--ajout {
  /* « + Produit » tient sur une ligne : c'est le seul onglet dont le libellé ne
     se tronque pas — il n'a pas de `<span>` —, et la rangée le comprimerait
     jusqu'au repli comme elle comprime le reste. */
  white-space: nowrap;
  margin-left: auto;
  color: var(--marine-600);
  border-radius: 6px;
}

.onglet--ajout:hover {
  background: #f0f5fc;
}

.retirer {
  padding: 0.3rem 0.55rem;
  font-size: 0.75rem;
  color: var(--encre-douce);
  background: none;
  border: 1px solid transparent;
  border-radius: 6px;
}

.retirer:hover {
  color: var(--refus);
  border-color: rgba(153, 35, 31, 0.25);
  background: var(--refus-fond);
}

/* La croix de retrait vit dans un groupe qui s'intercale entre le `tablist` et
   son `tab` : l'onglet est un bouton, un bouton ne s'imbrique pas dans un
   bouton, et `x-for` exige une racine unique. Le `role="presentation"` que le
   groupe porte retire ce `<div>` de l'arbre ARIA, **et lui seul** — ses enfants
   y remontent sous le `tablist`, qui n'admet que des `tab` ; l'écart est
   consigné au gabarit et laissé à son propre ticket.
   Le groupe est **étiré** et non centré : sans cela l'onglet actif, plus court
   que la croix, verrait son soulignement flotter au-dessus du filet. */
.onglets__groupe {
  display: flex;
  align-items: stretch;
  /* Même raison qu'à l'onglet : le groupe est à son tour un élément de rangée
     `flex`, et son plancher de largeur reporterait celui de l'onglet. */
  min-width: 0;
}

/* 2,5 rem de côté. Le plancher de cible tactile de WCAG 2.5.8 est de 24 px ; le
   poste est un écran de caisse, où le doigt remplace le pointeur, et la croix
   prend donc la mesure d'un doigt sans porter la barre d'onglets à la hauteur
   d'un bouton d'action. La paire de confirmation qui prend sa place porte le
   même plancher : la barre ne bouge pas d'un pixel à l'ouverture. */
.onglets__croix {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 2.5rem;
  min-height: 2.5rem;
  font-size: 1rem;
  line-height: 1;
  color: var(--encre-douce);
  background: none;
  border: 1px solid transparent;
  border-radius: 6px;
}

.onglets__croix:hover {
  color: var(--refus);
  border-color: rgba(153, 35, 31, 0.25);
  background: var(--refus-fond);
}

/* La confirmation en deux temps, **à l'emplacement du contrôle qui l'a
   ouverte** : la croix de l'onglet ou le bouton du pied de ligne lui cède sa
   place. Jamais une boîte système — `confirm()` n'est employé par aucun écran
   du service, et une boîte du navigateur n'aurait ni cet habillage ni cette
   langue. Le bloc est le même aux deux endroits, faute de quoi le même acte se
   présenterait de deux façons sur le même écran. */
.confirmation {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

.confirmation__acquiescement,
.confirmation__renoncement {
  /* Les deux libellés tiennent sur une ligne quoi qu'il arrive : la rangée les
     comprime comme le reste, et « Confirmer / le retrait » replié en deux
     donnerait à l'acte destructeur l'air d'un accident de mise en page. Ce sont
     les désignations qui cèdent la place, par troncature. */
  white-space: nowrap;
  min-height: 2.5rem;
  padding: 0.35rem 0.7rem;
  font-size: 0.75rem;
  font-weight: 600;
  border-radius: 6px;
}

/* L'acte qui retire porte la couleur du refus, seule urgence que la feuille
   déclare ; le renoncement reste neutre. Un vendeur qui clique vite doit
   distinguer les deux à la teinte avant de les distinguer au mot. */
.confirmation__acquiescement {
  color: var(--papier);
  background: var(--refus);
  border: 1px solid var(--refus);
}

.confirmation__acquiescement:hover {
  background: var(--refus-appuye);
  border-color: var(--refus-appuye);
}

.confirmation__renoncement {
  color: var(--encre-douce);
  background: var(--papier);
  border: 1px solid var(--trait-froid);
}

.confirmation__renoncement:hover {
  border-color: var(--encre-douce);
}

/* ═══ Fiche du certificat à émettre ════════════════════════════════════════ */

.apercu {
  padding: 1.15rem 1.25rem 1.5rem;
  background: #e6e9ee;
}

.apercu__entete {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--encre-douce);
}

.apercu__entete span {
  margin-left: auto;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
}

.fiche {
  position: sticky;
  top: 3.75rem;
  padding: 0.95rem 1rem 1.1rem;
  font-size: 0.75rem;
  background: var(--papier);
  border-radius: 6px;
  box-shadow: 0 1px 2px rgba(6, 15, 34, 0.12), 0 16px 34px -24px rgba(6, 15, 34, 0.6);
}

.fiche__entete {
  display: flex;
  gap: 0.7rem;
  padding-bottom: 0.7rem;
  border-bottom: 2px solid var(--marine-900);
}

/* L'aperçu ne porte plus que le **nom** de l'enseigne de l'acteur : ni logo, ni
   mention de groupe. Le logo est une donnée du référentiel qui voyage en URI de
   données, et cette fiche est un reflet de la frappe, redessiné à chaque saisie —
   le document le paie une fois par tirage, l'écran d'émission le paierait à
   chaque frappe. */
.fiche__enseigne {
  display: flex;
  align-items: center;
  gap: 0.45rem;
}

.fiche__enseigne b {
  display: block;
  font-size: 0.6875rem;
}

.fiche h2 {
  margin-top: 0.5rem;
  font-size: 0.9375rem;
  font-weight: 700;
}

.fiche__numero {
  margin-top: 0.15rem;
  font-family: var(--chiffres);
  font-size: 0.625rem;
  color: var(--marine-700);
}

.fiche__lieu {
  margin-top: 0.2rem;
  font-size: 0.5625rem;
  line-height: 1.45;
  color: var(--encre-douce);
}

.fiche__frise {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  margin: 0.7rem 0;
  background: var(--trait);
  border: 1px solid var(--trait);
}

.fiche__frise > div {
  padding: 0.35rem 0.4rem;
  background: var(--papier);
}

/* L'échéance est **dérivée**, jamais saisie : c'est le seul champ de la fiche
   que personne ne frappe, et c'est pourquoi il porte l'or. */
.fiche__frise .echeance {
  background: var(--or-100);
}

.fiche__frise .echeance dt,
.fiche__frise .echeance dd {
  color: var(--or-700);
}

.fiche__frise dt {
  font-size: 0.5rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--encre-douce);
}

.fiche__frise dd {
  margin-top: 0.1rem;
  font-size: 0.75rem;
  font-weight: 700;
}

.fiche__cartes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem;
}

.fiche__carte {
  padding: 0.45rem 0.55rem;
  border: 1px solid var(--trait);
  border-radius: 3px;
}

.fiche__carte h3 {
  margin-bottom: 0.3rem;
  font-size: 0.5rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--encre-douce);
}

.fiche__carte dl {
  display: grid;
  grid-template-columns: 4.2rem 1fr;
  gap: 0.12rem 0.3rem;
  font-size: 0.625rem;
}

.fiche__carte dt {
  color: var(--encre-douce);
}

.fiche__carte dd {
  font-weight: 600;
  overflow-wrap: anywhere;
}

.fiche__bareme {
  margin-top: 0.6rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--trait);
}

.fiche__bareme h3 {
  margin-bottom: 0.35rem;
  font-size: 0.5rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--encre-douce);
}

.pastilles {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}

.pastille {
  padding: 0.2rem 0.45rem;
  font-size: 0.5625rem;
  color: var(--encre-douce);
  border: 1px solid var(--trait);
  border-radius: 999px;
}

.pastille b {
  color: var(--encre);
}

.pastille--retenue {
  color: var(--marine-900);
  background: var(--marine-100);
  border-color: var(--marine-300);
}

.fiche__mention {
  margin-top: 0.7rem;
  padding-top: 0.5rem;
  font-size: 0.5625rem;
  line-height: 1.5;
  color: var(--encre-douce);
  border-top: 1px solid var(--trait);
}

.fiche__mention b {
  color: var(--attention);
}

/* ═══ Barre d'action ═══════════════════════════════════════════════════════ */

.action {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 25;
  display: flex;
  align-items: center;
  gap: 1.1rem;
  padding: 0.7rem clamp(0.9rem, 2vw, 1.6rem);
  background: rgba(255, 255, 255, 0.94);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--trait-froid);
}

.bilan {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  font-size: 0.8125rem;
}

.bilan b {
  font-weight: 600;
}

.bilan .separateur {
  width: 1px;
  height: 18px;
  background: var(--trait-froid);
}

.bilan .echeance {
  font-weight: 600;
  color: var(--or-700);
}

.bilan .vide {
  color: var(--encre-douce);
}

.action .droite {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-left: auto;
}

/* ═══ Boutons ══════════════════════════════════════════════════════════════ */

.principal {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  height: 42px;
  padding: 0 1.4rem;
  font-size: 0.9375rem;
  font-weight: 600;
  color: #fff;
  background: var(--marine-900);
  border: 0;
  border-radius: 7px;
  transition: background 0.16s, transform 0.08s;
}

.principal:hover:not(:disabled) {
  background: var(--marine-800);
}

.principal:active:not(:disabled) {
  transform: translateY(1px);
}

.principal:disabled {
  color: var(--encre-douce);
  background: #e4e7eb;
  cursor: not-allowed;
}

.page .principal {
  height: 46px;
  border-radius: 10px;
  box-shadow: 0 10px 24px -14px rgba(10, 26, 52, 0.9);
}

.secondaire {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  height: 40px;
  padding: 0 1rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--marine-800);
  text-decoration: none;
  background: var(--papier);
  border: 1px solid var(--trait-froid);
  border-radius: 7px;
  transition: border-color 0.16s, background 0.16s;
}

.secondaire:hover {
  border-color: var(--marine-600);
  background: #f5f8fd;
}

/* L'essai en cours désactive son bouton : un seul processus sert le site, et deux essais
   concurrents le mettraient à attendre deux fois dix secondes.

   La règle vient **après** le survol, à spécificité égale : le pointeur resté sur le bouton
   lui aurait sinon gardé sa bordure vive pendant tout l'appel. Les valeurs sont celles de
   `.principal:disabled` — un seul refus se dit d'une seule façon. */
.secondaire:disabled {
  color: var(--encre-douce);
  background: #e4e7eb;
  border-color: var(--trait-froid);
  cursor: not-allowed;
}

/* Bouton d'action serveur rendu comme un lien : la fermeture de session et le
   verrouillage sont des écritures, elles ne peuvent pas être des liens. */
.lien {
  padding: 0;
  font: inherit;
  color: var(--encre-douce);
  background: none;
  border: 0;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.lien:hover {
  color: var(--marine-800);
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1.25rem;
}

.grille > .actions {
  grid-column: span 12;
  margin-top: 0.35rem;
}

/* La suite du parcours, après le bloc de remise. Elle porte l'aplat du bouton `secondaire`,
   comme la sortie du document et comme la même suite sur la vue de série : c'est la charte de
   l'interface.

   Sa respiration haute est courte parce que l'aplat sépare déjà — un bouton n'a pas besoin du
   blanc dont un lien souligné avait besoin pour se détacher du relevé. Ces 6 px sont, avec la
   respiration basse du plan, ce qui rend au poste de caisse la hauteur que l'aplat lui coûte. */
.plan > .actions--suite {
  margin-top: 0.5rem;
}

/* La bobine tourne pendant que le serveur travaille. Elle est portée par le
   bouton lui-même : le vendeur ne doit pas avoir à chercher ailleurs si son
   geste a été pris. */
.principal[data-occupe='oui'] {
  color: transparent;
}

.principal[data-occupe='oui'] svg {
  opacity: 0;
}

.principal[data-occupe='oui']::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 16px;
  height: 16px;
  border: 2px solid rgba(255, 255, 255, 0.28);
  border-top-color: var(--or-400);
  border-radius: 50%;
  animation: tourner 0.65s linear infinite;
}

@keyframes tourner {
  to {
    transform: rotate(360deg);
  }
}

.touche {
  font-family: var(--chiffres);
  font-size: 0.6875rem;
  color: var(--encre-douce);
}

.touche kbd {
  padding: 0.1rem 0.3rem;
  background: #eceff3;
  border: 1px solid var(--trait-froid);
  border-bottom-width: 2px;
  border-radius: 4px;
}

/* ═══ Certificats déjà émis, dans une série interrompue ════════════════════ */

.deja-emis {
  margin-bottom: 1rem;
  padding: 0.85rem 1rem;
  background: var(--valide-fond);
  border-left: 3px solid var(--valide);
  border-radius: 0 6px 6px 0;
}

.deja-emis h2 {
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--valide);
}

.deja-emis p {
  margin-top: 0.3rem;
  font-size: 0.75rem;
  line-height: 1.55;
  color: var(--encre-moyenne);
}

.deja-emis ul {
  margin-top: 0.5rem;
  display: grid;
  gap: 0.2rem;
  font-size: 0.8125rem;
}

.deja-emis a {
  font-family: var(--chiffres);
  font-size: 0.75rem;
}

/* ═══ Écrans de suite : fiche d'un certificat, série, remise ═══════════════ */

/* ── Les mentions exceptionnelles ───────────────────────────────────────────
   Doublon confirmé et dérogation de durée sont hors du relevé et au-dessus de lui : ce ne
   sont pas des champs du certificat mais des circonstances de son émission. Alignées entre
   deux champs, elles se lisaient comme des données ordinaires, et leur phrase de deux lignes
   déformait la rangée où elles étaient prises.

   Elles partagent **un seul** encadré : deux cartouches empilées coûtaient deux bordures,
   deux respirations et un intervalle, pour une distinction que le libellé en tête de ligne
   suffit à porter. Les jetons d'attention de la feuille en font l'exception qu'elles sont,
   sans l'alarme d'un refus. */
.mentions {
  margin-top: 0.45rem;
  padding: 0.5rem 1rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--encre-moyenne);
  background: var(--attention-fond);
  border: 1px solid var(--or-100);
  border-radius: 10px;
}

/* Le libellé et sa phrase sur une même ligne : le libellé ne prend que sa laisse, la phrase
   occupe le reste. C'est ce qui tient les deux mentions alignées l'une sous l'autre. */
.mentions p {
  display: flex;
  gap: 0.7rem;
  margin: 0;
}

.mentions p + p {
  margin-top: 0.3rem;
}

.mentions b {
  flex: none;
  min-width: 5.5rem;
  color: var(--attention);
  font-weight: 600;
}

/* Le gabarit porte `releve` sur le `dl` lui-même : la grille est déclarée sur
   l'élément qui porte la classe, non sur un `dl` qui en descendrait. */
.releve {
  margin-top: 0.9rem;
  background: var(--papier);
  border: 1px solid var(--trait-froid);
  border-radius: 10px;
  overflow: hidden;
  display: grid;
  grid-template-columns: 14rem minmax(0, 1fr);
  font-size: 0.9375rem;
}

.releve dt {
  padding: 0.7rem 1rem;
  color: var(--encre-douce);
  border-top: 1px solid var(--trait-froid);
}

.releve dd {
  padding: 0.7rem 1rem;
  font-weight: 500;
  border-top: 1px solid var(--trait-froid);
  overflow-wrap: anywhere;
}

/* La première rangée est celle des **premières cellules**, non celle du premier `dt` :
   `:first-of-type` ne connaît pas les rangées d'une grille, et le viser laisserait un filet
   résiduel au milieu de la rangée dès que celle-ci porte plus d'une paire. Deux cellules ici,
   quatre sous le relevé en paires. */
.releve > :nth-child(-n + 2) {
  border-top: 0;
}

/* ── Le relevé en paires ────────────────────────────────────────────────────
   Quatre pistes au lieu de deux : libellé, valeur, libellé, valeur — les pistes de
   libellé dimensionnées au contenu, celles de valeur en fraction. Dix champs tiennent
   en six rangées au lieu de dix, sans que rien ne soit caché ni qu'un clic soit ajouté.

   Le placement reste **l'ordre du document** : aucune cellule n'est posée à la main, faute
   de quoi l'ajout d'un champ demanderait de renuméroter la grille. */
.releve--paires {
  grid-template-columns:
    minmax(8.5rem, auto) minmax(0, 1fr)
    minmax(8.5rem, auto) minmax(0, 1fr);
}

.releve--paires dt,
.releve--paires dd {
  padding: 0.5rem 1rem;
}

/* Un cran de plus, et sur la **seule** fiche d'un certificat émis. Le code article y a fait
   passer le relevé de cinq rangées à six, et la fiche dense — doublon confirmé **et**
   dérogation — tenait à 5 px de la ligne de flottaison du poste de caisse : la rangée de plus
   l'en chassait de 35. Les 38 px rendus ici sont ce qui la garde entière, et
   `hauteur_des_ecrans_test` les mesure.

   Un modificateur, et non la règle au-dessus : trois autres écrans portent le relevé en paires
   — l'envoi, l'annulation et les coordonnées —, aucun ne porte de budget de hauteur, et aucun
   n'a demandé à être resserré. Une densité imposée à quatre écrans pour la contrainte d'un
   seul serait un changement d'habillage déguisé en correctif. */
.releve--serre dt,
.releve--serre dd {
  padding: 0.3rem 1rem;
}

/* Un filet vertical sépare les deux paires d'une même rangée, posé sur le libellé de la
   seconde. Sans lui, l'œil lit quatre colonnes indépendantes et rattache la valeur de
   gauche au libellé de droite. */
.releve--paires dt:nth-of-type(2n) {
  border-left: 1px solid var(--trait-froid);
}

.releve--paires > :nth-child(-n + 4) {
  border-top: 0;
}

/* L'URL de vérification fait 78 caractères. À demi-largeur elle passe sur trois lignes et
   impose leur hauteur aux trois autres cellules de la rangée : elle prend donc la rangée
   entière, sa valeur s'étendant du libellé à la fin de la grille. Elle reste **en clair** —
   le vendeur la dicte au client dont le téléphone ne scanne pas le QR. */
.releve__large {
  grid-column: 2 / -1;
}

/* L'étiquette porte la même classe que sa valeur, et ouvre une rangée neuve : c'est la
   **paire** qui prend la largeur, non la seule valeur. Sans cette règle, un nombre impair de
   paires — neuf depuis le code article — laisse l'étiquette en troisième piste et chasse sa
   valeur sur une rangée à elle, dont la première piste reste vide.

   Sa spécificité l'emporte sur le `1 / -1` du second repli, et c'est sans conséquence : à une
   piste, `1` et `1 / -1` désignent la même colonne. La règle du repli continue de valoir pour
   la valeur, qui est la seule à en avoir besoin.

   Le filet vertical tombe avec la colonne. Il sépare les deux paires d'une rangée et se pose
   sur les étiquettes de **rang pair** ; celle-ci l'est devenue en même temps que la grille
   gagnait sa dixième, et l'aurait porté au bord gauche du relevé, où il ne sépare rien et
   double le trait du cadre.

   Le sélecteur reprend `.releve--paires` pour ce seul retrait, et c'est la spécificité qui
   l'exige : `.releve--paires dt:nth-of-type(2n)` pèse (0,2,1), `dt.releve__large` seul (0,1,1),
   et le filet l'emportait quel que soit l'ordre de la feuille. À poids égal, c'est la règle
   écrite en dernier qui gagne, et c'est celle-ci. La colonne, elle, n'a pas ce conflit :
   `.releve__large` seul pèse (0,1,0). */
dt.releve__large {
  grid-column: 1;
}

.releve--paires dt.releve__large {
  border-left: 0;
}

.releve .numero {
  font-family: var(--chiffres);
  font-weight: 600;
  color: var(--marine-800);
}

.releve .echeance {
  font-weight: 600;
  color: var(--or-700);
}

.serie {
  display: grid;
  gap: 0.85rem;
  margin-top: 1.5rem;
}

.serie > li {
  padding: 0.95rem 1.15rem;
  background: var(--papier);
  border: 1px solid var(--trait-froid);
  border-radius: 10px;
}

.serie h2 {
  font-family: var(--chiffres);
  font-size: 0.875rem;
  font-weight: 700;
}

.serie dl {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.6rem 1rem;
  margin-top: 0.7rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--trait-froid);
  font-size: 0.875rem;
}

.serie dt {
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--encre-douce);
}

.serie dd {
  margin-top: 0.15rem;
  font-weight: 500;
}

/* ═══ Archive du magasin ═══════════════════════════════════════════════════
   La première lecture multi-résultats du service. Un tableau, et non des
   fiches : les colonnes sont les mêmes d'une ligne à l'autre, et c'est en les
   balayant qu'on retrouve un certificat. Aucune colonne n'y porte de nom de
   client — le type que la page reçoit ne peut pas en porter (ADR-0013). */

/* La légende des états de remise, repliée sous le chapeau. C'est la voie de
   découverte, et la seule qui ne dépende de rien : le popover d'une ligne exige un
   navigateur qui le serve, celle-ci n'exige qu'un clic.

   Fermée, elle ne coûte que la hauteur de son résumé : le budget de hauteur du poste
   est ce que le ticket 01 vient de gagner, et une légende dépliée d'office l'aurait
   repris. */
.archive__legende {
  margin-top: 1.25rem;
  font-size: 0.8125rem;
  color: var(--encre-douce);
}

.archive__legende summary {
  font-weight: 600;
  color: var(--marine-700);
}

/* Deux colonnes : la pastille telle que la colonne l'écrit, et ce qu'elle recouvre. Une
   grille et non un flux, pour que les quatre textes s'alignent sur un seul bord — c'est
   ce qui les rend comparables, et la légende n'existe que pour les comparer. */
.archive__legende dl {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 0.45rem 0.9rem;
  max-width: 56rem;
  margin-top: 0.75rem;
}

.archive__recherche {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  margin-top: 1.5rem;
}

.archive__recherche label {
  flex: 1 0 100%;
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--encre-douce);
}

.archive__recherche input {
  flex: 1 1 22rem;
  padding: 0.55rem 0.75rem;
  font: inherit;
  font-size: 0.9375rem;
  color: var(--encre);
  background: var(--papier);
  border: 1px solid var(--trait-froid);
  border-radius: 8px;
}

.archive__recherche input:focus {
  border-color: var(--marine-500);
  outline: 0;
  box-shadow: 0 0 0 3px rgba(28, 58, 102, 0.12);
}

/* `.archive` est le **dessin de table** du service, et non la table de l'archive : les
   écrans d'administration — magasins, enseignes, comptes, journal — le portent aussi.
   Ce qui suit vaut donc pour cinq écrans, et rien de propre à l'archive n'y entre. */
.archive {
  width: 100%;
  margin-top: 1.5rem;
  font-size: 0.875rem;
  background: var(--papier);
  border: 1px solid var(--trait-froid);
  border-radius: 10px;
  border-collapse: separate;
  border-spacing: 0;
  overflow: hidden;
}

.archive th,
.archive td {
  padding: 0.7rem 0.9rem;
  text-align: left;
  vertical-align: top;
}

/* Le **modificateur de l'archive des certificats**, et de lui seul. Il porte tout ce
   que le ticket 01 a arrêté : la répartition déclarée, le plancher de largeur, la
   respiration resserrée et les coupures.

   Un modificateur et non le bloc nu, parce que le bloc est partagé : posées sur
   `.archive`, ces règles auraient donné aux quatre tables d'administration un plancher
   de 1 232 px dans un plan qui en offre 960 — sans boîte pour le recevoir —, et une
   répartition à parts égales sur des colonnes qui ne déclarent rien. Le dessin est
   commun, la mise en page ne l'est pas.

   Rien ne le mesure encore : les écrans d'administration ne sont pas du parcours du
   poste, et le relevé des familles ne les sert pas. C'est le cloisonnement du sélecteur
   qui tient ici, non l'instrument. */
.archive--certificats {
  /* La répartition est **déclarée**, jamais déduite de l'échantillon affiché. En
     `auto`, la même page à une ligne et à cinquante donne deux répartitions, et celle
     de cinquante lignes attribuait 209 px à un numéro structurellement borné à 25
     caractères et 78 px à une origine qui en demandait six lignes — inversement
     proportionnelle au besoin. Seul `fixed` ferme cela. */
  table-layout: fixed;
  /* Le plancher sous lequel le tableau cesse de se comprimer et se met à défiler dans
     sa boîte. Il vaut la largeur que le tableau prend **sur le poste de caisse**, à un
     cheveu près : au-dessus de la cote, le tableau s'étire et rien ne défile ; en
     dessous, il garde exactement la répartition du poste et c'est la boîte qui bouge.

     Un plancher plus bas aurait laissé les colonnes libres se comprimer avant de
     défiler — 78 px chacune à 1 024 px, soit la largeur même qui a motivé ce chantier.
     Le laisser tomber aurait, lui, écrasé neuf colonnes dans 390 px. */
  min-width: 77rem;
}

/* La respiration verticale est ce qui **reste** une fois les deux lignes de texte
   posées : la ligne fait deux lignes d'origine et deux d'« émis par », par décision, et
   le budget de 64 px est ce qui départage le reste. Elle est le seul levier si la ligne
   venait à dépasser — le nombre de lignes, lui, est arrêté. */
.archive--certificats th,
.archive--certificats td {
  padding: 0.6rem 0.7rem;
  overflow-wrap: anywhere;
}

/* La boîte de défilement du tableau. Sous la cote du poste, `table-layout: fixed`
   **comprime** les colonnes au lieu de déborder : sans elle et sans le `min-width`
   du tableau, 390 px écraserait les neuf colonnes au lieu de rendre une barre.

   Elle ne porte que le défilement : le cadre, le fond et l'arrondi restent au tableau,
   qui les partage avec les quatre tables d'administration. */
.archive__cadre {
  overflow-x: auto;
}

/* Les colonnes **bornées**, déclarées en absolu. Elles étaient cinq à l'arrêté du
   ticket ; le numéro de série les a rejointes, et le commentaire de sa règle dit sur
   quelle mesure. Les trois qui restent — origine, produit garanti, émis par — n'ont pas
   de largeur et se partagent le reste à parts égales ; quand l'origine n'est pas
   servie, les deux dernières reprennent sa part d'elles-mêmes. Un seul jeu de largeurs,
   donc, et pas deux. */

/* Le numéro est borné **structurellement** : code d'enseigne et code de magasin à six
   caractères, millésime à quatre, séquence à six, trois tirets — vingt-cinq caractères
   en chasse fixe. La colonne porte la police de la cellule pour que ses `ch` s'y
   résolvent : sous `fixed`, une largeur en `ch` se mesure contre la police de
   l'élément qui la porte, et celle du `<col>` serait sinon celle du tableau. */
.archive__col-numero {
  width: 27ch;
  font-family: var(--chiffres);
  font-size: 0.8125rem;
}

/* Un quantième en chiffres, et un nombre suivi de son unité : ni l'un ni l'autre ne se
   replie (`.archive__serre`), et leur forme est connue à l'avance. */
.archive__col-date {
  width: 6.5rem;
}

.archive__col-duree {
  width: 5.25rem;
}

/* Le numéro de série **sort du partage égal**, et c'est la mesure qui l'en a sorti : à
   parts égales il recevait 145 px, et « Article non sérialisé » — le motif que la case
   d'absence pose d'office, donc le plus fréquent des trois — y passait à deux lignes.
   Une valeur qui tient sur une ligne pour deux motifs sur trois n'est pas une colonne
   réglée, c'est une colonne réglée sur le plus court de ses cas.

   C'est la pondération que la spécification tenait en réserve — « la mesure d'abord, la
   pondération ensuite » —, appliquée à la colonne que la mesure a désignée et non à
   celle qu'elle prévoyait. Les trois autres restent à parts égales, et reprennent la
   part de l'origine quand celle-ci n'est pas servie. */
.archive__col-serie {
  width: 11rem;
}

/* Les deux colonnes d'étiquette ne portent que des libellés fermés, et l'étiquette ne
   se replie pas : la largeur est celle du plus long des libellés du tableau, non une
   part négociable. « Preuve manquante » gouverne la colonne de remise, « Remplacé »
   celle de la couverture. */
.archive__col-couverture {
  width: 7rem;
}

.archive__col-remise {
  width: 9.5rem;
}

.archive thead th {
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--encre-douce);
  white-space: nowrap;
  border-bottom: 1px solid var(--trait-froid);
}

.archive tbody tr + tr th,
.archive tbody tr + tr td {
  border-top: 1px solid var(--trait-froid);
}

.archive tbody tr:hover th,
.archive tbody tr:hover td {
  background: #f7f8fa;
}

.archive__numero {
  font-family: var(--chiffres);
  font-size: 0.8125rem;
  font-weight: 700;
  white-space: nowrap;
}

/* La date et la durée tiennent sur une ligne : les replier au milieu d'un
   quantième ou entre le nombre et son unité coûte une ligne à toute la table
   sans rien apprendre. */
.archive__serre {
  white-space: nowrap;
}

/* La désignation : **deux lignes, puis coupure**. À cette largeur une ligne porte une
   trentaine de caractères ; la médiane du catalogue réel est de 34 et son maximum de 40
   sur 15 893 articles. Une seule ligne couperait donc presque toutes les désignations
   réelles ; deux portent le catalogue et ne coupent que la saisie libre anormale, qui
   est le cas visé. La borne de saisie, elle, n'est pas touchée : refuser une émission
   parce qu'un libellé ne rentre pas dans une colonne ferait porter à un acte opposable
   une contrainte de feuille de style. */
.archive__designation span {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

/* Le magasin, puis l'enseigne en secondaire : le parti de « Émis par », où le nom porte
   et le code qualifie. Le magasin discrimine une ligne de l'autre, l'enseigne se répète.

   La règle est portée par le **modificateur** : `.archive__vendeur` sert aussi au
   journal d'administration, dont la colonne d'auteur n'est ni bornée ni coupée. */
.archive--certificats .archive__origine,
.archive--certificats .archive__vendeur {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.archive__origine span,
.archive__vendeur span {
  display: block;
  margin-top: 0.1rem;
  font-size: 0.75rem;
  color: var(--encre-douce);
}

/* Le nom de l'enseigne se coupe comme le magasin au-dessus de lui : c'est le second
   champ d'une colonne qui en porte deux, et rien ne le distingue du premier. */
.archive--certificats .archive__origine span {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Le code du vendeur, lui, ne se coupe **pas** : il fait trois caractères et lève
   l'homonymie, et le laisser entier est ce qui garantit qu'un nom coupé au-dessus de lui
   reste identifiable. Une coupure ici n'aurait jamais mordu — trois caractères tiennent
   dans toutes les largeurs —, et c'est précisément pourquoi elle n'a pas à être écrite :
   une règle qui ne s'exerce jamais se donne pour une décision qu'elle n'est pas. */
.archive__vendeur span {
  font-family: var(--chiffres);
}

/* L'étiquette de la colonne Remise est un **bouton** : le popover natif s'ouvre au
   clic, au tap et à Entrée, jamais au survol, et le poste visé est une dalle tactile.
   Ce qui suit ne fait que lui retirer ce que l'agent utilisateur donne à un bouton et
   qu'une pastille n'a pas.

   Elle précède `.etiquette` et ses modificateurs, et c'est **la seule raison de sa
   place** : `background: none` et le fond d'un modificateur ont la même spécificité, et
   c'est l'ordre de source qui les départage. Écrite plus bas, la remise à zéro aurait
   dépeint les quatre pastilles.

   Le raccourci `font: inherit` n'y est **pas** repris, bien que ce soit la forme
   ordinaire d'une remise à zéro de bouton : la règle d'élément `button, input, select`
   l'applique déjà plus haut, et `.etiquette` repose ensuite la taille. Ajouté ici, il
   ne change **rien** — mesuré : police, interligne et respiration identiques avec et
   sans. Ce serait donc une déclaration morte, et une déclaration morte dans une remise
   à zéro se lit comme une garde.

   Ce qui tient l'interligne du bouton est cette règle d'élément, et rien d'autre. Le
   jour où `button` en sortirait, la pastille de Remise reprendrait l'interligne
   `normal` de l'agent utilisateur et cesserait d'avoir la boîte de celle de Couverture
   — sans que la hauteur de la rangée bouge, ses deux lignes d'origine la tenant
   ailleurs. C'est ce qu'un cas garde, et non ce commentaire :
   `test_la_pastille_de_remise_a_la_meme_boite_que_celle_de_couverture`.

   Le pointeur est **rendu à la main** : `background: none` et `border: 0` retirent à ce
   bouton tout ce qui le donnait pour un bouton, et il ne reste alors rien qui annonce
   qu'il s'ouvre. La pastille de Couverture, à côté, lui ressemble et n'ouvre rien. */
.archive__remise {
  background: none;
  border: 0;
  cursor: pointer;
}

/* La pastille d'état reprend les aplats de la page publique : le même fait ne
   se dit pas de deux façons selon le lecteur. Elle est plus discrète, la
   couverture n'étant ici qu'une colonne parmi sept.

   Ses modificateurs sont les siens et non ceux de `.statut` : emprunter
   `statut--neutre` à un autre bloc aurait accolé à `etiquette` un modificateur
   orphelin, et le premier réglage de `.statut` se serait propagé ici sans que
   rien ne l'annonce. Les couleurs, elles, sont bien les mêmes variables. */
.etiquette {
  display: inline-block;
  padding: 0.2rem 0.55rem;
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
  border-radius: 999px;
}

.etiquette--actif {
  color: var(--valide);
  background: var(--valide-fond);
}

/* Deux faits sans rapport, un seul aplat : la couverture échue et la remise que
   personne n'atteste appellent l'une et l'autre le même degré d'attention. Les
   deux noms subsistent parce que les deux faits sont distincts — les fondre
   ferait afficher `etiquette--expire` sur une colonne qui ne parle pas de
   couverture, et le premier réglage de l'une se propagerait à l'autre. */
.etiquette--expire,
.etiquette--attention {
  color: var(--attention);
  background: var(--attention-fond);
}

/* Le seul aplat rouge des étiquettes, et il est réservé au certificat sans
   document (ADR-0019) : irrattrapable dans le service, et non pas seulement
   fâcheux. Un second emploi devra soutenir la comparaison. */
.etiquette--refus {
  color: var(--refus);
  background: var(--refus-fond);
}

.etiquette--neutre {
  color: var(--encre-moyenne);
  background: #eef0f3;
}

/* Le neutre **creux**, pour ce qui n'appelle aucune alerte mais n'est pas
   encore acquis — la remise en attente, seule à ce jour.

   Le plein et le creux disent l'acquis et le pendant, là où deux gris se
   seraient confondus sur un écran de caisse et où une quatrième teinte aurait
   fait concurrence aux deux défauts. La distinction tient donc à la forme, et
   se lit encore en niveaux de gris comme à l'impression.

   Le contour remplace le fond au lieu de s'y ajouter : une pastille pleine
   cerclée pèserait plus que l'ambre qu'elle ne doit pas concurrencer. Il est
   en revanche plus soutenu que `--trait-froid`, qui trace les filets du
   tableau : un contour de la même valeur que les lignes de la table se serait
   fondu dans la grille, et les deux neutres seraient restés jumeaux. */
.etiquette--creuse {
  color: var(--encre-douce);
  background: var(--papier);
  box-shadow: inset 0 0 0 1px #c2cad6;
}

/* L'infobulle d'une ligne : un popover natif, promu au *top layer*. C'est ce qui lui
   fait franchir les deux clips qu'aucun panneau positionné ne franchit — l'`overflow:
   hidden` qui coupe les angles du tableau, et la boîte de défilement du ticket 01. Les
   deux mordent précisément là où l'infobulle est attendue : la dernière colonne, et la
   cinquantième ligne.

   Elle paraît **centrée dans la fenêtre**, comportement par défaut du top layer.
   L'ancrer sous son étiquette demanderait le positionnement d'ancrage CSS, que seul
   Chrome sert : le poste de caisse aurait alors deux dessins selon son navigateur.

   Rien n'est écrit pour l'état fermé : l'agent utilisateur le pose en `display: none`,
   il ne peint rien et n'entre dans aucune mesure de hauteur. Une pseudo-classe
   d'interaction de plus n'aurait rien ajouté qu'une exception au relevé des
   sélecteurs. */
.archive__infobulle {
  max-width: min(32rem, 90vw);
  padding: 1rem 1.15rem;
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--encre-moyenne);
  background: var(--papier);
  border: 1px solid var(--trait-froid);
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(10, 26, 52, 0.18);
}

/* Le critère frappé est repris dans le message. Il vient d'une URL : rien n'en borne
   la longueur, et un paragraphe collé doit se replier au lieu d'élargir la page. */
.archive__vide {
  margin-top: 1.5rem;
  padding: 1.5rem;
  font-size: 0.9375rem;
  overflow-wrap: anywhere;
  color: var(--encre-douce);
  background: var(--papier);
  border: 1px solid var(--trait-froid);
  border-radius: 10px;
}

.archive__pages {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: 1.25rem;
}

.archive__rang {
  font-size: 0.8125rem;
  color: var(--encre-douce);
}

/* Le bloc suit les liens de sortie parce qu'il suit le geste : imprimer, faire
   signer, confirmer. */
.remise {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.25rem;
  margin-top: 1.25rem;
  padding: 0.95rem 1.15rem;
  background: var(--papier);
  border: 1px solid var(--trait-froid);
  border-radius: 10px;
}

.remise__indication {
  flex: 1 1 18rem;
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--encre-douce);
}

/* Acquise, la remise n'est plus une action ; en attente d'un tirage, elle ne
   l'est pas encore. Ni l'une ni l'autre ne porte d'aplat : un bouton
   suggérerait un acte disponible là où il ne l'est pas. */
.remise--acquise,
.remise--attente,
.remise--sans-document {
  display: block;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--encre-moyenne);
  background: #f7f8fa;
}

/* La fiche doit dire ce que la liste signale (ADR-0019) : le rouge de la colonne
   « Remise » se retrouve ici, faute de quoi le responsable envoyé sur la fiche
   par une ligne rouge y lirait un bloc que rien ne distingue et douterait de la
   liste. */
.remise--sans-document {
  color: var(--refus);
  background: var(--refus-fond);
  border-color: var(--refus);
}

/* ═══ Page publique de vérification ════════════════════════════════════════
   Atteinte au téléphone, par scan. Les trois réponses se ressemblent à dessein :
   rien ne doit distinguer un certificat inconnu d'une demande refusée, sans
   quoi la page devient un oracle (ADR-0004). */

.verification {
  max-width: 32rem;
  margin: 0 auto;
  padding: clamp(1.5rem, 5vw, 3rem) 1.25rem 3rem;
}

.verification__marque {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  margin-bottom: 1.75rem;
}

/* Le logo est désormais celui du référentiel, téléversé par un administrateur :
   la feuille ne sait plus rien de ses proportions, de son fond ni de ses marges.
   Trois conséquences, toutes tenues ici plutôt que supposées de l'actif.

   `object-fit: contain` : un logo qui n'est pas carré serait autrement étiré. La
   boîte reste carrée pour que la ligne ne se redessine pas d'une enseigne à
   l'autre ; c'est le logo qui s'y inscrit.

   La tuile blanche cesse d'être la conséquence d'un actif à fond opaque pour
   devenir une garantie : une charte au trait sombre et au fond transparent se
   rendrait sur le `--plan` de la page, où elle se lit mal. Le fond posé la place
   sur du papier, quelle que soit la charte.

   54 px, comme avant : c'est la hauteur du nom qu'elle accompagne. Au-delà, la
   vignette écrase l'enseigne au lieu de l'introduire. */
.verification__marque img {
  width: 54px;
  height: 54px;
  object-fit: contain;
  background: var(--papier);
  border-radius: 11px;
}

.verification__marque b {
  font-size: 0.9375rem;
  letter-spacing: 0.01em;
  text-transform: none;
  color: var(--encre);
}

.verification h1 {
  font-family: var(--didone);
  font-size: 1.75rem;
  font-weight: 400;
}

.statut {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 1.25rem;
  padding: 0.85rem 1rem;
  font-size: 1rem;
  font-weight: 600;
  border-radius: 10px;
}

.statut::before {
  content: '';
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: currentColor;
}

.statut--actif {
  color: var(--valide);
  background: var(--valide-fond);
}

.statut--expire {
  color: var(--attention);
  background: var(--attention-fond);
}

.statut--neutre {
  color: var(--encre-moyenne);
  background: #eef0f3;
}

.verification dl {
  margin-top: 1.5rem;
  background: var(--papier);
  border: 1px solid var(--trait-froid);
  border-radius: 10px;
  overflow: hidden;
}

.verification dt {
  padding: 0.75rem 1rem 0;
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--encre-douce);
}

.verification dd {
  padding: 0.15rem 1rem 0.75rem;
  font-size: 1rem;
  font-weight: 500;
  border-bottom: 1px solid var(--trait-froid);
}

.verification dd:last-child {
  border-bottom: 0;
}

.verification .chapeau {
  margin-top: 1.5rem;
  font-size: 0.8125rem;
  line-height: 1.7;
  color: var(--encre-douce);
}

/* ═══ Accueil ══════════════════════════════════════════════════════════════ */

.accueil {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 2rem 1.25rem;
  text-align: center;
  background: var(--marine-950);
  color: rgba(255, 255, 255, 0.6);
}

.accueil img {
  width: 260px;
  height: auto;
  margin: 0 auto 2rem;
}

.accueil h1 {
  font-family: var(--didone);
  font-size: clamp(1.75rem, 3vw, 2.4rem);
  font-weight: 400;
  color: #fff;
}

.accueil p {
  max-width: 44ch;
  margin: 0.9rem auto 0;
  font-size: 0.9375rem;
  line-height: 1.7;
}

.accueil .actions {
  justify-content: center;
  margin-top: 1.75rem;
}

.accueil .principal {
  color: var(--marine-950);
  background: var(--or-400);
}

.accueil .principal:hover {
  background: var(--or-500);
}

.accueil dl {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.3rem 1.5rem;
  margin: 2.75rem auto 0;
  padding-top: 1.5rem;
  font-size: 0.8125rem;
  text-align: left;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}

.accueil dt {
  color: rgba(255, 255, 255, 0.42);
}

.accueil dd {
  font-variant-numeric: tabular-nums;
  color: rgba(255, 255, 255, 0.78);
}

.hors-production {
  font-weight: 700;
  color: var(--or-400);
}

/* ═══ Adaptations ══════════════════════════════════════════════════════════ */

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

  .apercu {
    order: -1;
  }

  .fiche {
    position: static;
  }
}

/* ── Le groupe de session du rail d'administration, replié plus tôt ─────────
   Ce rail-là déborde depuis avant ce ticket, et le décompte y ajoutait 96 px à 1 024 px — la
   seule largeur où le bouton « Fermer », qui tenait dans la fenêtre, en sortait. Or c'est le
   contrôle dont le décompte est la face visible : le pousser hors écran est le seul défaut de
   ce ticket qui casse ce qui marchait.

   Le seuil est **propre à ce rail** et posé à 64 rem, une largeur au-dessus du seuil partagé :
   le rail du poste tient à 1 024 px sur une rangée et un cas l'exige, si bien qu'un seuil commun
   n'avait pas de valeur qui convienne aux deux. Le fil de ce rail-ci compte jusqu'à huit entrées
   contre deux au poste ; ce n'est pas la même contrainte.

   Le décompte y prend sa forme compacte, et le **groupe entier** passe en colonne : le décompte
   au-dessus du bouton qu'il annonce, la largeur du groupe devenant celle du plus large des deux
   au lieu de leur somme. C'est ce second geste qui rend les pixels décisifs — la forme compacte
   seule laissait le bouton à 39 px hors de la fenêtre.

   Le dessin du rail lui-même n'est pas repris : ni son fil, ni sa pastille de compte, ni ses
   marges. Ce bloc ne touche que le groupe que ce ticket a construit. Deux cas le tiennent de
   part et d'autre du seuil, dans `minuterie_d_ecran_test`. */
@media (max-width: 64rem) {
  /* La huitième entrée — « Diffusion », posée par l'écran de configuration de la source — a fait
     franchir au fil la largeur qu'une rangée offre ici : il occupait de nouveau 1 127 px pour
     1 024, et le bouton « Fermer » repartait hors de la fenêtre malgré le repli du groupe de
     session ci-dessous. Le fil seul passe donc à la ligne, et le rail gagne une rangée à cette
     largeur et en dessous.
     Le repli porte sur le **fil** et non sur `.rail` : replier le rail entier enverrait le groupe
     de session sur sa propre rangée, ce qui est un autre dessin. Ici, le fil cesse d'imposer sa
     largeur intrinsèque à la rangée, et `.rail__droite` rentre sans que sa mise en page bouge.
     La réduction typographique — interlettrage, marges intérieures — a été écartée : elle aurait
     regagné les 103 px manquants sur la longueur des huit libellés d'aujourd'hui, et les aurait
     reperdus au premier renommage. */
  .rail--administration .rail__fil {
    flex-wrap: wrap;
  }

  .rail--administration .rail__minuterie {
    flex-direction: column;
    align-items: flex-end;
    gap: 0;
  }

  .rail--administration .rail__decompte {
    flex-direction: column;
    gap: 0;
    align-items: flex-end;
    padding: 0.1rem 0.25rem;
    line-height: 1.3;
  }

  .rail--administration .rail__decompte span {
    font-size: 0.6875rem;
  }
}

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

  .panneau {
    min-height: 42vh;
  }

  .manchette {
    margin-top: 2.25rem;
  }

  .assertions {
    display: none;
  }

  /* ── Premier repli du relevé : deux pistes ────────────────────────────────
     Le parti « densifier » est tributaire de la largeur : deux paires côte à côte n'existent
     que s'il reste de la place pour deux paires. Ce qu'il gagne, il le rend ici — c'est une
     propriété du parti retenu, non un défaut à corriger.

     Aucune de ces règles n'est gardée par le contrôle d'appariement de `transport_test.py`,
     qui écarte les `@media` par construction : leur garde est la couture Chromium de
     `hauteur_des_ecrans_test.py`, seule à avoir une fenêtre. */
  .releve--paires {
    grid-template-columns: minmax(8.5rem, auto) minmax(0, 1fr);
  }

  /* Il n'y a plus deux paires à séparer. */
  .releve--paires dt:nth-of-type(2n) {
    border-left: 0;
  }

  /* La première rangée n'est plus celle des quatre premières cellules mais celle des deux
     premières : les deux suivantes reprennent le filet qui ouvre la seconde rangée. */
  .releve--paires > :nth-child(-n + 4) {
    border-top: 1px solid var(--trait-froid);
  }

  .releve--paires > :nth-child(-n + 2) {
    border-top: 0;
  }

  /* ── Forme compacte du décompte d'inactivité ──────────────────────────────
     Le libellé passe **au-dessus** de sa valeur : la phrase entière tient en 22 caractères sur
     une rangée déjà pleine, et le rail du poste débordait de sa boîte à 768 px depuis qu'elle
     s'y ajoute. Empilée, elle ne mesure plus que son mot le plus long.

     Le décompte **ne disparaît pas** : le poste de caisse fait 1 366 px, et il doit paraître à
     la largeur du poste comme à celle d'une dalle plus étroite. Ce qui change est sa forme, non
     sa présence — et le libellé du ticket n'est pas raccourci d'un mot.

     Le seuil est **celui du relevé**, 62 rem, et non un seuil propre : le rail du poste tient à
     1 024 px sous sa forme d'une rangée, et en ouvrir un second à quelques pixels de celui-ci
     aurait donné deux adaptations qui se croisent sans se voir. Deux cas de
     `minuterie_d_ecran_test` le tiennent de part et d'autre — `…_tient_sur_une_rangee_a_la_
     largeur_du_poste` et `…_s_empile_sous_le_seuil_du_releve_sans_disparaitre`. Une règle de
     repli écrite sans cas correspondant serait le code mort que ce chantier a entrepris de
     bannir. */
  .rail__decompte {
    flex-direction: column;
    gap: 0;
    align-items: flex-end;
    padding: 0.1rem 0.25rem;
    line-height: 1.3;
  }

  /* Le libellé descend d'un cran là où il devient la ligne la plus longue du bloc : c'est lui
     qui décide désormais de la largeur du décompte, et la valeur — le seul mot qu'on lit d'un
     coup d'œil — garde la sienne. */
  .rail__decompte span {
    font-size: 0.6875rem;
  }
}

@media (max-width: 46rem) {
  .champ,
  .champ--cinq,
  .champ--sept {
    grid-column: span 12;
  }

  .bilan .separateur,
  .touche {
    display: none;
  }

  .rail__acteur span,
  .rail__fil {
    display: none;
  }
}

/* ── Second repli du relevé : une piste ─────────────────────────────────────
   La paire elle-même ne tient plus : le libellé passe au-dessus de sa valeur, et le vendeur
   lit une fiche et non une grille comprimée. Le relevé redevient alors l'empilement de dix
   rangées qu'il corrigeait sur le poste de caisse ; la spécification l'assume.

   Cette bascule vivait à 46 rem, où elle avait été reprise du témoin. Elle est portée ici à
   son seuil — 40 rem, celui de la maquette de référence —, et sur le modificateur : le seul
   relevé que le service rende est celui en paires, et une règle qui n'apparie rien est le code
   mort que ce chantier a entrepris de bannir. */
@media (max-width: 40rem) {
  .releve--paires {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Le libellé perd sa respiration basse et la valeur son filet haut : les deux deviennent un
     même bloc. Un trait entre eux les ferait lire comme deux rangées distinctes. */
  .releve--paires dt {
    padding-bottom: 0;
  }

  /* Les valeurs sont les cellules de rang pair. C'est une formule de rang, et non
     `.releve--paires dd`, parce qu'il lui faut l'emporter sur le filet rétabli plus haut pour
     la seconde rangée : à une piste, la quatrième cellule est une valeur et non une rangée. */
  .releve--paires > :nth-child(2n) {
    border-top: 0;
  }

  /* Il n'y a plus de piste de libellé à sauter. Sans cette règle, la valeur viserait encore la
     seconde piste et en créerait une **implicite** : le relevé reprendrait deux colonnes que
     le style calculé de la grille ne montre même pas. */
  .releve__large {
    grid-column: 1 / -1;
  }
}

/* Sous 34 rem, le libellé de la mention exceptionnelle et sa phrase ne tiennent plus sur une
   ligne. Le libellé prend la largeur entière pour que la phrase passe dessous : les laisser se
   partager la ligne comprimerait la phrase sur une laisse de deux mots. */
@media (max-width: 34rem) {
  .mentions p {
    flex-wrap: wrap;
    gap: 0.1rem 0.7rem;
  }

  .mentions b {
    flex-basis: 100%;
  }
}

/* ═══ Les dossiers d'administration ════════════════════════════════════════
   Un dossier est une suite d'actes, chacun avec son titre, sa phrase et son
   bouton. Sans règle, ses `h2` prennent le rendu par défaut du navigateur : plus
   lourds que le `h1` du plan, collés à la phrase qui les précède, et rien ne dit
   où finit un acte et où commence le suivant.

   La classe est portée par le `h2` lui-même plutôt que déduite d'un `.plan h2` :
   celui-ci l'emporterait sur `.fiche h2` — même spécificité, déclaré plus bas —
   et changerait la typographie du certificat en réglant celle d'un écran
   d'administration.

   Le filet fait le travail que le blanc seul ne ferait pas : deux actes séparés
   par une respiration se lisent comme un seul formulaire long, et
   l'administrateur presse le premier bouton en croyant tout enregistrer. Ils
   sont deux écritures, et deux lignes au journal. */
.acte {
  margin-top: 2rem;
  padding-top: 1.25rem;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--marine-700);
  border-top: 1px solid var(--trait-froid);
}

/* ═══ Le carrefour du dossier d'enseigne ═══════════════════════════════════
   Troisième règle ajoutée à la feuille reprise du témoin, après `.refus__motif`
   et `a.rail__acteur` — et la première qui décrive une surface que le témoin
   n'avait pas. Elle se dit donc ici, comme les deux autres.

   Le dossier d'une enseigne n'a qu'un acte : nom et logo. Une page entière pour
   deux champs serait une dépense que les comptes — quatre actes — et les
   magasins — deux — n'imposaient pas. Ce qui la rachète est ce que le
   formulaire ne porte pas : le nombre de magasins, la version des conditions
   en vigueur ou son absence, et les liens qui y mènent. Aucune ligne de table
   ne peut porter l'un ni l'autre, et c'est le seul endroit du service où l'on
   voie d'un coup si une enseigne est en état d'émettre.

   Les bornes ne sont pas des `.fiche__carte` : celles-ci sont à l'échelle du
   document imprimé — 0,5 rem de titre —, et les emprunter accolerait à un bloc
   du certificat un emploi d'écran que le premier réglage de l'un romprait. */
.carrefour {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0.9rem;
  margin-top: 1.5rem;
}

.borne {
  padding: 1rem 1.1rem;
  background: var(--papier);
  border: 1px solid var(--trait-froid);
  border-radius: 10px;
}

.borne h2 {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--encre-douce);
}

.borne p {
  margin-top: 0.3rem;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--encre-douce);
}

/* L'or, parce que ces deux-là sont **calculés ou retenus** : le décompte des
   magasins se calcule, la version en vigueur se retient. Le code de l'enseigne,
   qui partage la classe, est structurel et non calculé — il la porte pour la
   seule taille, et c'est la limite que cet emploi accepte.

   `p.borne__chiffre` plutôt que `.borne__chiffre`, et **déclaré après** `.borne p` :
   les deux ont la même spécificité une fois l'élément ajouté, et c'est l'ordre qui
   les départage. La classe seule, elle, perdait — le chiffre sortait au corps du
   paragraphe. Même remède que `a.rail__acteur` pour la pastille du compte. */
p.borne__chiffre {
  margin-top: 0.35rem;
  font-family: var(--chiffres);
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--or-700);
}

/* ═══ L'écran de la Diffusion ══════════════════════════════════════════════
   Quatrième surface ajoutée à la feuille reprise du témoin, après `.refus__motif`,
   `a.rail__acteur` et le carrefour du dossier d'enseigne — et la première qui décrive
   une **disposition** et non un bloc.

   Le grief était une hauteur : on enregistrait la source, puis on faisait défiler pour
   l'essayer. Le coût tenait aux champs — 85 px chacun, parce que le libellé, la boîte et
   la note s'empilent. Quatre paramètres faisaient deux rangées pleines.

   Le registre les met **en rangées** : l'intitulé à gauche, la valeur et sa règle de
   saisie sur la même ligne. Le champ retombe à 40 px, et le bouton d'essai remonte
   au-dessus de la ligne de flottaison du poste.

   Aucun contrat de hauteur ne garde cet écran, et ce n'est pas un oubli :
   `transport_test.py` (voir `CARREFOUR_DU_DOSSIER_D_ENSEIGNE`) exempte en toutes lettres
   les écrans d'administration du budget de hauteur du poste. Ce qui est relevé, au
   Chromium et aux quatre largeurs du rail, est la **position** du bouton d'essai —
   `minuterie_d_ecran_test`. Une hauteur figée ici aurait contredit cette décision, et le
   premier paramètre ajouté l'aurait cassée.

   Relevé sur le gabarit servi, au Chromium épinglé, avec le plus long des six avis : le
   bouton d'essai s'arrête à 496 px à 1366, 543 à 1024, 557 à 900 et 540 à 768, contre 630
   offerts. La maquette annonçait 444 à 557 px de hauteur occupée ; l'écran réel est plus
   haut — le rail passe de 45 à 107 px sous 1 024 px, dette antérieure à cette tranche.

   Le relevé à 900 px est descendu de 568 à 557 au ticket 02, et c'est la **pastille** qui
   l'a payé : elle coûte 9 px de disque et 9,6 px de gouttière, le gras « Essai » qu'elle
   remplace en coûtait 35 — l'avis y gagne une ligne. L'apparence d'attente, que l'îlot pose
   au pied d'un registre qui n'avait pas d'avis, tient à 56 px à cette largeur ; un cas la
   borne à 98, faute de quoi le repli se déplacerait et ce relevé-ci tomberait à 768.

   Ces règles ne resservent nulle part en l'état, et c'est le prix accepté de la
   disposition : des trois maquettes, elle est la seule qui tienne aux quatre largeurs. */

/* Les deux chapeaux d'en-tête, repliés — même idiome que la légende de l'archive, et même
   motif : on les lit à la première visite, pas à la cinquantième. Les notes des champs,
   elles, restent dépliées : ce sont des règles de saisie, lues avant qu'on frappe. */
.apropos {
  margin-top: 1rem;
}

.apropos summary {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--marine-700);
}

.registre {
  margin-top: 0.9rem;
  background: var(--papier);
  border: 1px solid var(--trait-froid);
  border-radius: 10px;
  overflow: hidden;
}

/* `align-items: baseline` et non `center` : l'intitulé s'aligne sur le texte frappé dans
   la boîte, et non sur le milieu d'une rangée dont la hauteur change avec le repli de la
   note. Centré, il sautait d'une rangée à l'autre. */
.registre__rangee {
  display: grid;
  grid-template-columns: 11rem minmax(0, 1fr);
  gap: 0 1.1rem;
  align-items: baseline;
  padding: 0.5rem 1.05rem;
}

/* Le filet **entre** deux rangées, et non sous chacune : posé en bas avec une exception de
   dernière rangée, il aurait doublé le filet du pied. */
.registre__rangee + .registre__rangee {
  border-top: 1px solid var(--trait-froid);
}

.registre__intitule {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--marine-800);
}

.registre__valeur {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.15rem 0.75rem;
}

/* La laisse de largeur de la boîte, et le geste qui fait tout tenir : sans elle, la valeur
   prendrait la rangée entière et la note repasserait dessous — l'empilement que ce dessin
   défait.

   Les trois bornes se lisent de droite à gauche. `100% - 15rem` est ce que la boîte **cède**
   à la note : sa base de 14 rem, plus la gouttière, plus quatre pixels de jeu — un flottant
   arrondi au-dessus aurait suffi à faire replier la rangée. `30rem` est le plafond, qui loge
   une URL de source sans troncature sur une dalle large. `14rem` est le plancher, et il n'est
   pas décoratif : sous 464 px de rangée la soustraction descend sous la base de la note, et
   sous 240 px elle passerait sous zéro — un `max-width` négatif se ramène à zéro, et la boîte
   disparaîtrait. Le plancher rend alors la main à `width: 100%`, et c'est la note qui reprend
   sa ligne : le repli que ce dessin accepte, à des largeurs qu'aucun poste d'administration
   n'a.

   Mesuré au Chromium épinglé, avec le plus long des six avis : sans cette laisse, la rangée
   passe de 63 à 75 px à 900 et 768, et les quatre rangées coûtent 48 px que l'écran n'a pas. */
.registre__valeur input,
.registre__valeur select {
  max-width: min(30rem, max(14rem, 100% - 15rem));
}

/* La note à **côté** de la valeur, et non dessous. Sa base de 14 rem est ce qui décide du
   repli : sous une valeur plus étroite que cela, elle reprend sa ligne — c'est le seul
   endroit où la rangée retrouve les 85 px, et il n'arrive qu'aux dalles les plus étroites. */
.registre__valeur .note {
  flex: 1 1 14rem;
  margin-top: 0;
}

/* Le motif de refus prend la ligne entière : glissé entre la valeur et sa règle, il aurait
   poussé celle-ci hors de la rangée et fait lire la règle d'un autre champ. */
.registre__valeur .erreur {
  flex: 1 1 100%;
  margin-top: 0;
}

/* Le pied ferme le registre : les deux écritures, et l'avis de l'essai contre le bouton qui
   le produit. */
.registre__pied {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  padding: 0.7rem 1.05rem;
  background: var(--plan);
  border-top: 1px solid var(--trait-froid);
}

/* L'avis prend le reste de la ligne, et passe **sous** les deux boutons dès qu'il n'a plus
   24 rem pour se dire. Le seuil n'est pas choisi au jugé : à 768 px, le reste de la ligne
   fait 21 rem, le plus long des six libellés y monte à 118 px et le pied à 142 ; sur sa
   propre ligne, le même libellé tient en deux lignes de 56 px et le pied retombe à 131.
   C'est le seul endroit de l'écran où l'étroit coûte moins que le large, et ces 11 px sont
   ce qui rend la dalle de 768 px sans défilement. */
.registre__pied .avis {
  flex: 1 1 24rem;
  padding: 0.45rem 0.75rem;
}

/* La pastille de `.statut`, reprise telle quelle : disque de `currentColor`, 9 px. Le même
   fait ne se dit pas de deux façons selon l'écran, et la page publique la porte déjà.

   Elle est posée **au pied du registre** et non sur `.avis`, qui sert cinq autres écrans :
   une pastille d'état devant un avertissement y aurait annoncé un état qu'il n'a pas. Cet
   avis-ci est le seul de la feuille qui en porte un.

   `margin-top` et non `align-items: center` : `.statut` tient sur une ligne, celui-ci monte
   à trois au plus long des six libellés, et un centrage aurait fait descendre le disque au
   milieu du cartouche. 0,37 rem le pose sur l'axe de la **première** ligne — 20,8 px
   d'interligne, 9 px de disque. `flex: none` l'empêche de se comprimer quand la ligne se
   resserre : sans lui, le disque devient un ovale sous 768 px. */
.registre__pied .avis::before {
  content: '';
  flex: none;
  width: 9px;
  height: 9px;
  margin-top: 0.37rem;
  border-radius: 50%;
  background: currentColor;
}
