/* ==========================================================================
   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.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: 'Plex Sans KM';
  src: url('/themes/kardox/assets/fonts/IBMPlexSans-Variable-latin.woff2') format('woff2-variations');
  font-weight: 100 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Plex Sans KM';
  /* IBM ne publie pas d'italique VARIABLE pour Plex Sans : on sert la coupe
     statique à 400, celle des <em> du corps de texte, sous-ensemble latin
     taillé sur les 232 mêmes points de code que la romaine. Les rares <em>
     dans un texte plus gras retombent sur l'oblique synthétique — écart
     assumé, et invisible aux corps où il se produit. */
  src: url('/themes/kardox/assets/fonts/IBMPlexSans-Italic-latin.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: 'Plex Mono KM';
  src: url('/themes/kardox/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('/themes/kardox/assets/fonts/IBMPlexMono-Medium-latin.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* Complément latin étendu et cyrillique.
   Les coupes ci-dessus sont taillées sur le français : elles ignorent le « ş »
   et le « ğ » du turc et du kurde, et tout le cyrillique de l'ukrainien. Trois
   de nos douze langues tombaient donc sur une police du système, au milieu
   d'une page dessinée dans la Plex.
   On ne retaille pas les coupes en place — leur dessin est celui qui est validé
   à l'écran. On ajoute une seconde coupe sous le MÊME nom de famille, bornée
   par « unicode-range » : le navigateur ne la demande que s'il rencontre un des
   signes qu'elle couvre. Un visiteur francophone ne la télécharge jamais.
   La portée est fixée par BLOCS entiers, non d'après les traductions du jour :
   une chaîne traduite demain ne rouvrira pas le trou. */
@font-face {
  font-family: 'Plex Sans KM';
  src: url('/themes/kardox/assets/fonts/IBMPlexSans-Variable-complement.woff2') format('woff2-variations');
  font-weight: 100 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-0130, U+0132-0151, U+0154-017F, U+0400-045F, U+0462-0463,
                 U+046A-046B, U+0472-0475, U+0490-04C2, U+04CF-04D9, U+04DC-04E9,
                 U+04EE-04F9, U+0524-0525, U+2116;
}
@font-face {
  font-family: 'Plex Mono KM';
  src: url('/themes/kardox/assets/fonts/IBMPlexMono-Regular-complement.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-0130, U+0132-0151, U+0154-017F, U+0400-045F, U+0462-0463,
                 U+046A-046B, U+0472-0475, U+0490-04C2, U+04CF-04D9, U+04DC-04E9,
                 U+04EE-04F9, U+0524-0525, U+2116;
}
@font-face {
  font-family: 'Plex Mono KM';
  src: url('/themes/kardox/assets/fonts/IBMPlexMono-Medium-complement.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-0130, U+0132-0151, U+0154-017F, U+0400-045F, U+0462-0463,
                 U+046A-046B, U+0472-0475, U+0490-04C2, U+04CF-04D9, U+04DC-04E9,
                 U+04EE-04F9, U+0524-0525, U+2116;
}

/* --------------------------------------------------------------------------
   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.75rem; letter-spacing: -.016em; }
h4, .h4 { font-size: 1.0625rem; line-height: 1.5rem; letter-spacing: -.012em; }
h5, .h5 { font-size: 1rem;     line-height: 1.5rem; letter-spacing: -.008em; font-weight: 510; }
h6, .h6 { font-size: .875rem;  line-height: 1.25rem; letter-spacing: -.004em; font-weight: 510; }

p { max-width: 68ch; }
.lead { font-size: 1.25rem; line-height: 1.875rem; letter-spacing: -.012em; color: var(--km-t1); font-weight: 400; }
small, .small { font-size: .8125rem; line-height: 1.25rem; }
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: 1.875rem;
  line-height: 2.25rem;
  font-weight: 400;
  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.25rem; line-height: 1.5rem;
  font-weight: 400; 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: .8125rem; }
.valid-feedback   { color: var(--km-ok); font-family: var(--km-mono); font-size: .8125rem; }
.form-text { color: var(--km-t2); font-family: var(--km-mono); font-size: .8125rem; }

.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-inline-end: 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-c) !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; }
/* Bootstrap peint un anneau bleu au CLIC sur toute croix de fermeture — y
   compris celles des trois fenêtres de demande, hors alertes. On l'éteint ;
   l'anneau safran de :focus-visible continue de marquer le focus clavier. */
.btn-close:focus { box-shadow: none; }
/* Le lien d'alerte restait en Bootstrap nu : graisse 700 (bannie) et cyan
   hors jetons. On le ramène à la gamme de la maison, pour celui du tableau
   de bord comme pour tout futur lien d'alerte. */
.alert .alert-link { font-weight: 510; color: var(--km-ac); }
.alert .alert-link:hover { color: var(--km-ac-h); }

/* 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: 44px; min-height: 44px;
  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-inline-start: 2px solid transparent !important; }
.email-list .list-group-item.active {
  background: var(--km-ac-voile) !important;
  border-inline-start-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);
  /* Le rayon de la maison est 5 px : les surfaces flottantes le suivent. */
  border-radius: 5px;
  box-shadow: var(--km-ombre-2);
  color: var(--km-t0);
}
/* La fenêtre modale se DÉTACHE : mesuré en sombre, « plan-a » (19,26,32)
   sous un voile noir à .62 se confondait avec la page — la fenêtre de
   paiement se lisait comme un ÉCRAN NOIR, texte flottant, sortie invisible.
   Un plan plus clair, un filet franc et une vraie ombre portée : c'est une
   fenêtre, elle doit se voir comme telle, dans les deux thèmes. */
.modal-content {
  /* le plan-c — le barreau le plus clair de l'échelle d'ardoise — et non
     plan-b : mesuré sous le voile, plan-b (#18212A) restait à un cheveu du
     fond assombri. */
  background-color: var(--km-plan-c);
  border-color: var(--km-l2);
  box-shadow: 0 32px 80px rgba(0, 0, 0, .55), 0 2px 8px rgba(0, 0, 0, .35);
}
[data-bs-theme="light"] .modal-content,
:root:not([data-bs-theme]) .modal-content { background-color: #FFFFFF; }
.modal-header, .modal-footer { border-color: var(--km-l1); }
.modal-title { font-size: 1.0625rem; font-weight: 590; letter-spacing: -.014em; }
/* Garde-fou : si un futur gabarit garde la classe « fs-5 » du cœur, son
   !important Bootstrap battrait la règle ci-dessus — on répond au même poids. */
.modal-title.fs-5 { font-size: 1.0625rem !important; }
.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: .8125rem; 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);
}

/* Au clavier, le choix d'une passerelle doit se voir : Bootstrap route le
   focus sur « .btn-check:focus-visible + .btn » avec une ombre jamais
   définie. On décline l'anneau du tunnel de commande. */
.invoice-gateway .btn-check:focus-visible + .btn {
  outline: 2px solid var(--km-ac);
  outline-offset: 2px;
}

.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-inline-end: .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-inline-start: 0; padding-inline-end: 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-inline-start: 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-inline-end: 1px solid var(--km-l1);
  display: flex; flex-direction: column; gap: .375rem;
}
.km-cartouche > div:last-child { border-inline-end: 0; }
.km-cartouche-action { justify-content: center; }
.km-valeur {
  font-family: var(--km-mono); font-size: 1.25rem; line-height: 1.5rem;
  font-weight: 400; 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-inline-start: 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-inline-start: .625rem;
  font-family: var(--km-mono); font-size: .8125rem; 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.25rem; line-height: 1.875rem; 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-inline-start: 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-inline-end: 0; border-bottom: 1px solid var(--km-l1); }
  .km-cartouche > div:last-child { border-bottom: 0; }
  .km-entete-actions { margin-inline-start: 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-inline-end: 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-inline-start: 40px; padding-inline-end: 24px;
  }
  .container > .container:has(#sidebarMenu) { margin-inline-start: 78px; max-width: none; }

  /* En-tête : une barre mince, alignée sur la même gouttière */
  body:has(#sidebarMenu) > .container > header { margin-inline-start: 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;
  }
  /* Le rail ne fait que 78 px : le verrouillage horizontal (rapport 3,91:1)
     ramené à 54 px de large ne ferait plus que 13,8 px de haut, illisible.
     « contain » ne le déforme pas, il le miniaturise. On sert donc le SYMBOLE
     seul, qui est presque carré (rapport 0,845:1) et tient toute la place. */
  body:has(#sidebarMenu) > .container > header .navbar-brand img { display: none; }
  body:has(#sidebarMenu) > .container > header .navbar-brand img.km-marque-mono {
    display: block; height: 38px;
  }
}

@media (min-width: 768px) and (max-width: 1200px) {
  .container > .container > .row > [class*="col-"]:not(:has(#sidebarMenu)) {
    padding-inline-start: 28px; padding-inline-end: 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; }
/* ATTENTION : ce « z-index: 1 » fait du conteneur un CONTEXTE D'EMPILEMENT —
   toute fenêtre modale écrite dans le contenu y serait enfermée SOUS le
   voile. kardox.js § 16 remonte chaque fenêtre au corps à l'ouverture. */

/* 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.375rem; 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-inline-start: 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-inline-start: 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: 10px; 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: 10px; 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-inline-start: 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-inline-start: 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-inline-end: 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-inline-start: 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-inline-start: 0; margin: 0; }
/* Le socle « sur les trois formules » garde la lettre de la vitrine :
   ni le carré de puce, ni la maille de 240 px ne doivent le rattraper. */
#orderManager .accordion-body ul:not(.km-socle-liste) li {
  display: flex; align-items: flex-start; gap: .75rem;
  font-size: .875rem; line-height: 1.375rem; color: var(--km-t1);
  padding: .375rem 0;
}
#orderManager .accordion-body ul:not(.km-socle-liste) 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,
/* Les mesures des cartes d'offre sont en Mono par dessein (économie, terme,
   montant) : on les exempte, sinon ce « !important » les ramène en Sans et
   les chiffres cessent d'être tabulaires. */
#orderManager .accordion-body span:not(.km-etiquette):not(.badge):not(.km-offre-economie):not(.km-offre-terme):not(.km-valeur):not(.km-compte-offres):not(.km-offre-sous-titre):not(.km-recommande) {
  font-family: var(--km-sans) !important;
  text-transform: none !important;
  letter-spacing: -.008em !important;
}
#orderManager .accordion-body ul:not(.km-socle-liste) { 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-inline-start: 0 !important; border-inline-start: 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-inline-start: 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.25rem; line-height: 1.875rem; 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-inline-start: 1px solid var(--km-l1);
}
.km-doc-sommaire li { margin: 0; }
.km-doc-sommaire a {
  display: block; margin-inline-start: -1px;
  padding: .4375rem 0 .4375rem 1rem;
  border-inline-start: 1px solid transparent;
  font-size: .8125rem; line-height: 1.25rem; 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-inline-start-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-inline-start-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.75rem; 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-inline-start: 1.25rem; border-inline-start: 1px solid var(--km-ac-bord);
  font-size: 1.0625rem; line-height: 1.75rem; 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-inline-start: 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-inline-start: 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: start;
  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-inline-end: 0; }

.km-doc-texte blockquote {
  margin: 1.5rem 0; padding-inline-start: 1.25rem;
  border-inline-start: 1px solid var(--km-l2); color: var(--km-t2);
}
.km-doc-texte code {
  font-family: var(--km-mono); font-size: .875rem;
  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.5rem;
  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-inline-start: 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-inline-start: 1.125rem;
  font-size: .875rem; line-height: 1.375rem; 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-inline-start: auto; font-family: var(--km-mono); font-size: .6875rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--km-t2);
}
.km-kb-ligne-fleche { margin-inline-start: 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.75rem; 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-inline-start: 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-inline-start: 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-inline-end: 2.5rem;
  background-position: right .875rem center;
}
/* La macro du cœur rend ses menus déroulants en « form-control » : Bootstrap
   leur retire la flèche native sans dessiner le chevron, réservé aux
   « form-select ». On leur donne le même chevron — CSS additif, le gabarit
   hérité n'est pas touché. */
select.form-control {
  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-repeat: no-repeat;
  background-size: 15px;
  background-position: right .875rem center;
  padding-inline-end: 2.5rem;
}
.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) {
  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-inline-end: .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: .8125rem; 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-inline-start: 2rem; }
.form-check-input {
  width: 1.25rem; height: 1.25rem; margin-inline-start: -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-inline-start: -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-inline-start: 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; }

/* --------------------------------------------------------------------------
   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.5rem; }

/* ---------- 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.75rem;
  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; }
}

/* --------------------------------------------------------------------------
   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-inline-start: 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-entete-nom h1.km-fil-sujet {
  margin: 0; max-width: 34ch;
  font-size: 1.5rem; 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-inline-start: auto;
  font-family: var(--km-mono); font-size: .8125rem; line-height: 1.25rem;
  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-inline-start: 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.3125rem; line-height: 1.75rem; }
.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-inline-start: 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-inline-start: 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: .8125rem;
  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-inline-start: 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: start; 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-inline-start: 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-inline-start: 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-inline-start: 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-inline-start: 0; }
  .km-fil-eux::after { left: -1rem; width: 1rem; }
  .km-fil-quand { margin-inline-start: 0; }
  .km-entete-nom h1.km-fil-sujet { font-size: 1.3125rem; 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; }
}

/* --------------------------------------------------------------------------
   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-inline-start: 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; }
}

/* --------------------------------------------------------------------------
   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-inline-start: .5rem;
  font-family: var(--km-mono); font-size: .8125rem; 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-inline-start: .625rem;
  font-variant-numeric: tabular-nums;
  color: var(--km-t2);
}
.km-onglet-nb::before {
  content: ""; display: inline-block;
  width: 1px; height: .75em; margin-inline-end: .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: end; 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-inline-start: 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-inline-start: 1.25rem; border-inline-start: 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: 1.875rem; 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.0625rem; 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, .invoice-thankyou, .invoice-banklink, .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-inline-start: 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; }
}

/* --------------------------------------------------------------------------
   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-inline-start: 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; }
}

/* --------------------------------------------------------------------------
   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); font-weight: 400; }
.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-inline-start: auto; font-size: 1.5rem; line-height: 2rem; }
.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.3125rem; 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.875rem; 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.0625rem; 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-inline-start: 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: end;
}
.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-inline-start: 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); font-weight: 400; }
.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); font-weight: 400; }
.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-inline-start: auto; font-size: 1.5rem; 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,
.km-passerelles .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-inline-start: -80px; background: var(--km-l2); }
.loading::after {
  width: 48px; margin-inline-start: -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-inline-start: 1px solid var(--km-l1);
  }
  .km-jalon-fait, .km-jalon-ici { border-inline-start-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.3125rem; }
  .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-inline-start: -80px;
  }
  .km-promo-appel::before,
  #orderManager .km-addon-choix .btn { transition: none; }
}

/* --------------------------------------------------------------------------
   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-inline-end: 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-inline-start: .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-inline-start: 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-service .km-note, .order-manage .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-inline-start: 1.25rem;
  border-inline-start: 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-service .km-actions, .order-manage .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-service .km-champs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0 1.5rem;
  max-width: 46rem;
}
.km-service .km-champ, .modal-body .km-champ { display: block; margin-bottom: 1.5rem; }
.km-champ-large { grid-column: 1 / -1; }
.km-service .km-champ > .form-label, .modal-body .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; }

/* La même calibration pour le reste du registre : les règles du même dessin
   — mono, capitales, 11-12 px — restées à +0,2 em. Les .14/.16/.18em
   délibérés ne bougent pas ; « .km-offre-appel », repassé en Sans par la
   section 38, n'est pas repris. */
