/* ==========================================================================
   KARDOX MEDIA — « L'ardoise »
   Couche de marque de l'espace client. Chargée APRÈS vendor.css et huraga.css,
   elle ne réécrit aucun comportement : uniquement des jetons, des couleurs,
   des graisses, des espacements et des transitions.

   RÈGLE INTANGIBLE
   Ce fichier est purement visuel. Aucun nom de champ, aucune URL d'action,
   aucun identifiant ciblé par le JavaScript, aucun appel API n'est touché.
   Le tunnel de commande et le paiement Stripe fonctionnent à l'identique.

   Ardoise  #0E1418   fond profond, bleuté
   Safran   #F2A93B   accent, 9,29:1 sur l'ardoise
   Sienne   #A1590C   accent de la variante papier, 4,82:1
   Polices  IBM Plex Sans variable + IBM Plex Mono, auto-hébergées
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Polices — auto-hébergées. Aucune requête vers un domaine tiers.

   ATTENTION : cette feuille est la COPIE VITRINE de celle du thème. Le thème
   sert ses polices depuis « /themes/kardox/assets/fonts/ », chemin qui
   n'existe pas sur kardoxmedia.com : tel quel, il produisait TROIS 404 à
   chaque chargement de page, dans les six langues. Ici, les polices vivent
   sous « /assets/fonts/ ». À reporter à chaque recopie depuis le thème.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: 'Plex Sans KM';
  src: url('/assets/fonts/IBMPlexSans-Variable-latin.woff2') format('woff2-variations');
  font-weight: 100 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Plex Mono KM';
  src: url('/assets/fonts/IBMPlexMono-Regular-latin.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Plex Mono KM';
  src: url('/assets/fonts/IBMPlexMono-Medium-latin.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* --------------------------------------------------------------------------
   1. Jetons de marque — rampes complètes, identiques dans les deux modes
   -------------------------------------------------------------------------- */

:root {
  /* Safran doré — entre l'orange et l'or */
  --km-o-50:#FCF5E8;  --km-o-100:#F9E6C7; --km-o-200:#F7D097; --km-o-300:#F4BC66;
  --km-o-400:#F2A93B; --km-o-500:#E89117; --km-o-600:#C57411; --km-o-700:#A1590C;
  --km-o-800:#7B4009; --km-o-900:#542A07; --km-o-950:#331805;

  /* Ardoise et pierre — biais froid 205° */
  --km-n-25:#FAFBFC;  --km-n-50:#F4F6F8;  --km-n-100:#E8ECEF; --km-n-200:#D6DCE1;
  --km-n-300:#B9C2C9; --km-n-400:#939FA8; --km-n-500:#6E7B85; --km-n-600:#556069;
  --km-n-700:#3F4952; --km-n-800:#2A333A; --km-n-900:#1A2228; --km-n-950:#10171C;
  --km-ardoise:#0E1418;
  --km-plan:#131A20;
  --km-plan-2:#18212A;
  --km-plan-3:#1F2932;
  --km-craie:#E9EFF3;

  --km-sans: 'Plex Sans KM', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --km-mono: 'Plex Mono KM', ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;

  /* Courbes — aucune n'est linear ni ease */
  --km-e-micro:   cubic-bezier(.25,.46,.45,.94);
  --km-e-couleur: cubic-bezier(.25,1,.5,1);
  --km-e-sortie:  cubic-bezier(.32,.72,0,1);
  --km-e-entree:  cubic-bezier(.16,1,.3,1);
  --km-d-micro:140ms; --km-d-couleur:200ms; --km-d-elev:260ms; --km-d-entree:760ms;
}

/* --------------------------------------------------------------------------
   2. L'ARDOISE — mode sombre. C'est le parti par défaut de la marque.
   Pour l'activer partout : réglage « Thème » du thème → sombre.
   -------------------------------------------------------------------------- */

[data-bs-theme='dark'] {
  --km-fond: var(--km-ardoise);
  --km-plan-a: var(--km-plan);
  --km-plan-b: var(--km-plan-2);
  --km-plan-c: var(--km-plan-3);
  --km-l0: rgba(233,239,243,.028);
  --km-l1: rgba(233,239,243,.09);
  --km-l2: rgba(233,239,243,.19);
  /* Bord d'une commande de saisie. Mesuré : « --km-l2 » ne donnait que 1,26:1
     contre le plan du champ — la WCAG 1.4.11 exige 3:1 pour la limite visible
     d'une commande. Celui-ci tient 3,21 au pire des quatre plans. */
  --km-l3: #6A7781;
  --km-t0: var(--km-craie);
  --km-t1: #9DACB6;
  /* Mesuré : l'ancien #778894 tombait à 4,45:1 sur le plan 2 et 4,03:1 sur le
     plan 3 — sous le seuil AA. Relevé d'un cran sur la même teinte froide, il
     tient maintenant 5,88 · 5,56 · 5,16 · 4,68 sur les quatre plans. */
  --km-t2: #84939F;
  --km-ac:   var(--km-o-400);
  --km-ac-h: var(--km-o-300);
  --km-ac-plein: var(--km-o-400);
  --km-ac-txt:   var(--km-ardoise);
  --km-ac-voile:  rgba(242,169,59,.10);
  --km-ac-voile2: rgba(242,169,59,.18);
  --km-ac-bord:   rgba(242,169,59,.34);
  --km-ok:#59C08A; --km-ko:#E8798A; --km-at:#E3B84E; --km-inf:#7FB2E0;
  --km-piste: rgba(242,169,59,.14);
  --km-ombre-1: 0 1px 2px rgba(0,0,0,.36);
  --km-ombre-2: 0 18px 40px -26px rgba(0,0,0,.72);

  /* --- report sur les jetons Bootstrap --- */
  --bs-body-bg: var(--km-fond);
  --bs-body-color: var(--km-t0);
  --bs-body-color-rgb: 233,239,243;
  --bs-emphasis-color: #FFFFFF;
  --bs-secondary-color: var(--km-t1);
  --bs-secondary-bg: var(--km-plan-b);
  --bs-tertiary-color: var(--km-t2);
  --bs-tertiary-bg: var(--km-plan-a);
  --bs-border-color: var(--km-l1);
  --bs-border-color-translucent: var(--km-l1);
  --bs-primary: var(--km-o-400);
  --bs-primary-rgb: 242,169,59;
  --bs-primary-text-emphasis: var(--km-o-300);
  --bs-primary-bg-subtle: var(--km-ac-voile);
  --bs-primary-border-subtle: var(--km-ac-bord);
  --bs-link-color: var(--km-ac);
  --bs-link-color-rgb: 242,169,59;
  --bs-link-hover-color: var(--km-ac-h);
  --bs-success: var(--km-ok); --bs-success-rgb: 89,192,138;
  --bs-danger:  var(--km-ko); --bs-danger-rgb: 232,121,138;
  --bs-warning: var(--km-at); --bs-warning-rgb: 227,184,78;
  --bs-info:    var(--km-inf); --bs-info-rgb: 127,178,224;
  --bs-secondary: var(--km-t2);
  --bs-box-shadow: var(--km-ombre-2);
  color-scheme: dark;
}

/* --------------------------------------------------------------------------
   3. LE PAPIER — variante claire. Le safran y devient sienne brûlée,
   seule teinte qui tient le contraste sur fond clair.
   -------------------------------------------------------------------------- */

[data-bs-theme='light'],
:root:not([data-bs-theme]) {
  --km-fond: var(--km-n-50);
  --km-plan-a: #FAFBFB;
  --km-plan-b: #ECEFF1;
  --km-plan-c: #E2E7EA;
  --km-l0: rgba(14,20,24,.035);
  --km-l1: rgba(14,20,24,.11);
  --km-l2: rgba(14,20,24,.22);
  /* Même correction en miroir : 3,29 au pire des quatre plans clairs. */
  --km-l3: #727F8A;
  --km-t0: #0E1418;
  --km-t1: #4A5761;
  /* Même correction qu'en ardoise, en miroir : l'ancien #5F6C76 tombait à
     4,33:1 sur le plan 3. Assombri d'un cran, il tient 5,35 · 5,59 · 5,02 · 4,65. */
  --km-t2: #5B6771;
  --km-ac:   var(--km-o-700);
  --km-ac-h: var(--km-o-800);
  --km-ac-plein: var(--km-o-700);
  --km-ac-txt:   #FFFFFF;
  --km-ac-voile:  rgba(161,89,12,.07);
  --km-ac-voile2: rgba(161,89,12,.13);
  --km-ac-bord:   rgba(161,89,12,.32);
  --km-ok:#1E6B45; --km-ko:#993244; --km-at:#8A6410; --km-inf:#2A5F86;
  --km-piste: rgba(161,89,12,.16);
  --km-ombre-1: 0 1px 2px rgba(14,20,24,.06);
  --km-ombre-2: 0 18px 40px -26px rgba(14,20,24,.28);

  --bs-body-bg: var(--km-fond);
  --bs-body-color: var(--km-t0);
  --bs-body-color-rgb: 14,20,24;
  --bs-emphasis-color: #000000;
  --bs-secondary-color: var(--km-t1);
  --bs-secondary-bg: var(--km-plan-b);
  --bs-tertiary-color: var(--km-t2);
  --bs-tertiary-bg: var(--km-plan-a);
  --bs-border-color: var(--km-l1);
  --bs-border-color-translucent: var(--km-l1);
  --bs-primary: var(--km-o-700);
  --bs-primary-rgb: 161,89,12;
  --bs-primary-text-emphasis: var(--km-o-800);
  --bs-primary-bg-subtle: var(--km-ac-voile);
  --bs-primary-border-subtle: var(--km-ac-bord);
  --bs-link-color: var(--km-ac);
  --bs-link-color-rgb: 161,89,12;
  --bs-link-hover-color: var(--km-ac-h);
  --bs-success: var(--km-ok); --bs-success-rgb: 30,107,69;
  --bs-danger:  var(--km-ko); --bs-danger-rgb: 153,50,68;
  --bs-warning: var(--km-at); --bs-warning-rgb: 138,100,16;
  --bs-info:    var(--km-inf); --bs-info-rgb: 42,95,134;
  --bs-secondary: var(--km-t2);
  --bs-box-shadow: var(--km-ombre-2);
  color-scheme: light;
}

/* --------------------------------------------------------------------------
   4. Base et typographie
   Deux registres jamais mélangés : la Sans porte la parole, la Mono la mesure.
   Graisses 400 et 510, 590 pour les titres. Jamais 700.
   -------------------------------------------------------------------------- */

html { font-size: 16px; }

body {
  background-color: var(--km-fond);
  color: var(--km-t0);
  font-family: var(--km-sans) !important;
  font-size: 16px;
  line-height: 28px;
  font-weight: 400;
  letter-spacing: -.011em;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Trame d'ingénieur : la seule texture de la page */
  background-image:
    linear-gradient(var(--km-l0) 1px, transparent 1px),
    linear-gradient(90deg, var(--km-l0) 1px, transparent 1px);
  background-size: 52px 52px;
  transition: background-color var(--km-d-couleur) var(--km-e-couleur),
              color var(--km-d-couleur) var(--km-e-couleur);
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  font-family: var(--km-sans);
  font-weight: 590;
  color: var(--km-t0);
  text-wrap: balance;
}
h1, .h1 { font-size: 2.25rem; line-height: 1.08; letter-spacing: -.032em; }
h2, .h2 { font-size: 1.75rem; line-height: 1.12; letter-spacing: -.026em; }
h3, .h3 { font-size: 1.3125rem; line-height: 1.32; letter-spacing: -.016em; }
h4, .h4 { font-size: 1.125rem; line-height: 1.36; letter-spacing: -.012em; }
h5, .h5 { font-size: 1rem;     line-height: 1.4;  letter-spacing: -.008em; font-weight: 510; }
h6, .h6 { font-size: .875rem;  line-height: 1.42; letter-spacing: -.004em; font-weight: 510; }

p { max-width: 68ch; }
.lead { font-size: 1.1875rem; line-height: 1.6; letter-spacing: -.012em; color: var(--km-t1); font-weight: 400; }
small, .small { font-size: .8125rem; line-height: 1.45; }
strong, b { font-weight: 510; color: var(--km-t0); }
.text-muted, .text-secondary { color: var(--km-t1) !important; }
hr { border-color: var(--km-l1); opacity: 1; }

a { color: var(--km-ac); text-decoration: none;
    transition: color var(--km-d-micro) var(--km-e-micro); }
a:hover { color: var(--km-ac-h); text-decoration: underline;
          text-underline-offset: 4px; text-decoration-thickness: 1px; }

/* Étiquette technique : petites capitales en monospace, très espacées */
.form-label, .card-header h6, legend, .km-etiquette {
  font-family: var(--km-mono);
  font-size: .6875rem;
  line-height: 1rem;
  font-weight: 400;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--km-t2);
}

/* --------------------------------------------------------------------------
   5. LA SIGNATURE — toute valeur chiffrée passe en monospace tabulaire.
   Un prix se lit comme une constante technique, pas comme une promesse.
   -------------------------------------------------------------------------- */

.currency, .price, .total, .amount, .km-nombre,
td.text-end, th.text-end,
.table td:last-child, .table th:last-child,
code, kbd, samp, pre {
  font-family: var(--km-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}
.currency, .price, .total, .amount, .km-nombre { font-weight: 500; }

/* Bloc de prix de la page de commande */
.block.pricing .currency {
  font-family: var(--km-mono);
  font-size: 2.125rem;
  line-height: 1.1;
  font-weight: 500;
  letter-spacing: -.035em;
  color: var(--km-t0);
}
.block.pricing p { color: var(--km-t2); font-family: var(--km-mono);
  font-size: .6875rem; letter-spacing: .2em; text-transform: uppercase; }

code, kbd { background: var(--km-plan-b); color: var(--km-ac);
  padding: .12em .38em; border-radius: 3px; font-size: .875em; }
pre { background: var(--km-plan-a); border: 1px solid var(--km-l1);
  border-radius: 5px; padding: 1rem; color: var(--km-t1); }

/* --------------------------------------------------------------------------
   6. Focus et mouvement
   -------------------------------------------------------------------------- */

:focus-visible {
  outline: 2px solid var(--km-ac);
  outline-offset: 3px;
  border-radius: 3px;
  box-shadow: none;
}
.btn:focus-visible, .form-control:focus-visible, .form-select:focus-visible,
.nav-link:focus-visible, .dropdown-item:focus-visible, .page-link:focus-visible {
  outline: 2px solid var(--km-ac);
  outline-offset: 3px;
}

/* --------------------------------------------------------------------------
   7. La coquille — navbar, barre latérale, fil d'Ariane, pied de page
   -------------------------------------------------------------------------- */

.navbar {
  background-color: transparent !important;
  border-bottom: 1px solid var(--km-l1);
  padding-top: 1.25rem; padding-bottom: 1.25rem;
}
.navbar-brand { color: var(--km-t0); font-weight: 510; letter-spacing: -.012em; }
.navbar-brand:hover { color: var(--km-t0); text-decoration: none; }

/* Le logo de la société est dessiné pour un fond clair : sur l'ardoise il
   disparaît. Faute de logo sombre téléversé, le gabarit sert le logo clair en
   repli — il porte alors la classe « km-logo-replie », que le partage de logo
   pose lui-même. On le remonte donc en blanc plein.
   La règle visait d'abord la seule barre de navigation ; la page de connexion
   affiche le même repli hors de cette barre et restait donc en bleu nuit sur
   l'ardoise. Elle suit maintenant le repli partout où il apparaît.
   Dès qu'un vrai logo pour fond sombre est chargé dans l'administration, la
   classe de repli n'est plus posée et cette règle s'éteint d'elle-même. */
[data-bs-theme='dark'] img.km-logo-replie {
  filter: brightness(0) invert(1);
  opacity: .94;
  transition: opacity var(--km-d-couleur) var(--km-e-couleur);
}
[data-bs-theme='dark'] a:hover img.km-logo-replie { opacity: 1; }

.navbar-nav .nav-link,
.nav-link {
  color: var(--km-t1);
  font-size: .875rem;
  font-weight: 510;
  letter-spacing: -.006em;
  border-radius: 4px;
  transition: color var(--km-d-micro) var(--km-e-micro),
              background-color var(--km-d-micro) var(--km-e-micro);
}
.nav-link:hover { color: var(--km-t0) !important; background-color: var(--km-plan-b); }
.nav-link.active,
.offcanvas-item.active > .nav-link { color: var(--km-ac) !important; font-weight: 510 !important; }

.navbar-toggler { border-color: var(--km-l2); color: var(--km-t1); border-radius: 4px; }
.navbar-toggler:focus { box-shadow: none; outline: 2px solid var(--km-ac); outline-offset: 3px; }

/* Barre latérale : chaque entrée porte un repère d'ambre à gauche quand elle
   est active. Les filets pleins de huraga disparaissent. */
#sidebarMenu .nav { gap: 2px; }
.offcanvas-item {
  border: 0 !important;
  border-radius: 4px;
  position: relative;
  transition: background-color var(--km-d-micro) var(--km-e-micro);
}
.offcanvas-item > .nav-link { padding: .6875rem .875rem; color: var(--km-t1); }
.offcanvas-item:hover { background: var(--km-plan-b) !important; }
.offcanvas-item::before {
  content: ""; position: absolute; left: 0; top: 12px; bottom: 12px; width: 2px;
  background: var(--km-ac); transform: scaleY(0);
  transition: transform var(--km-d-elev) var(--km-e-sortie);
}
.offcanvas-item.active { background: transparent !important; }
.offcanvas-item.active::before { transform: scaleY(1); }
.offcanvas-item .icon { color: inherit; }

#sidebarMenu h5 {
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--km-t2) !important; font-weight: 400;
}
#sidebarMenu h6 strong {
  font-family: var(--km-mono); font-size: 1.1875rem; font-weight: 500;
  letter-spacing: -.02em; color: var(--km-t0);
}

.breadcrumb {
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .16em;
  text-transform: uppercase; margin-bottom: 1.75rem;
}
.breadcrumb-item, .breadcrumb-item a { color: var(--km-t2); }
.breadcrumb-item a:hover { color: var(--km-t0); text-decoration: none; }
.breadcrumb-item.active { color: var(--km-t1); }
.breadcrumb-item + .breadcrumb-item::before { color: var(--km-l2); content: "/"; }

#footer {
  border-top: 1px solid var(--km-l1);
  padding-top: 1.75rem; margin-top: 4rem !important;
  color: var(--km-t2) !important; font-size: .8125rem;
}
#footer a { color: var(--km-t1); }
#footer a:hover { color: var(--km-ac); }

/* Retour en haut : discret, jamais un aplat d'accent */
a.position-fixed.btn-primary {
  background: var(--km-plan-a) !important;
  border: 1px solid var(--km-l2) !important;
  color: var(--km-t1) !important;
  border-radius: 4px !important;
  box-shadow: var(--km-ombre-1);
}
a.position-fixed.btn-primary:hover {
  background: var(--km-plan-b) !important; color: var(--km-t0) !important;
  border-color: var(--km-ac-bord) !important;
}

/* --------------------------------------------------------------------------
   8. Les plans — ce que Bootstrap appelle « card ».
   À plat, un filet d'un pixel, cinq de rayon. Au survol un filet d'ambre
   se trace sur l'arête haute et le plan s'élève de trois pixels.
   -------------------------------------------------------------------------- */

.card {
  position: relative;
  background-color: var(--km-plan-a);
  border: 1px solid var(--km-l1);
  border-radius: 5px;
  box-shadow: var(--km-ombre-1);
  margin-bottom: 1.5rem;
  transition: background-color var(--km-d-elev) var(--km-e-couleur),
              border-color var(--km-d-elev) var(--km-e-couleur),
              transform var(--km-d-elev) var(--km-e-sortie),
              box-shadow var(--km-d-elev) var(--km-e-sortie);
}
.card::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: var(--km-ac); transform: scaleX(0); transform-origin: left;
  border-radius: 5px 5px 0 0; pointer-events: none;
  transition: transform 460ms var(--km-e-entree);
}
.card:hover, .card:focus-within {
  background-color: var(--km-plan-b);
  border-color: var(--km-l2);
  transform: translateY(-3px);
  box-shadow: var(--km-ombre-2);
}
.card:hover::before, .card:focus-within::before { transform: scaleX(1); }

.card-header {
  background-color: transparent !important;
  border-bottom: 1px solid var(--km-l1);
  padding: 1rem 1.375rem;
  color: var(--km-t0);
}
.card-header h1, .card-header h2, .card-header h3,
.card-header h4, .card-header h5 {
  font-size: 1rem; font-weight: 510; letter-spacing: -.008em; margin: 0;
}
.card-body { padding: 1.375rem; }
.card-footer {
  background-color: transparent; border-top: 1px solid var(--km-l1);
  padding: 1rem 1.375rem;
}

/* Les blocs hérités de huraga suivent la même grammaire */
.box, .h-block, .content-block > .block {
  background-color: var(--km-plan-a);
  border: 1px solid var(--km-l1);
  border-radius: 5px;
}

/* --------------------------------------------------------------------------
   9. Boutons — six états, cible tactile de 46 px
   -------------------------------------------------------------------------- */

.btn {
  --bs-btn-font-family: var(--km-sans);
  --bs-btn-font-size: .9375rem;
  --bs-btn-font-weight: 510;
  --bs-btn-line-height: 1.25rem;
  --bs-btn-padding-y: .75rem;
  --bs-btn-padding-x: 1.375rem;
  --bs-btn-border-radius: 4px;
  letter-spacing: -.006em;
  min-height: 46px;
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  transition: background-color var(--km-d-couleur) var(--km-e-couleur),
              border-color var(--km-d-couleur) var(--km-e-couleur),
              color var(--km-d-couleur) var(--km-e-couleur),
              transform var(--km-d-micro) var(--km-e-sortie);
}
.btn:active { transform: translateY(1px); }
.btn-sm { --bs-btn-padding-y: .5rem; --bs-btn-padding-x: 1rem;
          --bs-btn-font-size: .875rem; min-height: 38px; }
.btn-lg, .btn-big { --bs-btn-padding-y: .875rem; --bs-btn-padding-x: 1.75rem;
                    --bs-btn-font-size: 1rem; min-height: 52px; }

.btn-primary {
  --bs-btn-bg: var(--km-ac-plein);
  --bs-btn-border-color: var(--km-ac-plein);
  --bs-btn-color: var(--km-ac-txt);
  --bs-btn-hover-bg: var(--km-ac-h);
  --bs-btn-hover-border-color: var(--km-ac-h);
  --bs-btn-hover-color: var(--km-ac-txt);
  --bs-btn-active-bg: var(--km-ac-h);
  --bs-btn-active-border-color: var(--km-ac-h);
  --bs-btn-active-color: var(--km-ac-txt);
  --bs-btn-disabled-bg: transparent;
  --bs-btn-disabled-border-color: var(--km-l1);
  --bs-btn-disabled-color: var(--km-t2);
}
.btn-secondary, .btn-outline-secondary, .btn-light, .btn-outline-primary {
  --bs-btn-bg: transparent;
  --bs-btn-border-color: var(--km-l2);
  --bs-btn-color: var(--km-t0);
  --bs-btn-hover-bg: var(--km-plan-b);
  --bs-btn-hover-border-color: var(--km-ac-bord);
  --bs-btn-hover-color: var(--km-t0);
  --bs-btn-active-bg: var(--km-plan-c);
  --bs-btn-active-border-color: var(--km-ac-bord);
  --bs-btn-active-color: var(--km-t0);
  --bs-btn-disabled-bg: transparent;
  --bs-btn-disabled-border-color: var(--km-l1);
  --bs-btn-disabled-color: var(--km-t2);
}
.btn-link { --bs-btn-color: var(--km-ac); --bs-btn-hover-color: var(--km-ac-h); }
.btn-danger {
  --bs-btn-bg: transparent; --bs-btn-border-color: var(--km-ko);
  --bs-btn-color: var(--km-ko); --bs-btn-hover-bg: var(--km-ko);
  --bs-btn-hover-border-color: var(--km-ko); --bs-btn-hover-color: var(--km-fond);
}
.btn-success {
  --bs-btn-bg: transparent; --bs-btn-border-color: var(--km-ok);
  --bs-btn-color: var(--km-ok); --bs-btn-hover-bg: var(--km-ok);
  --bs-btn-hover-border-color: var(--km-ok); --bs-btn-hover-color: var(--km-fond);
}
.btn:disabled, .btn.disabled { cursor: not-allowed; transform: none; }

/* --------------------------------------------------------------------------
   10. Formulaires — la ligne plutôt que la boîte
   -------------------------------------------------------------------------- */

.form-control, .form-select, .ts-control, textarea.form-control {
  background-color: transparent;
  color: var(--km-t0);
  border: 0;
  border-bottom: 1px solid var(--km-l2);
  border-radius: 0;
  min-height: 46px;
  padding: .75rem 0;
  font-family: var(--km-sans);
  font-size: .9375rem;
  line-height: 1.375rem;
  letter-spacing: -.008em;
  box-shadow: none;
  transition: border-color var(--km-d-couleur) var(--km-e-couleur),
              box-shadow var(--km-d-couleur) var(--km-e-couleur);
}
.form-control::placeholder { color: var(--km-t2); }
.form-control:hover:not(:focus), .form-select:hover:not(:focus) { border-bottom-color: var(--km-t2); }
.form-control:focus, .form-select:focus, .ts-wrapper.focus .ts-control {
  background-color: transparent;
  color: var(--km-t0);
  border-bottom-color: var(--km-ac);
  box-shadow: 0 1px 0 0 var(--km-ac);
  outline: none;
}
.form-control:disabled, .form-control[readonly] {
  background-color: transparent; color: var(--km-t2);
  border-bottom-style: dashed; cursor: not-allowed;
}
.form-control.is-invalid, .was-validated .form-control:invalid {
  border-bottom-color: var(--km-ko); box-shadow: 0 1px 0 0 var(--km-ko);
  background-image: none;
}
.form-control.is-valid, .was-validated .form-control:valid {
  border-bottom-color: var(--km-ok); box-shadow: 0 1px 0 0 var(--km-ok);
  background-image: none;
}
.invalid-feedback { color: var(--km-ko); font-family: var(--km-mono); font-size: .75rem; }
.valid-feedback   { color: var(--km-ok); font-family: var(--km-mono); font-size: .75rem; }
.form-text { color: var(--km-t2); font-family: var(--km-mono); font-size: .75rem; }