.block.pricing p,
#sidebarMenu h5,
.table > thead > tr > th,
.card-body table > thead > tr > th,
.h-block h2,
.nav-tabs .nav-link,
.km-puce,
#orderManager h4, #orderManager h5,
.km-doc-repere-cle,
.km-doc-texte thead th,
.km-kb-carte-appel,
.km-actu-date,
.km-actu-appel,
.km-fil-texte.markdown-body th,
.km-dl dt,
.km-jalon-etat,
.km-fiche > dt { 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; }

/* ---- Harmonisations relevées à l'audit : des ajouts par-dessus ----
   Rien n'est réécrit plus haut : chaque règle reprend la main plus bas
   dans la cascade, sur un réglage resté en deçà des planchers. */

/* Le sommaire collant des documents dépassait la fenêtre sur les longues
   pages : borné à la hauteur visible, il défile dans sa propre colonne. */
.km-doc-sommaire { max-height: calc(100vh - 3rem); overflow-y: auto; }
@media (max-width: 992px) {
  /* Rangé dans le flux (position: static), il reprend sa hauteur naturelle. */
  .km-doc-sommaire { max-height: none; }
}

/* Aucune cible manipulable sous 44 px : le bouton court remonte au plancher. */
.btn-sm { min-height: 44px; }

/* ==========================================================================
   LA MARQUE
   Le verrouillage horizontal et le favicon viennent du dossier de remise et
   sont servis TELS QUELS. Le logo de société est administré : il est chargé
   dans les réglages FOSSBilling, en deux versions (clair et sombre), et le
   gabarit les sert déjà. Seul le monogramme est posé ici, parce que le rail
   replié ne fait que 78 px : un verrouillage de 5,31:1 y tomberait à 10 px de
   haut, illisible.
   ========================================================================== */
/* Piège de cascade, mesuré sur la page de commande : « .navbar-brand img »
   pose « display: block » avec un poids de (0,1,1), alors qu'une classe seule
   ne pèse que (0,1,0). Le monogramme restait donc visible partout, à côté du
   logo. Il faut au moins autant de poids pour le cacher. */
.navbar-brand img.km-marque-mono,
img.km-marque-mono {
  display: none;
  width: auto; height: auto; flex: none;
  aspect-ratio: 1 / 1;
  align-self: center;
}


/* ==========================================================================
   51. LA MÊME MAIN QUE LA VITRINE
   Les deux sites partagent la grammaire, mais trois réglages calibrés sur
   kardoxmedia.com n'avaient jamais été reportés ici. On les aligne — sans
   rien retirer de ce qui existe.
   ========================================================================== */

/* ---- 51.1 La trame d'ingénieur, à la maille de la vitrine ----
   Relevé sur l'accueil : la maille est passée de 52 à 68 px (un tiers de
   lignes en moins) et, sur le papier, le trait est descendu à un demi-pixel
   à 1,6 % d'encre — au-dessus, le quadrillage salissait les grandes surfaces
   claires. L'ardoise garde le trait plein, validé tel quel. */
body { background-size: 68px 68px; }
[data-bs-theme="light"] body {
  background-image:
    linear-gradient(rgba(14, 20, 24, .016) .5px, transparent .5px),
    linear-gradient(90deg, rgba(14, 20, 24, .016) .5px, transparent .5px);
}

/* ---- 51.2 Le compte des offres ----
   Remplace la pastille « badge bg-info » de Bootstrap, bannie par la
   grammaire : une mesure se dit en Mono, sans fond de couleur. */
.km-compte-offres {
  font-family: var(--km-mono); font-size: .8125rem;
  letter-spacing: .04em; color: var(--km-t2);
  font-variant-numeric: tabular-nums;
}
.km-compte-offres::before { content: "· "; color: var(--km-l2); }

/* ---- 51.3 La flèche du bouton « Haut » ----
   Le sprite de la maison n'a qu'une flèche, tournée vers la droite : elle
   pivote d'un quart de tour plutôt que d'ajouter un second dessin. */
.km-icone-haut { transform: rotate(-90deg); }

/* ---- 51.4 Le serment, sur les cartes de commande ----
   Repris au pixel de l'accueil (#tarifs .km-offre-serment) : un filet,
   la coche safran, et la phrase qui tient toute la promesse. */
.km-offres-cmd .km-offre-serment {
  display: flex; align-items: flex-start; gap: .5rem;
  margin-top: 1rem; padding-top: .875rem;
  border-top: 1px solid var(--km-l1);
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t1);
}
.km-offres-cmd .km-offre-serment .km-icone { color: var(--km-ac); flex: none; margin-top: .125rem; }


/* ==========================================================================
   52. LES CARTES DE COMMANDE, À L'IDENTIQUE DE L'ACCUEIL
   Règles RECOPIÉES de site-vitrine/assets/css/vitrine.css — pas réécrites :
   même sélecteur de durée, mêmes quatre jeux de prix, même prix barré, même
   pastille d'économie, même mention du montant payé d'avance. Seuls les
   ancrages changent : « #tarifs » devient « .km-offres-cmd » et la bascule
   « :has() » s'accroche à l'accordéon « #products ».
   ========================================================================== */

/* ---------- Les tarifs ---------- */ .km-duree { border: 0; padding: 0; margin: 0 0 2.5rem; min-width: 0; }
.km-duree > .km-etiquette { float: none; width: auto; padding: 0; margin-bottom: .875rem; display: inline-flex; align-items: center; gap: .5rem; font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .2em; text-transform: uppercase; color: var(--km-t2); }
.km-duree-rang { display: inline-flex; flex-wrap: wrap; gap: .375rem; padding: .375rem; border: 1px solid var(--km-l1); border-radius: 5px; background: var(--km-plan-a); }
.km-duree-choix { display: inline-flex; }
.km-duree-radio { position: absolute; opacity: 0; width: 1px; height: 1px; }
.km-duree-btn { display: inline-flex; align-items: center; gap: .5rem; min-height: 44px; padding: 0 1rem; border-radius: 4px; font-size: .9375rem; font-weight: 510; letter-spacing: -.006em; color: var(--km-t1); cursor: pointer; transition: color var(--km-d-micro) var(--km-e-micro), background-color var(--km-d-micro) var(--km-e-micro); }
.km-duree-carre { width: 6px; height: 6px; flex: none; border: 1px solid var(--km-l3); background: transparent; transition: background-color var(--km-d-micro) var(--km-e-micro), border-color var(--km-d-micro) var(--km-e-micro); }
.km-duree-btn:hover { color: var(--km-t0); background: var(--km-plan-b); }
.km-duree-radio:checked + .km-duree-btn { color: var(--km-t0); background: var(--km-plan-c); }
.km-duree-radio:checked + .km-duree-btn .km-duree-carre { background: var(--km-ac); border-color: var(--km-ac); }
.km-duree-radio:focus-visible + .km-duree-btn { outline: 2px solid var(--km-ac); outline-offset: 2px; }
.km-duree-note { margin: .875rem 0 0; font-size: .8125rem; color: var(--km-t2); }
.km-offre-jeux { display: contents; }
/* Sans JavaScript, les quatre durées restent lisibles l'une sous l'autre : aucun prix n'est caché derrière un script. Avec, on n'affiche que la durée choisie. */ /* Le changement de durée se fait en CSS PUR, par « :has() » sur le bouton radio coché. Deux raisons. D'abord la page reste entière sans JavaScript : un prix ne doit jamais dépendre d'un script. Ensuite le script livré cherchait « .km-v-duree-champ » quand le balisage porte « .km-duree-radio » — les deux moitiés ne se parlaient pas, et AUCUN prix ne s'affichait. Par défaut c'est la durée d'un an qui paraît : c'est le bouton coché dans le balisage, donc ce que voit un navigateur sans « :has() ». */ .km-offre-jeu { display: none; flex-direction: column; gap: .25rem; }
.km-offre-jeu[data-duree="a"] { display: flex; }
#products:has(#km-duree-m:checked) .km-offre-jeu[data-duree="a"], #products:has(#km-duree-bia:checked) .km-offre-jeu[data-duree="a"], #products:has(#km-duree-tria:checked) .km-offre-jeu[data-duree="a"] { display: none; }
#products:has(#km-duree-m:checked) .km-offre-jeu[data-duree="m"], #products:has(#km-duree-bia:checked) .km-offre-jeu[data-duree="bia"], #products:has(#km-duree-tria:checked) .km-offre-jeu[data-duree="tria"] { display: flex; }
.km-offre-barre { margin-inline-start: .5rem; font-size: .9375rem; color: var(--km-t2); }
.km-offre-barre s { text-decoration-thickness: 1px; text-underline-offset: 2px; }
.km-offre-economie { font-family: var(--km-mono); font-size: .75rem; letter-spacing: .04em; color: var(--km-ac); }
.km-offre-economie-nulle { color: var(--km-t2); }
@media (max-width: 767px) {
  .km-duree-rang { display: flex; width: 100%; }
  .km-duree-choix { flex: 1 1 auto; }
  .km-duree-btn { width: 100%; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .km-barre, .km-duree-btn, .km-duree-carre, .km-q-signe, .km-q-signe::after { transition: none; }
}
.km-offre-jeu { animation: km-prix-pose 320ms var(--km-e-sortie) both; }
.km-offre-jeu .km-offre-economie { animation: km-econo-pose 420ms var(--km-e-couleur) 120ms both; }
/* Le filet du sélecteur suit le choix : l'option active pousse un trait d'accent sous elle, qui glisse au lieu de sauter. */ .km-duree-btn { position: relative; }
.km-duree-btn::after { content: ""; position: absolute; left: .875rem; right: .875rem; bottom: 5px; height: 1px; background: var(--km-ac); transform: scaleX(0); transform-origin: center; transition: transform var(--km-d-couleur) var(--km-e-sortie); }
.km-duree-radio:checked + .km-duree-btn::after { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) {
  .km-offre-jeu, .km-offre-jeu .km-offre-economie { animation: none; }
  .km-duree-btn::after { transition: none; }
}
.km-offres-cmd .km-offre-barre { margin-inline-start: 0; font-size: .875rem; color: var(--km-t2); }
.km-offres-cmd .km-offre-barre s { text-decoration-color: var(--km-t2); }
/* L'économie devient une pastille sobre — un filet, pas un fond criard. */ .km-offres-cmd .km-offre-economie { display: inline-flex; align-items: center; align-self: flex-start; margin-top: .625rem; padding: .1875rem .5rem; border: 1px solid var(--km-ac-bord); border-radius: 3px; font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .06em; color: var(--km-ac); }
.km-offres-cmd .km-offre-economie-nulle { border-color: var(--km-l1); color: var(--km-t2); }
.km-offres, .km-tuiles, .km-services-grille, .km-duree, .km-argus { margin-top: 0; margin-bottom: 0; }
.km-barre-bascule, .km-duree-choix { position: relative; overflow: hidden; }
.km-haut::after, .km-barre-bascule::after, .km-duree-choix::after { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0; border-radius: inherit; background: radial-gradient(120px circle at var(--km-mx, 50%) var(--km-my, 50%), var(--km-ac-voile2), transparent 62%); transition: opacity var(--km-d-couleur) var(--km-e-couleur); }
.km-haut:hover::after, .km-barre-bascule:hover::after, .km-duree-choix:hover::after { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .km-haut::after, .km-barre-bascule::after, .km-duree-choix::after { display: none; }
}
/* ========================================================================== LES CARTES DE TARIF — PLUS DE DÉTAIL, MÊME LANGAGE Reprises des cartes du marché, trois idées seulement, et rien d'autre : · les caractéristiques sont GROUPÉES sous de petits intitulés, au lieu d'une liste unique où tout a le même poids ; · ce qui N'EST PAS inclus est écrit dans la carte, avec son propre signe. C'est le point le plus utile de tous : personne n'affiche ses manques, et c'est exactement la promesse de la maison — on le dit avant ; · chaque durée annonce ce qu'elle coûte EN TOUT et rappelle que le renouvellement se fait au même tarif. Ce qui n'est pas repris : le fond de couleur sur la formule vedette. Elle se distingue par le trait et l'élévation, pas par un aplat violet. ========================================================================== */ /* Les groupes et leurs intitulés */ .km-offre-groupe { display: block; margin-top: 1.25rem; padding-top: 1.25rem; border-top: 1px solid var(--km-l0); }
.km-offre-sous-titre { display: block; margin-bottom: .75rem; font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .12em; text-transform: uppercase; color: var(--km-t2); }
/* Le total du terme : la ligne que personne n'écrit et que tout le monde cherche. En monospace, comme tous les chiffres vérifiables du site. */ .km-offre-terme { display: block; margin-top: .375rem; font-family: var(--km-mono); font-size: .6875rem; line-height: 1.125rem; letter-spacing: .04em; color: var(--km-t2); }

/* ---- 52.1 Ce que la recopie n'a pas emporté ----
   Deux réglages de l'accueil se perdaient : la grille des offres y tient
   TROIS colonnes (jamais deux plus une, réglage validé le 18 août), et la
   Mono des mesures était battue ici par une règle plus spécifique. */
@media (min-width: 1000px) {
  .km-offres-cmd { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 999.98px) {
  .km-offres-cmd { grid-template-columns: minmax(0, 1fr); }
}
.km-offres-cmd .km-offre-economie,
.km-offres-cmd .km-offre-terme {
  font-family: var(--km-mono);
  font-variant-numeric: tabular-nums;
}
.km-offres-cmd .km-offre-economie { color: var(--km-ac); }
.km-offres-cmd .km-offre-economie-nulle { color: var(--km-t2); }
.km-offres-cmd .km-offre-terme { color: var(--km-t2); }


/* ==========================================================================
   53. LES DOUZE LANGUES
   L'espace client sert douze langues, dont trois écritures que le
   sous-ensemble latin de Plex ne couvre pas. IBM publie les familles
   correspondantes : même dessin, même graisse, même métrique — la page ne
   change pas de main quand elle change de langue.
   ========================================================================== */

@font-face {
  font-family: 'Plex Arabe KM';
  src: url('/themes/kardox/assets/fonts/IBMPlexSansArabic-latin-arabe.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Plex Coréen KM';
  src: url('/themes/kardox/assets/fonts/IBMPlexSansKR-sous-ensemble.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Plex Chinois KM';
  src: url('/themes/kardox/assets/fonts/IBMPlexSansSC-sous-ensemble.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}

/* ---- 53.1 La pile de polices suit la langue du document ----
   La famille latine reste EN TÊTE partout : les prix, les codes et les
   mesures restent dans la Plex de la maison, quelle que soit la langue. */
:root:lang(ar), :root:lang(fa) {
  --km-sans: 'Plex Sans KM', 'Plex Arabe KM', system-ui, sans-serif;
}
:root:lang(ko) {
  --km-sans: 'Plex Sans KM', 'Plex Coréen KM', system-ui, sans-serif;
}
:root:lang(zh) {
  --km-sans: 'Plex Sans KM', 'Plex Chinois KM', system-ui, sans-serif;
}

/* ---- 53.2 Les trois écritures de droite à gauche ----
   Le sens est posé sur <html> par le gabarit ; le navigateur retourne alors
   seul les colonnes flex, l'alignement et l'ordre de lecture. Restent les
   quelques dessins calés en dur — on les retourne ici. */
[dir="rtl"] .km-icone-haut { transform: rotate(90deg); }
[dir="rtl"] .km-fleche-droite,
[dir="rtl"] .km-offre-appel svg,
[dir="rtl"] .km-lien-fleche svg { transform: scaleX(-1); }
[dir="rtl"] .km-haut { right: auto; left: 1.5rem; }
[dir="rtl"] .toast-container { right: auto; left: 1rem; }
[dir="rtl"] .km-compte-offres::before { content: " ·"; }

/* Le quadrillage et les filets sont symétriques : rien à retourner.
   Les chiffres restent lus de gauche à droite, y compris en arabe et en
   persan — c'est la règle de l'écriture arabe pour les nombres. */
[dir="rtl"] .km-valeur,
[dir="rtl"] .km-offre-montant,
[dir="rtl"] .km-ref,
[dir="rtl"] time { direction: ltr; unicode-bidi: isolate; }

/* ---- 53.3 Les langues à idéogrammes ----
   Le coréen et le chinois n'ont pas de bas de casse : le crénage négatif
   et la casse forcée des étiquettes latines n'ont pas de sens pour eux. */
:lang(ko) .km-etiquette, :lang(zh) .km-etiquette {
  letter-spacing: .06em; text-transform: none;
}
:lang(ko) body, :lang(zh) body { letter-spacing: 0; }

/* ---- 52.2 L'appel à l'action suit la durée ----
   La carte n'est plus un lien : elle porte quatre appels, un par durée, dont
   un seul paraît — la même bascule « :has() » que les jeux de prix. Le survol
   et le focus se règlent donc sur la carte ET sur l'appel visible. */
.km-offres-cmd .km-offre-appels { display: contents; }
.km-offres-cmd .km-offre-appel[data-duree] { display: none; }
.km-offres-cmd .km-offre-appel[data-duree="a"] { display: flex; }
#products:has(#km-duree-m:checked)    .km-offre-appel[data-duree="a"],
#products:has(#km-duree-bia:checked)  .km-offre-appel[data-duree="a"],
#products:has(#km-duree-tria:checked) .km-offre-appel[data-duree="a"] { display: none; }
#products:has(#km-duree-m:checked)    .km-offre-appel[data-duree="m"],
#products:has(#km-duree-bia:checked)  .km-offre-appel[data-duree="bia"],
#products:has(#km-duree-tria:checked) .km-offre-appel[data-duree="tria"] { display: flex; }

/* La carte n'étant plus cliquable en entier, c'est l'appel qui porte le
   survol et le focus. Le reste du dessin ne change pas. */
.km-offres-cmd .km-offre:has(.km-offre-appel:hover),
.km-offres-cmd .km-offre:has(.km-offre-appel:focus-visible) {
  border-color: var(--km-l2);
}
.km-offres-cmd .km-offre-appel:focus-visible {
  outline: 2px solid var(--km-ac); outline-offset: 2px; border-radius: 3px;
}

/* ---- 52.3 Le focus sur le choix de passerelle ----
   Le radio est masqué par Bootstrap : c'est son étiquette qui doit montrer
   qu'il a le focus, sinon un client au clavier ne sait pas où il est. */
.invoice-gateway .btn-check:focus-visible + .btn {
  outline: 2px solid var(--km-ac); outline-offset: 2px;
}
.invoice-gateway .btn-check:checked + .btn {
  box-shadow: inset 0 0 0 1px var(--km-ac);
}

/* ==========================================================================
   54. LE MENU DES LANGUES — TRANSFÉRÉ DE LA VITRINE
   Le bloc est la COPIE de celui de vitrine.css (« La langue du site »), avec
   les trois seules adaptations que le contexte impose : les rangs sont des
   <button> et non des liens (le cœur ne lit la langue que dans le cookie
   « fb_locale », il n'existe pas d'adresse par langue) ; le panneau change
   de côté en écriture droite-à-gauche ; « --km-t3 », propre à la vitrine,
   devient « --km-t2 ». Rien d'autre ne diffère.
   ========================================================================== */
.km-langue { position: relative; }
.km-langue summary { list-style: none; }
.km-langue summary::-webkit-details-marker { display: none; }
.km-langue-declencheur {
  display: inline-flex; align-items: center; gap: .5rem;
  height: 44px; padding: 0 .875rem;
  border: 1px solid var(--km-l1); border-radius: 999px;
  color: var(--km-t1); cursor: pointer; user-select: none;
}
.km-langue-declencheur:hover { color: var(--km-t0); border-color: var(--km-ac-bord); background: var(--km-plan-b); }
.km-langue[open] .km-langue-declencheur { color: var(--km-t0); border-color: var(--km-ac-bord); }
.km-drapeau { display: block; border-radius: 2px; }
.km-langue-code {
  font-family: 'Plex Mono KM', monospace; font-size: .75rem;
  letter-spacing: .08em; color: var(--km-t2);
}
.km-langue-declencheur .km-langue-code { color: inherit; }
.km-langue-chevron { width: 12px; height: 8px; transition: transform .15s ease; }
.km-langue[open] .km-langue-chevron { transform: rotate(180deg); }
.km-langue-panneau {
  position: absolute; right: 0; top: calc(100% + .625rem); z-index: 60;
  min-width: 16.5rem; max-width: calc(100vw - 2rem);
  background: var(--km-plan-a); border: 1px solid var(--km-l1);
  border-radius: 5px; box-shadow: 0 18px 40px rgba(0, 0, 0, .35);
}
.km-langue-liste {
  list-style: none; margin: 0; padding: .375rem;
  max-height: min(70vh, 33rem); overflow-y: auto;
}
.km-langue-choix {
  /* ici le rang est un <button> : on efface l'habit de bouton du navigateur */
  width: 100%; background: none; border: 0; font: inherit; text-align: start;
  cursor: pointer;
  display: flex; align-items: center; gap: .75rem;
  min-height: 48px; padding: .375rem .75rem; border-radius: 4px;
  color: var(--km-t1); text-decoration: none;
}
.km-langue-choix:hover { background: var(--km-plan-b); color: var(--km-t0); text-decoration: none; }
.km-langue-choix .km-langue-code { min-width: 2.25ch; }
.km-langue-nom { font-size: .9375rem; }
.km-langue-exonyme { color: var(--km-t2); font-size: .8125rem; }
.km-langue-choix[aria-current] { background: var(--km-ac-voile); color: var(--km-ac); }
.km-langue-choix[aria-current] .km-langue-code { color: var(--km-ac); }
.km-langue-choix[aria-current] .km-langue-exonyme { color: var(--km-ac); opacity: .75; }
[dir="rtl"] .km-langue-panneau { right: auto; left: 0; }
@media (prefers-reduced-motion: reduce) {
  .km-langue-chevron { transition: none; }
}

/* Le pictogramme devant chaque caractéristique — recopié de la vitrine
   (#tarifs y devient le conteneur des cartes de commande). */
.km-offres .km-point-icone,
.km-config .km-point-icone { color: var(--km-t2); margin-top: .0625rem; transition: color var(--km-d-micro) var(--km-e-micro); flex: 0 0 auto; }
.km-offres .km-offre:hover .km-point-icone,
.km-offres .km-offre-vedette .km-point-icone { color: var(--km-ac); }

/* ==========================================================================
   55. LA CONFIGURATION PARLE LA LANGUE DES CARTES · LES JALONS SUR UNE LIGNE
   Rien d'inventé : le sélecteur de durée et le jeu de prix sont ceux de la
   vitrine, posés sur le formulaire de configuration — les radios PORTENT le
   champ « period ». La bascule est le même « :has() » que les cartes : la
   durée par défaut (l'année) reste visible sans lui, rien ne disparaît.
   ========================================================================== */
.km-config-duree { border: 0; margin: 0 0 .25rem; padding: 0; }
.km-config-jeux { display: block; margin-top: 1rem; }
.km-config-jeux .km-offre-jeu { display: none; }
.km-config-jeux .km-offre-jeu[data-periode="1Y"] { display: flex; }
.km-config-duree:has(#km-periode-1M:checked) .km-offre-jeu[data-periode="1Y"],
.km-config-duree:has(#km-periode-2Y:checked) .km-offre-jeu[data-periode="1Y"],
.km-config-duree:has(#km-periode-3Y:checked) .km-offre-jeu[data-periode="1Y"] { display: none; }
.km-config-duree:has(#km-periode-1M:checked) .km-offre-jeu[data-periode="1M"],
.km-config-duree:has(#km-periode-2Y:checked) .km-offre-jeu[data-periode="2Y"],
.km-config-duree:has(#km-periode-3Y:checked) .km-offre-jeu[data-periode="3Y"] { display: flex; }

/* Le document complet de l'offre, replié : un trait discret, pas un bouton. */
.km-config-tout { margin-top: 1.25rem; border-top: 1px solid var(--km-l1); padding-top: .875rem; }
.km-config-tout summary {
  cursor: pointer; list-style: none;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--km-t2);
}
.km-config-tout summary::-webkit-details-marker { display: none; }
.km-config-tout summary::after { content: " +"; color: var(--km-ac); }
.km-config-tout[open] summary::after { content: " −"; }
.km-config-tout summary:hover { color: var(--km-t0); }
.km-config-tout .km-config-desc { margin-top: 1rem; }

/* Les jalons tenaient sur trois lignes — deux mots, saut de ligne, du vide.
   Une seule ligne : le nom, la note en retrait, l'état au bout. */
.km-jalon { flex-direction: row; align-items: baseline; flex-wrap: wrap; gap: .5rem .625rem; }
.km-jalon-tete { align-items: baseline; }
.km-jalon-note { color: var(--km-t2); }
.km-jalon-note::before { content: "· "; color: var(--km-t3, var(--km-t2)); }
.km-jalon-etat { margin-top: 0; margin-inline-start: auto; }

/* ==========================================================================
   56. LES RETOUCHES DE LA REVUE DU TUNNEL
   Un pictogramme OU une puce, jamais les deux · l'état des jalons en carré ·
   la flèche des listes déroulantes visible dans les deux thèmes · le domaine
   saisi à gauche en grand · l'outillage du mot de passe.
   ========================================================================== */

/* ---- 56.1 Un pictogramme suffit : la puce carrée se retire devant lui ---- */
.km-point-offre:has(.km-point-icone)::before { display: none; }

/* ---- 56.2 L'état des jalons : un carré, plus un mot ----
   Plein = fait · contour safran qui respire = en cours · contour discret =
   à venir. Le mot reste dans la page pour les lecteurs d'écran. */
.km-jalon-carre {
  width: 8px; height: 8px; flex: none;
  border: 1px solid var(--km-l1); background: transparent;
  margin-inline-start: auto; align-self: center;
}
.km-jalon-fait .km-jalon-carre { background: var(--km-ac); border-color: var(--km-ac); }
.km-jalon-ici .km-jalon-carre { border-color: var(--km-ac); animation: km-jalon-souffle 2.2s ease-in-out infinite; }
@keyframes km-jalon-souffle {
  0%, 100% { box-shadow: 0 0 0 0 transparent; background: transparent; }
  50% { box-shadow: 0 0 0 3px var(--km-ac-voile); background: var(--km-ac-voile); }
}
/* le filet du jalon en cours se trace à l'arrivée — discret, une fois */
.km-jalon-ici { position: relative; }
.km-jalon-ici::after {
  content: ""; position: absolute; top: -1px; left: 0; height: 1px;
  background: var(--km-ac); width: 100%;
  animation: km-jalon-trace .9s var(--km-e-entree, ease-out) both;
}
@keyframes km-jalon-trace { from { width: 0; } to { width: 100%; } }
@media (prefers-reduced-motion: reduce) {
  .km-jalon-ici .km-jalon-carre { animation: none; background: var(--km-ac-voile); }
  .km-jalon-ici::after { animation: none; }
}

/* ---- 56.3 La flèche des listes déroulantes, dans les deux thèmes ----
   Bootstrap la dessine dans une image de fond à couleur FIGÉE : elle
   disparaissait en clair. On la retrace dans l'encre du thème courant. */
.form-select,
[data-bs-theme="light"] .form-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23A1590C' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
[data-bs-theme="dark"] .form-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23F2A93B' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* Même mal, même remède pour le chevron des accordéons : la coupe servie ne
   le définit qu'en sombre (et en bleu Bootstrap) — en clair il n'existait
   pas. Retracé dans le safran du thème ; l'état ouvert garde la même image,
   Bootstrap ne fait que la tourner. */
.accordion-button::after,
.accordion-button:not(.collapsed)::after,
[data-bs-theme="light"] .accordion-button::after,
[data-bs-theme="light"] .accordion-button:not(.collapsed)::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23A1590C' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-size: 12px 8px; background-position: center;
}
[data-bs-theme="dark"] .accordion-button::after,
[data-bs-theme="dark"] .accordion-button:not(.collapsed)::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23F2A93B' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-size: 12px 8px; background-position: center;
}

/* ---- 56.4 Le domaine : la saisie à gauche, grande ; les onglets à droite ---- */
.km-domaine { display: flex; gap: 2rem; align-items: flex-start; }
/* les utilitaires « order-* » et « flex-grow-1 » manquent à cette coupe de
   Bootstrap : l'ordre et les parts sont posés ICI, explicitement */
.km-domaine-panneaux { order: 1; flex: 1 1 auto; min-width: 0; }
.km-domaine-onglets { order: 2; }
.km-domaine-titre { margin: 2rem 0 1rem; }
.km-domaine-panneaux .form-label { font-weight: 510; color: var(--km-t0); }
.km-domaine-panneaux .input-group { width: 100%; }
.km-domaine-panneaux .form-control { min-height: 48px; font-size: 1rem; }
.km-domaine-panneaux .form-select { min-height: 48px; }
.km-domaine-onglets {
  flex: 0 0 auto; max-width: 15rem; border: 0; padding-inline-start: 1rem;
  border-inline-start: 1px solid var(--km-l1);
}
.km-domaine-onglets .nav-link {
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--km-t2);
  border-radius: 4px; padding: .5rem .75rem; background: none;
}
.km-domaine-onglets .nav-link:hover { color: var(--km-t0); background: var(--km-plan-b); }
.km-domaine-onglets .nav-link.active { color: var(--km-ac); background: var(--km-ac-voile); }
@media (max-width: 768px) {
  .km-domaine { flex-direction: column; }
  .km-domaine-onglets { border-inline-start: 0; padding-inline-start: 0; flex-direction: row !important; }
}

/* ---- 56.5 Le mot de passe : l'œil, la copie, le générateur, les critères ---- */
.km-champ-tete {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  /* hauteur STABLE : avec ou sans puce « Générer », les deux boîtes d'une
     même rangée gardent leurs bords au même niveau. */
  min-height: 2.125rem;
}
/* Le conteneur ne peint RIEN : le champ garde exactement son habit — quel
   qu'il soit sur cette page — et les outils se posent PAR-DESSUS, dans sa
   boîte. Le champ occupant toute la cellule, l'ancrage ne peut pas dériver. */
.km-compte-grille .km-champ { min-width: 0; display: flex; flex-direction: column; }
.km-compte-grille .km-champ > :first-child {
  min-height: 2.25rem; display: flex; align-items: flex-end; margin-bottom: .25rem;
}
.km-compte-grille .form-control { width: 100%; }
.km-mdp { position: relative; display: block; width: 100%; }
/* Le thème borne déjà les champs des onglets du compte à 28 rem
   (« #orderManager .tab-pane .form-control ») : le conteneur des outils et
   la ligne du libellé suivent LA MÊME borne, sinon l'œil et le générateur
   s'ancrent 50 px trop à droite. */
#orderManager .tab-pane .km-mdp,
#orderManager .tab-pane .km-champ-tete { max-width: 28rem; }
.km-mdp .form-control { padding-inline-end: 5.75rem; }
.km-mdp-outils {
  position: absolute; inset-inline-end: .25rem; top: 50%; transform: translateY(-50%);
  display: flex; gap: .125rem;
}
.km-mdp-bouton {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; padding: 0;
  background: none; border: 0; border-radius: 4px;
  color: var(--km-t2); cursor: pointer;
}
.km-mdp-bouton:hover { color: var(--km-ac); background: var(--km-plan-b); }
.km-mdp-bouton .km-oeil-cache { display: none; }
.km-mdp-bouton[aria-pressed="true"] .km-oeil-montre { display: none; }
.km-mdp-bouton[aria-pressed="true"] .km-oeil-cache { display: inline; }
.km-mdp-bouton.km-copie-faite { color: var(--km-ac); }

.km-mdp-generer {
  display: inline-flex; align-items: center; gap: .375rem;
  padding: .2rem .55rem; margin-bottom: .125rem; background: none; cursor: pointer;
  border: 1px dashed var(--km-ac-bord); border-radius: 4px;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--km-ac);
}
.km-mdp-generer:hover { background: var(--km-ac-voile); border-style: solid; }

.km-mdp-controle { display: block; margin: .25rem 0 1rem; }
.km-mdp-mesure { display: flex; align-items: center; gap: .75rem; }
.km-mdp-jauge {
  display: block; flex: 0 0 220px; height: 3px; border-radius: 2px;
  background: var(--km-l1); overflow: hidden;
}
.km-mdp-jauge-part {
  display: block; height: 100%; width: 0;
  background: var(--km-ko); transition: width .25s ease, background-color .25s ease;
}
.km-mdp-jauge-part[data-niveau="2"] { background: var(--km-ac); }
.km-mdp-jauge-part[data-niveau="3"] { background: var(--km-ok, #3E8E5A); }
.km-mdp-verdict {
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--km-t2);
}
.km-mdp-criteres {
  list-style: none; margin: .625rem 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: .375rem 1.5rem;
}
.km-mdp-criteres li {
  display: flex; align-items: center; gap: .5rem;
  font-size: .8125rem; color: var(--km-t2);
}
.km-mdp-criteres .km-icone { width: 16px; height: 16px; flex: none; }
.km-mdp-criteres .km-critere-non { color: var(--km-ko); }
.km-mdp-criteres .km-critere-oui { display: none; color: var(--km-ac); }
.km-mdp-criteres li.km-tenu { color: var(--km-t1); }
.km-mdp-criteres li.km-tenu .km-critere-non { display: none; }
.km-mdp-criteres li.km-tenu .km-critere-oui { display: inline; }

/* Dans la configuration, les pictogrammes s'affirment : safran au repos —
   il n'y a pas de survol de carte pour les allumer — et l'exclusion en rouge. */
.km-config .km-point-icone { color: var(--km-ac); }
.km-config .km-point-absent .km-point-icone { color: var(--km-ko); }
.km-config-tout .km-offre-groupe { display: block; margin-top: 1.5rem; }
.km-config-tout .km-offre-sous-titre { display: block; margin-bottom: .875rem; }

/* Les champs du compte perdent le voile bleu du remplissage automatique. */
.km-compte-grille input:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 1000px var(--km-plan-a) inset;
  -webkit-text-fill-color: var(--km-t0);
  transition: background-color 9999s ease-out;
}

/* ==========================================================================
   57. L'IDENTITÉ DES CARTES — RELEVÉ AU PIXEL CONTRE LA VITRINE
   Deux instantanés « getComputedStyle », même thème, élément par élément :
   chaque règle ci-dessous ferme un écart MESURÉ, aucune n'est décorative.
   La vitrine est la référence ; la commande et l'accueil s'y plient.
   ========================================================================== */
/* la vitrine est carrée — la grille soudée de la maison, pas des vignettes */
.km-offres .km-offre { border-radius: 0; }

/* le titre : 24 px / 32, comme la vitrine (20/28 relevé côté commande) */
.km-offres .km-offre-titre { font-size: 1.5rem; line-height: 2rem; letter-spacing: -.012em; }
.km-offres .km-offre-vedette .km-offre-titre { font-size: 1.375rem; color: var(--km-ac); }

/* le montant : 34 px, graisse 510, crénage serré, transition de couleur */
.km-offres .km-offre-montant {
  font-size: 2.125rem; line-height: 2.5rem; font-weight: 510; letter-spacing: -.03em;
  transition: color var(--km-d-micro) var(--km-e-micro);
}
.km-offres .km-offre-vedette .km-offre-montant { font-size: 3rem; line-height: 1.02; }

/* sous-titre et « Le plus choisi » : Mono, capitales, crénage large */
.km-offres .km-offre-sous-titre {
  font-family: var(--km-mono); font-size: .6875rem; line-height: 1.625rem;
  letter-spacing: .12em; text-transform: uppercase; color: var(--km-t2);
}
.km-offres .km-recommande {
  font-family: var(--km-mono); font-size: .6875rem;
  letter-spacing: .18em; text-transform: uppercase;
}
.km-offres .km-offre-periode { color: var(--km-t2); }

/* la vedette de la vitrine : filet l1, ARÊTE GAUCHE de safran, contour
   intérieur, voile dégradé — et le titre à l'encre d'accent */
.km-offres .km-offre-vedette {
  border-color: var(--km-l1);
  border-inline-start: 2px solid var(--km-ac);
  outline: 1px solid var(--km-ac-bord); outline-offset: -1px;
  background: linear-gradient(180deg, var(--km-ac-voile), transparent 42%), var(--km-plan-a);
}
.km-offres .km-offre-vedette:hover {
  border-inline-start-color: var(--km-ac-h, var(--km-ac));
  background: linear-gradient(180deg, var(--km-ac-voile), transparent 42%), var(--km-plan-b);
}

/* l'appel : gris au repos, safran au survol de la carte et sur la vedette —
   exactement la lecture de la vitrine */
.km-offres .km-offre .km-offre-appel { color: var(--km-t2); }
.km-offres .km-offre:hover .km-offre-appel,
.km-offres .km-offre-vedette .km-offre-appel { color: var(--km-ac); }

/* le survol de la vitrine ne SOULÈVE pas la carte : le fond s'éclaire, rien
   ne bouge — la translation copiée d'une version antérieure se retire */
.km-offres .km-offre:hover { background: var(--km-plan-a); transform: none; }
.km-offres-cmd .km-offre:hover { background: var(--km-plan-a); transform: none; }
.km-offres-cmd .km-offre-vedette:hover { transform: none; }

/* ==========================================================================
   58. LE MOT DE PASSE AFFINÉ · LES CHAMPS DU TUNNEL À LA RÈGLE DE LA MAISON
   ========================================================================== */
/* Les champs du tunnel reprennent l'habit UNIQUE de la maison : un filet
   bas, fin ; safran au focus ; jamais de boîte épaisse ni d'anneau. */
#orderManager .accordion-body .form-control,
#orderManager .accordion-body .form-select {
  border: 0; border-bottom: 1px solid var(--km-l2); border-radius: 0;
  background-color: transparent; box-shadow: none;
}
#orderManager .accordion-body .form-control:hover:not(:focus),
#orderManager .accordion-body .form-select:hover:not(:focus) {
  border-bottom-color: var(--km-t2);
}
#orderManager .accordion-body .form-control:focus,
#orderManager .accordion-body .form-select:focus {
  border-bottom-color: var(--km-ac);
  box-shadow: 0 1px 0 0 var(--km-ac);
  outline: none;
}

/* Les critères échappent aux règles génériques des listes de l'accordéon :
   ni carré de puce (l'icône dit déjà l'état), ni grille pleine largeur. */
#orderManager .accordion-body ul.km-mdp-criteres {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .375rem 1.5rem;
}
#orderManager .accordion-body ul.km-mdp-criteres li::before { content: none; }
.km-mdp-criteres li::marker { content: none; }
.km-mdp-controle { max-width: 28rem; }

/* La jauge à QUATRE crans : faible (rouge) · moyen (ambre) · fort (safran)
   · très fort (vert). Les crans s'allument avec la solidité. */
.km-mdp-jauge {
  display: flex; gap: 3px; flex: 0 0 220px; height: 4px;
  background: none; overflow: visible; border-radius: 0;
}
.km-mdp-jauge i {
  flex: 1 1 0; height: 100%; border-radius: 2px;
  background: var(--km-l1);
  transition: background-color .25s ease;
}
.km-mdp-jauge[data-niveau="1"] i:nth-child(1) { background: var(--km-ko); }
.km-mdp-jauge[data-niveau="2"] i:nth-child(-n+2) { background: var(--km-at); }
.km-mdp-jauge[data-niveau="3"] i:nth-child(-n+3) { background: var(--km-ac); }
.km-mdp-jauge[data-niveau="4"] i { background: var(--km-ok); }
@media (prefers-reduced-motion: reduce) { .km-mdp-jauge i { transition: none; } }

/* Le générateur, affiné : un trait pointillé discret, pas un bouton massif. */
.km-mdp-generer {
  padding: .1rem .5rem; gap: .3rem; margin-bottom: .125rem;
  font-size: .625rem; letter-spacing: .08em;
}
.km-mdp-generer .km-icone { width: 12px; height: 12px; }

/* La confirmation de copie : une pastille brève au-dessus des outils. */
.km-mdp-copie-note {
  position: absolute; inset-inline-end: 0; bottom: calc(100% + .5rem);
  padding: .25rem .625rem; white-space: nowrap;
  background: var(--km-plan-a); border: 1px solid var(--km-ac-bord); border-radius: 4px;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--km-ac);
  box-shadow: 0 8px 22px rgba(0, 0, 0, .18);
}

/* ==========================================================================
   59. (annulée après contre-relevé : la pastille bordée de la commande était
   DÉJÀ la règle finale de la vitrine — « #tarifs .km-offre-economie »,
   ligne 1733 de vitrine.css. Le gris relevé à l'instantané était la variante
   « nulle » du jeu mensuel, pas la pastille d'économie.)
   ========================================================================== */

/* ==========================================================================
   61. LE TUNNEL REPASSÉ — champs, onglets, panier
   (posée AVANT la section 60 : le recollage mécanique tronque à partir
   de son repère, tout ce qui est écrit après lui serait effacé.)
   ========================================================================== */

/* ---- 61.1 Le remplissage automatique perd son bleu, dans les deux thèmes.
   La section 58 pose « box-shadow: none » sur les champs du tunnel (1,2,1) :
   elle effaçait l'astuce du voile incrusté écrite en 5288 (0,2,1). On la
   récrit AU-DESSUS de cette spécificité, focus compris. */
#orderManager .accordion-body .form-control:-webkit-autofill,
#orderManager .accordion-body .form-control:-webkit-autofill:hover {
  -webkit-box-shadow: 0 0 0 1000px var(--km-plan-a) inset;
  -webkit-text-fill-color: var(--km-t0);
  caret-color: var(--km-t0);
  transition: background-color 9999s ease-out;
}
#orderManager .accordion-body .form-control:-webkit-autofill:focus {
  -webkit-box-shadow: 0 1px 0 0 var(--km-ac), 0 0 0 1000px var(--km-plan-a) inset;
  -webkit-text-fill-color: var(--km-t0);
  caret-color: var(--km-t0);
}