.form-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23778894' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6l6 -6'/%3E%3C/svg%3E");
  background-size: 15px; background-position: right .25rem center; padding-right: 1.75rem;
}
.form-check-input {
  background-color: transparent; border: 1px solid var(--km-l2);
  transition: background-color var(--km-d-micro) var(--km-e-micro),
              border-color var(--km-d-micro) var(--km-e-micro);
}
.form-check-input:checked { background-color: var(--km-ac-plein); border-color: var(--km-ac-plein); }
.form-check-input:focus { box-shadow: none; outline: 2px solid var(--km-ac); outline-offset: 2px; }
.form-check-label { color: var(--km-t1); font-size: .9375rem; }
.input-group-text {
  background-color: transparent; border: 0; border-bottom: 1px solid var(--km-l2);
  color: var(--km-t2); font-family: var(--km-mono); font-size: .8125rem;
}

/* TomSelect et intl-tel-input suivent le même langage */
.ts-wrapper.form-select, .ts-wrapper .ts-control { background-color: transparent !important; }
.ts-dropdown {
  background: var(--km-plan-a); border: 1px solid var(--km-l1); border-radius: 5px;
  box-shadow: var(--km-ombre-2); color: var(--km-t0); font-size: .9375rem;
}
.ts-dropdown .active { background-color: var(--km-plan-b) !important; color: var(--km-t0) !important; }
.ts-dropdown .selected { background-color: var(--km-ac-voile) !important; color: var(--km-ac) !important; }
.iti {
  --iti-border-color: var(--km-l2);
  --iti-country-selector-bg: var(--km-plan-a);
  --iti-hover-color: var(--km-ac-voile);
  --iti-icon-color: var(--km-t2);
}
.iti__country-list, .iti__dropdown-content {
  background: var(--km-plan-a); border: 1px solid var(--km-l1);
  border-radius: 5px; box-shadow: var(--km-ombre-2);
}
.iti__country-selector, .iti__search-input { color: var(--km-t0); background-color: transparent; }

/* --------------------------------------------------------------------------
   11. Tableaux — la densité, pas la boîte
   -------------------------------------------------------------------------- */

.table {
  --bs-table-bg: transparent;
  --bs-table-color: var(--km-t0);
  --bs-table-border-color: var(--km-l1);
  --bs-table-hover-bg: var(--km-plan-b);
  --bs-table-hover-color: var(--km-t0);
  --bs-table-striped-bg: var(--km-plan-a);
  margin-bottom: 0;
}
.table > thead > tr > th,
.card-body table > thead > tr > th {
  font-family: var(--km-mono) !important;
  font-size: .6875rem !important;
  line-height: 1rem;
  font-weight: 400 !important;
  letter-spacing: .2em;
  text-transform: uppercase !important;
  color: var(--km-t2) !important;
  border-bottom: 1px solid var(--km-l1);
  padding: 0 1.125rem .75rem;
  white-space: nowrap;
}
.table > tbody > tr > td {
  padding: .9375rem 1.125rem;
  border-bottom: 1px solid var(--km-l1);
  border-top: 0;
  vertical-align: middle;
  font-size: .9375rem;
  line-height: 1.375rem;
  color: var(--km-t0);
}
.table > tbody > tr { transition: background-color var(--km-d-micro) var(--km-e-micro); }
/* Repère de ligne : un tiret d'ambre dans la gouttière, jamais un fond coloré */
.table > tbody > tr > td:first-child { position: relative; }
.table > tbody > tr > td:first-child::before {
  content: ""; position: absolute; left: 0; top: 50%; width: 9px; height: 1px;
  background: var(--km-ac); transform: scaleX(0); transform-origin: left;
  transition: transform var(--km-d-micro) var(--km-e-micro);
}
.table > tbody > tr:hover > td:first-child::before { transform: scaleX(1); }
.table > tbody > tr:last-child > td { border-bottom: 0; }

/* --------------------------------------------------------------------------
   12. Les statuts — la forme porte le sens, pas seulement la couleur.
   Les pastilles pleines de Bootstrap deviennent un point suivi du libellé.
   Plein = stable · creux = transitoire · tiret = terminé.
   -------------------------------------------------------------------------- */

/* huraga.scss impose « .badge[class*="bg-"] { color:#fff !important } », plus
   spécifique que « .badge ». On reprend la main au même niveau de spécificité,
   sans quoi le libellé resterait blanc — donc invisible sur la variante papier. */
.badge,
.badge[class*="bg-"],
.badge[class*="text-bg-"] {
  display: inline-flex !important;
  align-items: center;
  gap: .5rem;
  background-color: transparent !important;
  color: var(--km-t0) !important;
  font-family: var(--km-sans) !important;
  font-size: .875rem !important;
  font-weight: 400 !important;
  letter-spacing: -.006em;
  padding: 0 !important;
  border-radius: 0 !important;
  white-space: nowrap;
}
.badge::before,
.badge[class*="bg-"]::before,
.badge[class*="text-bg-"]::before {
  content: "";
  width: 7px; height: 7px; flex: none;
  border-radius: 50%;
  background: var(--km-t2);
}
.badge.bg-success::before, .badge.text-bg-success::before { background: var(--km-ok); }
.badge.bg-danger::before,  .badge.text-bg-danger::before  { background: var(--km-ko); }
.badge.bg-warning::before, .badge.text-bg-warning::before {
  background: transparent; box-shadow: inset 0 0 0 1.6px var(--km-t2);
}
.badge.bg-info::before, .badge.text-bg-info::before {
  background: transparent; box-shadow: inset 0 0 0 1.6px var(--km-inf);
}
.badge.bg-secondary::before, .badge.text-bg-secondary::before {
  width: 9px; height: 1px; border-radius: 0; background: var(--km-t2); opacity: .55;
}
.badge.bg-primary::before, .badge.text-bg-primary::before { background: var(--km-ac); }
.badge:empty { display: none !important; }

/* --------------------------------------------------------------------------
   13. Alertes, messages système et messages flash
   -------------------------------------------------------------------------- */

.alert {
  display: flex !important;
  flex-direction: row !important;
  align-items: flex-start !important;
  gap: .875rem;
  background-color: var(--km-plan-a);
  border: 1px solid var(--km-l1);
  border-radius: 5px;
  padding: 1rem 1.125rem;
  color: var(--km-t0);
  font-size: .9375rem;
  line-height: 1.5rem;
}
.alert p { margin-bottom: 0; max-width: none; }
.alert-success { border-color: rgba(89,192,138,.30); }
.alert-danger, .alert-error { border-color: rgba(232,121,138,.30); }
.alert-warning { border-color: rgba(227,184,78,.30); }
.alert-info, .alert-primary { border-color: var(--km-ac-bord); }
.alert .btn-close { filter: none; opacity: .5; }
.alert .btn-close:hover { opacity: 1; }

/* Les messages flash de partial_message.html.twig n'avaient aucun style :
   la classe .h-block n'existait nulle part dans le projet. */
.h-block {
  display: flex; flex-direction: column; gap: .375rem;
  padding: 1rem 1.125rem; margin-bottom: 1.25rem;
  background: var(--km-plan-a);
  border: 1px solid var(--km-l1);
  border-radius: 5px;
}
.h-block h2 {
  font-family: var(--km-mono); font-size: .6875rem; font-weight: 400;
  letter-spacing: .2em; text-transform: uppercase; color: var(--km-t2); margin: 0;
}
.h-block p { margin: 0; color: var(--km-t0); font-size: .9375rem; }
.h-block.success, .h-block.info    { border-color: rgba(89,192,138,.30); }
.h-block.error,   .h-block.danger  { border-color: rgba(232,121,138,.30); }
.h-block.error h2, .h-block.danger h2 { color: var(--km-ko); }
.h-block.success h2 { color: var(--km-ok); }

/* --------------------------------------------------------------------------
   14. Pagination, onglets, accordéon, listes
   -------------------------------------------------------------------------- */

.pagination { --bs-pagination-border-radius: 4px; gap: 2px; }
.page-link {
  background: transparent; border: 1px solid transparent; color: var(--km-t1);
  font-family: var(--km-mono); font-size: .8125rem; letter-spacing: .04em;
  min-width: 38px; min-height: 38px;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color var(--km-d-micro) var(--km-e-micro),
              color var(--km-d-micro) var(--km-e-micro);
}
.page-link:hover { background: var(--km-plan-b); color: var(--km-t0); border-color: transparent; }
.page-item.active .page-link {
  background: transparent; color: var(--km-ac); border-color: var(--km-ac-bord);
}
.page-item.disabled .page-link { color: var(--km-t2); opacity: .5; }

.nav-tabs { border-bottom: 1px solid var(--km-l1); gap: 0; }
.nav-tabs .nav-link {
  position: relative; border: 0; background: transparent;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--km-t1); padding: .75rem 1.125rem .9375rem;
}
.nav-tabs .nav-link::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: var(--km-ac); transform: scaleX(0);
  transition: transform var(--km-d-elev) var(--km-e-sortie);
}
.nav-tabs .nav-link.active {
  background: transparent; border: 0; color: var(--km-t0) !important;
}
.nav-tabs .nav-link.active::after { transform: scaleX(1); }
.nav-pills .nav-link { border-radius: 4px; color: var(--km-t1); }
.nav-pills .nav-link.active {
  background: var(--km-ac-voile) !important; color: var(--km-ac) !important;
  box-shadow: inset 0 0 0 1px var(--km-ac-bord);
}

.accordion {
  --bs-accordion-bg: transparent;
  --bs-accordion-border-color: var(--km-l1);
  --bs-accordion-border-radius: 5px;
  --bs-accordion-btn-color: var(--km-t0);
  --bs-accordion-btn-bg: transparent;
  --bs-accordion-active-bg: var(--km-plan-b);
  --bs-accordion-active-color: var(--km-t0);
  --bs-accordion-btn-focus-box-shadow: none;
}
.accordion-button { font-weight: 510; letter-spacing: -.008em; }
.accordion-button:not(.collapsed) { box-shadow: inset 0 -1px 0 var(--km-l1); }

.list-group {
  --bs-list-group-bg: transparent;
  --bs-list-group-border-color: var(--km-l1);
  --bs-list-group-color: var(--km-t0);
  --bs-list-group-action-hover-bg: var(--km-plan-b);
  --bs-list-group-action-hover-color: var(--km-t0);
  --bs-list-group-active-bg: var(--km-ac-voile);
  --bs-list-group-active-color: var(--km-ac);
  --bs-list-group-active-border-color: var(--km-ac-bord);
}
.email-list .list-group-item { border-left: 2px solid transparent !important; }
.email-list .list-group-item.active {
  background: var(--km-ac-voile) !important;
  border-left-color: var(--km-ac) !important;
  color: var(--km-t0) !important;
}

/* --------------------------------------------------------------------------
   15. Modales, menus déroulants, infobulles, notifications
   -------------------------------------------------------------------------- */

.modal-content, .dropdown-menu, .toast, .popover {
  background-color: var(--km-plan-a);
  border: 1px solid var(--km-l1);
  border-radius: 6px;
  box-shadow: var(--km-ombre-2);
  color: var(--km-t0);
}
.modal-header, .modal-footer { border-color: var(--km-l1); }
.modal-title { font-size: 1.125rem; font-weight: 590; letter-spacing: -.014em; }
.modal-backdrop { --bs-backdrop-bg: #000; --bs-backdrop-opacity: .62; }

.dropdown-item {
  color: var(--km-t1); font-size: .9375rem; padding: .5625rem 1rem; border-radius: 3px;
  transition: background-color var(--km-d-micro) var(--km-e-micro),
              color var(--km-d-micro) var(--km-e-micro);
}
.dropdown-item:hover, .dropdown-item:focus { background: var(--km-plan-b); color: var(--km-t0); }
.dropdown-item.active { background: var(--km-ac-voile); color: var(--km-ac); }
.dropdown-divider { border-color: var(--km-l1); }

.tooltip-inner {
  background: var(--km-plan-c); color: var(--km-t0); border-radius: 4px;
  font-family: var(--km-mono); font-size: .75rem; letter-spacing: .02em; padding: .5rem .75rem;
}
.tooltip .tooltip-arrow::before { border-top-color: var(--km-plan-c); border-bottom-color: var(--km-plan-c); }

.toast-header { background: transparent; border-color: var(--km-l1); color: var(--km-t1); }
.toast-body { color: var(--km-t0); }

.offcanvas { background-color: var(--km-fond); border-color: var(--km-l1); color: var(--km-t0); }

/* --------------------------------------------------------------------------
   16. Jauges et progression — la gouttière est un pas plus clair de la teinte
   -------------------------------------------------------------------------- */

.progress, .progress-stacked {
  background-color: var(--km-piste);
  height: 6px;
  border-radius: 3px;
  overflow: hidden;
}
.progress-bar { background-color: var(--km-ac); transition: width 1300ms var(--km-e-entree); }
.progress-bar.bg-warning { background-color: var(--km-at); }
.progress-bar.bg-danger  { background-color: var(--km-ko); }
.progress-bar.bg-success { background-color: var(--km-ok); }

/* --------------------------------------------------------------------------
   17. Attente — squelettes plutôt qu'indicateurs tournants
   -------------------------------------------------------------------------- */

.km-squelette {
  background: linear-gradient(90deg, var(--km-plan-b) 20%, var(--km-plan-c) 40%, var(--km-plan-b) 60%);
  background-size: 300% 100%;
  border-radius: 3px;
  animation: km-balayage 1.5s var(--km-e-couleur) infinite;
}
@keyframes km-balayage { 0% { background-position: 100% 0 } 100% { background-position: 0 0 } }

.spinner-border, .spinner-grow { color: var(--km-ac); border-width: 2px; }
.wait { background: rgba(14,20,24,.62); }

/* --------------------------------------------------------------------------
   18. Pages métier — commande, facture, passerelles de paiement
   Habillage uniquement : aucun sélecteur fonctionnel n'est modifié.
   -------------------------------------------------------------------------- */

.invoice-gateway {
  border: 1px solid var(--km-l1) !important;
  border-radius: 5px;
  background: var(--km-plan-a);
  transition: border-color var(--km-d-couleur) var(--km-e-couleur),
              background-color var(--km-d-couleur) var(--km-e-couleur);
}
.invoice-gateway:hover {
  border-color: var(--km-ac-bord) !important;
  background: var(--km-plan-b);
}

.block.pricing .total { padding-bottom: 1rem; }
.block.pricing table td { padding: .375rem 0; font-size: .875rem; color: var(--km-t1); }
.block.pricing hr { margin: 1rem 0; }
#period-selector { margin-bottom: 1rem; }

.mod_orderbutton .accordion-body span:not(.badge) { font-size: .875rem; color: var(--km-t1); }

/* Icônes : épaisseur constante en poids optique */
.icon { stroke-width: 1.75; }
.icon-sm, .btn .icon { width: 16px; height: 16px; stroke-width: 1.9; }
.icon-lg { width: 28px; height: 28px; stroke-width: 1.45; }

.db-avatar { background-color: var(--km-plan-b); border: 1px solid var(--km-l1); }
.fi { border-radius: 2px; }

/* --------------------------------------------------------------------------
   19. Correctifs
   -------------------------------------------------------------------------- */

/* Les images insérées dans les descriptions de catégories et de produits
   s'affichaient en pleine largeur : img-fluid plafonne mais ne réduit pas.
   On borne la dimension réelle, et les images en tête de puce deviennent
   des pictogrammes alignés sur la ligne de base. */
.card-body img, .content-block img, .markdown img, .description img {
  max-width: 100%;
  height: auto;
}
.card-body li > img:first-child,
.content-block li > img:first-child,
.description li > img:first-child {
  width: 18px; height: 18px;
  vertical-align: -3px;
  margin-right: .5rem;
  flex-shrink: 0;
}
.img-fluid { max-height: 320px; width: auto; }

/* Conteneurs imbriqués de layout_default : la marge était doublée */
.container > .container { padding-left: 0; padding-right: 0; max-width: 100%; }

/* Les graisses 600 et 700 héritées sont ramenées dans l'échelle */
.fw-bold, .fw-bolder { font-weight: 510 !important; }

/* --------------------------------------------------------------------------
   20. Mouvement réduit — tout se fige, sauf l'anneau de focus
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
  .card:hover { transform: none; }
}

/* --------------------------------------------------------------------------
   21. LA CONSOLE — structures propres au tableau de bord refondu
   Ces classes n'existent que dans « mod_index_dashboard.html.twig ».
   -------------------------------------------------------------------------- */

/* En-tête de page */
.km-entete {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 1.25rem;
  padding-bottom: 1.75rem; margin-bottom: 2rem;
  border-bottom: 1px solid var(--km-l1);
}
.km-entete-nom { display: flex; flex-direction: column; gap: .5rem; }
.km-entete-nom h1 { font-size: 1.875rem; line-height: 1.1; letter-spacing: -.03em; margin: 0; }
.km-entete-actions { margin-left: auto; display: flex; gap: .625rem; flex-wrap: wrap; }

.km-statut { display: inline-flex; align-items: center; gap: .5625rem;
  font-size: .875rem; color: var(--km-t1); }
.km-point { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--km-t2); }
.km-point-ok { background: var(--km-ok); }

/* Cartouche — les faits que le client vient vérifier, sur un seul rang */
.km-cartouche {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  border: 1px solid var(--km-l2); border-radius: 5px;
  background: var(--km-plan-a); overflow: hidden; margin-bottom: 2rem;
}
.km-cartouche > div {
  padding: 1.125rem 1.375rem; border-right: 1px solid var(--km-l1);
  display: flex; flex-direction: column; gap: .375rem;
}
.km-cartouche > div:last-child { border-right: 0; }
.km-cartouche-action { justify-content: center; }
.km-valeur {
  font-family: var(--km-mono); font-size: 1.25rem; line-height: 1.6rem;
  font-weight: 500; letter-spacing: -.02em; color: var(--km-t0);
  font-variant-numeric: tabular-nums;
}
.km-valeur-accent { color: var(--km-ac); }

/* Tuiles de mesure */
.km-tuiles {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1.25rem; margin-bottom: 2.5rem;
}
.km-tuile {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; gap: .5rem;
  padding: 1.25rem; border: 1px solid var(--km-l1); border-radius: 5px;
  background: var(--km-plan-a); color: var(--km-t0); text-decoration: none;
  transition: background-color var(--km-d-elev) var(--km-e-couleur),
              border-color var(--km-d-elev) var(--km-e-couleur),
              transform var(--km-d-elev) var(--km-e-sortie);
}
.km-tuile::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: var(--km-ac); transform: scaleX(0); transform-origin: left;
  transition: transform 460ms var(--km-e-entree);
}
.km-tuile:hover {
  background: var(--km-plan-b); border-color: var(--km-l2);
  transform: translateY(-3px); color: var(--km-t0); text-decoration: none;
}
.km-tuile:hover::before { transform: scaleX(1); }
.km-chiffre {
  font-family: var(--km-mono); font-size: 1.875rem; line-height: 2.25rem;
  font-weight: 500; letter-spacing: -.03em; font-variant-numeric: tabular-nums;
}
.km-titre-tuile { font-size: 1.0625rem; font-weight: 510; letter-spacing: -.01em; }
.km-appui { font-size: .8125rem; line-height: 1.25rem; color: var(--km-t1); }

/* Sections à filet */
.km-section { margin-bottom: 2.5rem; }
.km-section-tete {
  display: flex; align-items: baseline; gap: 1rem;
  padding-bottom: .75rem; margin-bottom: .25rem;
  border-bottom: 1px solid var(--km-l1);
}
.km-section-tete .km-lien {
  margin-left: auto; font-family: var(--km-mono); font-size: .6875rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--km-t2);
}
.km-section-tete .km-lien:hover { color: var(--km-ac); text-decoration: none; }
.km-lien-ligne { color: var(--km-t0); font-weight: 400; }
.km-lien-ligne:hover { color: var(--km-ac); text-decoration: none; }
.km-ref {
  display: inline-block; margin-left: .625rem;
  font-family: var(--km-mono); font-size: .75rem; color: var(--km-t2);
}
.km-section td.text-end, .km-section th.text-end {
  font-family: var(--km-mono); font-size: .8125rem; color: var(--km-t1);
}

.km-vide {
  display: flex; flex-direction: column; align-items: center; gap: .875rem;
  padding: 2.5rem 1.25rem; text-align: center;
  border: 1px solid var(--km-l1); border-radius: 5px; background: var(--km-plan-a);
}
.km-vide p { margin: 0; color: var(--km-t1); }

/* Ouverture du visiteur non connecté */
.km-ouverture { padding: 2rem 0 4.5rem; }
.km-ouverture-texte { display: flex; flex-direction: column; gap: 1.5rem; max-width: 62ch; }
.km-ouverture-texte h1 {
  font-size: clamp(2.25rem, 5vw, 3.5rem); line-height: 1.02;
  letter-spacing: -.038em; margin: 0;
}
.km-puce {
  display: inline-flex; align-items: center; gap: .625rem; align-self: flex-start;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--km-ac);
}
.km-puce::before { content: ""; width: 24px; height: 1px; background: var(--km-ac); }
.km-ouverture-actions { display: flex; gap: .75rem; flex-wrap: wrap; }
.km-prose { color: var(--km-t1); }
.km-lead {
  font-size: 1.1875rem; line-height: 1.85rem; letter-spacing: -.012em;
  color: var(--km-t1); margin: 0; max-width: 58ch;
}
/* Les tuiles secondaires : plus discrètes que les offres */
.km-tuiles-secondaires { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); margin-top: 2rem; }
.km-tuiles-secondaires .km-tuile { padding: 1.125rem 1.25rem; gap: .375rem; }
.km-tuiles-secondaires .km-titre-tuile { font-size: 1rem; }
.km-prose p { margin-bottom: .75rem; }
.km-prose ul { padding-left: 1.125rem; margin-bottom: .75rem; }
.km-prose li { margin-bottom: .375rem; }
.km-prose strong { color: var(--km-t0); font-weight: 510; }

@media (max-width: 576px) {
  .km-cartouche > div { border-right: 0; border-bottom: 1px solid var(--km-l1); }
  .km-cartouche > div:last-child { border-bottom: 0; }
  .km-entete-actions { margin-left: 0; }
}

/* --------------------------------------------------------------------------
   22. LA COQUE — la colonne de menu devient une réglure fixe qui se déplie
   Transformation entièrement en CSS : le balisage Twig n'est pas touché.
   La colonne visée est celle qui contient « #sidebarMenu ».
   -------------------------------------------------------------------------- */