/* ---- 61.2 Le focus des champs : le filet safran existait, il gagne une
   nappe — le voile safran de la maison — et une transition douce. */
#orderManager .accordion-body .form-control,
#orderManager .accordion-body .form-select {
  transition: border-color var(--km-d-micro) var(--km-e-micro),
              box-shadow var(--km-d-micro) var(--km-e-micro),
              background-color var(--km-d-couleur) var(--km-e-couleur);
}
#orderManager .accordion-body .form-control:focus,
#orderManager .accordion-body .form-select:focus {
  background-color: var(--km-ac-voile);
}

/* ---- 61.3 Les onglets du compte, francs : l'inactif s'efface, l'actif
   porte DEUX pixels de safran, le survol répond. Le cadre qui apparaissait
   au CLIC était l'anneau de focus posé sur « :focus » : il ne se montre
   plus qu'au clavier (:focus-visible), comme il se doit. */
#orderManager [role="tab"] { color: var(--km-t2) !important; }
#orderManager [role="tab"]:hover {
  color: var(--km-t0) !important;
  box-shadow: inset 0 -1px 0 var(--km-l2);
}
#orderManager [role="tab"].active,
#orderManager [role="tab"][aria-selected="true"] {
  color: var(--km-ac) !important;
  box-shadow: inset 0 -2px 0 var(--km-ac);
}
#orderManager [role="tab"]:focus { outline: none; }
#orderManager [role="tab"]:focus-visible {
  outline: 2px solid var(--km-ac); outline-offset: 2px;
}
#orderManager .km-compte-onglets .km-onglet { font-size: .75rem !important; }

/* ---- 61.4 Les voies du domaine (enregistrer · transférer · le mien),
   en puces de la maison : colonne à droite — l'arrangement validé —,
   mais chaque voie lisible et l'active bordée de safran. */
.km-domaine-onglets .nav-link {
  border: 1px solid var(--km-l2) !important; border-radius: 5px !important;
  padding: .625rem .875rem !important;
  transition: border-color var(--km-d-micro) var(--km-e-micro),
              color var(--km-d-micro) var(--km-e-micro),
              background-color var(--km-d-couleur) var(--km-e-couleur);
}
#orderManager .km-domaine-onglets .nav-link,
#orderManager .km-domaine-onglets .nav-link:hover { box-shadow: none; }
.km-domaine-onglets .nav-link:hover { border-color: var(--km-t2) !important; }
#orderManager .km-domaine-onglets .nav-link.active {
  border-color: var(--km-ac) !important;
  background: var(--km-ac-voile) !important;
  box-shadow: none;
}

/* ---- 61.5 Le panier : les montants s'affirment (le Mono de la maison,
   plus grand), le total se lit avant tout le reste. */
.km-panier-montant .km-valeur { font-size: 1.1875rem; line-height: 1.75rem; }
.km-somme-montant { font-size: 1.875rem; line-height: 2.25rem; letter-spacing: -.02em; }
.km-somme { gap: 1.125rem; }

/* ---- 61.6 Les moyens de paiement : plus de logos PNG dépareillés — des
   puces au trait de la maison, le nom en toutes lettres, l'élue en safran. */
#orderManager .km-passerelle,
.km-passerelles .km-passerelle { padding: 0; border: 0 !important; background: transparent !important; }
#orderManager .km-passerelle .btn,
.km-passerelles .km-passerelle .btn {
  display: inline-flex; align-items: center; gap: .5625rem;
  min-height: 48px; padding: .625rem 1rem;
  border: 1px solid var(--km-l2); border-radius: 5px;
  background: var(--km-plan-a); color: var(--km-t1);
  font-size: .875rem; font-weight: 510;
  transition: border-color var(--km-d-micro) var(--km-e-micro),
              color var(--km-d-micro) var(--km-e-micro),
              background-color var(--km-d-couleur) var(--km-e-couleur);
}
#orderManager .km-passerelle .btn .km-icone,
.km-passerelles .km-passerelle .btn .km-icone { color: var(--km-t2); transition: color var(--km-d-micro) var(--km-e-micro); }
#orderManager .km-passerelle .btn:hover,
.km-passerelles .km-passerelle .btn:hover { border-color: var(--km-t2); color: var(--km-t0); }
#orderManager .km-passerelle .btn-check:checked + .btn {
  border-color: var(--km-ac); background: var(--km-ac-voile);
  color: var(--km-t0); box-shadow: none; border-radius: 5px;
}
#orderManager .km-passerelle .btn-check:checked + .btn .km-icone,
.km-passerelles .km-passerelle .btn-check:checked + .btn .km-icone { color: var(--km-ac); }
#orderManager .km-passerelle .btn-check:focus-visible + .btn,
.km-passerelles .km-passerelle .btn-check:focus-visible + .btn {
  outline: 2px solid var(--km-ac); outline-offset: 2px;
}