@media (min-width: 768px) {
  /* Le rail */
  .container > .container > .row > [class*="col-"]:has(#sidebarMenu) {
    position: fixed; left: 0; top: 0; bottom: 0; z-index: 1040;
    width: 78px; max-width: 78px; flex: 0 0 78px; padding: 0; overflow: hidden;
    background: var(--km-fond);
    border-right: 1px solid var(--km-l1);
    transition: width 340ms var(--km-e-sortie),
                max-width 340ms var(--km-e-sortie),
                box-shadow 340ms var(--km-e-sortie);
  }
  .container > .container > .row > [class*="col-"]:has(#sidebarMenu):hover,
  .container > .container > .row > [class*="col-"]:has(#sidebarMenu):focus-within {
    width: 244px; max-width: 244px;
    box-shadow: 24px 0 48px -24px rgba(0,0,0,.55);
  }

  #sidebarMenu { padding: 88px 12px 24px; }
  #sidebarMenu .nav { gap: 2px; }
  #sidebarMenu .nav-link {
    display: flex; align-items: center; gap: 16px;
    padding: 11px 14px; white-space: nowrap; border-radius: 4px;
  }
  #sidebarMenu .nav-link .icon { flex: none; }
  /* Le libellé s'efface tant que le rail est replié */
  #sidebarMenu .nav-link { font-size: 0; }
  #sidebarMenu .nav-link .icon { font-size: 1rem; }
  [class*="col-"]:has(#sidebarMenu):hover #sidebarMenu .nav-link,
  [class*="col-"]:has(#sidebarMenu):focus-within #sidebarMenu .nav-link {
    font-size: .875rem;
  }
  /* Solde et note : masqués tant que le rail est replié */
  #sidebarMenu .nav > li:not(.offcanvas-item) {
    opacity: 0; pointer-events: none;
    transition: opacity 220ms var(--km-e-couleur) 60ms;
  }
  [class*="col-"]:has(#sidebarMenu):hover #sidebarMenu .nav > li:not(.offcanvas-item),
  [class*="col-"]:has(#sidebarMenu):focus-within #sidebarMenu .nav > li:not(.offcanvas-item) {
    opacity: 1; pointer-events: auto;
  }

  /* La colonne de contenu occupe tout le reste */
  .container > .container > .row > [class*="col-"]:not(:has(#sidebarMenu)) {
    width: 100%; max-width: none; flex: 0 0 100%;
    padding-left: 40px; padding-right: 24px;
  }
  .container > .container:has(#sidebarMenu) { margin-left: 78px; max-width: none; }

  /* En-tête : une barre mince, alignée sur la même gouttière */
  body:has(#sidebarMenu) > .container > header { margin-left: 78px; }
  body:has(#sidebarMenu) > .container > header .navbar {
    padding-top: .75rem; padding-bottom: .75rem;
  }
  /* Le logo passe dans le rail : on le décale visuellement au-dessus du menu */
  body:has(#sidebarMenu) > .container > header .navbar-brand {
    position: fixed; left: 0; top: 0; width: 78px; height: 78px; z-index: 1041;
    display: flex; align-items: center; justify-content: center;
    margin: 0; padding: 0; overflow: hidden;
  }
  body:has(#sidebarMenu) > .container > header .navbar-brand img {
    height: 30px; width: auto; max-width: 54px; object-fit: contain;
  }
}

@media (min-width: 768px) and (max-width: 1200px) {
  .container > .container > .row > [class*="col-"]:not(:has(#sidebarMenu)) {
    padding-left: 28px; padding-right: 16px;
  }
}

/* --------------------------------------------------------------------------
   23. LA MISE EN SCÈNE — styles pilotés par kardox.js
   Tout est enfermé derrière « .km-js » : sans JavaScript, rien ne se cache.
   -------------------------------------------------------------------------- */

#km-trace { position: fixed; inset: 0; z-index: 0; pointer-events: none; }
body > .container { position: relative; z-index: 1; }

/* Apparitions */
.km-js .km-rv { opacity: 0; transform: translateY(16px); }
.km-js .km-rv.km-vu {
  opacity: 1; transform: none;
  transition: opacity 720ms var(--km-e-entree), transform 720ms var(--km-e-entree);
}
/* Volet de découpe sur le titre de page */
.km-js .km-wp { clip-path: inset(0 100% -0.2em 0); }
.km-js .km-wp.km-vu {
  clip-path: inset(0 -0.2em -0.2em 0);
  transition: clip-path 1000ms var(--km-e-entree);
}
/* Filet qui se trace sous les en-têtes de section */
.km-filet {
  display: block; height: 1px; background: var(--km-ac);
  transform: scaleX(0); transform-origin: left;
  position: absolute; left: 0; right: 0; bottom: -1px;
}
.km-js .km-filet.km-vu { transform: scaleX(1); transition: transform 900ms var(--km-e-entree); }
.km-section-tete, .km-entete { position: relative; }

/* Rouleau de chiffres */
.km-lu-seul {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.km-rouleau {
  display: inline-flex; align-items: flex-start;
  font-family: var(--km-mono); font-variant-numeric: tabular-nums;
  letter-spacing: -.03em;
}
.km-rouleau .km-col { display: block; overflow: hidden; height: 1em; line-height: 1em; }
.km-rouleau .km-col u { display: block; line-height: 1em; text-decoration: none; transform: translateY(0); }
.km-js .km-vu .km-rouleau .km-col u,
.km-js .km-a-rouler.km-vu .km-rouleau .km-col u {
  transform: translateY(calc(var(--d, 0) * -1em));
  transition: transform 1100ms var(--km-e-entree) var(--dl, 0ms);
}


/* Prix repérés dans du texte libre : la signature chiffrée s'applique
   partout, y compris dans la vitrine et les descriptions de produits. */
.km-prix {
  font-family: var(--km-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  letter-spacing: -.02em;
  color: var(--km-t0);
}
.km-prose .km-prix, .card-body .km-prix { color: var(--km-t0); }


/* ---------- Les offres, comme dans le spécimen ---------- */
.km-offres {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 378px));
  gap: 2rem; margin-top: 4.5rem;
}
.km-offre {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; gap: 1.5rem;
  padding: 1.5rem; border: 1px solid var(--km-l1); border-radius: 5px;
  background: var(--km-plan-a); color: var(--km-t0); text-decoration: none;
  transition: background-color var(--km-d-elev) var(--km-e-couleur),
              border-color var(--km-d-elev) var(--km-e-couleur),
              transform var(--km-d-elev) var(--km-e-sortie);
}
.km-offre::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: var(--km-ac); transform: scaleX(0); transform-origin: left;
  transition: transform 460ms var(--km-e-entree);
}
.km-offre::after {
  content: ""; position: absolute; right: -30%; top: -60%; width: 70%; height: 160%;
  pointer-events: none; opacity: 0;
  background: radial-gradient(closest-side, var(--km-ac-voile2), transparent 72%);
  transition: opacity 420ms var(--km-e-couleur);
}
.km-offre:hover {
  background: var(--km-plan-b); border-color: var(--km-l2);
  transform: translateY(-4px); color: var(--km-t0); text-decoration: none;
}
.km-offre:hover::before { transform: scaleX(1); }
.km-offre:hover::after { opacity: 1; }
.km-offre > * { position: relative; z-index: 1; }
.km-offre-titre { margin: 0; font-size: 1.25rem; line-height: 1.75rem; letter-spacing: -.014em; font-weight: 590; }
.km-offre-prix { display: flex; align-items: baseline; gap: .5rem; margin-top: -.25rem; }
.km-offre-montant { font-size: 2.5rem; line-height: 1.05; letter-spacing: -.03em; }
.km-offre-periode { font-size: .8125rem; color: var(--km-t1); }
.km-offre-detail { display: block; font-size: .875rem; line-height: 1.375rem; color: var(--km-t1); }
.km-offre-points {
  display: flex; flex-direction: column; gap: .75rem;
  padding-top: 1.5rem; border-top: 1px solid var(--km-l1); margin-top: auto;
}
.km-point-offre {
  display: flex; align-items: flex-start; gap: .75rem;
  font-size: .875rem; line-height: 1.3125rem; color: var(--km-t1);
}
/* Une coche tracée, pas une puce : on affirme ce qui est inclus. */
.km-point-offre::before {
  content: ""; flex: none; width: 4px; height: 4px; margin-top: .5rem;
  background: var(--km-ac);
}
.km-offre-vedette .km-point-offre { color: var(--km-t0); }
.km-offre-appel {
  margin-top: auto; font-family: var(--km-mono); font-size: .6875rem;
  letter-spacing: .2em; text-transform: uppercase; color: var(--km-ac);
  display: inline-flex; align-items: center; gap: .5rem;
}
.km-offre-appel::after {
  content: ""; width: 18px; height: 1px; background: var(--km-ac);
  transition: width var(--km-d-elev) var(--km-e-sortie);
}
.km-offre:hover .km-offre-appel::after { width: 30px; }
.km-offres-bloc { margin-top: 4.5rem; }

/* L'offre recommandée : plus grande, bordée d'ambre, prix agrandi.
   C'est le seul endroit de la page où l'accent borde une surface entière. */
.km-offre-haut { display: flex; align-items: center; gap: .75rem; }
/* Pas de pastille : un filet court et le mot, comme dans le spécimen. */
.km-recommande {
  margin-left: auto; display: inline-flex; align-items: center; gap: .5rem;
  font-family: var(--km-mono); font-size: .625rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--km-ac); white-space: nowrap;
}
.km-recommande::before { content: ""; width: 16px; height: 1px; background: var(--km-ac); }
.km-offre-vedette {
  border-color: var(--km-ac-bord);
  background: linear-gradient(180deg, var(--km-ac-voile), transparent 42%), var(--km-plan-a);
}
.km-offre-vedette::before { transform: scaleX(1); }
.km-offre-vedette .km-offre-montant { font-size: 3rem; line-height: 1.02; }
.km-offre-vedette .km-offre-titre { font-size: 1.375rem; }
@media (min-width: 900px) {
  .km-offres { align-items: stretch; }
  .km-offre-vedette { transform: translateY(-10px); }
  .km-offre-vedette:hover { transform: translateY(-14px); }
}

/* Anneau de proportion dans les tuiles */
.km-tuile { position: relative; }
.km-anneau { position: absolute; top: 16px; right: 16px; opacity: .9; }
.km-anneau-piste { stroke: var(--km-piste); }
.km-anneau-part  { stroke: var(--km-ac); }

/* Lueur suivant le pointeur */
.btn { position: relative; overflow: hidden; }
.btn::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(150px circle at var(--km-mx, 50%) var(--km-my, 50%),
              rgba(255,255,255,.26), transparent 62%);
  transition: opacity var(--km-d-couleur) var(--km-e-couleur);
}
.btn:hover::after { opacity: 1; }
.btn-secondary::after, .btn-outline-primary::after, .btn-light::after {
  background: radial-gradient(150px circle at var(--km-mx, 50%) var(--km-my, 50%),
              var(--km-ac-voile2), transparent 62%);
}

@media (prefers-reduced-motion: reduce) {
  .km-js .km-rv, .km-js .km-wp { opacity: 1; transform: none; clip-path: none; }
  .km-js .km-filet { transform: scaleX(1); }
  .km-js .km-rouleau .km-col u { transition: none; }
}

/* --------------------------------------------------------------------------
   24. Impression — les factures doivent rester lisibles sur papier
   -------------------------------------------------------------------------- */

@media print {
  body { background: #FFFFFF !important; color: #000000 !important; background-image: none; }
  .card { border-color: #CCCCCC; box-shadow: none; transform: none; }
  .navbar, #footer, #sidebarMenu, .btn, .toast-container { display: none !important; }
}

/* --------------------------------------------------------------------------
   25. LA BASCULE — rouverte
   Un garde-fou masquait ici la bascule clair/sombre : la variante papier était
   réputée illisible, à 1,00:1. Ce relevé était faux. Il venait d'une lecture
   de getComputedStyle faite dans le même tour que le changement d'attribut :
   le corps porte une transition de 200 ms sur background-color et color, donc
   la lecture immédiate rend encore l'ANCIENNE couleur, tandis que les titres,
   eux, n'ont pas de transition et basculent aussitôt. D'où le mirage d'un
   texte foncé sur un fond foncé.
   Remesuré en laissant la peinture se faire, sur l'accueil, la commande et la
   connexion, dans les deux variantes : aucun texte sous le seuil AA. Le fond
   du corps suit bien le thème (papier #F4F6F8, corps à 17,13:1).
   Toute mesure de thème doit donc laisser passer une image avant de lire.
   -------------------------------------------------------------------------- */

/* Le gabarit pose « px-0 », une utilitaire Bootstrap en !important : le
   rembourrage ne peut pas la reprendre. On donne donc la cible en dimensions,
   qui, elles, passent. Carré de 40 px, l'icône centrée dedans.
   La couleur n'est pas fixée ici : l'icône est en stroke: currentColor, donc
   elle suit le lien de navigation — et son survol — comme le reste de la barre. */
.km-bascule {
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
}
.km-bascule-icone { display: block; }

/* --------------------------------------------------------------------------
   26. Les faits du bandeau d'ouverture — ce qui rend la promesse vérifiable
   -------------------------------------------------------------------------- */
.km-faits {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.75rem 2.5rem; margin-top: .5rem; padding-top: 1.5rem;
  border-top: 1px solid var(--km-l1); max-width: 62rem;
}
.km-fait {
  display: grid; grid-template-columns: auto 1fr; column-gap: .875rem; row-gap: .1875rem;
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t1);
  padding-left: 1rem; position: relative;
}
.km-fait i {
  grid-row: 1 / span 2; align-self: start;
  font-family: var(--km-mono); font-style: normal; font-weight: 500;
  font-size: 1.75rem; line-height: 1.75rem; letter-spacing: -.03em;
  color: var(--km-ac); font-variant-numeric: tabular-nums;
  transition: color var(--km-d-couleur) var(--km-e-couleur);
}
.km-fait::before {
  content: ""; position: absolute; left: 0; top: .375rem; bottom: .25rem;
  width: 1px; background: var(--km-l2);
  transition: background-color var(--km-d-couleur) var(--km-e-couleur);
}
.km-fait:hover::before { background: var(--km-ac); }
.km-fait b {
  font-family: var(--km-mono); font-size: .6875rem; font-weight: 400;
  letter-spacing: .16em; text-transform: uppercase; color: var(--km-t0);
}

/* --------------------------------------------------------------------------
   27. LA DÉMONSTRATION — trente-six mois de tarif, tracés au trait fin
   Le trait plat de Kardox contre les paliers du marché. Les deux se dessinent
   à l'entrée ; sous prefers-reduced-motion ils apparaissent déjà tracés.
   -------------------------------------------------------------------------- */

@media (min-width: 992px) {
  .km-ouverture {
    display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(340px, .95fr);
    gap: 4rem; align-items: center;
  }
}
.km-demo { margin: 2.5rem 0 0; display: flex; flex-direction: column; gap: .875rem;
  max-width: 440px; width: 100%; }
@media (min-width: 992px) { .km-demo { margin: 0; } }
.km-demo-tete { margin: 0; }
.km-demo-svg { display: block; width: 100%; max-width: 440px; height: auto; overflow: visible; }

.km-demo-grille line { stroke: var(--km-l1); stroke-width: 1; shape-rendering: crispEdges; }
.km-demo-axe text {
  font-family: var(--km-mono); font-size: 10px; letter-spacing: .08em;
  fill: var(--km-t2);
}
.km-demo-marche, .km-demo-kardox {
  fill: none; stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round;
}
.km-demo-marche { stroke: var(--km-t2); stroke-dasharray: 4 4; opacity: .85; }
.km-demo-kardox { stroke: var(--km-ac); stroke-width: 2; }
.km-demo-fin { stroke-width: 2; }
.km-demo-fin-marche  { fill: var(--km-t2); stroke: var(--km-fond); }
.km-demo-fin-kardox  { fill: var(--km-ac); stroke: var(--km-fond); }
.km-demo-note {
  font-family: var(--km-mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
}
.km-demo-note-marche { fill: var(--km-t2); }
.km-demo-note-kardox { fill: var(--km-ac); }
.km-demo-legende {
  margin: 0; font-size: .8125rem; line-height: 1.25rem; color: var(--km-t1);
  padding-top: .875rem; border-top: 1px solid var(--km-l1); max-width: 46ch;
}

/* Tracé progressif — sans dépendance au JavaScript : si le script ne se
   charge pas, l'animation se joue quand même et rien ne reste caché. */
.km-demo-kardox { stroke-dasharray: 520; stroke-dashoffset: 520;
  animation: km-tracer 1400ms var(--km-e-entree) 400ms forwards; }
.km-demo-fin, .km-demo-note { opacity: 0; animation: km-paraitre 400ms var(--km-e-couleur) forwards; }
.km-demo-fin-marche, .km-demo-note-marche { animation-delay: 1000ms; }
.km-demo-fin-kardox, .km-demo-note-kardox { animation-delay: 1700ms; }
@keyframes km-tracer  { to { stroke-dashoffset: 0; } }
@keyframes km-paraitre{ to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .km-demo-kardox { stroke-dashoffset: 0; animation: none; }
  .km-demo-fin, .km-demo-note { opacity: 1; animation: none; }
}

/* Le balayage continu de la démonstration */
.km-balai { transition: opacity 500ms var(--km-e-couleur); }
.km-balai-trait { stroke: var(--km-l2); stroke-width: 1; stroke-dasharray: 2 3; }
.km-balai-pt { stroke: var(--km-fond); stroke-width: 2; }
.km-balai-pt-marche { fill: var(--km-t2); }
.km-balai-pt-kardox { fill: var(--km-ac); }
.km-balai-lecture {
  font-family: var(--km-mono); font-size: 9.5px; letter-spacing: .06em;
  fill: var(--km-t1); font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   28. RYTHME DE L'OUVERTURE — valeurs relevées chez Vercel, Linear, Fly.io
   h1 56/64 · titre→accroche 24 · accroche 20/30 sur 576 max
   bloc de texte → cartes 72 · padding de section 128
   -------------------------------------------------------------------------- */
.km-ouverture { padding: 6rem 0 8rem; }
.km-ouverture-texte { gap: 0; max-width: none; }
.km-ouverture-texte .km-puce { margin-bottom: 1.75rem; }
.km-ouverture-texte h1 {
  font-size: clamp(2.5rem, 4.6vw, 3.5rem); line-height: 1.14;
  letter-spacing: -.025em; margin: 0 0 1.5rem;
}
.km-lead {
  font-size: 1.25rem; line-height: 1.875rem; letter-spacing: -.011em;
  color: var(--km-t1); margin: 0; max-width: 36rem;
}
.km-faits { margin-top: 3rem; padding-top: 2rem; gap: 2rem 3rem; }
/* Les deux boutons respiraient trop peu : 20 px entre eux, 40 au-dessus. */
.km-ouverture-actions { margin-top: 2.5rem; gap: 1.25rem; }
.km-ouverture-actions .btn { min-height: 48px; padding: .875rem 1.5rem; }
.km-demo-legende { padding-top: 1.25rem; }

@media (min-width: 992px) {
  .km-ouverture { gap: 5rem; align-items: center; }
}
@media (max-width: 991px) {
  .km-ouverture { padding: 3.5rem 0 4.5rem; }
  .km-faits { margin-top: 2.25rem; gap: 1.5rem 2rem; }
}

/* Équilibre de la colonne de gauche : plus d'air au-dessus des boutons,
   moins sous le bloc. Et l'écart final, chiffré, à droite du graphique. */
.km-ouverture { padding: 6rem 0 5.5rem; }
.km-ouverture-actions { margin-top: 3.5rem; }
.km-faits { margin-top: 3rem; padding-top: 2rem; }

.km-demo-svg { overflow: visible; }
.km-demo-ecart line { stroke: var(--km-ac); stroke-width: 1; opacity: .55; }
.km-demo-ecart text {
  font-family: var(--km-mono); font-size: 9.5px; letter-spacing: .04em;
  fill: var(--km-ac); font-variant-numeric: tabular-nums;
}
.km-demo-ecart text + text { fill: var(--km-t2); letter-spacing: .1em; }
.km-demo-ecart { opacity: 0; animation: km-paraitre 500ms var(--km-e-couleur) 2100ms forwards; }
@media (prefers-reduced-motion: reduce) { .km-demo-ecart { opacity: 1; animation: none; } }
@media (max-width: 991px) { .km-ouverture { padding: 3.5rem 0 3.5rem; } }

/* Moins de vide sous les boutons : les deux colonnes s'alignent en haut. */
.km-ouverture { padding: 5rem 0 3rem; }
@media (min-width: 992px) { .km-ouverture { align-items: start; } }
@media (max-width: 991px) { .km-ouverture { padding: 3rem 0 2.5rem; } }
.km-offres-bloc { margin-top: 3rem; }

/* Le cumul d'économie qui monte pendant le balayage */
.km-balai-cumul {
  font-family: var(--km-mono); font-size: 10px; font-weight: 500;
  letter-spacing: .06em; fill: var(--km-ac); font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   29. LE PIED DE PAGE — quatre colonnes, filets, et l'année qui se met à jour
   -------------------------------------------------------------------------- */
.km-pied {
  margin-top: 6rem !important; padding-top: 3rem; padding-bottom: 2.5rem;
  border-top: 1px solid var(--km-l1); color: var(--km-t1); font-size: .875rem;
  display: flex; flex-direction: column; gap: 2.5rem;
}
.km-pied-haut {
  display: grid; grid-template-columns: minmax(240px, 1.6fr) repeat(3, minmax(140px, 1fr));
  gap: 2.5rem 3rem;
}
.km-pied-marque { display: flex; flex-direction: column; gap: .875rem; max-width: 34ch; }
.km-pied-nom {
  font-size: 1.0625rem; font-weight: 590; letter-spacing: -.012em; color: var(--km-t0);
}
.km-pied-phrase { margin: 0; font-size: .8125rem; line-height: 1.375rem; color: var(--km-t1); }
.km-pied-etat {
  display: inline-flex; align-items: center; gap: .5625rem;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--km-t2);
}

.km-pied-col { display: flex; flex-direction: column; gap: .75rem; }
.km-pied-col .km-etiquette { margin-bottom: .25rem; }
.km-pied-col a {
  color: var(--km-t1); font-size: .875rem; line-height: 1.25rem; width: fit-content;
  position: relative; padding-bottom: 1px;
  transition: color var(--km-d-micro) var(--km-e-micro);
}
/* Le soulignement se trace de gauche à droite, il n'apparaît pas d'un bloc. */
.km-pied-col a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--km-ac); transform: scaleX(0); transform-origin: left;
  transition: transform var(--km-d-elev) var(--km-e-sortie);
}
.km-pied-col a:hover { color: var(--km-ac); text-decoration: none; }
.km-pied-col a:hover::after { transform: scaleX(1); }

.km-pied-bas {
  display: flex; flex-wrap: wrap; align-items: center; gap: .75rem 2rem;
  padding-top: 1.75rem; border-top: 1px solid var(--km-l1);
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--km-t2);
}
.km-pied-lieu { margin-left: auto; }
.km-pied-banque { text-transform: none; letter-spacing: .04em; }

@media (max-width: 780px) {
  .km-pied-haut { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 2rem; }
  .km-pied-marque { grid-column: 1 / -1; }
  .km-pied-lieu { margin-left: 0; }
}

/* --------------------------------------------------------------------------
   30. Le graphique se cale au milieu de sa colonne, pas en haut.
   -------------------------------------------------------------------------- */
@media (min-width: 992px) {
  .km-ouverture { align-items: start; }
  .km-demo { align-self: center; }
}

/* --------------------------------------------------------------------------
   31. LE PIED — plat, réglé, signé
   Retour à la grammaire de la page : aucune surface flottante, aucun flou,
   aucun coin arrondi, aucune lueur. Ce qui fait la modernité ici, c'est la
   hiérarchie typographique et l'alignement, pas l'effet.
   -------------------------------------------------------------------------- */
.km-pied {
  position: relative;
  margin-top: 7rem !important;
  padding: 3.5rem 0 0;
  background: none;
  border-top: 1px solid var(--km-l1);
  border-radius: 0;
  backdrop-filter: none; -webkit-backdrop-filter: none;
  overflow: hidden;
}

/* Colonnes : l'index de la marque prend deux fois la place d'une colonne */
.km-pied-haut {
  display: grid;
  grid-template-columns: minmax(220px, 2fr) repeat(3, minmax(130px, 1fr));
  gap: 2rem 3.5rem;
}
.km-pied-marque { gap: 1rem; padding-right: 2rem; }
.km-pied-nom { font-size: 1rem; }
.km-pied-etat {
  padding: 0; border: 0; background: none; width: auto;
  color: var(--km-t2);
}

/* Les intitulés de colonne : mono, espacés, sans puce */
.km-pied-col { gap: .875rem; }
.km-pied-col .km-etiquette { display: block; margin-bottom: .375rem; }
.km-pied-col .km-etiquette::before { content: none; }
.km-pied-col a {
  padding: 0; margin-left: 0; border-radius: 0;
  color: var(--km-t1); font-size: .875rem; line-height: 1.375rem;
}
.km-pied-col a:hover { background: none; color: var(--km-t0); }
.km-pied-col a::after { left: 0; right: 0; bottom: -2px; background: var(--km-ac); }

/* La signature : le nom de la marque en très grand, à peine visible,
   coupé par le bas de page. C'est la seule liberté du pied. */
.km-pied-signature { display: none; }
.km-pied-signature-inutilise {
  margin: 3.5rem 0 -1.25rem;
  font-size: clamp(3.5rem, 11vw, 9rem);
  line-height: .82;
  font-weight: 590;
  letter-spacing: -.045em;
  color: var(--km-t0);
  opacity: .045;
  user-select: none;
  white-space: nowrap;
  transition: opacity 600ms var(--km-e-couleur);
}
.km-pied:hover .km-pied-signature { opacity: .07; }

.km-pied-bas {
  margin-top: 0; padding-top: 1.5rem; padding-bottom: 2rem;
  border-top: 1px solid var(--km-l1);
}
@media (max-width: 780px) {
  .km-pied { padding: 2.5rem 0 0; }
  .km-pied-signature { margin: 2.5rem 0 -.75rem; }
}

/* Le bloc vivant du pied : la dernière annonce, lue sur le module News.
   Pas d'infolettre : aucun point d'entrée public n'existe côté client,
   et un formulaire qui ne mène nulle part serait pire que rien. */
.km-pied-haut { grid-template-columns: minmax(220px, 1.7fr) minmax(190px, 1.2fr) repeat(3, minmax(120px, 1fr)); }
.km-pied-annonce { display: flex; flex-direction: column; gap: .75rem; }
.km-pied-annonce-lien {
  display: flex; flex-direction: column; gap: .5rem;
  padding: .875rem 1rem; border: 1px solid var(--km-l1); border-radius: 4px;
  color: var(--km-t1); text-decoration: none;
  transition: border-color var(--km-d-couleur) var(--km-e-couleur),
              background-color var(--km-d-couleur) var(--km-e-couleur);
}
.km-pied-annonce-lien:hover {
  border-color: var(--km-ac-bord); background: var(--km-plan-a); text-decoration: none;
}
.km-pied-annonce-titre {
  color: var(--km-t0); font-size: .875rem; line-height: 1.25rem; font-weight: 510;
}
.km-pied-annonce-lien:hover .km-pied-annonce-titre { color: var(--km-ac); }
.km-pied-annonce-date { font-size: .6875rem; letter-spacing: .1em; color: var(--km-t2); }
.km-pied-etat { display: none; }
@media (max-width: 980px) { .km-pied-haut { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); } }

/* --------------------------------------------------------------------------
   32. LA MARQUE EST LA VÔTRE
   L'espace client ne porte plus aucune signature tierce. Le widget de
   marque du moteur, la mention « Propulsé par », les liens vers le projet
   amont : tout cela sort du pied. Le seul nom affiché est Kardox Media.
   -------------------------------------------------------------------------- */
.km-pied [class*="branding"],
.km-pied a[href*="fossbilling"],
#footer a[href*="fossbilling"],
.km-pied-bas a[href*="fossbilling"] { display: none !important; }

/* La ligne « Propulsé par … » vit dans un widget : on neutralise le bloc
   qui la contient sans toucher au point d'extension lui-même. */
.km-pied > div:last-child:not(.km-pied-bas):not(.km-pied-haut) { display: none; }

.km-pied-haut { grid-template-columns: minmax(240px, 2fr) repeat(3, minmax(140px, 1fr)); }

/* Aucun lien vers le moteur ne s'affiche dans l'espace client, où qu'il soit
   injecté. Le fichier de script du moteur, lui, n'est évidemment pas touché. */
body a[href*="fossbilling.org"],
body a[title="Billing Software"] { display: none !important; }

/* Coordonnées du pied : cliquables, sobres, sans pastille ni promesse. */
.km-pied-contact { display: flex; flex-direction: column; gap: .5rem; margin-top: .25rem; }
.km-pied-contact a {
  color: var(--km-t1); font-size: .875rem; line-height: 1.25rem;
  width: fit-content; position: relative; padding-bottom: 1px;
  transition: color var(--km-d-micro) var(--km-e-micro);
}
.km-pied-contact a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: var(--km-ac); transform: scaleX(0); transform-origin: left;
  transition: transform var(--km-d-elev) var(--km-e-sortie);
}
.km-pied-contact a:hover { color: var(--km-ac); text-decoration: none; }
.km-pied-contact a:hover::after { transform: scaleX(1); }
.km-pied-adresse { font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2); }
.km-pied-tva { font-size: .6875rem; letter-spacing: .1em; color: var(--km-t2); }

/* Le widget « Powered by » du moteur : c'est le conteneur entier qui sort,
   pas seulement le lien — sinon la mention reste orpheline sous le pied. */
#footer + div:has(a[href*="fossbilling"]),
.km-pied ~ div:has(a[href*="fossbilling"]),
div.d-flex.justify-content-center:has(a[href*="fossbilling"]) { display: none !important; }

/* Coordonnées : deux lignes cliquables sous la phrase de marque */
.km-pied-contact { display: flex; flex-direction: column; gap: .5rem; margin-top: 1.25rem; }
.km-pied-contact a {
  color: var(--km-t1); font-size: .875rem; line-height: 1.25rem;
  width: fit-content; position: relative; padding-bottom: 1px;
  transition: color var(--km-d-micro) var(--km-e-micro);
}
.km-pied-contact a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: var(--km-ac); transform: scaleX(0); transform-origin: left;
  transition: transform var(--km-d-elev) var(--km-e-sortie);
}
.km-pied-contact a:hover { color: var(--km-ac); text-decoration: none; }
.km-pied-contact a:hover::after { transform: scaleX(1); }

/* --------------------------------------------------------------------------
   33. LA PAGE DE COMMANDE — même grammaire que l'accueil
   Le bloc fonctionnel du module garde sa structure : on l'entoure, on ne le
   réécrit pas. Seuls des espacements et des filets lui sont appliqués.
   -------------------------------------------------------------------------- */
.km-cmd-entete { padding: 1rem 0 3.5rem; border-bottom: 1px solid var(--km-l1); margin-bottom: 3rem; }
.km-cmd-entete .km-puce { margin-bottom: 1.5rem; }
.km-cmd-entete h1 {
  font-size: clamp(2.25rem, 4vw, 3rem); line-height: 1.1;
  letter-spacing: -.028em; margin: 0 0 1.25rem;
}
.km-cmd-entete .km-lead { max-width: 34rem; }
.km-cmd-faits {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 1.75rem 2.5rem; margin-top: 2.5rem; padding-top: 2rem;
  border-top: 1px solid var(--km-l1);
}

.km-cmd-devise {
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  padding-bottom: 1.5rem; margin-bottom: 2rem; border-bottom: 1px solid var(--km-l1);
}

/* Le catalogue du module : on lui donne l'air de la maison sans le toucher */
.km-cmd-catalogue .card { background: var(--km-plan-a); }
.km-cmd-catalogue .list-group-item {
  background: transparent; border: 0; border-bottom: 1px solid var(--km-l1);
  padding: 1.125rem 1.25rem; color: var(--km-t0);
  transition: background-color var(--km-d-micro) var(--km-e-micro);
}
.km-cmd-catalogue .list-group-item:hover { background: var(--km-plan-b); color: var(--km-ac); }
.km-cmd-catalogue .list-group-item .icon { color: var(--km-t2); }
.km-cmd-catalogue .list-group-item:hover .icon { color: var(--km-ac); }
.km-cmd-catalogue h1, .km-cmd-catalogue h2 { font-size: 1.25rem; letter-spacing: -.014em; }

.km-cmd-pied {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 2rem 3rem; margin-top: 3.5rem; padding-top: 2rem;
  border-top: 1px solid var(--km-l1);
}
.km-cmd-pied-bloc { display: flex; flex-direction: column; gap: .75rem; }
.km-cmd-pied-bloc p { margin: 0; font-size: .875rem; line-height: 1.375rem; color: var(--km-t1); max-width: 42ch; }

/* --------------------------------------------------------------------------
   34. Le choix du produit : le même jeu de cartes que l'accueil
   -------------------------------------------------------------------------- */
.km-cmd-cat { display: flex; align-items: center; gap: 1rem; margin: 0 0 1.5rem; }
.km-cmd-cat .km-cmd-cat-fil { flex: 1; height: 1px; background: var(--km-l1); }
.km-offres-cmd { margin-top: 0; margin-bottom: 2rem; }
.km-offres-cmd .km-offre-vedette { transform: none; }
.km-offres-cmd .km-offre-vedette:hover { transform: translateY(-4px); }

/* L'offre en cours : bordure pleine d'ambre, marque « Sélectionné » */
.km-offre-actif {
  border-color: var(--km-ac) !important;
  background: linear-gradient(180deg, var(--km-ac-voile), transparent 46%), var(--km-plan-a) !important;
}
.km-offre-actif::before { transform: scaleX(1); }
.km-offre-actif .km-recommande { color: var(--km-ac); }
.km-offre-actif .km-offre-appel { color: var(--km-ac); }

/* Le bouton de retour en haut ne doit plus recouvrir la mention du pied */
a.position-fixed.btn-primary, #back-to-top { bottom: 1.25rem !important; }
.km-pied-bas { padding-bottom: 4.5rem; }
@media (min-width: 992px) { .km-pied-bas { padding-bottom: 2rem; } }

/* --------------------------------------------------------------------------
   35. Les autres étapes du tunnel — configuration, panier, paiement
   Même grammaire que les cartes : plan à plat, filet d'un pixel, étiquette
   mono, chiffres en monospace, survol qui allume l'ambre.
   -------------------------------------------------------------------------- */
#orderManager { display: flex; flex-direction: column; gap: 1rem; }
#orderManager .accordion-item {
  background: var(--km-plan-a); border: 1px solid var(--km-l1); border-radius: 5px;
  overflow: hidden; transition: border-color var(--km-d-couleur) var(--km-e-couleur);
}
#orderManager .accordion-item:hover { border-color: var(--km-l2); }
#orderManager .accordion-button {
  background: transparent; color: var(--km-t0); box-shadow: none;
  font-size: .9375rem; font-weight: 510; letter-spacing: -.008em;
  padding: 1.125rem 1.375rem; gap: .75rem;
}
#orderManager .accordion-button:not(.collapsed) {
  box-shadow: inset 0 -1px 0 var(--km-l1); color: var(--km-t0);
}
#orderManager .accordion-button .icon { color: var(--km-t2); transition: color var(--km-d-couleur) var(--km-e-couleur); }
#orderManager .accordion-button:not(.collapsed) .icon { color: var(--km-ac); }
#orderManager .accordion-body { padding: 1.5rem 1.375rem; }

/* Le compteur d'étape : une pastille mono, pas un badge de couleur */
#orderManager .badge {
  font-family: var(--km-mono) !important; font-size: .6875rem !important;
  letter-spacing: .1em; color: var(--km-t2) !important; gap: .4375rem;
}
#orderManager .badge::before { background: var(--km-t2); }

/* Panier et paiement : les montants passent en monospace tabulaire */
#orderManager table td, #orderManager table th { border-color: var(--km-l1); }
#orderManager .table > tbody > tr > td:last-child,
#orderManager .cart-total, #orderManager .total, #orderManager .currency {
  font-family: var(--km-mono); font-variant-numeric: tabular-nums;
  font-weight: 500; letter-spacing: -.02em; color: var(--km-t0);
}
#orderManager h4, #orderManager h5 {
  font-family: var(--km-mono); font-size: .6875rem; font-weight: 400;
  letter-spacing: .2em; text-transform: uppercase; color: var(--km-t2);
  margin-bottom: 1rem;
}
/* Les passerelles de paiement : des plans sélectionnables, pas des boutons */
#orderManager .invoice-gateway, .km-cmd-catalogue .invoice-gateway {
  border-radius: 5px; padding: 1rem 1.125rem; background: transparent;
}
#orderManager .invoice-gateway:hover { background: var(--km-plan-b); }
#orderManager .form-control, #orderManager .form-select { background: transparent; }

/* --------------------------------------------------------------------------
   36. Correctifs relevés sur la page de commande
   -------------------------------------------------------------------------- */

/* La lueur d'angle des cartes se voyait comme un rectangle clair sur la
   troisième offre. C'est exactement l'effet décoratif que la direction
   refuse : on le retire partout. */
.km-offre::after, .km-tuile::after { display: none !important; }

/* Les trois cartes font la même hauteur et leur bouton s'aligne */
.km-offres { align-items: stretch; }
.km-offres .km-offre { height: 100%; }

/* La carte sélectionnée ne se décale plus : elle se distingue par la bordure */
.km-offres-cmd .km-offre-vedette,
.km-offres-cmd .km-offre-actif { transform: none; }
.km-offres-cmd .km-offre:hover { transform: translateY(-3px); }

/* Le rappel de la description dans « Configuration du produit » affichait
   les coches du Markdown en clair. On les masque et on remet la liste
   dans la grammaire des cartes. */
#orderManager .accordion-body ul { list-style: none; padding-left: 0; margin: 0; }
#orderManager .accordion-body ul li {
  display: flex; align-items: flex-start; gap: .75rem;
  font-size: .875rem; line-height: 1.3125rem; color: var(--km-t1);
  padding: .375rem 0;
}
#orderManager .accordion-body ul li::before {
  content: ""; flex: none; width: 4px; height: 4px; margin-top: .5rem;
  background: var(--km-ac);
}

/* Le sélecteur « Own domain » redevient un bouton secondaire, pas une pastille */
#orderManager .btn-warning, #orderManager .btn-info {
  background: transparent; border-color: var(--km-l2); color: var(--km-t0);
}
#orderManager .btn-warning:hover, #orderManager .btn-info:hover {
  background: var(--km-plan-b); border-color: var(--km-ac-bord);
}

/* --------------------------------------------------------------------------
   37. « Configuration de l'offre » — remise en ordre
   Le contenu revient au registre du texte : la Sans, en casse normale.
   Le monospace en capitales est réservé aux étiquettes, jamais aux listes.
   -------------------------------------------------------------------------- */
#orderManager .accordion-body ul li,
#orderManager .accordion-body p,
#orderManager .accordion-body label,
#orderManager .accordion-body span:not(.km-etiquette):not(.badge) {
  font-family: var(--km-sans) !important;
  text-transform: none !important;
  letter-spacing: -.008em !important;
}
#orderManager .accordion-body ul { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: .25rem 2rem; }

/* Le bloc du domaine : l'onglet passe au-dessus, le champ prend la largeur */
#orderManager .nav-tabs, #orderManager [role="tablist"] {
  border-bottom: 1px solid var(--km-l1); gap: 0; margin-bottom: 1.5rem;
}
#orderManager .nav-tabs .nav-link, #orderManager [role="tab"] {
  background: transparent !important; border: 0 !important; color: var(--km-t1) !important;
  font-family: var(--km-mono) !important; font-size: .6875rem !important;
  letter-spacing: .16em !important; text-transform: uppercase !important;
  padding: .75rem 1rem .875rem !important; border-radius: 0 !important;
}
#orderManager .nav-tabs .nav-link.active, #orderManager [role="tab"].active,
#orderManager [role="tab"][aria-selected="true"] {
  color: var(--km-ac) !important; box-shadow: inset 0 -1px 0 var(--km-ac);
}
#orderManager .tab-content, #orderManager .tab-pane { padding-left: 0 !important; border-left: 0 !important; }
#orderManager .tab-pane .form-control { max-width: 28rem; }

/* Les blocs de l'étape se séparent par un filet, pas par du vide */
#orderManager .accordion-body > h4,
#orderManager .accordion-body > h5 {
  padding-top: 1.75rem; margin-top: 1.75rem; border-top: 1px solid var(--km-l1);
}
#orderManager .accordion-body > h4:first-child,
#orderManager .accordion-body > h5:first-child { padding-top: 0; margin-top: 0; border-top: 0; }

/* Le sélecteur de cycle : aligné à gauche, monospace pour le montant */
#orderManager select.form-select, #orderManager select.form-control {
  max-width: 28rem; font-family: var(--km-mono); font-variant-numeric: tabular-nums;
}
#orderManager .row > [class*="col-"] { padding-left: 0; }

/* --------------------------------------------------------------------------
   38. Correctifs
   -------------------------------------------------------------------------- */

/* L'anneau de focus ne doit toucher QUE ce qui se manipule. Appliqué à tout,
   il encadrait des conteneurs entiers et recouvrait le texte. */
:focus-visible { outline: none; }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible,
textarea:focus-visible, summary:focus-visible, [tabindex]:not([tabindex="-1"]):focus-visible,
[role="tab"]:focus-visible, [role="button"]:focus-visible {
  outline: 2px solid var(--km-ac);
  outline-offset: 3px;
  border-radius: 3px;
}
#orderManager .tab-pane:focus-visible,
#orderManager .tab-content:focus-visible,
#orderManager .accordion-collapse:focus-visible { outline: none !important; }

/* L'appel à l'action des cartes : c'est un bouton, pas une étiquette.
   Il retrouve la Sans, la casse normale et une taille lisible. */
.km-offre-appel {
  font-family: var(--km-sans); font-size: .9375rem; font-weight: 510;
  letter-spacing: -.006em; text-transform: none; color: var(--km-ac);
  display: inline-flex; align-items: center; gap: .625rem;
  padding-top: 1.25rem; margin-top: auto; border-top: 1px solid var(--km-l1);
  width: 100%;
}
.km-offre-appel::after { width: 20px; }
.km-offre:hover .km-offre-appel::after { width: 34px; }

/* Le sélecteur de domaine : l'onglet au-dessus, en ligne, sans colonne étroite */
#orderManager .nav-tabs, #orderManager [role="tablist"] {
  display: flex; flex-direction: row; width: 100%;
}
#orderManager [role="tab"] { border-bottom: 2px solid transparent !important; }
#orderManager [role="tab"][aria-selected="true"] { border-bottom-color: var(--km-ac) !important; box-shadow: none; }
#orderManager .tab-content { width: 100%; }
#orderManager .row { --bs-gutter-x: 0; }

/* --------------------------------------------------------------------------
   39. LES PAGES PUBLIQUES DU PIED
   Conditions, confidentialité, à propos, contact, guides, annonces.
   Elles ne recevaient que la couche de couleur : le document entier tombait
   dans une carte plate, sans étiquette, sans rythme, sans filet.
   On leur donne la grammaire de l'accueil — une ouverture étiquetée, des
   repères vérifiables, un corps réglé — sans rien changer aux données ni
   aux formulaires. Le sommaire est monté par kardox.js à partir des titres
   du document : il ne peut donc pas se désynchroniser du texte.
   -------------------------------------------------------------------------- */

/* ---------- L'ouverture ---------- */

.km-doc-tete {
  position: relative;
  padding-bottom: 2rem;
  margin-bottom: 4.5rem;
  border-bottom: 1px solid var(--km-l1);
}
.km-doc-tete > .km-etiquette { display: block; margin-bottom: 1.125rem; }
.km-doc-tete h1 { margin: 0; max-width: 22ch; }

.km-doc-phrase {
  max-width: 64ch; margin: 1.25rem 0 0;
  font-size: 1.1875rem; line-height: 1.9rem; letter-spacing: -.012em;
  color: var(--km-t1);
}

/* Les repères : une clé en mesure, une valeur en parole. Jamais décoratifs —
   chacun se vérifie dans le texte de la page. */
.km-doc-reperes {
  display: flex; flex-wrap: wrap; gap: 1.5rem 3rem;
  margin: 2.5rem 0 0; padding: 0; list-style: none;
}
.km-doc-repere { display: flex; flex-direction: column; gap: .3125rem; }
.km-doc-repere-cle {
  font-family: var(--km-mono); font-size: .6875rem; line-height: 1rem;
  letter-spacing: .2em; text-transform: uppercase; color: var(--km-t2);
}
.km-doc-repere-val {
  font-size: .9375rem; line-height: 1.25rem; font-weight: 510;
  letter-spacing: -.008em; color: var(--km-t0);
}

/* ---------- Le corps : sommaire et texte ---------- */

.km-doc-corps {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  gap: 0 4.5rem;
  align-items: start;
}
.km-doc-corps-large { grid-template-columns: minmax(0, 1fr); }
.km-doc-corps-contact { grid-template-columns: minmax(0, 1fr) 320px; gap: 0 4rem; }

/* Le sommaire reste au bord de l'écran pendant la lecture. Tant que le
   JavaScript ne l'a pas rempli, il n'occupe pas de place. */
.km-doc-sommaire:empty { display: none; }
.km-doc-sommaire { position: sticky; top: 1.5rem; }
.km-doc-sommaire > .km-etiquette { display: block; margin-bottom: .875rem; }
.km-doc-sommaire ol {
  margin: 0; padding: 0; list-style: none;
  border-left: 1px solid var(--km-l1);
}
.km-doc-sommaire li { margin: 0; }
.km-doc-sommaire a {
  display: block; margin-left: -1px;
  padding: .4375rem 0 .4375rem 1rem;
  border-left: 1px solid transparent;
  font-size: .8125rem; line-height: 1.3125rem; letter-spacing: -.006em;
  color: var(--km-t2); text-decoration: none;
  transition: color var(--km-d-micro) var(--km-e-micro),
              border-color var(--km-d-micro) var(--km-e-micro);
}
.km-doc-sommaire a:hover {
  color: var(--km-t0); border-left-color: var(--km-l2); text-decoration: none;
}
/* La section lue se marque par un tiret d'ambre dans la gouttière —
   le motif des tableaux, pas une pastille de couleur. */
.km-doc-sommaire a.km-vu-ici { color: var(--km-ac); border-left-color: var(--km-ac); }

.km-doc-texte { max-width: 70ch; color: var(--km-t1); }
.km-doc-texte > *:first-child { margin-top: 0; }

.km-doc-texte h2 {
  margin: 3.5rem 0 1.125rem; padding-top: 1.75rem;
  border-top: 1px solid var(--km-l1);
  font-size: 1.3125rem; line-height: 1.32; letter-spacing: -.016em;
  font-weight: 590; color: var(--km-t0);
  scroll-margin-top: 1.5rem;
}
.km-doc-texte h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.km-doc-texte h3 {
  margin: 2rem 0 .75rem; font-size: 1.0625rem; line-height: 1.5rem;
  font-weight: 510; letter-spacing: -.012em; color: var(--km-t0);
  scroll-margin-top: 1.5rem;
}
.km-doc-texte p { margin: 0 0 1.0625rem; max-width: 68ch; }
.km-doc-texte p:last-child { margin-bottom: 0; }
.km-doc-texte strong { color: var(--km-t0); font-weight: 510; }

/* Le chapeau : quand le document s'ouvre sur une phrase et non sur un titre,
   elle se détache par un filet, comme une citation de bas de page. */
.km-doc-texte > p:first-child {
  padding-left: 1.25rem; border-left: 1px solid var(--km-ac-bord);
  font-size: 1.0625rem; line-height: 1.8125rem; color: var(--km-t1);
  margin-bottom: 2rem;
}

.km-doc-texte ul { margin: 0 0 1.0625rem; padding: 0; list-style: none; }
.km-doc-texte ul > li { position: relative; padding-left: 1.125rem; margin-bottom: .5rem; }
/* Le marqueur carré de 4 px, celui des caractéristiques d'offre. */
.km-doc-texte ul > li::before {
  content: ""; position: absolute; left: 0; top: .6875rem;
  width: 4px; height: 4px; background: var(--km-ac);
}
.km-doc-texte ol { margin: 0 0 1.0625rem; padding-left: 1.375rem; }
.km-doc-texte ol > li { margin-bottom: .5rem; }
.km-doc-texte ol > li::marker {
  font-family: var(--km-mono); font-size: .8125rem; color: var(--km-t2);
}

.km-doc-texte a {
  color: var(--km-ac); text-decoration: none;
  border-bottom: 1px solid var(--km-ac-bord);
  transition: color var(--km-d-micro) var(--km-e-micro),
              border-color var(--km-d-micro) var(--km-e-micro);
}
.km-doc-texte a:hover {
  color: var(--km-ac-h); border-bottom-color: var(--km-ac); text-decoration: none;
}

/* Le tableau des finalités : le langage des tableaux de l'espace client —
   filets horizontaux, en-tête en mesure, aucun fond coloré. */
.km-doc-texte table {
  width: 100%; margin: 1.5rem 0; border-collapse: collapse; font-size: .9375rem;
}
.km-doc-texte thead th {
  padding: 0 1.5rem .75rem 0; text-align: left;
  border-bottom: 1px solid var(--km-l2);
  font-family: var(--km-mono); font-size: .6875rem; font-weight: 400;
  letter-spacing: .2em; text-transform: uppercase; color: var(--km-t2);
}
.km-doc-texte tbody td {
  padding: .8125rem 1.5rem .8125rem 0; vertical-align: top;
  border-bottom: 1px solid var(--km-l1); color: var(--km-t1);
  line-height: 1.5rem;
}
.km-doc-texte tbody td:first-child { color: var(--km-t0); }
.km-doc-texte tbody tr:last-child td { border-bottom: 0; }
.km-doc-texte th:last-child, .km-doc-texte td:last-child { padding-right: 0; }

.km-doc-texte blockquote {
  margin: 1.5rem 0; padding-left: 1.25rem;
  border-left: 1px solid var(--km-l2); color: var(--km-t2);
}
.km-doc-texte code {
  font-family: var(--km-mono); font-size: .875em;
  color: var(--km-t0); background: var(--km-plan-b);
  padding: .125rem .375rem; border-radius: 3px;
}

/* ---------- Le pied de document ---------- */

.km-doc-pied {
  margin-top: 4.5rem; padding-top: 1.75rem;
  border-top: 1px solid var(--km-l1);
}
.km-doc-pied-phrase {
  max-width: 62ch; margin: 0 0 .875rem;
  font-size: .9375rem; line-height: 1.5rem; color: var(--km-t1);
}
.km-doc-pied-liens {
  display: flex; flex-wrap: wrap; align-items: center; gap: .625rem;
  margin: 0; font-size: .9375rem;
}
.km-doc-pied-sep { color: var(--km-t2); }

.km-vide-titre {
  font-size: 1.0625rem; font-weight: 510; letter-spacing: -.012em;
  color: var(--km-t0) !important;
}

/* ---------- La page de contact ---------- */

.km-contact-paire { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1.5rem; }
.km-contact-envoi {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; margin-top: 1.5rem;
}
.km-contact-note { font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2); }

.km-contact-cote { display: flex; flex-direction: column; gap: 2rem; }
.km-contact-bloc {
  padding: 1.5rem; border: 1px solid var(--km-l1); border-radius: 5px;
  background: var(--km-plan-a);
}
.km-contact-bloc > .km-etiquette { display: block; margin-bottom: .875rem; }
.km-contact-adresse {
  display: flex; flex-direction: column; gap: .1875rem;
  margin: 0; font-style: normal; font-size: .9375rem; line-height: 1.4375rem;
  color: var(--km-t1);
}
.km-contact-nom { color: var(--km-t0); font-weight: 510; }
.km-contact-liens { margin: .875rem 0 0; font-size: .9375rem; }
.km-contact-liens-colonne { display: flex; flex-direction: column; gap: .5rem; }
.km-contact-liste { margin: 0; padding: 0; list-style: none; }
.km-contact-liste li {
  position: relative; padding-left: 1.125rem; margin-bottom: .625rem;
  font-size: .875rem; line-height: 1.375rem; color: var(--km-t1);
}
.km-contact-liste li::before {
  content: ""; position: absolute; left: 0; top: .625rem;
  width: 4px; height: 4px; background: var(--km-ac);
}
.km-contact-liste li:last-child { margin-bottom: 0; }

/* ---------- La base de connaissances ---------- */

.km-kb-recherche { margin-bottom: 3rem; }
.km-kb-recherche .km-etiquette { display: block; margin-bottom: .75rem; }
.km-kb-champ { display: flex; gap: .75rem; max-width: 34rem; }
.km-kb-champ .form-control { flex: 1 1 auto; }

.km-kb-categories {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(17.5rem, 1fr));
  gap: 2rem; margin-top: 2rem;
}
/* La carte reprend « km-offre » : même plan, même filet de safran au survol.
   Ici on ne pose que les écarts. */
.km-kb-carte { gap: .875rem; }
.km-kb-carte-titre {
  font-size: 1.25rem; line-height: 1.75rem; letter-spacing: -.014em; font-weight: 590;
}
.km-kb-carte-desc { font-size: .875rem; line-height: 1.375rem; color: var(--km-t1); }
.km-kb-carte-liste {
  display: flex; flex-direction: column; gap: .5rem;
  margin: 0; padding-top: 1.25rem; list-style: none;
  border-top: 1px solid var(--km-l1);
}
.km-kb-carte-liste li {
  position: relative; padding-left: 1.125rem;
  font-size: .875rem; line-height: 1.3125rem; color: var(--km-t1);
}
.km-kb-carte-liste li::before {
  content: ""; position: absolute; left: 0; top: .5625rem;
  width: 4px; height: 4px; background: var(--km-ac);
}
.km-kb-carte-appel {
  margin-top: auto; padding-top: 1.25rem;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--km-ac);
  display: inline-flex; align-items: center; gap: .5rem;
}
.km-kb-carte-appel::after {
  content: ""; width: 18px; height: 1px; background: var(--km-ac);
  transition: width var(--km-d-elev) var(--km-e-sortie);
}
.km-kb-carte:hover .km-kb-carte-appel::after { width: 30px; }

.km-kb-trouves, .km-kb-voisins { margin-top: 3.5rem; }
.km-kb-liste { margin: 1.5rem 0 0; padding: 0; list-style: none; }
.km-kb-liste-large { margin-top: 0; }
.km-kb-ligne {
  display: flex; align-items: baseline; gap: 1.5rem;
  padding: 1.0625rem .25rem 1.0625rem 0;
  border-bottom: 1px solid var(--km-l1);
  color: var(--km-t0); text-decoration: none;
  transition: color var(--km-d-micro) var(--km-e-micro),
              padding-left var(--km-d-micro) var(--km-e-micro);
}
/* Le tiret d'ambre glisse dans la gouttière, comme sur les lignes de tableau. */
.km-kb-ligne::before {
  content: ""; width: 0; height: 1px; background: var(--km-ac); flex: none;
  transition: width var(--km-d-micro) var(--km-e-micro);
}
.km-kb-ligne:hover { color: var(--km-ac); text-decoration: none; }
.km-kb-ligne:hover::before { width: 14px; }
.km-kb-ligne-titre { font-size: 1rem; line-height: 1.5rem; letter-spacing: -.01em; }
.km-kb-ligne-cat {
  margin-left: auto; font-family: var(--km-mono); font-size: .6875rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--km-t2);
}
.km-kb-ligne-fleche { margin-left: auto; color: var(--km-t2); }
.km-kb-ligne:hover .km-kb-ligne-fleche { color: var(--km-ac); }

/* ---------- Les annonces ---------- */

.km-actus { margin: 0; padding: 0; list-style: none; }
.km-actu {
  padding: 2rem 0; border-bottom: 1px solid var(--km-l1);
}
.km-actu:first-child { padding-top: 0; }
.km-actu:last-child { border-bottom: 0; }
.km-actu-date {
  display: block; margin-bottom: .625rem;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--km-t2);
}
.km-actu-titre { margin: 0 0 .75rem; font-size: 1.3125rem; line-height: 1.32; letter-spacing: -.016em; }
.km-actu-titre a { color: var(--km-t0); text-decoration: none; }
.km-actu-titre a:hover { color: var(--km-ac); text-decoration: none; }
.km-actu-extrait { max-width: 68ch; font-size: .9375rem; line-height: 1.5rem; }
.km-actu-extrait p:last-child { margin-bottom: 0; }
.km-actu-appel {
  display: inline-flex; align-items: center; gap: .5rem; margin-top: .875rem;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--km-ac); text-decoration: none;
}
.km-actu-appel::after {
  content: ""; width: 18px; height: 1px; background: var(--km-ac);
  transition: width var(--km-d-elev) var(--km-e-sortie);
}
.km-actu-appel:hover { text-decoration: none; }
.km-actu-appel:hover::after { width: 30px; }
.km-actu-image { max-width: 100%; height: auto; border-radius: 5px; margin-bottom: 1.5rem; }

/* ---------- Les tailles d'écran ---------- */

@media (max-width: 992px) {
  .km-doc-corps, .km-doc-corps-contact { grid-template-columns: minmax(0, 1fr); gap: 0; }
  /* Le sommaire passe devant le texte et cesse de coller. */
  .km-doc-sommaire {
    position: static; margin-bottom: 2.5rem;
    padding-bottom: 2rem; border-bottom: 1px solid var(--km-l1);
  }
  .km-contact-cote { margin-top: 3rem; }
  .km-doc-texte, .km-doc-phrase { max-width: none; }
}