/* ---- 61.7 Les pages d'accès (connexion · inscription) : les champs
   passent à l'habit UNIQUE de la maison — filet bas fin, safran au focus
   avec la nappe, jamais de boîte — et le bleu du remplissage automatique
   est éteint ici aussi, dans les deux thèmes. */
.km-page-acces .form-control,
.km-page-acces .form-select {
  border: 0; border-bottom: 1px solid var(--km-l2); border-radius: 0;
  background-color: transparent; box-shadow: none; min-height: 48px;
  transition: border-color var(--km-d-micro) var(--km-e-micro),
              box-shadow var(--km-d-micro) var(--km-e-micro),
              background-color var(--km-d-couleur) var(--km-e-couleur);
}
.km-page-acces .form-control:hover:not(:focus),
.km-page-acces .form-select:hover:not(:focus) {
  border-bottom-color: var(--km-t2);
}
.km-page-acces .form-control:focus,
.km-page-acces .form-select:focus {
  border-bottom-color: var(--km-ac);
  box-shadow: 0 1px 0 0 var(--km-ac);
  background-color: var(--km-ac-voile);
  outline: none;
}
.km-page-acces .form-control:-webkit-autofill,
.km-page-acces .form-control:-webkit-autofill:hover {
  -webkit-box-shadow: 0 0 0 1000px var(--km-plan-a) inset;
  -webkit-text-fill-color: var(--km-t0);
  caret-color: var(--km-t0);
  transition: background-color 9999s ease-out;
}
.km-page-acces .form-control:-webkit-autofill:focus {
  -webkit-box-shadow: 0 1px 0 0 var(--km-ac), 0 0 0 1000px var(--km-plan-a) inset;
  -webkit-text-fill-color: var(--km-t0);
  caret-color: var(--km-t0);
}
/* Le contrôle du mot de passe garde l'air du tunnel dans la grille d'accès. */
.km-page-acces .km-mdp-controle { margin-top: 1rem; }

/* ---- 61.8 L'entrée en scène : la colonne du formulaire puis le panneau
   de marque se posent d'un léger relevé. Sans script (pas de « km-js »)
   ou en mouvement réduit : tout est en place d'emblée. */