@media (max-width: 576px) {
  .km-doc-tete { margin-bottom: 3rem; }
  .km-doc-reperes { gap: 1.25rem 2rem; }
  .km-contact-paire { grid-template-columns: minmax(0, 1fr); }
  .km-kb-champ { flex-direction: column; max-width: none; }
  .km-kb-ligne { flex-wrap: wrap; gap: .375rem 1rem; }
  .km-kb-ligne-cat, .km-kb-ligne-fleche { margin-left: 0; }
  /* Le tableau des finalités déborde plutôt que d'écraser ses colonnes. */
  .km-doc-texte table { display: block; overflow-x: auto; }
  .km-doc-texte h2 { margin-top: 2.5rem; }
}

/* La mise en scène ne s'impose à personne. */
@media (prefers-reduced-motion: reduce) {
  .km-doc-sommaire a, .km-kb-ligne, .km-kb-ligne::before,
  .km-kb-carte-appel::after, .km-actu-appel::after, .km-doc-texte a {
    transition: none;
  }
}

/* Le bouton « Haut » est fixé en bas à droite de la fenêtre : mesuré, il
   occupe 62 px de haut (46 de bouton + 16 de marge) et vient donc recouvrir
   la fin de la ligne de mentions, que « margin-left: auto » pousse justement
   à droite. On dégage la hauteur nécessaire sous la barre plutôt que de
   déplacer le bouton, qui appartient au cœur. */
.km-pied-bas { padding-bottom: 5rem; }

/* --------------------------------------------------------------------------
   40. LES CHAMPS, L'ÉDITEUR ET L'AFFORDANCE DES LIENS
   Trois reproches mesurés, trois réponses.

   1. LES CHAMPS. Ils étaient réduits à un soulignement : « border: 0 ;
      border-bottom: 1px ; background: transparent ; min-height: 46px ».
      Mesuré sur la page de contact : l'étiquette flotte 8 px au-dessus d'une
      boîte de 47 px entièrement vide, et le filet arrive tout en bas. L'œil ne
      lit pas un champ, il lit un blanc suivi d'un trait. On rend donc au champ
      un corps — un plan, un filet d'un pixel, un rayon de 5 px — exactement la
      grammaire des cartes. Rien d'autre ne change : ni les noms, ni les
      identifiants, ni le comportement.

   2. L'ÉDITEUR RICHE. CKEditor arrivait sans habillage : barre d'outils
      #FFFFFF et bordures #333 posées sur l'ardoise, l'élément le plus violent
      de la page. On redéfinit ses propres variables « --ck-* » plutôt que
      d'empiler les !important : il suit alors les deux variantes tout seul.

   3. LES LIENS. Rien ne les distinguait du texte courant. On pose trois
      registres — prose, navigation, action — chacun avec un second signal en
      plus de la couleur, comme l'exige le critère WCAG 1.4.1.
   -------------------------------------------------------------------------- */

/* ---------- 40.1 Les champs ---------- */

.form-control, .form-select, textarea.form-control, .ts-control {
  background-color: var(--km-plan-a);
  color: var(--km-t0);
  border: 1px solid var(--km-l1);
  border-bottom: 1px solid var(--km-l1);
  border-radius: 5px;
  min-height: 46px;
  padding: .6875rem .875rem;
  box-shadow: none;
  transition: background-color var(--km-d-micro) var(--km-e-micro),
              border-color var(--km-d-micro) var(--km-e-micro);
}
textarea.form-control { min-height: 8rem; line-height: 1.625rem; }

.form-control:hover:not(:focus), .form-select:hover:not(:focus),
.ts-wrapper:not(.focus):hover .ts-control {
  border-color: var(--km-l2);
  background-color: var(--km-plan-b);
}

/* Le focus : le filet passe à l'accent et se double d'un anneau d'un pixel.
   Pas de lueur — un anneau franc, comme le reste de la maison. */
.form-control:focus, .form-select:focus, .ts-wrapper.focus .ts-control {
  background-color: var(--km-plan-b);
  color: var(--km-t0);
  border-color: var(--km-ac);
  box-shadow: 0 0 0 1px var(--km-ac);
  outline: none;
}
.form-control:disabled, .form-control[readonly], .form-select:disabled {
  background-color: transparent; color: var(--km-t2);
  border-style: dashed; cursor: not-allowed;
}
.form-control.is-invalid, .was-validated .form-control:invalid {
  border-color: var(--km-ko); box-shadow: 0 0 0 1px var(--km-ko); background-image: none;
}
.form-control.is-valid, .was-validated .form-control:valid {
  border-color: var(--km-ok); box-shadow: none; background-image: none;
}

/* L'étiquette se rapproche : 8 px d'écart pour un champ qui a maintenant un
   corps, c'est juste. On marque en revanche le champ obligatoire. */
.form-label { display: block; margin-bottom: .5rem; }
.form-label .km-requis, .form-label abbr[title] {
  color: var(--km-ac); text-decoration: none; border: 0;
}

/* Le rythme vertical d'un formulaire : des multiples de 4, jamais autre chose. */
.km-contact-formulaire .mb-3, form .mb-3 { margin-bottom: 1.5rem !important; }
.km-contact-paire { gap: 0 1.5rem; }

.form-select {
  padding-right: 2.5rem;
  background-position: right .875rem center;
}
.input-group .form-control { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.input-group .btn { border-top-left-radius: 0; border-bottom-left-radius: 0; }

/* TomSelect : même corps, même filet, et sa liste devient un plan de la maison. */
.ts-wrapper .ts-control { display: flex; align-items: center; }
.ts-dropdown {
  background: var(--km-plan-b); border: 1px solid var(--km-l1);
  border-radius: 5px; box-shadow: var(--km-ombre-2); margin-top: .375rem;
}
.ts-dropdown .option { padding: .625rem .875rem; color: var(--km-t1); }
.ts-dropdown .option:hover, .ts-dropdown .active { background: var(--km-plan-c); color: var(--km-t0); }

/* ---------- 40.2 CKEditor 5 ---------- */

.ck.ck-editor, .ck.ck-reset, .ck-content {
  --ck-border-radius: 5px;
  --ck-color-base-background: var(--km-plan-a);
  --ck-color-base-foreground: var(--km-plan-b);
  --ck-color-base-border: var(--km-l1);
  --ck-color-base-text: var(--km-t0);
  --ck-color-base-active: var(--km-ac);
  --ck-color-base-active-focus: var(--km-ac);
  --ck-color-text: var(--km-t0);
  --ck-color-shadow-drop: transparent;
  --ck-color-shadow-inner: transparent;
  --ck-color-toolbar-background: var(--km-plan-b);
  --ck-color-toolbar-border: var(--km-l1);
  --ck-color-button-default-background: transparent;
  --ck-color-button-default-hover-background: var(--km-plan-c);
  --ck-color-button-default-active-background: var(--km-plan-c);
  --ck-color-button-on-background: var(--km-ac-voile2);
  --ck-color-button-on-hover-background: var(--km-ac-voile2);
  --ck-color-button-on-color: var(--km-ac);
  --ck-color-button-on-active-background: var(--km-ac-voile2);
  --ck-color-dropdown-panel-background: var(--km-plan-b);
  --ck-color-dropdown-panel-border: var(--km-l1);
  --ck-color-list-background: var(--km-plan-b);
  --ck-color-list-button-hover-background: var(--km-plan-c);
  --ck-color-list-button-on-background: var(--km-ac-voile2);
  --ck-color-list-button-on-text: var(--km-ac);
  --ck-color-panel-background: var(--km-plan-b);
  --ck-color-panel-border: var(--km-l1);
  --ck-color-input-background: var(--km-plan-a);
  --ck-color-input-border: var(--km-l1);
  --ck-color-input-text: var(--km-t0);
  --ck-color-labeled-field-label-background: var(--km-plan-a);
  --ck-color-split-button-hover-background: var(--km-plan-c);
  --ck-color-split-button-hover-border: var(--km-l2);
  --ck-focus-ring: 1px solid var(--km-ac);
  --ck-focus-outer-shadow: 0 0 0 1px var(--km-ac);
  --ck-inner-shadow: none;
  --ck-drop-shadow: none;
}
.ck.ck-editor__main > .ck-editor__editable {
  background: var(--km-plan-a);
  border-color: var(--km-l1);
  color: var(--km-t0);
  font-family: var(--km-sans);
  font-size: .9375rem;
  line-height: 1.625rem;
  min-height: 9rem;
  padding: .875rem;
}
.ck.ck-editor__main > .ck-editor__editable.ck-focused {
  border-color: var(--km-ac);
  box-shadow: 0 0 0 1px var(--km-ac);
}
.ck.ck-toolbar {
  background: var(--km-plan-b);
  border-color: var(--km-l1);
  border-top-left-radius: 5px; border-top-right-radius: 5px;
  padding: .375rem;
}
.ck.ck-toolbar .ck-toolbar__separator { background: var(--km-l1); }
.ck.ck-button, .ck.ck-button.ck-off { color: var(--km-t1); }
.ck.ck-button:not(.ck-disabled):hover { color: var(--km-t0); }
.ck.ck-button.ck-on { color: var(--km-ac); }
.ck.ck-icon, .ck.ck-icon * { color: inherit; fill: currentColor; }
.ck.ck-dropdown__panel, .ck.ck-list, .ck.ck-balloon-panel {
  background: var(--km-plan-b); border-color: var(--km-l1); box-shadow: var(--km-ombre-2);
}
.ck.ck-list__item .ck-button { color: var(--km-t1); }
.ck.ck-list__item .ck-button:hover { color: var(--km-t0); }
.ck.ck-editor__editable a { color: var(--km-ac); }
.ck.ck-placeholder::before, .ck .ck-placeholder::before { color: var(--km-t2); }

/* ---------- 40.3 Les trois registres du lien ---------- */

/* Registre 1 — le lien de prose. Il vit dans une phrase : il prend l'accent
   ET un filet sous le texte, pour ne pas reposer sur la seule couleur. */
.km-doc-texte a:not(.btn),
.km-prose a:not(.btn),
.km-actu-extrait a:not(.btn) {
  color: var(--km-ac);
  text-decoration: none;
  border-bottom: 1px solid var(--km-ac-bord);
  transition: color var(--km-d-micro) var(--km-e-micro),
              border-color var(--km-d-micro) var(--km-e-micro);
}
.km-doc-texte a:not(.btn):hover,
.km-prose a:not(.btn):hover {
  color: var(--km-ac-h); border-bottom-color: var(--km-ac); text-decoration: none;
}

/* Registre 2 — le lien de navigation : listes du pied, blocs latéraux,
   sommaire, appels de carte. Il reste en couleur de texte pour ne pas
   piquer la page, mais porte un tiret d'accent dans la gouttière — le motif
   des tableaux — qui se déploie au survol. Le second signal est là. */
.km-pied-col a,
.km-pied-contact a,
.km-contact-liens a,
.km-doc-pied-liens a {
  position: relative;
  display: inline-flex; align-items: baseline; gap: .5rem;
  color: var(--km-t1);
  text-decoration: none;
  transition: color var(--km-d-micro) var(--km-e-micro);
}
.km-pied-col a::before,
.km-pied-contact a::before,
.km-contact-liens a::before,
.km-doc-pied-liens a::before {
  content: ""; flex: none; align-self: center;
  width: 6px; height: 1px; background: var(--km-l2);
  transition: width var(--km-d-micro) var(--km-e-micro),
              background-color var(--km-d-micro) var(--km-e-micro);
}
.km-pied-col a:hover,
.km-pied-contact a:hover,
.km-contact-liens a:hover,
.km-doc-pied-liens a:hover {
  color: var(--km-ac); text-decoration: none;
}
.km-pied-col a:hover::before,
.km-pied-contact a:hover::before,
.km-contact-liens a:hover::before,
.km-doc-pied-liens a:hover::before {
  width: 14px; background: var(--km-ac);
}

/* Registre 3 — le lien d'action : déjà traité par « .km-offre-appel »,
   « .km-actu-appel » et « .km-kb-carte-appel ». On aligne seulement le
   séparateur du pied de document, qui ne doit pas hériter du tiret. */
.km-doc-pied-sep::before { content: none; }
.km-doc-pied-liens { gap: .25rem 1.25rem; }

@media (prefers-reduced-motion: reduce) {
  .form-control, .form-select, .ts-control,
  .km-doc-texte a, .km-prose a, .km-pied-col a, .km-pied-col a::before,
  .km-contact-liens a, .km-contact-liens a::before,
  .km-doc-pied-liens a, .km-doc-pied-liens a::before { transition: none; }
}

/* --------------------------------------------------------------------------
   41. LES ICÔNES
   Trait d'un pixel, couleur héritée : une icône posée dans un bloc prend la
   couleur de ce bloc et suit les deux variantes sans règle supplémentaire.
   Le trait ne s'épaissit jamais avec la taille — « non-scaling-stroke ».
   -------------------------------------------------------------------------- */

.km-icone {
  width: 20px; height: 20px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1;
  stroke-linecap: square; stroke-linejoin: miter;
  vector-effect: non-scaling-stroke;
  display: inline-block; vertical-align: -.2em;
}
.km-icone-petite { width: 16px; height: 16px; }
.km-icone-grande { width: 28px; height: 28px; }

/* Posée devant une étiquette, l'icône se cale sur la ligne de mesure. */
.km-etiquette .km-icone { vertical-align: -.25em; margin-right: .5rem; }
.km-bloc-tete { display: flex; align-items: center; gap: .625rem; margin-bottom: .875rem; }
.km-bloc-tete .km-etiquette { margin: 0; }
.km-bloc-tete .km-icone { color: var(--km-ac); }

/* Dans les cartes de guide, l'icône marque la catégorie sans la surcharger. */
.km-kb-carte .km-icone { color: var(--km-ac); margin-bottom: .25rem; }

/* --------------------------------------------------------------------------
   42. LES MOTIFS DESSINÉS
   Trois figures au trait, définies dans « macro_motifs.html.twig ». Elles
   rompent la prose des pages de document sans rien décorer : chacune dit
   quelque chose de vrai — une graduation, un enchaînement, une durée.
   Le tracé se dévoile quand un ancêtre reçoit « km-vu », que kardox.js pose
   déjà. Sans script ou en mouvement réduit, tout est visible d'emblée : un
   tracé ne peut jamais rester à moitié dessiné.
   -------------------------------------------------------------------------- */

.km-icone-md { width: 24px; height: 24px; }
.km-icone-ac { color: var(--km-ac); }

/* ---- La règle graduée ---- */
.km-regle { margin: 3rem 0; }
.km-regle-svg { display: block; width: 100%; height: 24px; overflow: visible; }
.km-regle-svg line { stroke: var(--km-l1); stroke-width: 1; }
.km-regle-base { stroke: var(--km-l2) !important; }
.km-regle-cran-haut { stroke: var(--km-l2) !important; }
.km-regle-ac { stroke: var(--km-ac) !important; }
.km-js .km-regle-svg line { transform: scaleX(0); transform-origin: left center; }
.km-js .km-vu .km-regle-svg line,
.km-js .km-regle.km-vu line { transform: scaleX(1); transition: transform 900ms var(--km-e-entree); }

/* ---- Le flux en trois temps ---- */
.km-flux {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 2rem; margin: 3rem 0; padding: 0; list-style: none;
}
.km-flux-etape {
  position: relative;
  display: flex; flex-direction: column; gap: .5rem;
  padding: 1.25rem 1.25rem 1.375rem;
  border: 1px solid var(--km-l1); border-radius: 5px;
  background: var(--km-plan-a);
}
.km-flux-etape .km-etiquette { color: var(--km-t2); }
.km-flux-icone { margin: .25rem 0 .125rem; }
.km-flux-titre {
  margin: 0; font-size: 1rem; line-height: 1.5rem; font-weight: 510;
  letter-spacing: -.01em; color: var(--km-t0); max-width: none;
}
.km-flux-note {
  margin: 0; font-size: .875rem; line-height: 1.375rem; color: var(--km-t1); max-width: none;
}
.km-flux-mesure {
  margin-top: auto; padding-top: .5rem;
  font-family: var(--km-mono); font-size: .75rem; color: var(--km-ac);
}
/* Le lien entre deux étapes : une flèche au trait, dans la gouttière. */
.km-flux-lien {
  position: absolute; right: -2rem; top: 50%; width: 2rem; height: 24px;
  transform: translateY(-50%); overflow: visible;
  fill: none; stroke: var(--km-l2); stroke-width: 1;
}
.km-flux-etape:last-child .km-flux-lien { display: none; }
@media (max-width: 767px) { .km-flux-lien { display: none; } }

/* ---- La frise des trente-six mois ---- */
.km-frise { margin: 3rem 0; }
.km-frise-tete { margin-bottom: .875rem; }
.km-frise-svg { display: block; width: 100%; height: 56px; overflow: visible; }
.km-frise-svg line { stroke: var(--km-l1); stroke-width: 1; }
.km-frise-ligne { stroke: var(--km-ac) !important; }
.km-frise-socle { stroke: var(--km-l2) !important; }
.km-frise-cran-haut { stroke: var(--km-l2) !important; }
.km-frise-legende {
  display: flex; justify-content: space-between; margin: .5rem 0 0;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--km-t2); max-width: none;
}
.km-js .km-frise-ligne { stroke-dasharray: 720; stroke-dashoffset: 720; }
.km-js .km-vu .km-frise-ligne,
.km-js .km-frise.km-vu .km-frise-ligne {
  stroke-dashoffset: 0; transition: stroke-dashoffset 1400ms var(--km-e-entree);
}

/* Rien ne se dessine pour qui a demandé moins de mouvement : tout est là. */
@media (prefers-reduced-motion: reduce) {
  .km-js .km-regle-svg line { transform: none; transition: none; }
  .km-js .km-frise-ligne { stroke-dasharray: none; stroke-dashoffset: 0; transition: none; }
}

/* --------------------------------------------------------------------------
   43. CORRECTIFS D'ACCESSIBILITÉ SUR LES COMMANDES
   Relevés au navigateur après la section 40, sur la page de contact.

   1. LE BORD DU CHAMP ÉTAIT INVISIBLE. Mesuré : « --km-l1 » aplati sur le plan
      du champ donne 1,26:1 en ardoise et 1,25:1 sur papier. Le plan seul ne
      rattrape rien — il ne se détache du fond que de 1,06:1. La WCAG 1.4.11
      demande 3:1 pour la limite visible d'une commande de saisie : sans cela,
      une vision basse ne trouve pas où écrire. On passe donc au jeton --km-l3.
      Le filet d'un pixel reste : c'est sa couleur qui change, pas la grammaire.

   2. LA COCHE ÉTAIT BLANCHE SUR SAFRAN. Bootstrap peint le glyphe des cases et
      des boutons radio en #FFFFFF : 2,00:1 sur notre accent. On le reprend en
      « --km-ac-txt » — 9,29:1 en ardoise, et la case redevient lisible.
      Le glyphe est une image de données : sa couleur ne peut pas être un jeton,
      c'est la seule raison pour laquelle cette règle est écrite deux fois.

   3. L'INTERRUPTEUR VIRAIT AU BLEU BOOTSTRAP au premier focus clavier.

   4. DES CIBLES PASSAIENT SOUS 44 px : champs « -sm », lignes de liste
      déroulante, champs internes de l'éditeur.
   -------------------------------------------------------------------------- */

.form-control, .form-select, textarea.form-control,
.ts-wrapper.form-select, .ts-wrapper.form-control {
  border-color: var(--km-l3);
}
.form-control:hover:not(:focus), .form-select:hover:not(:focus),
.ts-wrapper.form-select:not(.focus):hover { border-color: var(--km-t2); }

/* L'enveloppe de TomSelect porte la classe du select : c'est elle qui dessine
   le bord, la commande intérieure étant mise à « border: none !important » par
   la feuille du composant. On aligne donc les deux hauteurs. */
.ts-wrapper.form-select { padding: 0; min-height: 46px; display: flex; align-items: stretch; }
.ts-wrapper.form-select .ts-control { min-height: 44px; border-radius: 5px; }

/* Cases, boutons radio, interrupteurs */
.form-check { min-height: 1.5rem; padding-left: 2rem; }
.form-check-input {
  width: 1.25rem; height: 1.25rem; margin-left: -2rem; margin-top: .125rem;
  background-color: var(--km-plan-a);
  border: 1px solid var(--km-l3);
  border-radius: 3px;
  transition: background-color var(--km-d-micro) var(--km-e-micro),
              border-color var(--km-d-micro) var(--km-e-micro);
}
.form-check-input[type="radio"] { border-radius: 50%; }
.form-check-input:checked { background-color: var(--km-ac); border-color: var(--km-ac); }
.form-check-input:focus {
  border-color: var(--km-ac); box-shadow: 0 0 0 1px var(--km-ac); outline: none;
}
.form-check-input:disabled { opacity: 1; background-color: transparent; border-style: dashed; }
.form-check-input:disabled ~ .form-check-label { color: var(--km-t2); opacity: 1; }
.form-check-label { line-height: 1.5rem; }

/* Le glyphe : ardoise sur safran en mode sombre, blanc sur sienne en clair. */
[data-bs-theme='dark'] .form-check-input:checked[type=checkbox] {
  --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%230E1418' stroke-linecap='square' stroke-width='2.5' d='m6 10 3 3 6-6'/%3e%3c/svg%3e");
}
[data-bs-theme='dark'] .form-check-input:checked[type=radio] {
  --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%230E1418'/%3e%3c/svg%3e");
}
[data-bs-theme='light'] .form-check-input:checked[type=checkbox],
:root:not([data-bs-theme]) .form-check-input:checked[type=checkbox] {
  --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='square' stroke-width='2.5' d='m6 10 3 3 6-6'/%3e%3c/svg%3e");
}
[data-bs-theme='light'] .form-check-input:checked[type=radio],
:root:not([data-bs-theme]) .form-check-input:checked[type=radio] {
  --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23ffffff'/%3e%3c/svg%3e");
}

/* L'interrupteur : son bouton suit nos jetons, jamais le bleu de Bootstrap. */
.form-switch .form-check-input {
  width: 2.25rem; border-radius: 1rem; margin-left: -2.75rem;
  --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%236A7781'/%3e%3c/svg%3e");
}
.form-switch { padding-left: 2.75rem; }
.form-switch .form-check-input:focus { --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%236A7781'/%3e%3c/svg%3e"); }
[data-bs-theme='dark'] .form-switch .form-check-input:checked {
  --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%230E1418'/%3e%3c/svg%3e");
}
[data-bs-theme='light'] .form-switch .form-check-input:checked,
:root:not([data-bs-theme]) .form-switch .form-check-input:checked {
  --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23ffffff'/%3e%3c/svg%3e");
}

/* Aucune cible manipulable sous 44 px : un champ plat n'oblige pas à être bas. */
.form-control-sm, .form-select-sm { min-height: 44px; padding: .5rem .75rem; font-size: .875rem; }
.ts-dropdown .option, .ts-dropdown .dropdown-item { min-height: 44px; display: flex; align-items: center; }
.ck.ck-input, .ck.ck-input-text { min-height: 44px; }

/* ==== lot : ? ==== */
/* --------------------------------------------------------------------------
   44. LE PROFIL ET LE COMPTE — un écran de réglages, rangé par sujets
   Le gabarit du cœur enfermait quatre sujets dans quatre onglets Bootstrap :
   trois d'entre eux étaient invisibles, absents de l'impression, et hors de
   portée d'une recherche dans la page. On les déplie en quatre plans empilés,
   chacun avec son étiquette, son icône et son titre. Rien d'autre ne bouge :
   mêmes formulaires, mêmes actions, mêmes identifiants — ceux des panneaux
   deviennent des ancres, ceux des onglets restent portés par le sommaire.

   Deux écarts assumés à la grammaire, tous deux raisonnés :
   — le filet de safran de l'arête haute ne s'allume PAS au survol du plan.
     Un panneau de réglages fait toute la largeur : l'allumer quand la souris
     le traverse ne dit rien. Il s'allume quand on y travaille — « :target »
     après un clic dans le sommaire, « :focus-within » dès qu'un champ prend
     le foyer. Le signal reste le même, il devient vrai.
   — aucune élévation au survol : rien ici ne se clique en entier.
   -------------------------------------------------------------------------- */

/* ---------- 42.1 Le sommaire des sujets ---------- */

.km-reglages-sommaire {
  display: flex; flex-wrap: wrap; gap: .625rem;
  margin: 0 0 2.5rem;
}
.km-reglages-sommaire a {
  display: inline-flex; align-items: center; gap: .625rem;
  min-height: 46px; padding: .625rem 1.125rem;
  border: 1px solid var(--km-l1); border-radius: 5px;
  background: var(--km-plan-a);
  color: var(--km-t1); font-size: .875rem; letter-spacing: -.006em;
  text-decoration: none;
  transition: background-color var(--km-d-couleur) var(--km-e-couleur),
              border-color var(--km-d-couleur) var(--km-e-couleur),
              color var(--km-d-couleur) var(--km-e-couleur);
}
.km-reglages-sommaire a:hover {
  background: var(--km-plan-b); border-color: var(--km-ac-bord);
  color: var(--km-t0); text-decoration: none;
}
.km-reglages-sommaire .km-icone { color: var(--km-t2); transition: color var(--km-d-couleur) var(--km-e-couleur); }
.km-reglages-sommaire a:hover .km-icone { color: var(--km-ac); }

/* Dans le cartouche, un état se dit par un point suivi d'un libellé, jamais
   par une pastille. On lui rend la hauteur de ligne d'une valeur chiffrée
   pour que les quatre cases restent d'aplomb. */
.km-cartouche .km-statut { min-height: 1.6rem; }

/* ---------- 42.2 Le plan d'un sujet ---------- */

/* Pas de « overflow: hidden » ici, contrairement aux tuiles : la liste des
   pays de « intl-tel-input » se déploie en position absolue sous le champ de
   téléphone et serait tranchée par le bas du plan. */
.km-reglage {
  position: relative;
  margin: 0 0 1.5rem; padding: 1.75rem;
  border: 1px solid var(--km-l1); border-radius: 5px;
  background: var(--km-plan-a);
  scroll-margin-top: 1.5rem;
}
.km-reglage::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: var(--km-ac); transform: scaleX(0); transform-origin: left;
  transition: transform 460ms var(--km-e-entree);
}
.km-reglage:target::before, .km-reglage:focus-within::before { transform: scaleX(1); }
/* Le panneau ne reçoit le foyer que comme cible d'ancre : l'anneau se pose à
   l'intérieur du filet pour ne jamais déborder de la colonne. */
.km-reglage:focus-visible { outline-offset: -2px; }

.km-reglage-tete {
  padding-bottom: 1.5rem; margin-bottom: 1.75rem;
  border-bottom: 1px solid var(--km-l1);
}
.km-reglage-tete .km-bloc-tete { margin-bottom: .75rem; }
.km-reglage-titre {
  margin: 0; font-size: 1.3125rem; line-height: 1.32;
  letter-spacing: -.016em; font-weight: 590; color: var(--km-t0);
}
.km-reglage-phrase {
  margin: .75rem 0 0; max-width: 68ch;
  font-size: .9375rem; line-height: 1.5rem; color: var(--km-t1);
}

/* ---------- 42.3 Les groupes de champs ---------- */

.km-groupe + .km-groupe {
  margin-top: 2rem; padding-top: 1.75rem; border-top: 1px solid var(--km-l1);
}
/* L'étiquette du groupe tire un filet jusqu'au bord : la mesure d'abord,
   la ligne ensuite — le motif des catégories de la page de commande. */
.km-groupe-tete { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.25rem; }
.km-groupe-tete .km-etiquette { flex: none; }
.km-groupe-tete::after { content: ""; flex: 1; height: 1px; background: var(--km-l1); }

.km-champs {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem;
}
.km-champ { display: flex; flex-direction: column; min-width: 0; }
.km-champ-large { grid-column: 1 / -1; }
/* « intl-tel-input » enveloppe le champ de téléphone dans un « .iti » : sans
   cette ligne, l'enveloppe se rétracte à la largeur du drapeau. */
.km-champ .iti { width: 100%; }
.km-champ .form-label { margin-bottom: .5rem; }
/* Un champ qui n'en est plus un — la devise, arrêtée pour de bon — garde la
   même colonne : une étiquette de mesure, puis la valeur. */
.km-champ > .km-etiquette { margin-bottom: .375rem; }
.km-aide {
  display: block; margin-top: .5rem;
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2);
}

/* ---------- 42.4 L'avis — ce qu'il faut savoir AVANT d'agir ---------- */
/* Un plan d'un cran plus haut, un filet d'un pixel, une icône colorée : la
   couleur ne porte jamais le sens seule, le mot « Attention » est écrit. */

.km-avis {
  display: flex; align-items: flex-start; gap: .875rem;
  padding: 1rem 1.125rem; margin: 0 0 1.5rem;
  border: 1px solid var(--km-l1); border-radius: 5px;
  background: var(--km-plan-b);
}
.km-avis .km-icone { margin-top: .1875rem; color: var(--km-t2); }
.km-avis-corps { display: flex; flex-direction: column; align-items: flex-start; gap: .75rem; }
.km-avis-texte {
  margin: 0; max-width: 72ch;
  font-size: .9375rem; line-height: 1.5rem; color: var(--km-t1);
}
.km-avis-texte strong { color: var(--km-t0); font-weight: 510; }
.km-avis-texte a {
  color: var(--km-ac); text-decoration: none;
  border-bottom: 1px solid var(--km-ac-bord);
  transition: color var(--km-d-micro) var(--km-e-micro),
              border-color var(--km-d-micro) var(--km-e-micro);
}
.km-avis-texte a:hover { color: var(--km-ac-h); border-bottom-color: var(--km-ac); text-decoration: none; }
.km-avis-at .km-icone { color: var(--km-at); }
.km-avis-ko .km-icone { color: var(--km-ko); }
.km-avis-inf .km-icone { color: var(--km-inf); }
.km-avis-ok .km-icone { color: var(--km-ok); }

/* ---------- 42.5 Le pied d'un formulaire ---------- */

.km-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem;
  margin-top: 2rem; padding-top: 1.5rem;
  border-top: 1px solid var(--km-l1);
}
/* La note brève, généralisation de « .km-contact-note ». */
.km-note { font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2); }
.km-note-bloc { margin: 1rem 0 0; max-width: 68ch; }
.km-requis-legende { display: block; margin: 0 0 1.75rem; }

/* ---------- 42.6 L'identité : l'image et sa provenance ---------- */
/* La fonction « avatar() » du cœur impose la classe « img-thumbnail » et peut
   rendre soit une balise « img », soit un « div » à image de fond. On habille
   les deux cas plutôt que de toucher à l'appel. */

.km-identite {
  display: flex; align-items: center; gap: 1.25rem;
  padding-bottom: 1.75rem; margin-bottom: 1.75rem;
  border-bottom: 1px solid var(--km-l1);
}
.km-identite p {
  margin: 0; max-width: 52ch;
  font-size: .875rem; line-height: 1.375rem; color: var(--km-t1);
}
.km-identite .img-thumbnail {
  width: 100px; height: 100px; flex: none; padding: 0; overflow: hidden;
  border: 1px solid var(--km-l1); border-radius: 5px;
  background-color: var(--km-plan-b);
  background-size: cover; background-position: center; background-repeat: no-repeat;
  box-shadow: none;
}
.km-identite .img-thumbnail img { display: block; width: 100%; height: 100%; }

/* ---------- 42.7 La clé d'API ---------- */
/* Le champ en lecture seule reste en pointillé — il ne s'édite pas — mais sa
   valeur reprend la couleur du texte plein : une clé se lit pour être copiée,
   elle ne peut pas rester dans le registre effacé. */

.km-champ-mono { font-family: var(--km-mono); font-size: .875rem; letter-spacing: -.01em; }
.km-cle .form-control[readonly] { color: var(--km-t0); }

/* ---------- 42.8 Les tailles d'écran ---------- */

@media (max-width: 768px) {
  .km-champs { grid-template-columns: minmax(0, 1fr); }
  .km-reglage { padding: 1.375rem 1.25rem 1.5rem; }
  .km-reglages-sommaire a { flex: 1 1 auto; justify-content: flex-start; }
  .km-identite { flex-direction: column; align-items: flex-start; gap: 1rem; }
}

/* ---------- 42.9 La mise en scène ne s'impose à personne ---------- */

@media (prefers-reduced-motion: reduce) {
  .km-reglage::before, .km-reglages-sommaire a, .km-reglages-sommaire .km-icone,
  .km-avis-texte a { transition: none; }
}

/* ==== lot : ? ==== */
/* --------------------------------------------------------------------------
   45. L'ASSISTANCE — le registre des tickets et le fil de conversation
   Deux gabarits : « mod_support_tickets » (la liste) et « mod_support_ticket »
   (le fil). Le premier reprend la grammaire de la console, déjà écrite en
   section 21 ; on ne pose ici que les écarts. Le second demande une structure
   qui n'existait pas : une conversation.

   LE PARTI DU FIL
   Un échange se lit à deux colonnes — vos messages à gauche, ceux de
   l'assistance à droite — accrochées à un filet vertical qui tient lieu de
   ligne de temps. L'auteur se lit donc à sa place avant même son nom. Aucun
   fond coloré : le message garde le plan de la maison, son filet d'un pixel,
   son rayon de 5 px. L'horodatage passe en monospace, comme toute mesure.
   Sous 992 px, les deux colonnes n'en font plus qu'une et le filet se range
   à gauche : tous les messages s'y accrochent, l'assistance décalée d'un cran.
   -------------------------------------------------------------------------- */

/* ---------- 43.1 Compléments du cartouche ----------
   Le cartouche de la section 21 ne savait porter que des nombres. Un ticket
   affiche aussi un état, un service et une date : trois registres, trois
   traitements, sans jamais mettre du monospace là où il y a de la parole. */

.km-cartouche-texte {
  font-size: .9375rem; line-height: 1.5rem; font-weight: 510;
  letter-spacing: -.008em; color: var(--km-t0);
}
.km-cartouche-date {
  font-family: var(--km-mono); font-size: .875rem; line-height: 1.25rem;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em; color: var(--km-t0);
}
/* Le point de statut se cale sur la ligne des autres valeurs. */
.km-cartouche-statut { display: flex; align-items: center; min-height: 1.5rem; }

/* Posée dans une étiquette de tête, l'icône prend l'accent — même règle que
   « km-bloc-tete », qui ne s'applique pas ici faute de ce conteneur. */
.km-tickets-page .km-entete-nom .km-etiquette .km-icone,
.km-fil-page .km-entete-nom .km-etiquette .km-icone,
.km-tickets-page .km-section-tete .km-etiquette .km-icone,
.km-fil-page .km-section-tete .km-etiquette .km-icone { color: var(--km-ac); }

/* Le compte, la page : à droite de leur filet de section. */
.km-tickets-page .km-section-tete .km-ref,
.km-fil-page .km-section-tete .km-ref { margin-left: auto; }

/* ---------- 43.2 Le registre des tickets ---------- */

/* Un troisième point pour la ligne d'état de l'en-tête : quelque chose vous
   attend. Le vert dit « rien à faire », le safran dit « à lire ». Jamais de
   pastille : un point de 7 px et un libellé, comme partout. */
.km-point-attente { background: var(--km-ac); }

.km-tickets-service { color: var(--km-t1); }
.km-tickets-quand {
  font-family: var(--km-mono); font-size: .8125rem;
  letter-spacing: .01em; color: var(--km-t1); white-space: nowrap;
}
.km-tickets-pagination { margin-top: 1.5rem; }

/* La fenêtre d'ouverture de ticket : une phrase d'entrée, une note de pied. */
.km-modal-phrase {
  margin: 0 0 1.5rem; max-width: 58ch;
  font-size: .875rem; line-height: 1.375rem; color: var(--km-t1);
}
.km-modal-pied {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 1rem;
}
.km-modal-pied > * { margin: 0; }
.km-modal-note { font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2); }

/* ---------- 43.3 Le fil ---------- */

.km-fil-sujet {
  margin: 0; max-width: 34ch;
  font-size: 1.625rem; line-height: 2rem; letter-spacing: -.026em;
}
.km-fil-section { margin-top: .5rem; }

.km-fil {
  position: relative;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: 3rem; row-gap: 1.25rem;
  margin: 0; padding: 1.75rem 0 0; list-style: none;
}
/* La ligne de temps : un filet d'un pixel au milieu de la gouttière. */
.km-fil::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 50%;
  width: 1px; background: var(--km-l1);
}

.km-fil-message {
  position: relative;
  display: flex; flex-direction: column; gap: .875rem;
  padding: 1.25rem 1.375rem;
  border: 1px solid var(--km-l1); border-radius: 5px;
  background: var(--km-plan-a);
  transition: background-color var(--km-d-couleur) var(--km-e-couleur),
              border-color var(--km-d-couleur) var(--km-e-couleur);
}
/* Le filet de safran de l'arête haute, comme partout ailleurs au survol.
   Aucune élévation ici : un message n'est pas une carte que l'on clique. */
.km-fil-message::before {
  /* Le filet s'arrête au rayon des angles : le message ne peut pas être mis
     en « overflow: hidden », il porte le trait d'accroche à la ligne de temps. */
  content: ""; position: absolute; left: 5px; right: 5px; top: 0; height: 1px;
  background: var(--km-ac); transform: scaleX(0); transform-origin: left;
  transition: transform 460ms var(--km-e-entree);
}
.km-fil-message:hover { background: var(--km-plan-b); border-color: var(--km-l2); }
.km-fil-message:hover::before { transform: scaleX(1); }

/* Chaque message s'accroche à la ligne de temps par un trait court. */
.km-fil-message::after {
  content: ""; position: absolute; top: 1.75rem;
  width: 1.5rem; height: 1px; background: var(--km-l1);
}
.km-fil-vous { grid-column: 1; }
.km-fil-vous::after { right: -1.5rem; }
.km-fil-eux { grid-column: 2; }
.km-fil-eux::after { left: -1.5rem; background: var(--km-ac-bord); }

.km-fil-entete {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem 1rem;
  padding-bottom: .875rem; border-bottom: 1px solid var(--km-l1);
}
.km-fil-qui { display: flex; flex-direction: column; gap: .3125rem; }
.km-fil-nom {
  font-size: .9375rem; line-height: 1.25rem; font-weight: 510;
  letter-spacing: -.008em; color: var(--km-t0);
}
/* L'étiquette d'auteur : la voix de la maison prend l'accent, la vôtre non. */
.km-fil-role { color: var(--km-t2); }
.km-fil-eux .km-fil-role { color: var(--km-ac); }

.km-fil-quand {
  margin-left: auto;
  font-family: var(--km-mono); font-size: .75rem; line-height: 1rem;
  letter-spacing: .04em; font-variant-numeric: tabular-nums; color: var(--km-t2);
}

.km-fil-pied {
  display: flex; align-items: center; gap: .75rem;
  padding-top: .875rem; border-top: 1px solid var(--km-l1);
}
.km-fil-ref {
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--km-t2);
}
/* Le bouton de citation garde la cible de 38 px du bouton court : on ne
   resserre que l'horizontale, une icône n'a pas besoin de la largeur d'un mot. */
.km-fil-citer { margin-left: auto; --bs-btn-padding-x: .75rem; }

/* ---------- 43.4 Le corps du message ----------
   « markdown.css » du cœur est chargé APRÈS la feuille de marque : on reprend
   la main avec la double classe, jamais avec des !important. */

.km-fil-texte.markdown-body {
  font-family: var(--km-sans);
  font-size: .9375rem; line-height: 1.5rem; letter-spacing: -.006em;
  color: var(--km-t1);
}
.km-fil-texte.markdown-body > *:first-child { margin-top: 0; }
.km-fil-texte.markdown-body > *:last-child { margin-bottom: 0; }
.km-fil-texte.markdown-body p { margin: 0 0 .75rem; }
.km-fil-texte.markdown-body h1,
.km-fil-texte.markdown-body h2,
.km-fil-texte.markdown-body h3,
.km-fil-texte.markdown-body h4 {
  margin: 1.25rem 0 .5rem; padding-bottom: 0; border-bottom: 0;
  font-family: var(--km-sans); font-weight: 590; letter-spacing: -.012em;
  color: var(--km-t0);
}
.km-fil-texte.markdown-body h1 { font-size: 1.125rem; line-height: 1.5rem; }
.km-fil-texte.markdown-body h2 { font-size: 1.0625rem; line-height: 1.5rem; }
.km-fil-texte.markdown-body h3,
.km-fil-texte.markdown-body h4 { font-size: 1rem; line-height: 1.5rem; }
.km-fil-texte.markdown-body strong { color: var(--km-t0); font-weight: 510; }

.km-fil-texte.markdown-body a {
  color: var(--km-ac); text-decoration: none;
  border-bottom: 1px solid var(--km-ac-bord);
  transition: color var(--km-d-micro) var(--km-e-micro),
              border-color var(--km-d-micro) var(--km-e-micro);
}
.km-fil-texte.markdown-body a:hover {
  color: var(--km-ac-h); border-bottom-color: var(--km-ac); text-decoration: none;
}

/* Le marqueur carré de 4 px, celui des offres et des documents. */
.km-fil-texte.markdown-body ul { margin: 0 0 .75rem; padding: 0; list-style: none; }
.km-fil-texte.markdown-body ul > li { position: relative; padding-left: 1.125rem; margin-bottom: .375rem; }
.km-fil-texte.markdown-body ul > li::before {
  content: ""; position: absolute; left: 0; top: .625rem;
  width: 4px; height: 4px; background: var(--km-ac);
}
.km-fil-texte.markdown-body ol { margin: 0 0 .75rem; padding-left: 1.375rem; }
.km-fil-texte.markdown-body ol > li { margin-bottom: .375rem; }
.km-fil-texte.markdown-body ol > li::marker {
  font-family: var(--km-mono); font-size: .8125rem; color: var(--km-t2);
}

.km-fil-texte.markdown-body code {
  font-family: var(--km-mono); font-size: .875em;
  color: var(--km-t0); background: var(--km-plan-b);
  padding: .125rem .375rem; border-radius: 3px;
}
.km-fil-texte.markdown-body pre {
  margin: 0 0 .75rem; padding: .875rem 1rem;
  background: var(--km-plan-b); border: 1px solid var(--km-l1); border-radius: 5px;
  overflow-x: auto;
}
.km-fil-texte.markdown-body pre code { background: transparent; padding: 0; }
.km-fil-texte.markdown-body blockquote {
  margin: 0 0 .75rem; padding: 0 0 0 1rem;
  border-left: 1px solid var(--km-l2); color: var(--km-t2);
}
.km-fil-texte.markdown-body hr {
  height: 1px; margin: 1.25rem 0;
  background: var(--km-l1); border: 0;
}
.km-fil-texte.markdown-body img { max-width: 100%; height: auto; border-radius: 5px; }

/* Un tableau collé dans un message : filets horizontaux, aucun fond. */
.km-fil-texte.markdown-body table {
  display: block; width: 100%; margin: 0 0 .75rem;
  overflow-x: auto; border-collapse: collapse; font-size: .875rem;
}
.km-fil-texte.markdown-body th,
.km-fil-texte.markdown-body td {
  padding: .5rem 1rem .5rem 0; text-align: left; vertical-align: top;
  background: transparent; border: 0; border-bottom: 1px solid var(--km-l1);
}
.km-fil-texte.markdown-body th {
  font-family: var(--km-mono); font-size: .6875rem; font-weight: 400;
  letter-spacing: .2em; text-transform: uppercase; color: var(--km-t2);
}

/* ---------- 43.5 La réponse, l'avis, la clôture ---------- */

.km-fil-avis { margin: 2rem 0 0; }
.km-fil-avis .km-icone { color: var(--km-ac); margin-top: .125rem; }
.km-fil-clos { margin-top: 2rem; }

.km-fil-reponse { margin-top: 2rem; }
.km-fil-reponse .form-label { margin-top: 1.25rem; }
.km-fil-envoi {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; margin-top: 1.5rem;
}
.km-fil-note { font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2); }

/* ---------- 43.6 Les tailles d'écran ---------- */

@media (max-width: 992px) {
  /* Une seule colonne : le filet de temps se range à gauche et tout le monde
     s'y accroche. L'assistance garde son cran de décalage, sa place reste
     donc lisible sans qu'un fond de couleur ait à le dire. */
  .km-fil { grid-template-columns: minmax(0, 1fr); padding-left: 1.5rem; }
  .km-fil::before { left: 0; }
  .km-fil-message { grid-column: 1; }
  .km-fil-message::after { left: -1.5rem; right: auto; width: 1.5rem; }
  .km-fil-eux { margin-left: 1.25rem; }
  /* Décalé d'un cran, le message de l'assistance a un trait plus long
     pour rejoindre quand même la ligne de temps. */
  .km-fil-eux::after { left: -2.75rem; width: 2.75rem; }
}

@media (max-width: 576px) {
  .km-fil { padding-left: 1rem; }
  .km-fil-message { padding: 1rem 1.125rem; }
  .km-fil-message::after { left: -1rem; width: 1rem; }
  /* Plus de place pour un décalage : l'étiquette d'auteur suffit. */
  .km-fil-eux { margin-left: 0; }
  .km-fil-eux::after { left: -1rem; width: 1rem; }
  .km-fil-quand { margin-left: 0; }
  .km-fil-sujet { font-size: 1.375rem; line-height: 1.75rem; }
  .km-modal-pied { justify-content: flex-start; }
}

/* La mise en scène ne s'impose à personne. */
@media (prefers-reduced-motion: reduce) {
  .km-fil-message,
  .km-fil-message::before,
  .km-fil-texte.markdown-body a { transition: none; }
}

/* ==== lot : ? ==== */
/* --------------------------------------------------------------------------
   46. LES PAGES D'ACCÈS — connexion, inscription, mot de passe oublié,
   nouveau mot de passe.
   Elles étaient la seule surface publique sans identité : une carte de trois
   cent cinquante pixels, centrée dans le vide, sans titre de niveau 1, sans
   promesse, sans provenance. On les ouvre en deux : une colonne de formulaire
   et un panneau de marque adossé. Le panneau ne dit rien qui ne soit écrit
   ailleurs sur le site — il n'invente aucune promesse.
   Sous 992 px il passe SOUS le formulaire ; sous 576 px il perd sa frise et
   garde ses trois arguments, qui sont la partie utile.
   -------------------------------------------------------------------------- */

/* ---------- La partition ---------- */

/* « min-height » et non « height » : la colonne la plus haute — l'inscription
   et ses dix-huit champs — commande la hauteur de la rangée, si bien que le
   centrage vertical ne peut jamais rogner le haut du formulaire. */
.km-acces {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  min-height: 100vh;
  min-height: 100svh;
}

.km-acces-colonne {
  display: flex; flex-direction: column; justify-content: center;
  padding: 3.5rem 1.5rem;
}
.km-acces-boite { width: 100%; max-width: 26rem; margin: 0 auto; }
/* L'inscription respire sur deux colonnes de champs : elle est plus large. */
.km-acces-boite-large { max-width: 40rem; }

/* Le logo garde la hauteur passée en attribut par le gabarit ; « contain »
   l'empêche de s'écraser quand la colonne devient plus étroite que lui. */
.km-acces-logo { display: flex; margin-bottom: 1rem; }
.km-acces-logo img { max-width: 100%; object-fit: contain; object-position: left center; }

/* ---------- L'ouverture de la colonne ---------- */

.km-acces-tete { margin-bottom: 2.5rem; }
.km-acces-tete > .km-etiquette { display: block; margin-bottom: 1rem; }
.km-acces-tete h1 {
  margin: 0; max-width: 18ch;
  font-size: clamp(1.75rem, 3.4vw, 2.125rem);
  line-height: 1.12; letter-spacing: -.028em;
}
.km-acces-phrase {
  margin: 1rem 0 0; max-width: 46ch;
  font-size: .9375rem; line-height: 1.5rem; color: var(--km-t1);
}

/* ---------- Les champs ---------- */

/* Chaque champ de l'inscription est conditionnel : une grille laisse les
   cellules absentes se refermer d'elles-mêmes, ce qu'une paire de colonnes
   fixes ne sait pas faire. Le champ qui a besoin de toute la largeur le
   demande par « km-champ-large ». */
.km-acces-champs {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem;
}
.km-acces-champs > * { min-width: 0; }
.km-acces-champs > .mb-3 { margin-bottom: 0 !important; }
.km-champ-large { grid-column: 1 / -1; }

/* Le groupe de champs est un vrai « fieldset » : son intitulé est annoncé par
   les lecteurs d'écran avant chaque champ du groupe. Reboot le fait flotter,
   on le remet dans le flux et on lui donne le filet de la maison. */
.km-acces-groupe { min-width: 0; border: 0; padding: 0; margin: 0 0 2.5rem; }
.km-acces-groupe > legend {
  float: none; width: 100%;
  padding: 0 0 .75rem; margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--km-l1);
}

.km-acces .form-text, .km-acces .form-hint {
  display: block; margin-top: .5rem;
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2);
}

/* ---------- L'acceptation des conditions ---------- */

/* La case reste la case de Bootstrap — on ne l'entoure que d'un plan, pour
   qu'un consentement ne se lise pas comme une ligne de formulaire ordinaire. */
.km-acces-tos {
  margin-bottom: 1.5rem; padding: 1rem 1.125rem;
  background: var(--km-plan-a);
  border: 1px solid var(--km-l1); border-radius: 5px;
}
.km-acces-tos .form-check { margin-bottom: 0 !important; }
.km-acces-tos .form-check-input { width: 1.125rem; height: 1.125rem; margin-top: .125rem; }
.km-acces-tos .form-check-label {
  font-size: .875rem; line-height: 1.375rem; color: var(--km-t1);
}
.km-acces-note {
  margin: 0; max-width: 52ch;
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2);
}
/* Registre 1 du lien : la couleur ET un filet, jamais la couleur seule. */
.km-acces-note a, .km-acces-tos a {
  color: var(--km-ac); text-decoration: none;
  border-bottom: 1px solid var(--km-ac-bord);
  transition: color var(--km-d-micro) var(--km-e-micro),
              border-color var(--km-d-micro) var(--km-e-micro);
}
.km-acces-note a:hover, .km-acces-tos a:hover {
  color: var(--km-ac-h); border-bottom-color: var(--km-ac); text-decoration: none;
}

/* ---------- Les issues : l'autre page d'accès, puis les mentions ---------- */

/* Ces deux lignes portent « km-doc-pied-liens » : elles héritent donc du
   registre 2 — le tiret qui se déploie dans la gouttière au survol. */
.km-acces-liens {
  margin: .5rem 0 0; padding-top: 1.5rem;
  border-top: 1px solid var(--km-l1);
  font-size: .9375rem;
}
.km-acces-mentions { margin: 2.5rem 0 0; font-size: .8125rem; }
.km-acces-mentions a { color: var(--km-t2); }

/* ---------- Le panneau de marque ---------- */

.km-acces-panneau {
  display: flex; flex-direction: column; justify-content: center;
  margin-bottom: 0;                      /* annule le rythme de « km-section » */
  padding: 3rem 1.5rem;
  background: var(--km-plan-a);
  border-top: 1px solid var(--km-l1);
}
.km-acces-panneau-corps { width: 100%; max-width: 30rem; margin: 0 auto; }
.km-acces-panneau-corps > .km-etiquette { display: block; }

.km-acces-promesse {
  margin: 1.125rem 0 0; max-width: 30ch;
  font-size: 1.25rem; line-height: 1.875rem; letter-spacing: -.016em;
  font-weight: 400; color: var(--km-t0);
}
.km-acces-panneau .km-frise { margin: 2.25rem 0 0; }

.km-acces-args {
  display: flex; flex-direction: column; gap: 1.75rem;
  margin: 2.5rem 0 0; padding: 0; list-style: none;
}
.km-acces-arg { padding-top: 1.5rem; border-top: 1px solid var(--km-l1); }
.km-acces-arg .km-bloc-tete { margin-bottom: .625rem; }
.km-acces-arg p {
  margin: 0; max-width: 44ch;
  font-size: .875rem; line-height: 1.375rem; color: var(--km-t1);
}

/* ---------- Les tailles d'écran ---------- */

@media (min-width: 992px) {
  .km-acces { grid-template-columns: minmax(0, 1fr) minmax(23rem, 30rem); }
  .km-acces-colonne { padding: 4rem 3.5rem; }
  .km-acces-panneau {
    padding: 4rem 3.5rem;
    border-top: 0; border-left: 1px solid var(--km-l1);
  }
  /* Le panneau reste en vue pendant qu'on descend un long formulaire. */
  .km-acces-panneau-corps { position: sticky; top: 4rem; max-width: 26rem; margin: 0; }
}

@media (max-width: 575.98px) {
  .km-acces-colonne, .km-acces-panneau { padding: 2.5rem 1.25rem; }
  .km-acces-champs { grid-template-columns: minmax(0, 1fr); }
  .km-acces-tete h1 { max-width: none; }
  /* Trente-six crans écrasés sur trois cents pixels ne disent plus rien :
     la frise s'efface, la phrase et les trois arguments restent. */
  .km-acces-panneau .km-frise { display: none; }
  .km-acces-groupe { margin-bottom: 2rem; }
}

@media (prefers-reduced-motion: reduce) {
  .km-acces-note a, .km-acces-tos a { transition: none; }
}

/* ==== lot : ? ==== */
/* --------------------------------------------------------------------------
   47. LES FACTURES ET LE PORTEFEUILLE
   Une facture n'est pas un écran de gestion : c'est un document. Elle en
   reprend donc la grammaire — un numéro en mesure, un état marqué par un
   point, deux parties en regard, un détail en tableau à filets horizontaux,
   et un total qui se détache du reste par un seul filet de safran.
   Rien de fonctionnel n'est touché ici : les passerelles gardent leurs
   identifiants, la macro d'état du cœur garde son rendu de la section 12.
   -------------------------------------------------------------------------- */