@keyframes km-acces-entree {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
.km-js .km-acces-boite { animation: km-acces-entree .45s var(--km-e-sortie) both; }
.km-js .km-acces-panneau { animation: km-acces-entree .45s var(--km-e-sortie) .12s both; }
@media (prefers-reduced-motion: reduce) {
  .km-js .km-acces-boite, .km-js .km-acces-panneau { animation: none; }
}

/* ---- 61.9 Le panneau de marque tient dans l'écran. Il déroulait sa
   colonne plus bas que le formulaire de connexion : la page entière
   défilait pour un panneau. Il se cale désormais dans la fenêtre et son
   rythme se resserre avec la hauteur disponible ; sur un long formulaire
   d'inscription, il reste en vue pendant qu'on descend. Le défilement
   INTERNE ne sert que de garde-fou aux écrans très bas. */
@media (min-width: 992px) {
  .km-acces-panneau {
    position: sticky; top: 0;
    height: 100vh; height: 100svh;
    overflow-y: auto;
    padding: clamp(1.75rem, 4vh, 4rem) 3.5rem;
  }
  .km-acces-panneau-corps { position: static; top: auto; }
}
.km-acces-promesse { font-size: clamp(1.0625rem, .95rem + .4vw, 1.25rem); }
.km-acces-promesse { margin-top: clamp(.625rem, 1.5vh, 1.125rem); }
.km-acces-panneau .km-frise { margin-top: clamp(1rem, 3vh, 2.25rem); }
.km-acces-args {
  margin-top: clamp(1.25rem, 3.4vh, 2.5rem);
  gap: clamp(.875rem, 2.6vh, 1.75rem);
}
.km-acces-arg { padding-top: clamp(.75rem, 2vh, 1.5rem); }

/* La colonne du formulaire suit le même resserrement : sur un écran de
   720 px, la connexion tenait à 835 — la page défilait pour 115 pixels
   de marges. Chaque respiration se plie à la hauteur disponible. */
@media (min-width: 992px) {
  .km-acces-colonne { padding-block: clamp(1.5rem, 4vh, 4rem); }
}
.km-acces-logo img.my-4 { margin-block: clamp(.5rem, 1.6vh, 1.5rem); }
.km-acces-tete { margin-bottom: clamp(1.5rem, 3.6vh, 2.5rem); }
.km-acces-phrase { margin-top: .75rem; }
.km-acces-boite .km-doc-pied-liens { margin-block: clamp(.625rem, 1.6vh, 1rem); }
.km-acces-boite .km-acces-mentions { margin-bottom: 0; }

/* ---- 61.12 La marque du rail, LIÉE AU MENU : le signe (le favicon
   officiel) reste en place tant que le rail est replié ; quand le MENU se
   déplie — survol ou focus du rail, ou de la marque elle-même, les deux
   voies ouvrent les deux choses ENSEMBLE — la marque pleine paraît à la
   place du signe, à la largeur du menu déplié (244 px), jamais plus. */
.km-marque { position: relative; }
.km-marque img { display: block; }
.km-marque-signe { display: inline-flex; transition: opacity 200ms var(--km-e-couleur); }
.km-marque-signe img { width: 44px; height: 44px; }
.km-marque-pleine {
  position: absolute; inset: 0;
  display: flex; align-items: center; padding-inline-start: 16px;
  white-space: nowrap;
  opacity: 0; visibility: hidden;
  transition: opacity 200ms var(--km-e-couleur), visibility 0s linear 200ms;
}
.km-marque-pleine img { height: 34px; width: auto; }

/* Une règle plus ancienne masque TOUTE image de marque du bandeau client
   (elle cachait le mot-symbole tronqué). Le nouveau bloc est exempté avec
   un cran de spécificité de plus — on n'annule pas l'ancienne règle. */
body:has(#sidebarMenu) > .container > header .navbar-brand.km-marque img { display: block; }
/* Les variantes de thème, pilotées ICI : sans attribut = clair. Écrites
   au poids de l'exemption, sinon son « display: block » montrait les
   deux marques empilées. */
body:has(#sidebarMenu) > .container > header .navbar-brand.km-marque img.km-marque-va-sombre,
.km-marque-va-sombre { display: none; }
[data-bs-theme="dark"] body:has(#sidebarMenu) > .container > header .navbar-brand.km-marque img.km-marque-va-clair,
[data-bs-theme="dark"] .km-marque-va-clair { display: none; }
[data-bs-theme="dark"] body:has(#sidebarMenu) > .container > header .navbar-brand.km-marque img.km-marque-va-sombre,
[data-bs-theme="dark"] .km-marque-va-sombre { display: block; }

@media (min-width: 768px) {
  /* la case de la marque suit la cadence du rail : 78 repliée, 244 dépliée.
     ATTENTION : « :has() » ne s'imbrique pas dans « :has() » — un sélecteur
     invalide fait tomber TOUTE sa liste. L'état est donc porté par la
     classe « km-rail-ouvert » sur <html>, posée par kardox.js (§ 15)
     quand le rail OU la marque est survolé ou reçoit le focus. Sans
     script : le rail garde son dépliage CSS, le signe reste — rien ne
     casse. */
  body:has(#sidebarMenu) > .container > header .navbar-brand.km-marque {
    transition: width 340ms var(--km-e-sortie);
  }
  /* le poids d'identifiant de « :has(#sidebarMenu) » de la règle de base
     doit être égalé, sinon les 78 px l'emportent */
  html.km-rail-ouvert body:has(#sidebarMenu) > .container > header .navbar-brand.km-marque { width: 244px; }
  /* le rail suit quand c'est la MARQUE qu'on survole — même classe */
  html.km-rail-ouvert .container > .container > .row > [class*="col-"]:has(#sidebarMenu) {
    width: 244px; max-width: 244px;
    box-shadow: 24px 0 48px -24px rgba(0, 0, 0, .55);
  }
  /* le MENU suit aussi : libellés et lignes annexes s'ouvrent avec la
     même classe — sinon survoler la marque ouvrait la largeur mais
     laissait les étiquettes effacées (constaté à l'écran). */
  html.km-rail-ouvert #sidebarMenu .nav-link { font-size: .875rem; }
  html.km-rail-ouvert #sidebarMenu .nav > li:not(.offcanvas-item) {
    opacity: 1; pointer-events: auto;
  }
  /* l'échange signe → marque pleine */
  html.km-rail-ouvert .km-marque-signe { opacity: 0; }
  html.km-rail-ouvert .km-marque-pleine {
    opacity: 1; visibility: visible; transition-delay: 0s;
  }
}
/* Sous 768 px le rail n'existe pas : le signe seul, jamais d'échange. */
@media (max-width: 767.98px) { .km-marque-pleine { display: none; } }
@media (prefers-reduced-motion: reduce) {
  .km-marque-signe, .km-marque-pleine,
  body:has(#sidebarMenu) > .container > header .navbar-brand.km-marque { transition: none; }
}

/* ---- 61.13 L'argent s'affirme, le lien se reconnaît ----
   Les montants des tableaux passent au Mono de la maison, un cran plus
   grands, encre pleine ; et tout lien posé dans une carte ou un tableau
   se lit comme un lien : souligné fin, safran au survol. Les motifs déjà
   validés (km-lien-ligne, boutons) sont exclus, rien n'est annulé. */
.card table td.text-end,
.km-doc table td.text-end,
.km-facture-lignes td.text-end {
  font-family: var(--km-mono); font-size: 1rem; font-weight: 510;
  letter-spacing: -.01em; color: var(--km-t0);
}
.card a:not(.btn):not(.km-lien-ligne):not(.nav-link):not(.dropdown-item):not(.km-offre-appel),
table a:not(.btn):not(.km-lien-ligne):not(.nav-link):not(.dropdown-item) {
  color: var(--km-t0);
  text-decoration: underline;
  text-underline-offset: .2em;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--km-l2);
  transition: color var(--km-d-micro) var(--km-e-micro),
              text-decoration-color var(--km-d-micro) var(--km-e-micro);
}
.card a:not(.btn):not(.km-lien-ligne):not(.nav-link):not(.dropdown-item):not(.km-offre-appel):hover,
table a:not(.btn):not(.km-lien-ligne):not(.nav-link):not(.dropdown-item):hover {
  color: var(--km-ac);
  text-decoration-color: var(--km-ac);
}
/* la référence de marque (KRDX-T…, KRDX-C…) : Mono, nette, jamais criarde */
.km-ref { font-family: var(--km-mono); letter-spacing: .05em; }

/* ---- 61.14 Le salut du tableau de bord ---- */
.km-entete-jour { display: block; margin-bottom: .625rem; }
/* le prénom à l'accent de la maison — safran en sombre, sienne en clair */
.km-salut-nom { color: var(--km-ac); }
/* l'horloge bat sans faire trembler la ligne : chiffres tabulaires */
[data-km-horloge] { font-variant-numeric: tabular-nums; }

/* ---- 61.15 Le graphe des dépenses : la carte, la courbe, le viseur ----
   Une CARTE bornée — plus de bande qui avale la page — flanquée d'une
   colonne de repères. La courbe de safran se dévoile derrière un rideau
   de découpe ; au survol, un viseur vertical suit la souris et une bulle
   donne le mois et le montant exacts. Tout vient des jetons de la maison.
*/
.km-graphe-rangee {
  display: grid; grid-template-columns: minmax(0, 1fr) 17rem;
  gap: 1.5rem; align-items: stretch; margin-top: 2rem;
}
@media (max-width: 991.98px) { .km-graphe-rangee { grid-template-columns: minmax(0, 1fr); } }
.km-graphe, .km-graphe-cotes {
  border: 1px solid var(--km-l2); border-radius: 5px;
  background: var(--km-plan-a); padding: 1.5rem;
}
.km-graphe-tete { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.km-graphe-periode {
  font-family: var(--km-mono); font-size: .625rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--km-t2);
}
.km-graphe-total { display: flex; align-items: baseline; gap: .75rem; margin: .875rem 0 1rem; }
.km-graphe-total .km-valeur { font-size: 1.75rem; line-height: 2.25rem; letter-spacing: -.02em; }
.km-graphe-total-note { font-size: .8125rem; color: var(--km-t2); }

.km-graphe-cadre { position: relative; }
.km-graphe-svg { display: block; width: 100%; height: 140px; overflow: visible; }
.km-grille line { stroke: var(--km-l0); stroke-width: 1; }
.km-graphe-socle { stroke: var(--km-l1); stroke-width: 1; }
.km-ligne {
  fill: none; stroke: var(--km-ac); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.km-aire-haut { stop-color: var(--km-ac); stop-opacity: .2; }
.km-aire-bas  { stop-color: var(--km-ac); stop-opacity: 0; }
.km-graphe-point { fill: var(--km-ac); stroke: var(--km-plan-a); stroke-width: 1.5; }
.km-graphe-halo {
  fill: none; stroke: var(--km-ac); stroke-width: 1.5; opacity: 0;
  transform-box: fill-box; transform-origin: center;
  animation: km-halo-souffle 2.6s var(--km-e-couleur) 1.2s infinite;
}
@keyframes km-halo-souffle {
  0%   { opacity: .55; transform: scale(.5); }
  70%  { opacity: 0;   transform: scale(1.4); }
  100% { opacity: 0;   transform: scale(1.4); }
}
.km-devoile-fenetre {
  transform-origin: 0 0;
  animation: km-devoiler 1.1s cubic-bezier(.32, .72, 0, 1) both;
}
@keyframes km-devoiler { from { transform: scaleX(0); } }
.km-viseur { stroke: var(--km-t2); stroke-width: 1; stroke-dasharray: 3 3; opacity: .6; vector-effect: non-scaling-stroke; }
.km-viseur-point { fill: var(--km-ac); stroke: var(--km-plan-a); stroke-width: 1.5; }
.km-graphe-toucher { fill: transparent; }
.km-graphe-bulle {
  position: absolute; z-index: 2; pointer-events: none;
  display: flex; flex-direction: column; gap: .125rem;
  padding: .4375rem .625rem;
  background: var(--km-plan-c); border: 1px solid var(--km-l2); border-radius: 4px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .28);
  transform: translate(-50%, calc(-100% - 12px));
  white-space: nowrap;
}
.km-graphe-bulle-mois {
  font-family: var(--km-mono); font-size: .625rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--km-t2);
}
.km-graphe-bulle-montant { font-size: .9375rem; }
@media (prefers-reduced-motion: reduce) {
  .km-graphe-halo { animation: none; opacity: .4; }
  .km-devoile-fenetre { animation: none; }
}
.km-graphe-mois {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  margin-top: .375rem;
  font-family: var(--km-mono); font-size: .625rem; letter-spacing: .08em;
  color: var(--km-t2); text-align: center;
}
.km-graphe-cotes { display: flex; flex-direction: column; gap: 1rem; }
.km-graphe-cotes > div {
  display: flex; flex-direction: column; gap: .25rem;
  padding-bottom: 1rem; border-bottom: 1px solid var(--km-l1);
}
.km-graphe-cotes .km-valeur { font-size: 1.25rem; line-height: 1.75rem; }
.km-graphe-cotes .km-lien { margin-top: auto; }
.km-graphe-rien {
  margin: 1.25rem 0 0; font-size: .9375rem; line-height: 1.5rem; color: var(--km-t2);
}

/* ---- 61.16 La fiche en deux colonnes ----
   Les paires clé/valeur coulent sur DEUX colonnes dès que l'écran est
   large : plus de moitié droite déserte sous une pile interminable. */
@media (min-width: 992px) {
  .km-fiche-deux {
    grid-template-columns: minmax(8rem, max-content) minmax(0, 1fr)
                           minmax(8rem, max-content) minmax(0, 1fr);
    column-gap: 2.5rem;
  }
}

/* ---- 61.17 La page du service : le titre respire, la période fond ----
   Le plafond de 22 ch des documents cassait « Hébergement Starter for … »
   en deux lignes dans une page à moitié vide : sur les pages de service,
   le titre court sur SA ligne et ne plie que s'il ne tient vraiment pas.
   La phrase s'élargit du même geste. */
.km-page-service .km-doc-tete h1 { max-width: none; }
.km-page-service .km-doc-phrase { max-width: 78ch; }
/* la part de période RESTANTE : elle fond d'un jour chaque jour */
.km-echeance-piste {
  display: block; width: 12rem; max-width: 100%; height: 3px;
  margin-top: .625rem; border-radius: 2px; background: var(--km-l1);
  overflow: hidden;
}
.km-echeance-piste > i {
  display: block; height: 100%; background: var(--km-ac); border-radius: 2px;
}

/* ---- 61.18 La page de la passerelle : le formulaire À SA TAILLE ----
   L'élément de paiement de la passerelle prenait toute la largeur de la
   page — des onglets géants, une mise en page qui se noie. Il vit
   désormais dans une colonne de formulaire : 40 rem au plus. Les moyens
   proposés (carte, Klarna, Bancontact…) viennent du COMPTE de la
   passerelle, pas du thème. */
/* PLEINE largeur — le resserrement à 40 rem laissait un désert à droite
   et a été refusé : les moyens de paiement restent des ONGLETS fins,
   amincis par l'Appearance de la passerelle, sur toute la colonne. */
.invoice-banklink .km-attente-corps { max-width: none; }
/* la grille du paiement : le formulaire à gauche, le récapitulatif collant
   à droite — les onglets de la passerelle retrouvent une taille normale
   SANS désert : la colonne de droite travaille. */
.km-paiement-grille {
  /* colonne de règlement COMPACTE et CENTRÉE : les onglets de la
     passerelle retombent à ~160 px, et aucun côté ne reste désert. */
  display: grid; grid-template-columns: minmax(0, 1fr) 18rem;
  gap: 1.5rem; align-items: start; margin-top: .25rem;
}
@media (max-width: 991.98px) { .km-paiement-grille { grid-template-columns: minmax(0, 1fr); } }
.km-paiement-recap {
  position: sticky; top: 1.5rem;
  display: flex; flex-direction: column; gap: .875rem;
  border: 1px solid var(--km-l2); border-radius: 5px;
  background: var(--km-plan-a); padding: 1.25rem 1.5rem;
}
.km-paiement-recap .km-etiquette { display: block; margin-bottom: .25rem; }
.km-paiement-montant { font-size: 1.5rem; line-height: 2rem; }
.km-paiement-note { margin: 0; font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2); }
/* la rangee des moyens : SEPT puces de la maison, petites, sur UNE ligne —
   la passerelle plafonnait ses onglets, les boutons sont desormais a nous. */
.km-moyens { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1rem; }
.km-moyen {
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 40px; padding: .4375rem .875rem;
  border: 1px solid var(--km-l2); border-radius: 5px;
  background: var(--km-plan-a); color: var(--km-t1);
  font-size: .8125rem; font-weight: 510; cursor: pointer;
  transition: border-color var(--km-d-micro) var(--km-e-micro),
              color var(--km-d-micro) var(--km-e-micro),
              background-color var(--km-d-couleur) var(--km-e-couleur);
}
.km-moyen:hover { border-color: var(--km-t2); color: var(--km-t0); }
.km-moyen.km-actif {
  border-color: var(--km-ac); background: var(--km-ac-voile); color: var(--km-t0);
}
.km-moyen:focus-visible { outline: 2px solid var(--km-ac); outline-offset: 2px; }
.km-moyen svg { display: block; flex: 0 0 auto; }
/* le reglement : les champs de la passerelle en pleine largeur, puis NOTRE
   champ Pays seul sur sa ligne — a sa juste taille, pas toute la carte. */
.km-ligne-paiement { display: flex; flex-direction: column; align-items: stretch; gap: 1rem; margin-bottom: 1.25rem; }
.km-ligne-paiement #payment-element { width: 100%; }
.km-pays-champ { width: 14rem; max-width: 100%; display: flex; flex-direction: column; gap: .375rem; }
.km-pays-champ > span { font-size: .875rem; color: var(--km-t1); }
.km-pays-champ > select {
  min-height: 44px; padding: 0 2.25rem 0 .75rem;
  border: 1px solid var(--km-l2); border-radius: 5px;
  background-color: var(--km-plan-b); color: var(--km-t0);
  font-size: .9375rem; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23A1590C' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .75rem center; background-size: 12px 8px;
}
[data-bs-theme="dark"] .km-pays-champ > select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23F2A93B' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
.km-pays-champ > select:focus { outline: none; border-color: var(--km-ac); box-shadow: 0 0 0 1px var(--km-ac); }
@media (max-width: 767.98px) {
  .km-pays-champ { width: 100%; }
}
.invoice-banklink .km-attente-note { max-width: none; }
.invoice-banklink .km-doc-phrase { max-width: 78ch; }

/* la boite d erreur du reglement : pleine largeur, nettement separee de la
   rangee des moyens, et qui dit sa couleur — celle des erreurs de la maison. */
.invoice-banklink #error-message .alert {
  display: block; width: 100%; max-width: none; margin: 0 0 1.5rem;
  padding: .875rem 1.125rem;
  border: 1px solid rgba(var(--bs-danger-rgb), .35);
  border-radius: 5px;
  background: rgba(var(--bs-danger-rgb), .10);
  color: var(--km-t1); font-size: .9375rem;
}
.invoice-banklink #error-message .alert strong { color: var(--km-ko); }

/* le menu du compte : une tete d identite, des entrees icones a 44 px,
   la sortie qui vire au rouge — decline du vocabulaire des tableaux. */
.km-compte-menu { min-width: 16.5rem; padding: .5rem; }
.km-compte-tete { display: flex; align-items: center; gap: .75rem; padding: .5rem .625rem .875rem; border-bottom: 1px solid var(--km-l1); margin-bottom: .5rem; }
.km-compte-identite { display: flex; flex-direction: column; gap: .125rem; min-width: 0; }
.km-compte-nom { font-weight: 590; color: var(--km-t0); line-height: 1.25rem; }
.km-compte-courriel { font-family: var(--km-mono); font-size: .75rem; letter-spacing: .02em; color: var(--km-t2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.km-compte-menu .dropdown-item { display: flex; align-items: center; gap: .625rem; min-height: 44px; border-radius: 5px; padding: .375rem .625rem; }
.km-compte-menu .dropdown-item:hover, .km-compte-menu .dropdown-item:focus-visible { text-decoration: none; }
.km-compte-menu .dropdown-item .icon { width: 18px; height: 18px; flex: none; color: var(--km-t2); }
.km-compte-menu .dropdown-item:hover .icon, .km-compte-menu .dropdown-item:focus-visible .icon { color: var(--km-ac); }
.km-compte-menu .dropdown-divider { margin: .5rem .25rem; border-color: var(--km-l1); opacity: 1; }
.km-compte-sortie:hover, .km-compte-sortie:focus { background: rgba(var(--bs-danger-rgb), .10); color: var(--km-ko); }
.km-compte-menu .km-compte-sortie:hover .icon, .km-compte-menu .km-compte-sortie:focus .icon { color: var(--km-ko); }

/* le monogramme du client : le langage du sceau de la marque — anneau et
   initiales safran sur voile — a la place de l image generee par le cœur. */
.km-avatar {
  --km-avatar-taille: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--km-avatar-taille); height: var(--km-avatar-taille);
  border-radius: 50%; flex: none; vertical-align: middle;
  border: 1.5px solid var(--km-ac);
  background: var(--km-ac-voile);
  color: var(--km-ac);
  font-family: var(--km-mono);
  font-size: calc(var(--km-avatar-taille) * .36);
  font-weight: 500; letter-spacing: .04em; line-height: 1;
  text-transform: uppercase; user-select: none;
}
.km-avatar-grand { --km-avatar-taille: 40px; }
.km-avatar-page  { --km-avatar-taille: 96px; border-width: 2px; }

/* la mention de la franchise en base : discrete, alignee sur les totaux */
.km-mention-tva { margin: .5rem 0 0; text-align: right; font-size: .8125rem; color: var(--km-t2); }

/* la recherche vivante de la base de connaissances : loupe dans le champ,
   propositions en surface flottante, paliers de resultats, terme surligne. */
.km-kb-boite { position: relative; flex: 1 1 auto; display: flex; align-items: center; }
.km-kb-loupe { position: absolute; left: .875rem; width: 18px; height: 18px; color: var(--km-t2); pointer-events: none; }
.km-kb-boite > .form-control { width: 100%; padding-left: 2.625rem; }
.km-kb-effacer { align-self: center; }
.km-kb-sugg {
  position: absolute; top: calc(100% + .375rem); left: 0; right: 0; z-index: 30;
  padding: .375rem; background: var(--km-plan-a);
  border: 1px solid var(--km-l2); border-radius: 5px; box-shadow: var(--km-ombre-2);
}
.km-kb-sugg-ligne {
  display: flex; align-items: baseline; gap: .75rem;
  padding: .5625rem .75rem; border-radius: 3px; min-height: 44px; align-items: center;
  color: var(--km-t1); text-decoration: none;
}
.km-kb-sugg-ligne:hover, .km-kb-sugg-ligne.km-kb-sugg-visee { background: var(--km-plan-b); color: var(--km-t0); text-decoration: none; }
.km-kb-sugg-titre { font-size: .9375rem; line-height: 1.375rem; }
.km-kb-sugg-cat {
  margin-inline-start: auto; flex: none;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--km-t2);
}
.km-kb-palier { margin: 2rem 0 0; }
.km-kb-liste-corps .km-kb-ligne-titre { font-size: .9375rem; color: var(--km-t1); }
.km-surligne { background: var(--km-ac-voile); color: inherit; border-radius: 2px; padding: 0 .125rem; }

/* ==========================================================================
   60. LES CARTES DE LA VITRINE, COLLÉES TELLES QUELLES
   Extraction MÉCANIQUE de vitrine.css : toute règle touchant .km-offre*,
   .km-duree*, .km-point*, .km-recommande, .km-econo — sans tri. « #tarifs »
   devient « #products » (commande) et « .km-console » (accueil) ;
   « .km-vitrine » tombe. Appendues en fin de feuille : à spécificité égale,
   LA VITRINE GAGNE. Ne rien retoucher ici à la main — recoller au besoin.
   ========================================================================== */

.btn {
  background-color: var(--bs-btn-bg, transparent);
  color: var(--bs-btn-color, var(--km-t0));
  border: 1px solid var(--bs-btn-border-color, transparent);
  border-radius: var(--bs-btn-border-radius, 4px);
  padding: var(--bs-btn-padding-y, .75rem) var(--bs-btn-padding-x, 1.375rem);
  font-family: var(--bs-btn-font-family, var(--km-sans));
  font-size: var(--bs-btn-font-size, .9375rem);
  font-weight: var(--bs-btn-font-weight, 510);
  line-height: var(--bs-btn-line-height, 1.25rem);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.btn:hover {
  background-color: var(--bs-btn-hover-bg, var(--bs-btn-bg, transparent));
  border-color: var(--bs-btn-hover-border-color, var(--bs-btn-border-color, transparent));
  color: var(--bs-btn-hover-color, var(--bs-btn-color, var(--km-t0)));
  text-decoration: none;
}

.btn:active {
  background-color: var(--bs-btn-active-bg, var(--bs-btn-hover-bg, transparent));
  border-color: var(--bs-btn-active-border-color, var(--bs-btn-hover-border-color, transparent));
  color: var(--bs-btn-active-color, var(--bs-btn-hover-color, var(--km-t0)));
}

.btn:disabled,
.btn.disabled {
  background-color: var(--bs-btn-disabled-bg, transparent);
  border-color: var(--bs-btn-disabled-border-color, var(--km-l1));
  color: var(--bs-btn-disabled-color, var(--km-t2));
}

.km-v-issue .btn {
  min-height: 48px;
}

.km-offre-montant {
  transition: color var(--km-d-couleur) var(--km-e-couleur);
}

@media (max-width: 767.98px) {
.km-v-issue .btn {
  width: 100%;
}
}

.km-duree {
  border: 0; padding: 0; margin: 0 0 2.5rem; min-width: 0;
}

.km-duree > legend {
  float: none; width: auto; padding: 0; margin-bottom: .875rem;
  display: inline-flex; align-items: center; gap: .5rem;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--km-t2);
}

.km-duree-rang {
  display: inline-flex; flex-wrap: wrap; gap: .375rem;
  padding: .375rem; border: 1px solid var(--km-l1); border-radius: 5px;
  background: var(--km-plan-a);
}

.km-duree-choix {
  display: inline-flex;
}

.km-duree-radio {
  position: absolute; opacity: 0; width: 1px; height: 1px;
}

.km-duree-btn {
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 44px; padding: 0 1rem; border-radius: 4px;
  font-size: .9375rem; font-weight: 510; letter-spacing: -.006em;
  color: var(--km-t1); cursor: pointer;
  transition: color var(--km-d-micro) var(--km-e-micro),
  background-color var(--km-d-micro) var(--km-e-micro);
}

.km-duree-carre {
  width: 6px; height: 6px; flex: none;
  border: 1px solid var(--km-l3); background: transparent;
  transition: background-color var(--km-d-micro) var(--km-e-micro),
  border-color var(--km-d-micro) var(--km-e-micro);
}

.km-duree-btn:hover {
  color: var(--km-t0); background: var(--km-plan-b);
}

.km-duree-radio:checked + .km-duree-btn {
  color: var(--km-t0); background: var(--km-plan-c);
}

.km-duree-radio:checked + .km-duree-btn .km-duree-carre {
  background: var(--km-ac); border-color: var(--km-ac);
}

.km-duree-radio:focus-visible + .km-duree-btn {
  outline: 2px solid var(--km-ac); outline-offset: 2px;
}

.km-duree-note {
  margin: .875rem 0 0; font-size: .8125rem; color: var(--km-t2);
}

.km-offre-jeux {
  display: contents;
}

.km-offre-jeu {
  display: none; flex-direction: column; gap: .25rem;
}

.km-offre-jeu[data-duree="a"] {
  display: flex;
}

#products:has(#km-duree-m:checked)    .km-offre-jeu[data-duree="a"],
.km-console:has(#km-duree-m:checked)    .km-offre-jeu[data-duree="a"],
#products:has(#km-duree-bia:checked)  .km-offre-jeu[data-duree="a"],
.km-console:has(#km-duree-bia:checked)  .km-offre-jeu[data-duree="a"],
#products:has(#km-duree-tria:checked) .km-offre-jeu[data-duree="a"],
.km-console:has(#km-duree-tria:checked) .km-offre-jeu[data-duree="a"] {
  display: none;
}

#products:has(#km-duree-m:checked)    .km-offre-jeu[data-duree="m"],
.km-console:has(#km-duree-m:checked)    .km-offre-jeu[data-duree="m"],
#products:has(#km-duree-bia:checked)  .km-offre-jeu[data-duree="bia"],
.km-console:has(#km-duree-bia:checked)  .km-offre-jeu[data-duree="bia"],
#products:has(#km-duree-tria:checked) .km-offre-jeu[data-duree="tria"],
.km-console:has(#km-duree-tria:checked) .km-offre-jeu[data-duree="tria"] {
  display: flex;
}

.km-offre-barre {
  margin-left: .5rem; font-size: .9375rem; color: var(--km-t2);
}

.km-offre-barre s {
  text-decoration-thickness: 1px; text-underline-offset: 2px;
}

.km-offre-economie {
  font-family: var(--km-mono); font-size: .75rem; letter-spacing: .04em;
  color: var(--km-ac);
}

.km-offre-economie-nulle {
  color: var(--km-t2);
}

.km-offre-serment {
  padding-top: .875rem; margin-top: .25rem;
  border-top: 1px solid var(--km-l1);
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t1);
}

.km-tarifs .km-offres {
  margin-top: 2.5rem;
}

@media (max-width: 767px) {
.km-duree-rang {
  display: flex; width: 100%;
}
}

@media (max-width: 767px) {
.km-duree-choix {
  flex: 1 1 auto;
}
}

@media (max-width: 767px) {
.km-duree-btn {
  width: 100%; justify-content: center;
}
}

@media (prefers-reduced-motion: reduce) {
.km-barre,
.km-duree-btn,
.km-duree-carre,
.km-q-signe,
.km-q-signe::after {
  transition: none;
}
}

#products .km-offres,
.km-console .km-offres {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: stretch;
}

@media (max-width: 1100px) {
#products .km-offres,
.km-console .km-offres {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
}

@media (max-width: 760px) {
#products .km-offres,
.km-console .km-offres {
  grid-template-columns: minmax(0, 1fr);
}
}

#products .km-offre,
.km-console .km-offre {
  margin: 0;
}

#products .km-offre-vedette,
.km-console .km-offre-vedette {
  border-color: var(--km-ac-bord); background: var(--km-plan-b);
}

.km-barre-actions .btn,
.km-barre-actions .btn-sm {
  min-height: 44px; display: inline-flex; align-items: center;
}

.km-offre-montant,
.km-fait i,
.km-valeur {
  font-weight: 510;
}


@keyframes km-econo-pose {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.km-offre-jeu {
  animation: km-prix-pose 320ms var(--km-e-sortie) both;
}

.km-offre-jeu .km-offre-economie {
  animation: km-econo-pose 420ms var(--km-e-couleur) 120ms both;
}

.km-duree-btn {
  position: relative;
}

.km-duree-btn::after {
  content: ""; position: absolute; left: .875rem; right: .875rem; bottom: 5px; height: 1px;
  background: var(--km-ac); transform: scaleX(0); transform-origin: center;
  transition: transform var(--km-d-couleur) var(--km-e-sortie);
}

.km-duree-radio:checked + .km-duree-btn::after {
  transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {
.km-js .km-offre,
.km-js .km-vitrine .km-tuile,
.km-js .km-argu,
.km-js .km-flux-etape {
  opacity: 1; transform: none; transition: none;
}
}

@media (prefers-reduced-motion: reduce) {
.km-offre-jeu,
.km-offre-jeu .km-offre-economie {
  animation: none;
}
}

@media (prefers-reduced-motion: reduce) {
.km-duree-btn::after {
  transition: none;
}
}

#products .km-offres,
.km-console .km-offres {
  gap: 0;
  border: 1px solid var(--km-l1);
  border-radius: 5px;
  overflow: hidden;
}

#products .km-offre,
.km-console .km-offre {
  border: 0; border-radius: 0;
  border-left: 1px solid var(--km-l1);
  background: transparent;
  padding: 2rem;
  transform: none;
}

#products .km-offre:first-child,
.km-console .km-offre:first-child {
  border-left: 0;
}

#products .km-offre-vedette,
.km-console .km-offre-vedette {
  background: linear-gradient(180deg, var(--km-ac-voile), transparent 42%), var(--km-plan-a);
  border-color: var(--km-l1);
  outline: 1px solid var(--km-ac-bord); outline-offset: -1px;
}

#products .km-offre-vedette::before,
.km-console .km-offre-vedette::before {
  transform: scaleX(1);
}

#products .km-offre:hover,
.km-console .km-offre:hover {
  background: var(--km-plan-a); transform: none;
}

#products .km-offre-vedette:hover,
.km-console .km-offre-vedette:hover {
  background: linear-gradient(180deg, var(--km-ac-voile), transparent 42%), var(--km-plan-b);
}

#products .km-offre::after,
.km-console .km-offre::after {
  display: none;
}

@media (max-width: 1100px) {
#products .km-offre:nth-child(3),
.km-console .km-offre:nth-child(3) {
  border-left: 0; border-top: 1px solid var(--km-l1);
}
}

@media (max-width: 760px) {
#products .km-offre,
.km-console .km-offre {
  border-left: 0; border-top: 1px solid var(--km-l1); padding: 1.5rem;
}
}

@media (max-width: 760px) {
#products .km-offre:first-child,
.km-console .km-offre:first-child {
  border-top: 0;
}
}

#products .km-offre-titre,
.km-console .km-offre-titre {
  font-size: 1.5rem; line-height: 2rem; letter-spacing: -.012em;
}

@media (prefers-reduced-motion: reduce) {
.km-js .km-offre,
.km-js .km-vitrine .km-tuile,
.km-js .km-argu,
.km-js .km-flux-etape {
  transform: none; transition: none;
}
}

.km-haut {
  position: fixed; right: 1.5rem; bottom: 1.5rem; z-index: 70;
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; padding: 0;
  background: var(--km-plan-b); color: var(--km-t1);
  border: 1px solid var(--km-l1); border-radius: 999px;
  text-decoration: none;
  opacity: 0; pointer-events: none; transform: translateY(6px);
  transition: opacity var(--km-d-couleur) var(--km-e-couleur),
  transform var(--km-d-couleur) var(--km-e-sortie),
  color var(--km-d-micro) var(--km-e-micro),
  border-color var(--km-d-micro) var(--km-e-micro);
}

.km-haut.km-visible {
  opacity: 1; pointer-events: auto; transform: none;
}

.km-haut:not(.km-visible) {
  visibility: hidden;
}

.km-haut:hover {
  color: var(--km-ac); border-color: var(--km-ac-bord); text-decoration: none;
}

@media (prefers-reduced-motion: reduce) {
.km-haut {
  transition: none;
}
}

#products .km-offre-points,
.km-console .km-offre-points {
  gap: .875rem; padding-top: 1.5rem;
}

#products .km-point-offre,
.km-console .km-point-offre {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .75rem;
  align-items: start; font-size: .875rem; line-height: 1.375rem; color: var(--km-t1);
}

#products .km-point-offre::before,
.km-console .km-point-offre::before {
  content: none;
}

#products .km-point-icone,
.km-console .km-point-icone {
  color: var(--km-t2); margin-top: .0625rem; transition: color var(--km-d-micro) var(--km-e-micro);
}

#products .km-offre:hover .km-point-icone,
.km-console .km-offre:hover .km-point-icone,
#products .km-offre-vedette .km-point-icone,
.km-console .km-offre-vedette .km-point-icone {
  color: var(--km-ac);
}

#products .km-offre-prix,
.km-console .km-offre-prix {
  align-items: baseline; flex-wrap: wrap; gap: .5rem; margin-top: .25rem;
}

#products .km-offre-montant,
.km-console .km-offre-montant {
  font-size: 2.75rem; line-height: 1; letter-spacing: -.03em; color: var(--km-t0);
}

#products .km-offre-periode,
.km-console .km-offre-periode {
  font-size: .8125rem; color: var(--km-t2);
}

#products .km-offre-barre,
.km-console .km-offre-barre {
  margin-left: 0; font-size: .875rem; color: var(--km-t2);
}

#products .km-offre-barre s,
.km-console .km-offre-barre s {
  text-decoration-color: var(--km-t2);
}

#products .km-offre-economie,
.km-console .km-offre-economie {
  display: inline-flex; align-items: center; align-self: flex-start;
  margin-top: .625rem; padding: .1875rem .5rem;
  border: 1px solid var(--km-ac-bord); border-radius: 3px;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .06em;
  color: var(--km-ac);
}

#products .km-offre-economie-nulle,
.km-console .km-offre-economie-nulle {
  border-color: var(--km-l1); color: var(--km-t2);
}

#products .km-offre-serment,
.km-console .km-offre-serment {
  display: flex; align-items: flex-start; gap: .5rem;
  margin-top: 1rem; padding-top: .875rem;
  border-top: 1px solid var(--km-l1);
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t1);
}

#products .km-offre-serment .km-icone,
.km-console .km-offre-serment .km-icone {
  color: var(--km-ac); flex: none; margin-top: .125rem;
}

#products .km-offre,
.km-console .km-offre {
  transition: background-color var(--km-d-elev) var(--km-e-couleur);
}

#products .km-offre::before,
.km-console .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);
}

#products .km-offre:hover::before,
.km-console .km-offre:hover::before {
  transform: scaleX(1);
}

#products .km-offre-appel,
.km-console .km-offre-appel {
  color: var(--km-t2); transition: color var(--km-d-micro) var(--km-e-micro);
}

#products .km-offre:hover .km-offre-appel,
.km-console .km-offre:hover .km-offre-appel,
#products .km-offre-vedette .km-offre-appel,
.km-console .km-offre-vedette .km-offre-appel {
  color: var(--km-ac);
}

#products .km-offre-appel::after,
.km-console .km-offre-appel::after {
  background: currentColor;
}

section[id] > .km-offres + *,
section[id] > .km-tuiles + *,
section[id] > .km-services-grille + *,
section[id] > .km-tableau-defile + *,
section[id] > .km-faq + *,
section[id] > .km-argus + *,
section[id] > .km-comp-cadre + *,
section[id] > .km-flux + *,
section[id] > .km-services-duo + * {
  margin-top: 64px;
}

.km-offres,
.km-tuiles,
.km-services-grille,
.km-duree,
.km-argus {
  margin-top: 0; margin-bottom: 0;
}

@media (max-width: 767px) {
section[id] > .km-offres + *,
section[id] > .km-tuiles + *,
section[id] > .km-services-grille + *,
section[id] > .km-tableau-defile + *,
section[id] > .km-faq + *,
section[id] > .km-argus + *,
section[id] > .km-comp-cadre + *,
section[id] > .km-flux + *,
section[id] > .km-services-duo + * {
  margin-top: 48px;
}
}

.km-haut {
  overflow: hidden;
}

.km-barre-bascule,
.km-duree-choix {
  position: relative; overflow: hidden;
}

.km-haut::after,
.km-barre-bascule::after,
.km-duree-choix::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0;
  border-radius: inherit;
  background: radial-gradient(120px circle at var(--km-mx, 50%) var(--km-my, 50%),
  var(--km-ac-voile2), transparent 62%);
  transition: opacity var(--km-d-couleur) var(--km-e-couleur);
}

.km-haut:hover::after,
.km-barre-bascule:hover::after,
.km-duree-choix:hover::after {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
.km-haut::after,
.km-barre-bascule::after,
.km-duree-choix::after {
  display: none;
}
}

.btn,
.km-barre-liens > li > a,
.km-barre-bascule,
.km-haut,
.km-barre-declencheur,
summary,
.km-q {
  min-height: 48px;
}

.btn,
.km-barre-liens > li > a,
.km-barre-bascule,
.km-haut {
  display: inline-flex; align-items: center; justify-content: center;
}

section[id] .km-offre h3 {
  line-height: 32px;
}

.km-recommande {
  font-size: .6875rem;
}

p a.btn,
li a.btn,
.km-barre-liens a,
.km-barre-actions a {
  text-decoration: none;
}

@media (min-width: 1000px) {
#products .km-offres,
.km-console .km-offres {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
}

@media (max-width: 999.98px) {
#products .km-offres,
.km-console .km-offres {
  grid-template-columns: minmax(0, 1fr);
}
}

.km-offre-groupe {
  display: block; margin-top: 1.25rem;
  padding-top: 1.25rem; border-top: 1px solid var(--km-l0);
}

.km-offre-sous-titre {
  display: block; margin-bottom: .75rem;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--km-t2);
}

.km-point-absent {
  color: var(--km-t2);
}

.km-point-absent .km-point-icone {
  color: var(--km-t3, var(--km-t2)); opacity: .75;
}

.km-offre-terme {
  display: block; margin-top: .375rem;
  font-family: var(--km-mono); font-size: .6875rem; line-height: 1.125rem;
  letter-spacing: .04em; color: var(--km-t2);
}

@media (min-width: 1000px) {
#products .km-offre-vedette,
.km-console .km-offre-vedette {
  position: relative; z-index: 1;
}
}

#products .km-offre-vedette,
.km-console .km-offre-vedette {
  border-left-color: var(--km-ac);
  border-left-width: 2px;
}

#products .km-offre-vedette .km-offre-titre,
.km-console .km-offre-vedette .km-offre-titre {
  color: var(--km-ac);
}

#products .km-offre-vedette:hover,
.km-console .km-offre-vedette:hover {
  border-left-color: var(--km-ac-h, var(--km-ac));
}

.km-socle {
  margin-top: 24px;
  padding: 1.5rem 1.75rem;
  border: 1px solid var(--km-l1);
  border-radius: 5px;
  background: color-mix(in srgb, var(--km-plan-a) 55%, transparent);
}

.km-socle-tete {
  display: inline-flex; align-items: center; gap: .625rem; margin-bottom: 1rem;
}

.km-socle-tete .km-icone {
  color: var(--km-ac);
}

.km-socle-liste {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: .75rem 1.5rem; margin: 0; padding: 0; list-style: none;
}

.km-socle-liste li {
  display: flex; align-items: baseline; gap: .625rem;
  font-size: .9375rem; color: var(--km-t1);
}

.km-socle-liste .km-point-icone {
  flex: 0 0 auto; color: var(--km-ac); opacity: .85;
}

@media (min-width: 1100px) {
.km-socle-liste {
  grid-template-columns: repeat(5, minmax(0, 1fr));
}
}

@media (max-width: 599.98px) {
.km-socle {
  padding: 1.25rem;
}
}

@media (max-width: 599.98px) {
.km-socle-liste {
  grid-template-columns: minmax(0, 1fr);
}
}

@media (max-width: 760px) {
#products .km-offre .km-valeur,
.km-console .km-offre .km-valeur,
#products .km-offre-montant,
.km-console .km-offre-montant {
  font-size: 2.125rem; line-height: 40px;
}
}

/* La carte entière se laisse cliquer : le geste suit l'appel visible. */
.km-offres-cmd .km-offre { cursor: pointer; }

/* ---- 61.24 La marque quand il n'y a PAS de rail ----------------------
   Relevé à l'écran sur /order : hors de l'espace connecté, le menu
   latéral n'existe pas, donc la classe « km-rail-ouvert » n'est jamais
   posée et l'échange signe → marque pleine du 61.12 ne se déclenche
   jamais. Le SIGNE seul tenait le bandeau — le visiteur y lisait le
   favicon, pas le logo. Sur ces pages, c'est la marque PLEINE qui doit
   tenir, dans sa variante de thème. Le bandeau du client connecté n'est
   pas touché : tout est verrouillé par « body:not(:has(#sidebarMenu)) ». */
body:not(:has(#sidebarMenu)) .navbar-brand.km-marque .km-marque-signe { display: none; }
body:not(:has(#sidebarMenu)) .navbar-brand.km-marque .km-marque-pleine {
  position: static; inset: auto;
  padding-inline-start: 0;
  opacity: 1; visibility: visible;
  transition: none;
}
/* Les deux variantes sont pilotées ici, au poids voulu : la règle
   « .km-marque img { display: block } » du 61.12 pèse plus qu'une classe
   seule et montrerait sinon les DEUX marques empilées. */
body:not(:has(#sidebarMenu)) .navbar-brand.km-marque img.km-marque-va-clair { display: block; }
body:not(:has(#sidebarMenu)) .navbar-brand.km-marque img.km-marque-va-sombre { display: none; }
[data-bs-theme="dark"] body:not(:has(#sidebarMenu)) .navbar-brand.km-marque img.km-marque-va-clair { display: none; }
[data-bs-theme="dark"] body:not(:has(#sidebarMenu)) .navbar-brand.km-marque img.km-marque-va-sombre { display: block; }
/* Sous 768 px, le 61.12 masque la marque pleine parce que le rail n'y
   existe pas ; ici c'est la seule marque disponible — elle reste, d'un
   cran plus basse pour tenir à côté du bouton du menu. */
@media (max-width: 767.98px) {
  body:not(:has(#sidebarMenu)) .navbar-brand.km-marque .km-marque-pleine { display: flex; }
  body:not(:has(#sidebarMenu)) .navbar-brand.km-marque .km-marque-pleine img { height: 28px; }
}

/* ==========================================================================
   61.25 LE TÉLÉPHONE : la barre colle, la langue reste à portée, le menu
   se tient droit
   --------------------------------------------------------------------------
   Relevé à l'écran sur un iPhone de 375 px, page « Commander » :
   1. la langue et la bascule de thème étaient ENFERMÉES dans le menu replié ;
   2. le menu ouvert montrait DEUX FOIS « Tableau de bord » et « Commande » —
      les entrées du grand écran portaient « d-md-flex », qui ne cache rien
      sous 768 px, et la liste mobile s'ajoutait par-dessus ;
   3. tout était centré, sans rythme ni filet, la langue flottant au milieu
      comme une pastille trop grande ;
   4. la barre partait au défilement : plus de logo, plus de langue, plus rien.
   Le gabarit règle 1 et 2 ; ce bloc règle le reste. Rien ici ne descend sous
   768 px de large : le grand écran garde exactement son dessin validé.
   ========================================================================== */

@media (max-width: 767.98px) {

  /* ---- La barre colle en haut, avec le voile de la maison ---- */
  body > .container > header {
    position: sticky; top: 0; z-index: 1035;
    background: color-mix(in srgb, var(--km-fond) 94%, transparent);
    backdrop-filter: saturate(140%) blur(10px);
    border-bottom: 1px solid var(--km-l1);
    margin-inline: calc(var(--bs-gutter-x, 1.5rem) * -.5);
    padding-inline: calc(var(--bs-gutter-x, 1.5rem) * .5);
  }
  @supports not (backdrop-filter: blur(4px)) {
    body > .container > header { background: var(--km-fond); }
  }
  body > .container > header .navbar { padding-block: .5rem; }
  /* La rangée reste « wrap » : c'est ainsi que le menu déplié descend sur sa
     propre ligne, sous la marque. En « nowrap », il se rangeait À CÔTÉ et la
     marque passait sous le drapeau — vu à l'écran. */
  body > .container > header .navbar > .container-fluid {
    padding-inline: 0; gap: .5rem;
    flex-wrap: wrap !important;   /* le lot du cœur impose « nowrap » ici */
  }
  #navbarSupportedContent { flex-basis: 100%; }

  /* la marque tient la moitié de la barre, jamais plus */
  body > .container > header .navbar-brand.km-marque { flex: 0 1 auto; min-width: 0; }
  body:not(:has(#sidebarMenu)) .navbar-brand.km-marque .km-marque-pleine img { height: 26px; }

  /* ---- Les outils : trois cibles de 48 px, alignées à droite ---- */
  .km-barre-outils {
    margin-left: auto;
    align-items: center; gap: .125rem;
  }
  .km-barre-outils .km-bascule,
  .km-barre-outils .navbar-toggler {
    display: inline-flex; align-items: center; justify-content: center;
    width: 48px; height: 48px; padding: 0;
    border: 0; border-radius: 5px; background: transparent;
    color: var(--km-t1);
  }
  .km-barre-outils .km-bascule:hover,
  .km-barre-outils .navbar-toggler:hover { color: var(--km-t0); background: var(--km-plan-b); }
  .km-barre-outils .navbar-toggler:focus-visible,
  .km-barre-outils .km-bascule:focus-visible { outline: 2px solid var(--km-ac); outline-offset: 2px; box-shadow: none; }
  .km-barre-outils .km-bascule-icone { width: 20px; height: 20px; }

  /* Le sélecteur de langue : sur téléphone, une cible carrée — drapeau et
     chevron. La pastille bordée et le code « FR » sont le dessin du GRAND
     écran ; ici ils faisaient un bouton deux fois plus large que les autres. */
  .km-barre-outils .km-langue-declencheur {
    width: 48px; height: 48px; padding: 0; gap: .25rem;
    border: 0; border-radius: 5px; justify-content: center;
  }
  .km-barre-outils .km-langue-declencheur .km-langue-code { display: none; }
  .km-barre-outils .km-langue-declencheur .km-drapeau { width: 22px; height: auto; }
  .km-barre-outils .km-langue-declencheur:hover { background: var(--km-plan-b); }

  /* le panneau des langues : une feuille alignée sur la barre, jamais hors champ */
  .km-barre-outils .km-langue { position: static; }
  .km-barre-outils .km-langue-panneau {
    position: absolute; left: .75rem; right: .75rem; top: calc(100% + .5rem);
    min-width: 0; max-width: none; width: auto;
  }
  .km-barre-outils .km-langue-panneau .km-langue-choix { min-height: 48px; }

  /* ---- Le menu déplié : une feuille, pas une colonne centrée ---- */
  #navbarSupportedContent {
    margin-top: .5rem;
    border-top: 1px solid var(--km-l1);
    padding-top: .5rem;
  }
  /* « d-flex justify-content-end » du gabarit pèse d'un « !important » :
     sans le même poids, la liste restait collée à droite, large de 131 px. */
  #navbarSupportedContent > .navbar-nav {
    display: block !important;
    width: 100%; margin-bottom: .25rem;
  }
  #navbarSupportedContent .navbar-nav .nav-link {
    display: flex; align-items: center; gap: .75rem;
    min-height: 48px; padding: .25rem .25rem;
    text-align: left; font-size: 1rem;
  }
  #navbarSupportedContent .navbar-nav .nav-link .icon,
  #navbarSupportedContent .navbar-nav .nav-link svg {
    width: 18px; height: 18px; flex: none; opacity: .8;
  }
  #navbarSupportedContent .navbar-nav > li + li { border-top: 1px solid var(--km-l1); }
  #navbarSupportedContent .navbar-nav .nav-link.active { color: var(--km-ac); }

  /* la liste mobile occupe toute la largeur, sans puce ni décalage */
  #navbarSupportedContent .list-unstyled { width: 100%; padding: 0; margin: 0; }
  #navbarSupportedContent .list-unstyled > .navbar-nav { display: block !important; width: 100%; }

  /* les actions : deux colonnes égales, cibles de 48 px, rien qui déborde */
  #navbarSupportedContent .btn {
    display: flex; width: 100%; min-height: 48px;
    align-items: center; justify-content: center;
    padding-inline: .75rem; white-space: nowrap;
  }
  #navbarSupportedContent .km-menu-actions { margin: .75rem 0 .25rem; }

  /* ---- Le pied : des cibles tenables au doigt ---- */
  .km-pied-liens a { min-height: 44px; display: inline-flex; align-items: center; }
  .km-pied-col + .km-pied-col { margin-top: .25rem; }
}

/* Sous 380 px, la marque cède la place aux outils plutôt que de les serrer. */
@media (max-width: 379.98px) {
  body:not(:has(#sidebarMenu)) .navbar-brand.km-marque .km-marque-pleine img { height: 22px; }
  .km-barre-outils { gap: 0; }
}

/* ---- 61.26 Le pied de page sur téléphone : il était COUPÉ ----------------
   Relevé à l'écran : « .km-pied-haut » est redéclaré plus bas dans cette
   feuille, hors de toute requête de média, avec quatre colonnes fixes
   (240 + 3 × 140 = 660 px). Cette redéclaration l'emportait sur la règle
   mobile écrite plus haut, et le pied — largeur 351 px, « overflow: hidden »
   — cachait purement et simplement TROIS colonnes sur quatre : sur
   téléphone, aucun lien du pied n'était atteignable.
   La grille est donc reposée ici, après elle, et les liens reçoivent enfin
   une cible tenable au doigt. */
@media (max-width: 767.98px) {
  .km-pied-haut {
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 2rem 1.5rem;
  }
  .km-pied-marque { grid-column: 1 / -1; padding-inline-end: 0; }
  .km-pied-col { gap: .25rem; }
  .km-pied-col a { min-height: 44px; display: flex; align-items: center; }
  .km-pied-bas { flex-direction: column; align-items: flex-start; gap: .75rem; }

  /* Le sommaire des documents : des rangs de 44 px, comme partout ailleurs. */
  .km-doc-sommaire a { min-height: 44px; display: flex; align-items: center; }
}

/* ---- 61.27 Le sommaire replié sur téléphone ---- */
@media (max-width: 767.98px) {
  .km-doc-sommaire-repli { border-block: 1px solid var(--km-l1); }
  .km-doc-sommaire-repli > summary {
    display: flex; align-items: center; justify-content: space-between;
    min-height: 48px; cursor: pointer; list-style: none;
  }
  .km-doc-sommaire-repli > summary::-webkit-details-marker { display: none; }
  /* le chevron : dessiné, pas emprunté à une police */
  .km-doc-sommaire-repli > summary::after {
    content: ''; width: 9px; height: 9px; margin-inline-start: .75rem;
    border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform .15s ease; color: var(--km-t2);
  }
  .km-doc-sommaire-repli[open] > summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
  .km-doc-sommaire-repli > ol { padding-block: .25rem .75rem; }
  /* Le sommaire cesse d'être une colonne collante à défilement propre :
     sa barre de défilement se dessinait en travers, sous l'étiquette. */
  .km-doc-sommaire {
    border: 0; padding: 0;
    position: static; max-height: none; overflow: visible;
    margin-bottom: 2rem;
  }
}

/* ---- 61.28 Les gouttières du tunnel de commande sur téléphone ------------
   Mesuré sur 375 px : la première carte d'offre commençait à 39 px du bord,
   là où les pages de document commencent à 24 px. L'empilement en était la
   cause — conteneur 12, corps de carte 4, bordure 1, puis 22 px de corps
   d'accordéon. Trois épaisseurs pour un seul retrait. On ramène le tout à
   la gouttière de la maison : 24 px, comme partout ailleurs. */
@media (max-width: 767.98px) {
  /* « #orderManager .accordion-body » pèse un identifiant, et « p-1 » un
     « !important » : il faut le même poids pour être entendu. */
  .km-tunnel .card-body.p-1,
  .km-cmd-catalogue .card-body.p-1 { padding-inline: 0 !important; }
  #orderManager .accordion-body,
  .km-tunnel .accordion-body,
  .km-cmd-catalogue .accordion-body { padding-inline: .6875rem; }
  #orderManager .accordion-button,
  .km-tunnel .accordion-button { padding-inline: .6875rem; }

  /* Les cartes d'offre prennent toute la largeur utile, une par ligne. */
  .km-offres-cmd { gap: 1rem; }
  .km-offres-cmd .km-offre { width: 100%; }
}

/* ---- 61.29 Les champs ne font plus zoomer l'iPhone ----------------------
   Safari sur iOS agrandit la page dès qu'un champ reçoit le focus avec une
   police inférieure à 16 px — la mise en page saute, et il faut repincer
   pour revenir. Nos champs étaient à 15 px. Sur téléphone seulement, ils
   passent à 16 px : le zoom automatique ne se déclenche plus, et rien ne
   change au grand écran. */
@media (max-width: 767.98px) {
  input:not([type='checkbox']):not([type='radio']),
  select, textarea,
  .form-control, .form-select {
    font-size: 16px;
  }
  /* les étiquettes gardent leur échelle : seules les zones de saisie montent */
  .form-label, .form-text, .invalid-feedback { font-size: .8125rem; }
}

/* ---- 61.30 UNE seule gouttière sur téléphone ----------------------------
   Mesuré page par page à 375 px : le formulaire de contact commençait à
   12 px du bord, les champs d'inscription à 20, les cartes d'offre à 25,
   le pied à 12. Quatre marges pour un même écran — c'est ce qui donne
   l'impression que rien n'est aligné.
   La gouttière du cœur (« --bs-gutter-x », 24 px, donc 12 de chaque côté)
   passe à 40 px, soit 20 de chaque côté. Les rangées annulent la gouttière
   de leur conteneur et les colonnes la reposent : le compte reste juste,
   même imbriqué. Tout le contenu part donc de 20 px, partout. */
@media (max-width: 767.98px) {
  .container, .container-fluid, .container-sm, .container-md { --bs-gutter-x: 2.5rem; }

  /* la barre du haut suit la même gouttière que la page */
  body > .container > header {
    margin-inline: -1.25rem; padding-inline: 1.25rem;
  }
}

/* ---- 61.31 La tablette : le bandeau tient sur une ligne ------------------
   Entre 768 et 991 px, le menu du grand écran est déjà déplié mais la place
   manque : « Tableau de bord » se coupait en deux et la barre gagnait une
   ligne. Les libellés cessent de se couper, l'échelle baisse d'un cran, et
   la pastille de langue se resserre. Au-delà de 992 px, rien ne change. */
@media (min-width: 768px) and (max-width: 991.98px) {
  body > .container > header .navbar-nav .nav-link {
    white-space: nowrap; font-size: .875rem;
  }
  body > .container > header .navbar-nav > li + li { margin-inline-start: .125rem; }
  body > .container > header .btn { white-space: nowrap; padding-inline: .75rem; font-size: .875rem; }

  /* Mesuré : la rangée débordait de 49 px et le bouton « S'inscrire » sortait
     du cadre. Plutôt que de cacher un appel à l'action, on reprend la place
     là où elle ne coûte rien — la pastille de langue redevient un carré
     (le drapeau dit déjà la langue) et la marque baisse d'un cran. */
  body > .container > header .km-langue-declencheur {
    width: 44px; padding: 0; justify-content: center; gap: .25rem;
  }
  body > .container > header .km-langue-declencheur .km-langue-code { display: none; }
  body:not(:has(#sidebarMenu)) > .container > header .km-marque-pleine img { height: 28px; }
}