/* ---------- 42.1 Le vocabulaire commun : dates, numéros, mesures ---------- */

/* Une date est une mesure : elle passe en monospace tabulaire, jamais en Sans.
   La seconde règle reprend la main sur « .table > tbody > tr > td », plus
   spécifique que la première : sans elle, la cellule garderait sa taille. */
.km-date {
  font-family: var(--km-mono);
  font-variant-numeric: tabular-nums;
  font-size: .8125rem;
  letter-spacing: -.01em;
  color: var(--km-t1);
  white-space: nowrap;
}
.table > tbody > tr > td.km-date { font-size: .8125rem; color: var(--km-t1); }

/* Un numéro de facture est un identifiant : même registre. */
.km-facture-nr {
  font-family: var(--km-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  letter-spacing: -.014em;
}

/* Les listes de définition d'une facture — émetteur, destinataire.
   Clé en mesure au-dessus ou à gauche, valeur en parole, filet entre les
   lignes : le même dessin que le tableau des finalités des pages publiques. */
.km-dl { margin: 0; }
.km-dl-ligne {
  display: grid;
  grid-template-columns: 10.5rem minmax(0, 1fr);
  gap: .25rem 1.5rem;
  padding: .625rem 0;
  border-bottom: 1px solid var(--km-l1);
}
.km-dl-ligne:last-child { border-bottom: 0; }
.km-dl dt {
  font-family: var(--km-mono);
  font-size: .6875rem;
  line-height: 1.25rem;
  font-weight: 400;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--km-t2);
}
.km-dl dd {
  margin: 0;
  font-size: .9375rem;
  line-height: 1.5rem;
  color: var(--km-t0);
}
/* Un numéro de TVA, un IBAN, un téléphone : de la mesure, pas de la parole. */
.km-dl-mesure {
  font-family: var(--km-mono);
  font-variant-numeric: tabular-nums;
  font-size: .875rem;
  letter-spacing: -.01em;
}

/* Le total détaché. Un seul filet de safran le sépare du détail : pas de
   fond, pas de cadre, pas de graisse 700. */
.km-total { display: flex; justify-content: flex-end; margin-top: 2rem; }
.km-total-liste { min-width: 18rem; margin: 0; }
.km-total-ligne {
  display: flex; align-items: baseline; justify-content: space-between; gap: 2rem;
  padding: .625rem 0;
  border-bottom: 1px solid var(--km-l1);
}
.km-total-ligne dt { font-size: .875rem; line-height: 1.25rem; color: var(--km-t1); font-weight: 400; }
.km-total-ligne dd {
  margin: 0;
  font-family: var(--km-mono);
  font-variant-numeric: tabular-nums;
  font-size: .9375rem;
  letter-spacing: -.02em;
  color: var(--km-t0);
}
.km-total-final {
  margin-top: .25rem; padding-top: 1rem;
  border-top: 1px solid var(--km-ac);
  border-bottom: 0;
}
.km-total-final dt { font-size: .9375rem; font-weight: 510; color: var(--km-t0); }
.km-total-final dd { font-size: 1.5rem; line-height: 2rem; font-weight: 500; letter-spacing: -.03em; }

/* Le détail : le tableau de la maison, sans un fond de couleur. Seules la
   colonne de rang et la quantité reçoivent un traitement propre. */
.km-lignes-rang { width: 3rem; color: var(--km-t2); font-variant-numeric: tabular-nums; }
.km-lignes > tbody > tr > td.km-lignes-rang {
  font-family: var(--km-mono); font-size: .8125rem; color: var(--km-t2);
}
.km-lignes-qte {
  margin-left: .5rem;
  font-family: var(--km-mono); font-size: .75rem; letter-spacing: .02em;
  color: var(--km-t2); white-space: nowrap;
}

/* ---------- 42.2 La liste des factures ---------- */

.km-factures .km-doc-tete { margin-bottom: 2.5rem; }
.km-factures .tab-content { padding-top: 1.5rem; }
.km-factures .pagination { margin-top: 1.75rem; }

/* Le compteur d'un onglet : un filet le sépare du libellé, jamais une
   pastille. Il prend le safran quand l'onglet est celui qu'on lit. */
.km-onglet-nb {
  margin-left: .625rem;
  font-variant-numeric: tabular-nums;
  color: var(--km-t2);
}
.km-onglet-nb::before {
  content: ""; display: inline-block;
  width: 1px; height: .75em; margin-right: .625rem;
  background: var(--km-l2); vertical-align: -.05em;
}
.nav-tabs .nav-link.active .km-onglet-nb { color: var(--km-ac); }
.nav-tabs .nav-link.active .km-onglet-nb::before { background: var(--km-ac-bord); }

/* La colonne d'action ne s'étire pas : elle se serre à droite. */
.km-col-action { width: 1%; text-align: right; white-space: nowrap; }

/* ---------- 42.3 La facture ---------- */

/* Le titre d'une facture est son numéro : c'est un identifiant, donc de la
   mesure. C'est le seul H1 du site en monospace, et il l'est pour cette
   raison précise. */
.km-facture .km-doc-tete { margin-bottom: 1.75rem; padding-bottom: 1.5rem; }
.km-facture .km-doc-tete h1 {
  font-family: var(--km-mono);
  font-variant-numeric: tabular-nums;
  font-size: 2.25rem; line-height: 2.5rem;
  font-weight: 500; letter-spacing: -.035em;
}

/* La barre d'état : à gauche le point et son libellé, à droite les sorties
   papier. Un filet ferme la ligne. */
.km-facture-barre {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 1.25rem;
  padding-bottom: 1.5rem; margin-bottom: 2.5rem;
  border-bottom: 1px solid var(--km-l1);
}
.km-facture-etat { display: flex; flex-direction: column; gap: .5rem; margin: 0; }
.km-facture-actions { display: flex; flex-wrap: wrap; gap: .625rem; margin-left: auto; }

/* Les moyens de règlement. Plan à plat, filet d'un pixel : l'encadré n'est
   pas une alerte, c'est un choix à faire. */
.km-facture-paiement {
  padding: 1.5rem; margin-bottom: 3rem;
  border: 1px solid var(--km-l2); border-radius: 5px;
  background: var(--km-plan-a);
}
.km-facture-paiement-phrase {
  max-width: 62ch; margin: 0 0 1.25rem;
  font-size: .9375rem; line-height: 1.5rem; color: var(--km-t1);
}
.km-passerelles { display: flex; flex-wrap: wrap; gap: 1rem; }

/* Les deux parties en regard. Chacune s'ouvre sur un filet, comme un en-tête
   de colonne de registre. */
.km-facture-parties {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: 2.5rem 4rem; margin-bottom: 3rem;
}
.km-facture-partie { padding-top: 1.25rem; border-top: 1px solid var(--km-l2); }

.km-facture-lignes { margin-bottom: 3rem; }
.km-facture-lignes .km-section-tete { margin-bottom: 1rem; }

/* Les mentions libres de la facture, telles que l'administration les écrit. */
.km-facture-note {
  max-width: 70ch; margin: 0 0 2.5rem;
  padding-left: 1.25rem; border-left: 1px solid var(--km-ac-bord);
  font-size: .9375rem; line-height: 1.5rem; color: var(--km-t1);
}
.km-prose.km-facture-note > *:last-child { margin-bottom: 0; }

/* Les trois boutons de la fenêtre de confirmation ne se marchent plus dessus. */
.km-modal-actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.25rem; }

/* ---------- 42.4 Les pages d'attente : passerelle et retour de paiement --- */

.km-attente .km-doc-tete { margin-bottom: 2.5rem; }
.km-attente-corps {
  display: flex; flex-direction: column; gap: 1rem;
  padding: 1.75rem;
  border: 1px solid var(--km-l1); border-radius: 5px;
  background: var(--km-plan-a);
}
.km-attente-corps p { margin: 0; font-size: .9375rem; line-height: 1.5rem; color: var(--km-t1); }
/* Deux classes dans le sélecteur : c'est ce qu'il faut pour passer devant
   « .km-attente-corps p » sans recourir à !important. */
.km-attente-corps .km-attente-titre {
  display: flex; align-items: center; gap: .625rem;
  font-size: 1.0625rem; line-height: 1.5rem;
  font-weight: 510; color: var(--km-t0);
}
.km-attente-titre .km-icone { color: var(--km-ac); }
.km-attente-corps form { margin: 0; }
.km-attente-jauge { max-width: 22rem; margin-top: .25rem; }
.km-attente-note {
  max-width: 62ch; margin: 1.25rem 0 0;
  font-size: .875rem; line-height: 1.25rem; color: var(--km-t2);
}

/* ---------- 42.5 Le portefeuille ---------- */

.km-portefeuille .km-doc-tete { margin-bottom: 2.5rem; }
.km-portefeuille .pagination { margin-top: 1.75rem; }

.km-solde-barre {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: 1.5rem 2rem; padding: 1.5rem;
  border: 1px solid var(--km-l2); border-radius: 5px;
  background: var(--km-plan-a);
}
.km-solde-etat { display: flex; flex-direction: column; gap: .5rem; }
/* Le solde est le chiffre que le client vient lire : il est plus gros ici
   qu'ailleurs, sans changer de registre. */
.km-solde-etat .km-valeur { font-size: 2rem; line-height: 2.25rem; letter-spacing: -.03em; }
.km-solde-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: .75rem; }
.km-solde-champ { display: flex; flex-direction: column; gap: .5rem; min-width: 12rem; }
.km-solde-champ .form-control {
  font-family: var(--km-mono); font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}
.km-solde-note {
  max-width: 62ch; margin: 1rem 0 3rem;
  font-size: .875rem; line-height: 1.25rem; color: var(--km-t2);
}
.km-solde-releve .km-section-tete { margin-bottom: 1rem; }

/* ---------- 42.6 La feuille à imprimer ---------- */

.km-impression-barre {
  max-width: 52rem; margin: 0 auto;
  padding: 1.5rem 1.5rem 0;
  display: flex; justify-content: flex-end;
}
.km-impression-feuille { max-width: 52rem; margin: 0 auto; padding: 2rem 1.5rem 4rem; }
.km-impression-tete {
  display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between;
  gap: 1.5rem 2rem; padding-bottom: 1.5rem; margin-bottom: 2rem;
  border-bottom: 1px solid var(--km-l2);
}
.km-impression-logo { max-height: 44px; width: auto; }
.km-impression-nom { font-size: 1.25rem; font-weight: 590; letter-spacing: -.02em; color: var(--km-t0); }
.km-impression-titre { display: flex; flex-direction: column; align-items: flex-end; gap: .5rem; }
.km-impression-nr { margin: 0; font-size: 1.75rem; line-height: 2rem; color: var(--km-t0); }
.km-impression-reperes {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1.25rem 2rem; padding: 1.125rem 1.375rem; margin-bottom: 2.5rem;
  border: 1px solid var(--km-l1); border-radius: 5px;
}
.km-impression-reperes > div { display: flex; flex-direction: column; gap: .5rem; }
.km-impression-total {
  font-family: var(--km-mono); font-variant-numeric: tabular-nums;
  font-size: 1.125rem; font-weight: 500; letter-spacing: -.02em; color: var(--km-t0);
}
.km-impression-pied {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: .5rem 1.5rem;
  margin-top: 3rem; padding-top: 1rem;
  border-top: 1px solid var(--km-l1);
  font-size: .8125rem; color: var(--km-t2);
}
.km-impression-pied-ref { font-family: var(--km-mono); letter-spacing: .04em; }

/* ---------- 42.7 Le papier ----------
   Sur une imprimante, l'ardoise coûte de l'encre et se lit mal. Les pages
   comptables repassent donc sur la palette claire, quel que soit le thème
   choisi à l'écran, et l'on retire ce qui n'a aucun sens sur une feuille :
   les moyens de règlement, les liens de pied, la barre d'impression. */
@media print {
  .invoice-invoice, .invoice-index, .client-balance, .km-impression {
    --km-fond: #FFFFFF;
    --km-plan-a: #FFFFFF;
    --km-plan-b: #FFFFFF;
    --km-plan-c: #FFFFFF;
    --km-l0: rgba(14,20,24,.06);
    --km-l1: rgba(14,20,24,.22);
    --km-l2: rgba(14,20,24,.42);
    --km-l3: var(--km-n-600);
    --km-t0: #000000;
    --km-t1: var(--km-n-800);
    --km-t2: var(--km-n-700);
    --km-ac: var(--km-o-800);
    --km-ac-bord: rgba(123,64,9,.45);
    background: var(--km-fond);
    color: var(--km-t0);
  }
  .km-impression-barre,
  .km-facture-paiement,
  .km-facture-actions,
  .km-doc-pied,
  .km-attente-jauge { display: none !important; }
  .km-impression-feuille { max-width: none; padding: 0; }
  .km-facture-partie, .km-total, .km-impression-reperes { break-inside: avoid; }
  .km-lignes tr { break-inside: avoid; }
}

/* ---------- 42.8 Les tailles d'écran ---------- */

@media (max-width: 768px) {
  .km-facture .km-doc-tete h1 { font-size: 1.75rem; line-height: 2rem; }
  .km-facture-actions { margin-left: 0; }
  .km-dl-ligne { grid-template-columns: minmax(0, 1fr); gap: .25rem; }
  .km-total { justify-content: flex-start; }
  .km-total-liste { min-width: 0; width: 100%; }
  .km-solde-barre { flex-direction: column; align-items: stretch; }
  .km-solde-form { width: 100%; }
  .km-solde-champ { flex: 1 1 12rem; }
  .km-impression-titre { align-items: flex-start; }
}

/* ==== lot : ? ==== */
/* --------------------------------------------------------------------------
   48. LA PAGE D'ERREUR
   (numéro à ajuster : la feuille s'arrêtait à la section 42 au moment où ce
   bloc a été écrit — d'autres sections ont pu s'ajouter depuis.)

   Le gabarit du cœur centrait un « display-1 » : un nombre énorme, en Sans,
   sans rien autour. On rend le code à sa nature — une mesure, donc la Mono,
   donc les chiffres tabulaires — et on rend la parole à la Sans. Le filet
   vertical de safran est celui du chapeau des pages de document : la page
   d'erreur n'invente pas un vocabulaire, elle emprunte celui de la maison.
   Les issues réemploient la tuile secondaire de l'accueil ; la recherche des
   404 réemploie le champ des guides. Aucune règle nouvelle pour l'une ni pour
   l'autre. Les pages du site (mod_custompages_content) n'ont besoin d'aucune
   règle : elles tiennent entièrement dans le vocabulaire .km-doc-* de la
   section 39.
   -------------------------------------------------------------------------- */

.km-erreur { padding-top: .5rem; }

.km-erreur-tete {
  padding-bottom: 2rem; margin-bottom: 3.5rem;
  border-bottom: 1px solid var(--km-l1);
}
.km-erreur-tete > .km-etiquette { display: block; margin-bottom: 1.125rem; }
.km-erreur-tete h1 { margin: 0; max-width: 20ch; }

/* Le code : monospace tabulaire, adossé au filet de safran. Graisse 400 —
   à cette taille, la Mono n'a besoin d'aucun renfort pour tenir la page. */
.km-erreur-code {
  position: relative; display: inline-block;
  margin: 0 0 1.5rem; padding-left: 1.25rem;
  font-family: var(--km-mono);
  font-size: clamp(3rem, 9vw, 4.5rem); line-height: 1;
  font-weight: 400; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
  color: var(--km-t0);
}
.km-erreur-code::before {
  content: ""; position: absolute; left: 0; top: .12em; bottom: .12em;
  width: 1px; background: var(--km-ac);
}

/* Les issues : la tuile secondaire de l'accueil, sans rien y ajouter qu'un
   peu d'air autour de l'icône. */
.km-erreur-issues { margin-bottom: 3.5rem; }
.km-erreur-issues .km-tuiles { margin-bottom: 0; }
.km-erreur-issues .km-tuile { gap: .5rem; padding: 1.25rem; }
.km-erreur-issues .km-icone { color: var(--km-ac); margin-bottom: .125rem; }

.km-erreur-recherche { margin-bottom: 3.5rem; }

@media (max-width: 576px) {
  .km-erreur-tete { padding-bottom: 1.5rem; margin-bottom: 2.5rem; }
  .km-erreur-code { margin-bottom: 1.25rem; }
  .km-erreur-issues, .km-erreur-recherche { margin-bottom: 2.5rem; }
}

/* ==== lot : ? ==== */
/* --------------------------------------------------------------------------
   49. LE TUNNEL DE COMMANDE — la progression, la fiche, le panier, la somme
   Les sections 33 à 38 habillaient l'accordéon du cœur SANS toucher au
   balisage : elles corrigeaient de l'extérieur. Les gabarits du tunnel sont
   maintenant repris, le balisage nous appartient, et ce vocabulaire-ci le
   nomme. Rien n'annule les réglages validés plus haut : on ajoute par-dessus,
   et lorsqu'il faut reprendre la main sur une règle en « !important », c'est
   dit et justifié à l'endroit même.
   -------------------------------------------------------------------------- */

/* ---------- 42.0 La mesure reste en Mono, même dans le tunnel ---------- */

/* La section 37 impose la Sans à tout « span » du tunnel, avec « !important » :
   « #orderManager .accordion-body span:not(.km-etiquette):not(.badge) ».
   Elle a raison pour les listes de caractéristiques — mais un MONTANT n'est
   pas de la parole, c'est de la mesure, et jusqu'ici aucun montant du tunnel
   n'était porté par un « span ». Le sélecteur d'origine pèse (1,3,1) : ses
   deux « :not() » comptent chacun pour une classe. La classe triplée nous
   met à (1,4,0), ce qui l'emporte sur le nombre de classes — on reprend donc
   la main sans rien annuler de la règle validée, et pour les seuls chiffres. */
#orderManager .accordion-body .km-valeur.km-valeur.km-valeur {
  font-family: var(--km-mono) !important;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em !important;
  text-transform: none !important;
}

/* ---------- 42.0 bis Les libellés de champ du tunnel ----------
   Hors du tunnel, « .form-label » EST une étiquette : Mono, capitales, 11 px
   (section 4). La section 37 a délibérément ramené les libellés du tunnel
   dans le registre du texte — Sans, casse normale — et elle a raison : ici on
   nomme un champ, on ne pose pas une mesure. Mais elle n'a pas touché à la
   taille ni à la couleur, si bien qu'un libellé s'y lisait en Sans de 11 px
   gris tertiaire : illisible, et sous le seuil de contraste. On complète. */
#orderManager .km-compte .form-label,
#orderManager .km-config .form-label,
#orderManager .km-addons .form-label,
#orderManager .km-promo .form-label {
  font-size: .875rem; line-height: 1.25rem;
  font-weight: 510; color: var(--km-t1);
}

/* ---------- 42.1 Le tunnel servi seul (fenêtre ou cadre embarqué) ---------- */

body.km-tunnel-seul { background: var(--km-fond); }
.km-tunnel-gouttiere { padding-top: 2.5rem; padding-bottom: 3rem; }
.km-tunnel { display: block; }

.km-tunnel-signature {
  margin: 1.5rem 0 0; text-align: center;
  font-family: var(--km-mono); font-size: .6875rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--km-t2);
}
.km-tunnel-signature a { color: var(--km-t2); }
.km-tunnel-signature a:hover { color: var(--km-ac); text-decoration: none; }

/* ---------- 42.2 Où j'en suis, ce qui reste ----------
   Un jalon par étape, sur un seul rang. Le filet d'arête dit l'avancement —
   safran pour ce qui est acquis, gris pour ce qui vient — et le point de
   7 px reprend la grammaire des statuts : tiret = terminé, creux =
   en cours, plein discret = à venir. Aucune pastille de couleur. */

.km-tunnel-progression {
  padding-bottom: 2rem; margin-bottom: 2.5rem;
  border-bottom: 1px solid var(--km-l1);
}
.km-tunnel-mesure { margin: 0 0 1.25rem; }

.km-jalons {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1.5rem; margin: 0; padding: 0; list-style: none;
}
.km-jalon {
  display: flex; flex-direction: column; gap: .375rem;
  padding-top: .875rem; border-top: 1px solid var(--km-l1);
}
.km-jalon-fait, .km-jalon-ici { border-top-color: var(--km-ac); }

.km-jalon-tete { display: flex; align-items: center; gap: .5rem; }
.km-jalon-icone { color: var(--km-t2); }
.km-jalon-fait .km-jalon-icone, .km-jalon-ici .km-jalon-icone { color: var(--km-ac); }

.km-jalon-nom {
  font-size: .9375rem; line-height: 1.25rem; font-weight: 510;
  letter-spacing: -.008em; color: var(--km-t0);
}
.km-jalon-reste .km-jalon-nom { font-weight: 400; color: var(--km-t2); }
.km-jalon-note { font-size: .8125rem; line-height: 1.25rem; color: var(--km-t1); }
.km-jalon-reste .km-jalon-note { color: var(--km-t2); }
.km-jalon-etat {
  margin-top: .125rem;
  font-family: var(--km-mono); font-size: .6875rem; line-height: 1rem;
  letter-spacing: .2em; text-transform: uppercase; color: var(--km-t2);
}
.km-jalon-ici .km-jalon-etat { color: var(--km-ac); }

/* Les trois formes du point — reprises de la section 12. */
.km-point-fait  { width: 9px; height: 1px; border-radius: 0; background: var(--km-ac); }
.km-point-ici   { background: transparent; box-shadow: inset 0 0 0 1.6px var(--km-ac); }
.km-point-reste { background: var(--km-l2); }

/* ---------- 42.3 Ce que je vais payer, avant même d'ouvrir le panier ---------- */

.km-recap {
  display: flex; flex-direction: column; gap: .875rem;
  padding: 1.375rem 1.5rem; margin-bottom: 2.5rem;
  border: 1px solid var(--km-l2); border-radius: 5px;
  background: var(--km-plan-a);
}
.km-recap > .km-bloc-tete { margin-bottom: 0; }
.km-recap-lignes { display: flex; flex-direction: column; gap: .5rem; margin: 0; }
.km-recap-ligne { display: flex; align-items: baseline; gap: 1rem; }
.km-recap-ligne dt { margin: 0; font-size: .875rem; color: var(--km-t1); }
.km-recap-ligne dd { margin: 0 0 0 auto; }
.km-recap-nombre {
  font-family: var(--km-mono); font-variant-numeric: tabular-nums;
  font-size: .875rem; letter-spacing: -.02em; color: var(--km-t0);
}
.km-recap-remise, .km-somme-remise, .km-panier-remise { color: var(--km-ok); }
.km-recap-total {
  display: flex; align-items: baseline; gap: 1rem; margin: 0;
  padding-top: .875rem; border-top: 1px solid var(--km-l1);
}
.km-recap-montant { margin-left: auto; font-size: 1.5rem; line-height: 1.9rem; }
.km-recap-note { margin: 0; font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2); max-width: 56ch; }

/* ---------- 42.4 La réassurance, en pied de tunnel ---------- */

.km-tunnel-appui {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 2rem 3rem; margin-top: 3rem; padding-top: 2rem;
  border-top: 1px solid var(--km-l1);
}
.km-tunnel-appui-bloc p {
  margin: 0; max-width: 42ch;
  font-size: .875rem; line-height: 1.375rem; color: var(--km-t1);
}

/* ---------- 42.5 La devise ---------- */

.km-devise { display: inline-flex; align-items: center; }
.km-devise-champ { min-width: 12rem; font-family: var(--km-mono); }

/* ---------- 42.6 La fiche de configuration ----------
   Le titre, ce qu'on achète, puis les deux seules décisions à prendre.
   Chacune dans son bloc, séparée par un filet, jamais par du vide. */

.km-config { display: flex; flex-direction: column; gap: 0; }
.km-config-fiche { display: flex; flex-direction: column; gap: .625rem; }
.km-config-fiche > .km-etiquette { display: block; }
.km-config-titre {
  margin: 0; font-size: 1.375rem; line-height: 1.75rem;
  letter-spacing: -.016em; font-weight: 590; color: var(--km-t0);
}
.km-config-desc { font-size: .9375rem; line-height: 1.5rem; }

.km-config-bloc {
  display: flex; flex-direction: column; align-items: flex-start; gap: 0;
  margin-top: 1.75rem; padding-top: 1.75rem;
  border-top: 1px solid var(--km-l1);
}
.km-config-bloc .form-label { margin-top: .25rem; }
.km-config-champ, .km-config-nombre { max-width: 28rem; }
.km-config-nombre { max-width: 8rem; text-align: center; }
.km-config-note {
  margin: .75rem 0 0; font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2);
}
.km-config-mesure { display: flex; align-items: baseline; gap: 1rem; margin: 0; }
.km-config-mesure-cle { font-size: .9375rem; color: var(--km-t1); }
.km-config-montant { font-size: 1.75rem; line-height: 2.25rem; }
.km-config-stock { font-size: .8125rem; }

.km-config-suite {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem;
  margin-top: 2rem; padding-top: 1.75rem; border-top: 1px solid var(--km-l1);
}
.km-config-suite-note { font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2); }

/* ---------- 42.7 Les options ----------
   Le refus reste coché : rien n'est ajouté dans le dos du client. Les deux
   boutons muets du cœur — coche verte, croix rouge — deviennent deux choix
   nommés, dans un même segment à filet. */

.km-addons { margin-top: 2.5rem; padding-top: 1.75rem; border-top: 1px solid var(--km-l1); }
.km-addons-phrase { margin: 0 0 1rem; font-size: .875rem; line-height: 1.375rem; color: var(--km-t2); }

/* La section 37 met TOUTE liste du tunnel en grille à deux colonnes et lui
   pose un carré de 4 px : c'est juste pour une liste de caractéristiques,
   faux pour une liste d'articles. On ne l'annule que sur nos deux listes. */
#orderManager .accordion-body ul.km-addons-liste,
#orderManager .accordion-body ul.km-panier-lignes {
  display: block; grid-template-columns: none; gap: 0;
  margin: 0; padding: 0; list-style: none;
}
#orderManager .accordion-body ul.km-addons-liste > li,
#orderManager .accordion-body ul.km-panier-lignes > li {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center; gap: .5rem 1.5rem;
  padding: 1.125rem 0; margin: 0;
  font-size: 1rem; line-height: 1.5rem; color: var(--km-t0);
  border-bottom: 1px solid var(--km-l1);
}
#orderManager .accordion-body ul.km-addons-liste > li:first-child,
#orderManager .accordion-body ul.km-panier-lignes > li:first-child { padding-top: 0; }
#orderManager .accordion-body ul.km-addons-liste > li:last-child,
#orderManager .accordion-body ul.km-panier-lignes > li:last-child { border-bottom: 0; }
#orderManager .accordion-body ul.km-addons-liste > li::before,
#orderManager .accordion-body ul.km-panier-lignes > li::before { content: none; display: none; }

.km-addon-objet { display: flex; align-items: flex-start; gap: .875rem; }
.km-addon-icone { width: 36px; height: 36px; flex: none; border-radius: 3px; }
.km-addon-texte { display: flex; flex-direction: column; gap: .1875rem; }
.km-addon-titre {
  margin: 0; font-size: 1rem; line-height: 1.5rem; font-weight: 510;
  letter-spacing: -.01em; color: var(--km-t0);
}
.km-addon-desc { font-size: .875rem; line-height: 1.375rem; color: var(--km-t1); }
.km-addon-desc p:last-child { margin-bottom: 0; }

.km-addon-prix { display: flex; flex-direction: column; align-items: flex-start; gap: .25rem; }
.km-addon-prix .form-label { margin-bottom: .25rem; }
.km-addon-champ { min-width: 16rem; }
.km-addon-montant { font-size: 1.125rem; line-height: 1.5rem; }

/* Le couple « btn-check » + étiquette : le champ reste masqué par Bootstrap,
   l'étiquette porte l'état. Un segment à deux volets, filet commun. */
#orderManager .km-addon-choix {
  display: inline-flex; flex: none;
  border: 1px solid var(--km-l1); border-radius: 5px; overflow: hidden;
}
#orderManager .km-addon-choix .btn {
  min-height: 42px; border: 0; border-radius: 0;
  background: transparent; color: var(--km-t1);
  font-size: .875rem; padding: .5rem 1rem;
  transition: background-color var(--km-d-couleur) var(--km-e-couleur),
              color var(--km-d-couleur) var(--km-e-couleur);
}
#orderManager .km-addon-choix .btn:hover { background: var(--km-plan-b); color: var(--km-t0); }
#orderManager .km-addon-non { border-left: 1px solid var(--km-l1) !important; }
#orderManager .km-addon-choix .btn-check:checked + .km-addon-oui {
  background: var(--km-ac-voile2); color: var(--km-ac);
}
#orderManager .km-addon-choix .btn-check:checked + .km-addon-non {
  background: var(--km-plan-c); color: var(--km-t0);
}
#orderManager .km-addon-choix .btn-check:focus-visible + .btn {
  outline: 2px solid var(--km-ac); outline-offset: -2px;
}

/* ---------- 42.8 Se connecter ou créer un compte ---------- */

.km-compte { display: flex; flex-direction: column; }
/* La barre d'onglets hérite déjà des sections 37 et 38 (filet, mono, safran
   sur l'onglet actif) : on ne pose ici que la cible tactile. */
.km-onglet {
  display: inline-flex; align-items: center; min-height: 46px;
  cursor: pointer;
}
.km-compte-phrase {
  margin: 0 0 1.5rem; max-width: 60ch;
  font-size: .9375rem; line-height: 1.5rem; color: var(--km-t1);
}
.km-compte-sous-titre { margin: 2rem 0 1rem; }
.km-compte-form > .km-compte-sous-titre:first-of-type { margin-top: 0; }

.km-compte-grille {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1.25rem 1.5rem; align-items: start;
}
.km-champ { display: flex; flex-direction: column; min-width: 0; }
.km-champ-large { grid-column: 1 / -1; }
.km-champ .form-label { margin-bottom: .5rem; }

/* La section 35 rend les champs du tunnel transparents — c'était juste quand
   le tunnel n'en portait que deux. Le formulaire d'inscription en aligne
   quinze : on leur rend le corps de la section 40, et seulement à eux. */
#orderManager .km-compte .form-control,
#orderManager .km-compte .form-select,
#orderManager .km-config .form-control,
#orderManager .km-config .form-select,
#orderManager .km-promo .form-control { background-color: var(--km-plan-a); }
#orderManager .km-compte .form-control:focus,
#orderManager .km-compte .form-select:focus,
#orderManager .km-config .form-control:focus,
#orderManager .km-config .form-select:focus,
#orderManager .km-promo .form-control:focus { background-color: var(--km-plan-b); }

.km-compte-envoi {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem;
  margin-top: 1.75rem; padding-top: 1.5rem; border-top: 1px solid var(--km-l1);
}
.km-compte-note, .km-compte-mention {
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2); margin: 0;
}
.km-compte-mention { margin-top: 1rem; max-width: 62ch; }

/* ---------- 42.9 L'acceptation des conditions ----------
   La case est imbriquée dans son libellé : l'association ne dépend plus d'un
   « for » qui, l'identifiant « flexCheckDefault » étant imposé deux fois par
   le cœur sur la même page, désignait la mauvaise case. */
.km-consentement { margin: 1.25rem 0 0; }
.km-consentement-libelle {
  display: flex; align-items: flex-start; gap: .75rem;
  font-size: .875rem; line-height: 1.375rem; color: var(--km-t1);
  cursor: pointer; max-width: 62ch;
}
.km-consentement-case {
  flex: none; width: 18px; height: 18px; margin-top: .0625rem;
  accent-color: var(--km-ac); cursor: pointer;
}
.km-consentement-case:focus-visible { outline: 2px solid var(--km-ac); outline-offset: 3px; }

/* ---------- 42.10 Le panier ----------
   Deux colonnes : la liste à gauche, la somme à droite. Le montant du bas
   est la dernière chose lue avant le bouton, et c'est voulu. */

.km-panier {
  display: grid; grid-template-columns: minmax(0, 1fr) 20rem;
  gap: 0 3rem; align-items: start;
}
.km-panier-detail { min-width: 0; }

.km-panier-objet { display: flex; flex-direction: column; gap: .25rem; min-width: 0; }
.km-panier-titre {
  margin: 0; font-size: 1rem; line-height: 1.5rem; font-weight: 510;
  letter-spacing: -.01em; color: var(--km-t0);
}
.km-panier-titre-suite { font-weight: 400; color: var(--km-t1); font-size: .9375rem; }
.km-panier-mesures { display: flex; flex-wrap: wrap; gap: .375rem 1rem; margin: 0; }
.km-panier-mesure {
  display: inline-flex; align-items: center; gap: .375rem;
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2);
}
.km-panier-montant {
  display: flex; flex-direction: column; align-items: flex-end; gap: .125rem;
  margin: 0; text-align: right;
}
.km-panier-montant .km-valeur { font-size: 1.0625rem; line-height: 1.5rem; }
/* « del » n'est pas visé par la règle 37 : une déclaration directe suffit à
   battre l'héritage de la Sans posé sur le « p » parent. */
.km-panier-barre {
  font-family: var(--km-mono); font-variant-numeric: tabular-nums;
  font-size: .8125rem; color: var(--km-t2); text-decoration: line-through;
}

#orderManager .km-panier-retirer {
  flex: none; min-height: 38px; width: 38px; padding: 0;
  border: 1px solid var(--km-l1); border-radius: 4px;
  background: transparent; color: var(--km-t2);
}
#orderManager .km-panier-retirer:hover {
  border-color: var(--km-ko); color: var(--km-ko); background: transparent;
}

/* Les réponses au formulaire personnalisé passent sous la ligne, en retrait. */
.km-panier-choix {
  grid-column: 1 / -1; margin: .625rem 0 0; padding: .875rem 1rem;
  border-left: 1px solid var(--km-ac-bord); background: var(--km-plan-a);
}
.km-panier-choix-ligne { display: flex; gap: 1rem; align-items: baseline; }
.km-panier-choix-ligne dt { margin: 0; font-size: .8125rem; color: var(--km-t2); }
.km-panier-choix-ligne dd { margin: 0 0 0 auto; font-size: .8125rem; color: var(--km-t0); }

/* ---------- 42.11 Le code promotionnel ---------- */

.km-promo { margin-top: 1.75rem; padding-top: 1.5rem; border-top: 1px solid var(--km-l1); }
.km-promo-appel {
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: .875rem; color: var(--km-ac); text-decoration: none;
}
.km-promo-appel::before {
  content: ""; width: 10px; height: 1px; background: var(--km-ac);
  transition: width var(--km-d-micro) var(--km-e-micro);
}
.km-promo-appel:hover { text-decoration: none; color: var(--km-ac-h); }
.km-promo-appel:hover::before { width: 18px; }
.km-promo-champ { display: flex; gap: .625rem; max-width: 26rem; }
.km-promo-champ .form-control { flex: 1 1 auto; }
.km-promo-champ .btn { flex: none; }

/* ---------- 42.12 La somme ---------- */

.km-somme {
  display: flex; flex-direction: column; gap: 1rem;
  padding: 1.5rem; border: 1px solid var(--km-l2); border-radius: 5px;
  background: var(--km-plan-a);
}
.km-somme > .km-bloc-tete { margin-bottom: 0; }
.km-somme-lignes { display: flex; flex-direction: column; gap: .5rem; margin: 0; }
.km-somme-ligne { display: flex; align-items: baseline; gap: 1rem; }
.km-somme-ligne dt { margin: 0; font-size: .875rem; color: var(--km-t1); }
.km-somme-ligne dd { margin: 0 0 0 auto; font-size: .875rem; color: var(--km-t0); }
.km-somme-total {
  display: flex; align-items: baseline; gap: 1rem; margin: 0;
  padding-top: .875rem; border-top: 1px solid var(--km-l1);
}
.km-somme-montant { margin-left: auto; font-size: 1.625rem; line-height: 2rem; }

.km-somme-reglement {
  margin: 0; padding: 1.25rem 0 0; border: 0; border-top: 1px solid var(--km-l1);
}
.km-somme-reglement legend {
  float: none; width: auto; padding: 0; margin-bottom: .75rem;
}
.km-somme-note { margin: 0 0 .875rem; font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2); }
.km-somme-solde { display: flex; align-items: center; gap: .5625rem; color: var(--km-t1); }

.km-passerelles { display: flex; flex-wrap: wrap; gap: .625rem; margin-bottom: 1.25rem; }
#orderManager .km-passerelle { padding: .625rem .75rem; }
#orderManager .km-passerelle .btn-check:checked + .btn {
  box-shadow: inset 0 0 0 1px var(--km-ac); border-radius: 4px; color: var(--km-ac);
}
#orderManager .km-passerelle:has(.btn-check:checked) {
  border-color: var(--km-ac) !important; background: var(--km-ac-voile);
}

.km-somme-envoi { display: flex; flex-direction: column; gap: .75rem; }
.km-somme-envoi .btn { width: 100%; }
.km-somme-attente {
  display: flex; align-items: flex-start; gap: .5625rem; margin: 0;
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2);
}
.km-somme-attente .km-point { margin-top: .375rem; }
.km-somme-appui {
  display: flex; align-items: center; gap: .5rem; margin: 0;
  padding-top: 1rem; border-top: 1px solid var(--km-l1);
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2);
}

/* ---------- 42.13 Le voile d'attente ----------
   Le cœur pose un voile noir à 50 % et un GIF qui tourne. Le noir n'est pas
   une de nos couleurs et l'indicateur tournant est refusé depuis la section
   17 : on garde l'élément et son comportement, on remplace ce qu'on en voit
   par une réglure — la piste, et le segment de safran qui la parcourt. */
.loading {
  background: rgba(12, 13, 15, .78) !important;
  background: color-mix(in srgb, var(--km-fond) 82%, transparent) !important;
}
.loading img { display: none !important; }
.loading::before, .loading::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  height: 2px; margin-top: -1px;
}
.loading::before { width: 160px; margin-left: -80px; background: var(--km-l2); }
.loading::after {
  width: 48px; margin-left: -24px; background: var(--km-ac);
  animation: km-attente 1100ms var(--km-e-micro) infinite alternate;
}
@keyframes km-attente {
  from { transform: translateX(-56px); }
  to   { transform: translateX(56px); }
}

/* ---------- 42.14 Les tailles d'écran ---------- */

@media (max-width: 992px) {
  .km-panier { grid-template-columns: minmax(0, 1fr); gap: 2.5rem 0; }
  .km-jalons { grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: 1.25rem; }
}

@media (max-width: 768px) {
  /* Les jalons se replient en liste : un filet à gauche plutôt qu'en haut. */
  .km-jalons { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .km-jalon {
    padding: .875rem 0 .875rem 1rem;
    border-top: 0; border-left: 1px solid var(--km-l1);
  }
  .km-jalon-fait, .km-jalon-ici { border-left-color: var(--km-ac); }

  #orderManager .accordion-body ul.km-addons-liste > li,
  #orderManager .accordion-body ul.km-panier-lignes > li {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start; gap: .75rem 1rem;
  }
  .km-addon-prix, .km-addon-choix { grid-column: 1 / -1; }
  .km-addon-champ { min-width: 0; width: 100%; }
  .km-recap-montant, .km-somme-montant { font-size: 1.375rem; }
  .km-promo-champ { flex-direction: column; max-width: none; }
  .km-promo-champ .btn { width: 100%; }
  .km-config-suite .btn { width: 100%; }
}

@media (max-width: 576px) {
  .km-compte-grille { grid-template-columns: minmax(0, 1fr); }
  .km-tunnel-gouttiere { padding-top: 1.5rem; }
}

/* ---------- 42.15 Le mouvement ne s'impose à personne ---------- */

@media (prefers-reduced-motion: reduce) {
  .loading::after {
    animation: none; width: 160px; margin-left: -80px;
  }
  .km-promo-appel::before,
  #orderManager .km-addon-choix .btn { transition: none; }
}

/* ==== lot : ? ==== */
/* --------------------------------------------------------------------------
   50. LES SERVICES DU CLIENT — liste, fiche de service, modules de service
   Le client vient vérifier trois choses, dans cet ordre : ce qu'il a, dans
   quel état, jusqu'à quand. Le cartouche du haut répond aux trois, la fiche
   en dessous permet de tout vérifier ligne à ligne.

   Aucune classe nouvelle n'invente de grammaire : la fiche reprend le filet
   d'un pixel des tableaux, la clé reprend le plan des cartes, les onglets
   sont ceux de la section 14, et l'état reste le point de 7 px de la
   section 12 — la macro « status_badge » du cœur, jamais une pastille.

   VOCABULAIRE PARTAGÉ : « .km-champs », « .km-champ », « .km-champ-large »,
   « .km-note » et « .km-actions » sont également employés par le profil, la
   création de compte et le tunnel de commande. Les règles ci-dessous les
   définissent une fois pour toutes — à fondre avec celles des autres reprises
   plutôt qu'à dupliquer. « .km-champ » doit rester valable qu'il soit porté
   par un « div » enveloppant un « label for », ou par un « label » enveloppant
   directement son champ : d'où le simple « display: block ».
   -------------------------------------------------------------------------- */

/* ---------- 42.1 Les titres de section ----------
   L'étiquette de section devient un vrai titre de niveau 2 : la page ne doit
   compter qu'un seul H1, celui de l'ouverture. Reste à annuler les marges
   d'un titre, que l'étiquette n'attend pas. */
.km-section-tete h2,
.km-section-tete h3 { margin: 0; }

/* ---------- 42.2 La fiche : une clé en mesure, une valeur en parole ----------
   Deux colonnes, un filet par ligne. C'est le tableau de la section 11 privé
   de sa boîte : la donnée y est lue, pas comparée. */
.km-fiche {
  display: grid;
  grid-template-columns: minmax(9rem, 15rem) minmax(0, 1fr);
  margin: 0 0 .5rem;
}
.km-fiche > dt,
.km-fiche > dd {
  margin: 0;
  padding: .8125rem 1.5rem .8125rem 0;
  border-bottom: 1px solid var(--km-l1);
}
.km-fiche > dt {
  font-family: var(--km-mono);
  font-size: .6875rem;
  line-height: 1.375rem;
  font-weight: 400;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--km-t2);
}
.km-fiche > dd {
  padding-right: 0;
  color: var(--km-t0);
  font-size: .9375rem;
  line-height: 1.375rem;
}
.km-fiche > dt:last-of-type,
.km-fiche > dd:last-of-type { border-bottom: 0; }
.km-fiche > dd .km-prose p:last-child { margin-bottom: 0; }

/* ---------- 42.3 La mesure : dates, identifiants, adresses, montants ----------
   La Sans porte la parole, la Mono porte la mesure. Tout ce qui se recopie
   ou se compare passe ici. */
.km-donnee {
  font-family: var(--km-mono);
  font-variant-numeric: tabular-nums;
  font-size: .875rem;
  letter-spacing: -.01em;
  color: var(--km-t0);
}
.km-donnee-vide { color: var(--km-t2); }

/* Le complément d'une mesure — la période d'un montant, le délai d'une date. */
.km-appui-ligne {
  display: inline-block;
  margin-left: .625rem;
  font-family: var(--km-sans);
  font-size: .8125rem;
  line-height: 1.25rem;
  letter-spacing: 0;
  color: var(--km-t2);
}
/* Dans un tableau, la colonne est étroite : le complément passe sous la
   mesure plutôt que de forcer un retour à la ligne au milieu d'un montant. */
.km-console td .km-appui-ligne,
.km-service td .km-appui-ligne {
  display: block;
  margin-left: 0;
  margin-top: .1875rem;
}

/* ---------- 42.4 La clé : une donnée que l'on recopie ----------
   Un seul clic la sélectionne en entier ; c'est l'affordance la plus sûre,
   et elle ne demande pas une ligne de JavaScript. */
.km-cle-bloc {
  display: flex; flex-direction: column; gap: .625rem;
  margin: 0 0 2rem;
}
.km-cle-valeur {
  display: block;
  padding: .875rem 1rem;
  background: var(--km-plan-a);
  border: 1px solid var(--km-l1);
  border-radius: 5px;
  font-family: var(--km-mono);
  font-size: .9375rem;
  line-height: 1.5rem;
  letter-spacing: 0;
  color: var(--km-t0);
  word-break: break-all;
  user-select: all;
  -webkit-user-select: all;
}

/* Une suite de valeurs de même nature — adresses IP, domaines, versions. */
.km-liste-mono {
  display: flex; flex-direction: column; gap: .25rem;
  margin: 0; padding: 0; list-style: none;
  font-family: var(--km-mono);
  font-size: .875rem;
  line-height: 1.375rem;
  color: var(--km-t0);
}

/* ---------- 42.5 La phrase d'explication ----------
   Elle dit ce que l'action fait avant qu'on la fasse. Jamais plus large que
   la mesure de lecture. */
.km-note {
  max-width: 68ch;
  margin: 0 0 1.5rem;
  font-size: .9375rem;
  line-height: 1.5rem;
  color: var(--km-t1);
}
/* Le rappel qui accompagne un bouton dont l'état ne s'écrit pas : filet de
   safran, comme le chapeau des documents. */
.km-note-appui {
  padding-left: 1.25rem;
  border-left: 1px solid var(--km-ac-bord);
  font-size: .875rem;
  line-height: 1.375rem;
}

/* ---------- 42.6 La rangée d'actions ----------
   Séparée du contenu par un filet : on ne clique pas par inadvertance sur
   ce qui suit une phrase. */
.km-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: .75rem;
  margin-top: 1.75rem; padding-top: 1.5rem;
  border-top: 1px solid var(--km-l1);
}
.km-actions .btn { flex: none; }

/* ---------- 42.7 Les champs des modules de service ----------
   Deux colonnes tant que la place le permet, une seule ensuite. Les intitulés
   enveloppent leur champ : l'association ne dépend pas d'un identifiant. */
.km-champs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0 1.5rem;
  max-width: 46rem;
}
.km-champ { display: block; margin-bottom: 1.5rem; }
.km-champ-large { grid-column: 1 / -1; }
.km-champ > .form-label { display: block; margin-bottom: .5rem; }
/* Dans une fenêtre de demande, le dernier champ ne pousse pas le pied. */
.modal-body > .km-champ:last-child { margin-bottom: 0; }
/* La mention « facultatif » se lit dans la même mesure que l'intitulé ;
   elle s'en détache par un point médian, pas par une couleur plus pâle. */
.km-facultatif::before { content: "·"; margin: 0 .375rem; }

/* ---------- 42.8 Les onglets d'un module de service ---------- */
.km-onglets-corps { padding-top: 2rem; }
.km-service .nav-tabs .nav-link { text-decoration: none; }

/* ---------- 42.9 Le cartouche, quand il porte un état ou un lien ----------
   Le point de statut se cale sur la ligne des valeurs voisines. */
.km-cartouche-statut {
  display: flex; align-items: center;
  min-height: 1.6rem;
}
/* Un nom de domaine est une mesure : il reste en Mono, et son filet de safran
   dit qu'on peut cliquer — le second signal exigé en plus de la couleur. */
.km-valeur-lien {
  align-self: flex-start;
  color: var(--km-t0);
  text-decoration: none;
  border-bottom: 1px solid var(--km-ac-bord);
  transition: color var(--km-d-micro) var(--km-e-micro),
              border-color var(--km-d-micro) var(--km-e-micro);
}
.km-valeur-lien:hover {
  color: var(--km-ac); border-bottom-color: var(--km-ac); text-decoration: none;
}

/* Un bloc-tête qui ouvre un second temps dans le même onglet respire. */
.km-bloc-tete-espace { margin-top: 2.5rem; }

/* ---------- 42.10 La pagination de la liste ----------
   Le partiel du cœur ne rend rien tant qu'il n'y a qu'une page : la marge se
   porte donc sur la navigation elle-même, jamais sur son conteneur. */
.km-pagination nav { margin-top: 2rem; }

/* ---------- 42.11 Les tailles d'écran ---------- */
@media (max-width: 768px) {
  /* Six onglets ne tiennent pas sur une ligne étroite. Ils défilent
     horizontalement dans leur propre barre : la page, elle, ne défile pas. */
  .km-service .nav-tabs {
    flex-wrap: nowrap; overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .km-service .nav-tabs .nav-link { white-space: nowrap; }
}

@media (max-width: 576px) {
  /* La fiche se déplie : la clé au-dessus de sa valeur, un seul filet par
     ligne de donnée. */
  .km-fiche { grid-template-columns: minmax(0, 1fr); }
  .km-fiche > dt { padding: .8125rem 0 .25rem; border-bottom: 0; }
  .km-fiche > dd { padding: 0 0 .8125rem; }
  .km-champs { grid-template-columns: minmax(0, 1fr); }
  .km-actions .btn { width: 100%; }
  .km-cle-valeur { font-size: .875rem; }
}

/* ---------- 42.12 Mouvement réduit ---------- */
@media (prefers-reduced-motion: reduce) {
  .km-valeur-lien { transition: none; }
}
/* --------------------------------------------------------------------------
   44. AFFINAGE MESURÉ SUR TREIZE RÉFÉRENCES
   Relevé du 18 août 2026 sur linear.app, stripe.com, vercel.com, railway.app,
   scaleway.com, hetzner.com, fly.io, planetscale.com, supabase.com,
   tailwindcss.com, hostinger.com, ovhcloud.com et infomaniak.com — lecture de
   leurs feuilles de style, 10,4 Mio analysés, 2 813 déclarations de filet.

   CE QUE LA MESURE A CONFIRMÉ, et qu'on ne touche donc pas :
   · Le filet d'UN pixel est la norme : 74,6 % du corpus. Le sous-pixel est une
     curiosité (0,36 %), employé pour dessiner des vignettes, pas l'interface.
     Nos filets validés avaient raison.
   · Notre h1 à 56 px est exactement au barème (Linear 56, Vercel 56).
   · 200 ms pour la couleur est la valeur la plus fréquente du corpus.

   CE QUE LA MESURE A CORRIGÉ :
   · Un grand caractère n'a pas besoin de graisse. Vercel ramène son h1 à 400,
     Stripe compose ses titres en 300. Notre 590 à 56 px était le plus lourd
     du panel « fin ».
   · Aucun site ne laisse un grand titre à approche nulle. Linear serre de
     −0,022 em entre 32 et 72 px.
   · Notre interlignage de texte, 1,647, était le plus lâche du panel ; la
     valeur dominante est 1,5. L'épaisseur ressentie était verticale.
   · 760 ms n'existe nulle part dans le corpus : c'est au-delà du 96e centile.
     Le panel distingue l'entrée d'un élément (350 ms) de celle d'un bloc
     (600 ms). Une entrée qui dure encore quand l'œil a fini de lire pèse.
   · 260 ms n'apparaît que 2 fois sur 1 842 relevés ; 250 ms en compte 185.
   -------------------------------------------------------------------------- */

:root {
  /* L'entrée cesse d'être un seul geste trop long. 760 ms reste, réservé au
     seul tracé des figures, où la durée fait le dessin. */
  --km-d-entree-el:  350ms;
  --km-d-bloc:       600ms;
  --km-d-trace:      760ms;
  /* La distance d'entrée : 8 px pour un élément, 12 px pour un bloc. Les
     références translatent très peu — c'est là que se joue la finesse. */
  --km-dist-el:      8px;
  --km-dist-bloc:    12px;
  /* Le pas de cascade dominant du corpus. */
  --km-pas:          100ms;
}

/* 250 ms au lieu de 260 : même effet à l'œil, valeur que tout le monde emploie. */
:root { --km-d-elev: 250ms; }

/* ---- Les titres : moins de graisse, plus d'approche, interligne serré ---- */

h1, .h1 {
  font-weight: 510;
  line-height: 1.1;
  letter-spacing: -.022em;
}
h2, .h2 {
  font-size: 2rem;            /* 30 → 32 px : rétablit le rapport 1,75 du panel */
  line-height: 1.16;
  letter-spacing: -.018em;
}
h3, .h3 { letter-spacing: -.014em; }

/* ---- Le texte : l'interlignage descend de 1,647 à 1,53 ---- */
body { line-height: 26px; }
p, .km-prose, .km-doc-texte { line-height: 26px; }

/* ---- L'étiquette : +0,2 em désagrégeait le mot à 11 px ----
   Le plafond du corpus est +0,1 em (Tailwind, Vercel, Supabase) ; Fly compose
   ses badges monospace à +0,05 em. On garde le caractère de la maison sans
   disloquer les lettres. */
.km-etiquette, .form-label, .card-header h6, legend { letter-spacing: .12em; }

/* ---- Les chiffres : colonnes alignées et zéro barré ----
   Linear, Tailwind, Stripe et Vercel activent tous « tnum ». Pour un hébergeur
   qui affiche des prix, des quotas et des identifiants, c'est un gain net. */
body { font-feature-settings: "tnum" 1, "zero" 1; }
.km-valeur, .km-offre-montant, .km-prix, .km-mono, code,
.km-etiquette, .km-doc-repere-cle { font-variant-numeric: tabular-nums slashed-zero; }

/* ---- Le prix : grand ET léger, comme partout ailleurs ----
   Tout site qui grossit le prix allège la graisse : Vercel force 450,
   Supabase 400. Le nôtre était en 510 à 40 px. */
.km-offre-montant, .km-valeur { font-weight: 400; }
