/* ==========================================================================
   KARDOX MEDIA — LA FEUILLE DU SITE DE PRÉSENTATION
   Chargée APRÈS « kardox.css », jamais à sa place.

   RÈGLE INTANGIBLE
   Cette feuille n'annule rien. « kardox.css » porte les jetons, les cartes
   d'offre, les tableaux, les icônes, les motifs, le pied, le focus et le
   mouvement réduit : tout cela est déjà juste et reste tel quel. On ajoute
   ici les seules structures qu'une page de présentation demande et que
   l'espace client n'avait pas besoin d'avoir.

   Deux ajouts sortent de ce cadre et sont justifiés sur place, car sans eux
   la page ne peut pas exister : le rappel des polices (§ 1) et le socle que
   Bootstrap fournissait dans l'espace client et qui n'est pas chargé ici
   (§ 2). Aucun des deux ne change une valeur de la maison : ils rendent
   simplement applicables celles qui existent déjà.

    1. Les polices, servies depuis « assets/ » quoi qu'il arrive
    2. Le socle — ce que Bootstrap donnait ailleurs
    3. Le cadre et le rythme vertical
    4. La barre de navigation collante
    5. Le sélecteur de durée
    6. Le prix barré et la mention d'économie
    7. La grille des tuiles « inclus »
    8. Le tableau comparatif large
    9. La foire aux questions
   10. Le pied du site de présentation
   11. Les apparitions
   12. Les tailles d'écran — 1200 · 992 · 768 · 576
   13. Mouvement réduit
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. LES POLICES
   « kardox.css » déclare ses fontes sur « /themes/kardox/assets/fonts/ » :
   c'est le chemin de l'espace client, où le thème est servi par le moteur.
   Le site de présentation est une page statique dont les fichiers vivent dans
   « assets/ » ; ce chemin absolu n'y répond pas, et la page retomberait sur
   les polices du système — l'identité typographique disparaîtrait.

   On redéclare donc les MÊMES familles, avec les MÊMES graisses, en donnant
   plusieurs sources : le navigateur essaie la première, et passe à la
   suivante si le téléchargement échoue. La page tient ainsi qu'elle soit
   servie avec la feuille en fichier (« ../fonts/ »), avec la feuille en
   ligne dans le document (« assets/fonts/ »), ou à côté du thème.
   Aucune requête ne sort du domaine : c'est un argument de la maison.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: 'Plex Sans KM';
  src: url('../fonts/IBMPlexSans-Variable-latin.woff2') format('woff2-variations'),
       url('assets/fonts/IBMPlexSans-Variable-latin.woff2') format('woff2-variations'),
       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 Mono KM';
  src: url('../fonts/IBMPlexMono-Regular-latin.woff2') format('woff2'),
       url('assets/fonts/IBMPlexMono-Regular-latin.woff2') format('woff2'),
       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('../fonts/IBMPlexMono-Medium-latin.woff2') format('woff2'),
       url('assets/fonts/IBMPlexMono-Medium-latin.woff2') format('woff2'),
       url('/themes/kardox/assets/fonts/IBMPlexMono-Medium-latin.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}


/* --------------------------------------------------------------------------
   2. LE SOCLE — ce que Bootstrap donnait ailleurs
   Dans l'espace client, « kardox.css » est posée par-dessus Bootstrap : elle
   se contente de régler des variables (« --bs-btn-bg »…) que Bootstrap
   applique. Le site de présentation ne charge aucune bibliothèque — c'est le
   choix de la maison — donc ces variables ne peignent rien tant qu'on ne
   fournit pas les quelques déclarations qui les consomment.

   On n'invente aucune valeur : chaque propriété lit le jeton que
   « kardox.css » a déjà réglé. Six boutons, un conteneur, une remise à zéro
   minimale. Rien de plus : ce n'est pas un cadriciel.
   -------------------------------------------------------------------------- */

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

body { margin: 0; }
[hidden] { display: none !important; }
img, svg, video { max-width: 100%; }
img { height: auto; }

/* Le corps garde sa trame d'ingénieur ; le canevas de « kardox.js » se pose
   en fond (z-index 0). Tout ce qui porte du texte passe donc au-dessus. */
.km-v-barre, .km-v-corps, .km-v-section, .km-v-pied { position: relative; z-index: 1; }

/* Les listes de la page de présentation ne sont pas des listes de prose. */
.km-v-liste-nue { margin: 0; padding: 0; list-style: none; }

/* Le bouton. « kardox.css » règle « --bs-btn-* » pour six variantes ; ces
   huit lignes sont ce que Bootstrap en faisait. Le survol, l'appui et l'état
   désactivé lisent les mêmes variables — aucune couleur en dur. */
.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));
}

/* Un tableau sans Bootstrap n'a ni largeur ni fusion de filets. Les cellules,
   elles, sont déjà réglées par la section 11 de « kardox.css ». */
.table { width: 100%; border-collapse: collapse; }

/* Le lien d'évitement : première tabulation de la page, invisible tant qu'on
   ne le vise pas. Il n'a rien de facultatif — sans lui, on retraverse la
   barre entière à chaque page. */
.km-v-saut {
  position: absolute; left: 1rem; top: -4rem; z-index: 60;
  padding: .75rem 1.125rem;
  background: var(--km-plan-a);
  border: 1px solid var(--km-ac);
  border-radius: 4px;
  color: var(--km-t0);
  font-size: .875rem; font-weight: 510;
  transition: top var(--km-d-couleur) var(--km-e-sortie);
}
.km-v-saut:focus { top: 1rem; text-decoration: none; color: var(--km-t0); }


/* --------------------------------------------------------------------------
   3. LE CADRE ET LE RYTHME VERTICAL
   Les valeurs sont celles relevées et validées pour l'ouverture (section 28
   de « kardox.css ») : rembourrage de carte 24, gouttière 32, bloc de texte
   vers les cartes 72, hauteur de section 128. On les nomme une fois, en
   jetons, et les tailles d'écran ne changent ensuite que ces jetons — pas
   les règles. C'est ce qui garde le rythme cohérent d'un bout à l'autre.
   -------------------------------------------------------------------------- */

:root {
  --km-v-largeur: 71.25rem;   /* 1140 — la mesure courante */
  --km-v-largeur-large: 82.5rem; /* 1320 — réservée au tableau comparatif */
  --km-v-marge: 1.5rem;       /* 24 — la gouttière du cadre */
  --km-v-section: 8rem;       /* 128 — le pas d'une section */
  --km-v-tete: 4.5rem;        /* 72 — du bloc de texte aux cartes */
  --km-v-gouttiere: 2rem;     /* 32 — entre deux cartes */
  --km-v-carte: 1.5rem;       /* 24 — le rembourrage d'une carte */
  --km-v-barre-h: 4rem;       /* 64 — la hauteur de la barre collante */
}

.km-v-cadre,
.container {
  width: 100%;
  max-width: calc(var(--km-v-largeur) + 2 * var(--km-v-marge));
  margin-inline: auto;
  padding-inline: var(--km-v-marge);
}
.km-v-cadre-large {
  max-width: calc(var(--km-v-largeur-large) + 2 * var(--km-v-marge));
}

.km-v-section { padding-block: var(--km-v-section); }
/* Une section qui prolonge la précédente ne recommence pas le pas complet. */
.km-v-section-suite { padding-top: 0; }

/* La cible d'une ancre doit s'arrêter SOUS la barre collante, pas dessous. */
.km-v-section[id], [id].km-v-ancre { scroll-margin-top: calc(var(--km-v-barre-h) + 1.5rem); }

/* Le chapeau d'une section : étiquette, titre, une phrase. Puis 72 de vide
   avant ce qu'il annonce. La mesure de lecture reste courte : un chapeau
   qui court sur toute la largeur n'est plus un chapeau. */
.km-v-tete { margin-bottom: var(--km-v-tete); max-width: 44rem; }
.km-v-tete > .km-etiquette { display: block; margin-bottom: 1.125rem; }
.km-v-tete h2 {
  margin: 0 0 1rem;
  font-size: clamp(1.75rem, 3.2vw, 2.25rem);
  line-height: 1.14;
  letter-spacing: -.028em;
}
.km-v-tete-phrase {
  margin: 0;
  font-size: 1.0625rem; line-height: 1.75rem;
  letter-spacing: -.011em;
  color: var(--km-t1);
  max-width: 60ch;
}
/* Un chapeau centré, quand la section qui suit est elle-même centrée. */
.km-v-tete-centre { margin-inline: auto; text-align: center; }
.km-v-tete-centre .km-v-tete-phrase { margin-inline: auto; }

/* La rangée d'appels à l'action qui clôt une section. */
.km-v-issue {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1.25rem;
  margin-top: var(--km-v-tete);
}
.km-v-issue .btn { min-height: 48px; }
.km-v-issue-note {
  margin: 0; font-size: .875rem; line-height: 1.375rem; color: var(--km-t2);
  max-width: 46ch;
}


/* --------------------------------------------------------------------------
   4. LA BARRE DE NAVIGATION COLLANTE
   Fond plein — jamais de verre dépoli : le fond du site porte une trame, et
   la flouter en ferait une bouillie. Le filet du bas n'apparaît qu'une fois
   la page défilée : tant qu'on est en haut, rien ne sépare la barre de
   l'ouverture, et la page commence d'un seul tenant.

   Sans JavaScript, le filet est là en permanence : mieux vaut une séparation
   toujours visible qu'un texte qui glisse sous une barre sans limite.
   -------------------------------------------------------------------------- */

.km-v-barre {
  position: sticky; top: 0; z-index: 50;
  background: var(--km-fond);
  border-bottom: 1px solid var(--km-l1);
  transition: border-color var(--km-d-couleur) var(--km-e-couleur);
}
.km-v-js .km-v-barre { border-bottom-color: transparent; }
.km-v-js .km-v-barre-posee { border-bottom-color: var(--km-l1); }

.km-v-barre-corps {
  display: flex; align-items: center; gap: 1.5rem;
  min-height: var(--km-v-barre-h);
}

.km-v-marque {
  display: inline-flex; align-items: center; gap: .625rem;
  color: var(--km-t0); font-weight: 510; letter-spacing: -.014em;
  font-size: 1rem; text-decoration: none; white-space: nowrap;
}
.km-v-marque:hover { color: var(--km-t0); text-decoration: none; }
.km-v-marque .km-icone { color: var(--km-ac); }

/* Les liens de section. Sur écran étroit, la rangée défile horizontalement
   plutôt que de se replier derrière un bouton : un menu qui a besoin de
   JavaScript pour s'ouvrir est un menu qui peut ne pas s'ouvrir. */
.km-v-nav {
  display: flex; align-items: center; gap: .25rem;
  margin: 0; padding: 0; list-style: none;
  overflow-x: auto;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
.km-v-nav-lien {
  position: relative;
  display: inline-flex; align-items: center;
  min-height: 44px; padding: 0 .75rem;
  color: var(--km-t1);
  font-size: .875rem; font-weight: 510; letter-spacing: -.006em;
  white-space: nowrap; text-decoration: none;
  transition: color var(--km-d-micro) var(--km-e-micro);
}
.km-v-nav-lien:hover { color: var(--km-t0); text-decoration: none; }
/* Le soulignement se trace de la gauche, comme partout dans la maison. */
.km-v-nav-lien::after {
  content: ""; position: absolute; left: .75rem; right: .75rem; bottom: 9px;
  height: 1px; background: var(--km-ac);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--km-d-elev) var(--km-e-sortie);
}
.km-v-nav-lien[aria-current] { color: var(--km-t0); }
.km-v-nav-lien[aria-current]::after { transform: scaleX(1); }

.km-v-barre-actions {
  display: flex; align-items: center; gap: .5rem;
  margin-left: auto;
}
/* La bascule reprend « .km-bascule » de la maison ; elle n'a besoin ici que
   d'une couleur de départ et d'un survol, la barre n'étant pas celle de
   l'espace client. */
.km-v-barre .km-bascule {
  background: none; border: 0; padding: 0; cursor: pointer;
  border-radius: 4px;
  color: var(--km-t1);
  transition: color var(--km-d-micro) var(--km-e-micro),
              background-color var(--km-d-micro) var(--km-e-micro);
}
.km-v-barre .km-bascule:hover { color: var(--km-t0); background: var(--km-plan-b); }


/* --------------------------------------------------------------------------
   5. LE SÉLECTEUR DE DURÉE
   Un groupe de boutons radio, pas un menu : les quatre durées se voient
   toutes en même temps, et la flèche du clavier passe de l'une à l'autre
   sans qu'on écrive une ligne pour cela.

   Le champ est masqué à l'œil mais reste focalisable ; l'anneau de focus est
   donc porté par l'intitulé, sinon il serait invisible. L'option retenue
   prend le voile et le filet d'accent — le même état actif que les onglets
   en pastille de la maison — et sa couleur, elle, tient le contraste :
   l'information ne repose jamais sur le seul fond.
   -------------------------------------------------------------------------- */

/* Le <fieldset> reste un bloc : un fieldset en « display: flex » rend son
   <legend> de façon inégale d'un navigateur à l'autre. Le flottant sur le
   <legend> est le seul moyen sûr de le remettre dans le flux ; le rang
   lui-même vit dans « .km-v-durees-corps ». */
.km-v-durees { margin: 0 0 var(--km-v-tete); padding: 0; border: 0; min-width: 0; }
.km-v-durees > legend {
  display: block; float: left; width: 100%;
  margin: 0 0 1rem; padding: 0;
}
.km-v-durees-corps {
  clear: both;
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem;
}

.km-v-durees-groupe {
  display: inline-flex; flex-wrap: wrap; gap: 2px;
  padding: 4px;
  /* --km-l3 et pas --km-l1 : c'est la limite visible d'une commande, elle
     doit tenir 3:1 ; la maison a déjà mesuré ce jeton pour cela. */
  border: 1px solid var(--km-l3);
  border-radius: 5px;
  background: var(--km-plan-a);
}

.km-v-duree-champ {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.km-v-duree {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: 44px; padding: .625rem 1.125rem;
  border-radius: 4px;
  color: var(--km-t1);
  font-size: .875rem; font-weight: 510; letter-spacing: -.006em;
  white-space: nowrap; cursor: pointer;
  transition: color var(--km-d-couleur) var(--km-e-couleur),
              background-color var(--km-d-couleur) var(--km-e-couleur),
              box-shadow var(--km-d-couleur) var(--km-e-couleur);
}
.km-v-duree:hover { color: var(--km-t0); background: var(--km-plan-b); }
.km-v-duree-champ:checked + .km-v-duree {
  color: var(--km-ac);
  background: var(--km-ac-voile);
  box-shadow: inset 0 0 0 1px var(--km-ac-bord);
}
.km-v-duree-champ:focus-visible + .km-v-duree {
  outline: 2px solid var(--km-ac);
  outline-offset: 3px;
}
/* La remise, dans l'intitulé : c'est une mesure, donc la Mono. */
.km-v-duree-remise {
  font-family: var(--km-mono); font-size: .6875rem; font-weight: 400;
  letter-spacing: .1em; color: var(--km-t2);
  font-variant-numeric: tabular-nums;
  transition: color var(--km-d-couleur) var(--km-e-couleur);
}
.km-v-duree-champ:checked + .km-v-duree .km-v-duree-remise { color: var(--km-ac); }

/* La phrase qui accompagne le groupe — et qui porte l'annonce vocale. */
.km-v-durees-note {
  margin: 0; max-width: 46ch;
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2);
}


/* --------------------------------------------------------------------------
   6. LE PRIX BARRÉ ET LA MENTION D'ÉCONOMIE
   Le prix barré est le tarif mensuel, jamais un prix d'appel : c'est la
   promesse centrale de la maison, et elle mérite d'être lisible. Le trait de
   rature ne porte pas seul le sens — un intitulé pour lecteur d'écran le
   précède dans le HTML —, et l'économie est écrite en toutes lettres.
   -------------------------------------------------------------------------- */

.km-v-prix-avant {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .375rem .875rem;
  margin: -.25rem 0 0;
  font-family: var(--km-mono); font-size: .8125rem; line-height: 1.25rem;
  color: var(--km-t2);
  font-variant-numeric: tabular-nums;
}
.km-v-prix-avant s {
  text-decoration-line: line-through;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--km-t2);
}
/* L'économie : un filet court puis le mot, comme « recommandée » sur la
   carte vedette. Jamais de pastille. */
.km-v-econo {
  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-v-econo::before { content: ""; width: 14px; height: 1px; background: var(--km-ac); }
.km-v-econo:empty { display: none; }

/* La note sous le prix : ce que la durée engage, et le renouvellement. */
.km-v-prix-note {
  margin: 0; font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2);
}
/* Le montant change sous le doigt : on adoucit le remplacement, sans jamais
   faire monter un compteur tout seul. */
.km-offre-montant { transition: color var(--km-d-couleur) var(--km-e-couleur); }
.km-v-montant-change { color: var(--km-ac); }


/* --------------------------------------------------------------------------
   7. LA GRILLE DES TUILES « INCLUS »
   Ce qui est dans les trois formules, dit une fois pour toutes. Même plan,
   même filet, même rayon, même survol que les tuiles de l'espace client :
   filet de safran sur l'arête haute, plan d'un cran, élévation de trois
   pixels. La tuile n'est pas cliquable — donc pas de flèche, pas d'appel.
   -------------------------------------------------------------------------- */

.km-v-inclus {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--km-v-gouttiere);
  margin: 0; padding: 0; list-style: none;
}
.km-v-tuile {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; gap: .625rem;
  padding: var(--km-v-carte);
  border: 1px solid var(--km-l1); border-radius: 5px;
  background: var(--km-plan-a);
  color: var(--km-t0);
  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-v-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-v-tuile:hover, .km-v-tuile:focus-within {
  background: var(--km-plan-b); border-color: var(--km-l2);
  transform: translateY(-3px);
}
.km-v-tuile:hover::before, .km-v-tuile:focus-within::before { transform: scaleX(1); }
.km-v-tuile > .km-icone { color: var(--km-ac); margin-bottom: .25rem; }
.km-v-tuile-titre {
  margin: 0; font-size: 1rem; line-height: 1.5rem; font-weight: 510;
  letter-spacing: -.01em; color: var(--km-t0); max-width: none;
}
.km-v-tuile-note {
  margin: 0; font-size: .875rem; line-height: 1.375rem; color: var(--km-t1);
  max-width: none;
}
/* La mesure qui clôt une tuile — une version, un nom de serveur, un quota. */
.km-v-tuile-mesure {
  margin-top: auto; padding-top: .625rem;
  font-family: var(--km-mono); font-size: .75rem; letter-spacing: .04em;
  color: var(--km-ac);
  font-variant-numeric: tabular-nums;
}

/* Ce qui N'EST PAS inclus se dit dans la même grille, du même trait : la
   franchise n'a pas besoin d'un traitement à part, seulement d'être dite.
   L'icône passe en gris et le filet de survol ne s'allume pas. */
.km-v-tuile-absent { background: transparent; border-style: dashed; }
.km-v-tuile-absent > .km-icone { color: var(--km-t2); }
.km-v-tuile-absent::before { display: none; }
.km-v-tuile-absent:hover { transform: none; background: transparent; border-color: var(--km-l2); }

/* Un état transitoire — « en préparation » — se dit comme tous les statuts
   de la maison : un point de 7 px et un libellé. Le point est creux, parce
   que rien n'est encore stable. Jamais de pastille de couleur. */
.km-v-point-creux {
  background: transparent;
  box-shadow: inset 0 0 0 1.6px var(--km-t2);
}


/* --------------------------------------------------------------------------
   8. LE TABLEAU COMPARATIF LARGE
   Trois formules, dix lignes de quotas : c'est large, et ça doit le rester.
   Le tableau garde donc sa largeur minimale et défile dans son propre cadre
   quand l'écran ne suffit plus — la page, elle, ne défile jamais de côté.
   Ce cadre reçoit le focus au clavier (« kardox.js » ne s'en occupe pas,
   « vitrine.js » le fait) : une zone qui défile et qu'on ne peut pas
   atteindre au clavier est une zone perdue.

   La colonne de la formule vedette n'est pas remplie d'une couleur : elle
   porte un filet de safran sous son intitulé, comme la carte vedette porte
   le sien sur son arête haute.
   -------------------------------------------------------------------------- */

.km-v-tableau-cadre {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border-radius: 5px;
}
.km-v-tableau-cadre:focus-visible { outline: 2px solid var(--km-ac); outline-offset: 3px; }

.km-v-tableau {
  width: 100%; min-width: 44rem;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
.km-v-tableau caption {
  margin-bottom: 1.25rem; text-align: left;
  font-family: var(--km-mono); font-size: .6875rem; line-height: 1rem;
  font-weight: 400; letter-spacing: .2em; text-transform: uppercase;
  color: var(--km-t2);
}
.km-v-tableau thead th {
  padding: 0 1.125rem .875rem;
  border-bottom: 1px solid var(--km-l2);
  font-family: var(--km-mono); font-size: .6875rem; line-height: 1rem;
  font-weight: 400; letter-spacing: .2em; text-transform: uppercase;
  color: var(--km-t2);
  text-align: center; white-space: nowrap;
  vertical-align: bottom;
}
.km-v-tableau thead th:first-child { text-align: left; padding-left: 0; }
/* La formule vedette : un filet, pas un aplat. */
.km-v-tableau thead .km-v-col-vedette {
  color: var(--km-ac);
  box-shadow: inset 0 -1px 0 var(--km-ac);
}
.km-v-tableau tbody th,
.km-v-tableau tbody td {
  padding: .9375rem 1.125rem;
  border-bottom: 1px solid var(--km-l1);
  font-size: .9375rem; line-height: 1.375rem;
  vertical-align: middle;
}
/* L'intitulé de ligne porte la parole : Sans, graisse normale, aligné à
   gauche. Les valeurs sont des mesures : Mono, centrées sous leur colonne. */
.km-v-tableau tbody th {
  text-align: left; padding-left: 0;
  font-weight: 400; color: var(--km-t0);
}
.km-v-tableau tbody td {
  text-align: center;
  font-family: var(--km-mono); letter-spacing: -.01em;
  color: var(--km-t0);
}
.km-v-tableau tbody .km-v-col-vedette { color: var(--km-t0); }
.km-v-tableau tbody tr { transition: background-color var(--km-d-micro) var(--km-e-micro); }
.km-v-tableau tbody tr:hover { background: var(--km-plan-a); }
.km-v-tableau tbody tr:last-child th,
.km-v-tableau tbody tr:last-child td { border-bottom: 0; }
/* Une valeur absente se dit par un tiret, jamais par une case vide. */
.km-v-tableau .km-v-nul { color: var(--km-t2); }

/* Le rappel sous le tableau : d'où viennent les chiffres. */
.km-v-tableau-note {
  margin: 1.25rem 0 0; max-width: 68ch;
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2);
}


/* --------------------------------------------------------------------------
   9. LA FOIRE AUX QUESTIONS
   Des <details> : ils s'ouvrent, se ferment, se cherchent et s'impriment
   sans une ligne de JavaScript. Le triangle du navigateur disparaît au
   profit d'un chevron dessiné — un carré d'angle de 8 px, deux filets d'un
   pixel — qui pivote d'un quart de tour à l'ouverture. Le marqueur de la
   question, lui, est le carré de 4 px de la maison.
   -------------------------------------------------------------------------- */

.km-v-faq {
  max-width: 56rem;
  border-top: 1px solid var(--km-l1);
}
.km-v-faq-item { border-bottom: 1px solid var(--km-l1); }

.km-v-q {
  display: flex; align-items: center; gap: .875rem;
  min-height: 48px; padding: 1.25rem 0;
  color: var(--km-t0);
  font-size: 1rem; line-height: 1.5rem; font-weight: 510; letter-spacing: -.01em;
  cursor: pointer;
  list-style: none;          /* Firefox */
  transition: color var(--km-d-micro) var(--km-e-micro);
}
.km-v-q::-webkit-details-marker { display: none; }  /* Safari, anciens Chrome */
.km-v-q:hover { color: var(--km-ac); }
.km-v-q:focus-visible { outline: 2px solid var(--km-ac); outline-offset: 3px; }
/* Le marqueur de liste de la maison. */
.km-v-q::before {
  content: ""; flex: none; width: 4px; height: 4px;
  background: var(--km-ac);
}
/* Le chevron : deux filets d'un pixel formant un angle, tourné vers la
   droite au repos, vers le bas une fois la réponse ouverte. */
.km-v-q::after {
  content: ""; flex: none; width: 8px; height: 8px; margin-left: auto;
  border-top: 1px solid currentColor;
  border-right: 1px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--km-d-elev) var(--km-e-sortie),
              border-color var(--km-d-couleur) var(--km-e-couleur);
}
.km-v-faq-item[open] > .km-v-q { color: var(--km-t0); }
.km-v-faq-item[open] > .km-v-q::after { transform: rotate(135deg); border-color: var(--km-ac); }

.km-v-r {
  margin: 0; padding: 0 2rem 1.5rem 1.125rem;
  max-width: 68ch;
  font-size: .9375rem; line-height: 1.625rem; color: var(--km-t1);
}
.km-v-r > *:last-child { margin-bottom: 0; }
/* La réponse se déplie plutôt que d'apparaître d'un bloc. L'animation ne
   porte aucune information : si elle ne joue pas, rien n'est perdu. */
.km-v-faq-item[open] > .km-v-r { animation: km-v-deplier 320ms var(--km-e-sortie) both; }
@keyframes km-v-deplier {
  from { opacity: 0; transform: translateY(-6px); }
}


/* --------------------------------------------------------------------------
   10. LE PIED DU SITE DE PRÉSENTATION
   Le pied de l'espace client est déjà écrit (sections 29 et 31 de
   « kardox.css ») : colonnes, filets, survols qui se tracent. On le
   réemploie tel quel — c'est ce qui rend les deux sites indiscernables — et
   on n'ajoute ici que le cadre extérieur, parce que « .km-pied » porte une
   marge haute pensée pour une page d'application, pas pour une page dont la
   dernière section respire déjà de 128 px.

   D'où « .km-v-pied » à la place de « .km-pied » sur la balise <footer> :
   les classes internes (.km-pied-haut, .km-pied-col, .km-pied-bas…) sont
   définies indépendamment et fonctionnent sans lui. Rien n'est annulé.
   -------------------------------------------------------------------------- */

.km-v-pied {
  display: flex; flex-direction: column; gap: 2.5rem;
  padding-top: 3.5rem; padding-bottom: 0;
  border-top: 1px solid var(--km-l1);
  color: var(--km-t1);
  font-size: .875rem;
}
.km-v-pied .km-pied-bas { padding-bottom: 2.5rem; }
/* La mention de conformité qui ferme la page : mesure, donc Mono. */
.km-v-pied-mention {
  margin: 0;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--km-t2);
}
.km-v-pied-mention-libre { text-transform: none; letter-spacing: .04em; }


/* --------------------------------------------------------------------------
   11. LES APPARITIONS
   « kardox.js » dévoile déjà .km-section, .card, .km-tuile… en leur posant
   « km-vu ». On ne réécrit pas ce mécanisme : « vitrine.js » pose la MÊME
   classe sur les blocs propres à la présentation, avec le même seuil et le
   même filet de sûreté. Ici, seulement l'état de départ.

   La classe de garde est « km-v-anime », que « vitrine.js » ne pose qu'une
   fois son observateur en place — et jamais avant. Si le script ne se charge
   pas, ou s'il échoue en route, rien n'est jamais caché : c'est la seule
   façon d'être certain qu'aucun bloc ne peut disparaître pour de bon.
   -------------------------------------------------------------------------- */

.km-v-anime .km-v-rv { opacity: 0; transform: translateY(16px); }
.km-v-anime .km-v-rv.km-vu {
  opacity: 1; transform: none;
  transition: opacity 720ms var(--km-e-entree) var(--km-v-delai, 0ms),
              transform 720ms var(--km-e-entree) var(--km-v-delai, 0ms);
}


/* --------------------------------------------------------------------------
   12. LES TAILLES D'ÉCRAN — 1200 · 992 · 768 · 576
   Les règles ne changent pas : seuls les jetons de rythme changent. Une
   section perd de la hauteur avant de perdre de la matière.
   -------------------------------------------------------------------------- */

/* 1200 — la mesure large du tableau rentre dans la mesure courante. */
@media (max-width: 1199.98px) {
  :root { --km-v-largeur-large: var(--km-v-largeur); }
}

/* 992 — le pas de section descend de 128 à 96, le chapeau de 72 à 56. */
@media (max-width: 991.98px) {
  :root {
    --km-v-section: 6rem;
    --km-v-tete: 3.5rem;
  }
  .km-v-tete h2 { font-size: clamp(1.625rem, 4.2vw, 2rem); }
}

/* 768 — la barre se resserre, les liens de section défilent sous la marque,
   et les grilles passent à une colonne quand la place manque. */
@media (max-width: 767.98px) {
  :root {
    --km-v-section: 4.5rem;
    --km-v-tete: 3rem;
    --km-v-gouttiere: 1.25rem;
    --km-v-barre-h: 3.5rem;
  }
  .km-v-barre-corps { flex-wrap: wrap; gap: .25rem 1rem; padding-block: .5rem; }
  .km-v-nav { order: 3; width: 100%; margin-inline: calc(var(--km-v-marge) * -1); padding-inline: var(--km-v-marge); }
  .km-v-barre-actions { margin-left: auto; }
  .km-v-issue { flex-direction: column; align-items: stretch; }
  .km-v-issue .btn { width: 100%; }
  /* La barre passe sur deux rangs : l'ancre doit s'arrêter plus bas. */
  .km-v-section[id], [id].km-v-ancre { scroll-margin-top: 7.5rem; }
  /* Le tableau défile : son intitulé de ligne reste à vue, sinon on ne sait
     plus quel quota on lit. */
  .km-v-tableau tbody th {
    position: sticky; left: 0; z-index: 1;
    background: var(--km-fond);
    padding-right: 1rem;
  }
  .km-v-tableau tbody tr:hover th { background: var(--km-plan-a); }
}

/* 576 — la gouttière du cadre se réduit, les cartes gardent leur 24. */
@media (max-width: 575.98px) {
  :root {
    --km-v-marge: 1rem;
    --km-v-section: 3.5rem;
    --km-v-tete: 2.5rem;
  }
  .km-v-inclus { grid-template-columns: minmax(0, 1fr); }
  .km-v-durees-groupe { width: 100%; }
  .km-v-duree { flex: 1 1 8rem; }
  .km-v-tete h2 { font-size: 1.5rem; line-height: 1.16; }
  .km-v-r { padding-right: 0; }
}


/* --------------------------------------------------------------------------
   13. MOUVEMENT RÉDUIT
   La section 20 de « kardox.css » ramène déjà toutes les durées à 1 ms. On
   complète ici pour ce qui ne se règle pas par une durée : les états de
   départ qui, figés, laisseraient un bloc invisible ou un chevron immobile
   mais juste. Rien ne doit jamais rester à moitié dessiné.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .km-v-anime .km-v-rv { opacity: 1; transform: none; }
  .km-v-faq-item[open] > .km-v-r { animation: none; }
  .km-v-saut { transition: none; }
  .km-v-tuile:hover, .km-v-tuile:focus-within { transform: none; }
}

/* ==========================================================================
   L'OSSATURE DE LA PAGE DE PRÉSENTATION
   Écrite après coup : le lot chargé de la feuille s'est interrompu en cours
   de route et cent cinq classes employées par les sections n'avaient aucune
   règle — la page sortait collée au bord gauche, sans barre, sans rythme.
   Tout ici s'appuie sur les jetons de « kardox.css » : la page de
   présentation et l'espace client doivent rester indiscernables.
   ========================================================================== */

/* ---------- Le conteneur et le rythme ---------- */

.km-conteneur {
  width: 100%; max-width: 76rem; margin-inline: auto;
  padding-inline: 1.5rem;
}
.km-vitrine .km-section,
.km-vitrine section[id] { padding-block: 5rem; margin-bottom: 0; }
.km-vitrine section[id] > * { max-width: 76rem; margin-inline: auto; padding-inline: 1.5rem; }
/* Le lien d'évitement : invisible tant qu'il n'a pas le focus, puis bien
   visible. Il doit rester ATTEIGNABLE au clavier — donc jamais « display:none ». */
.km-saut, .km-v-saut {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  width: auto; padding: .75rem 1.25rem;
  background: var(--km-plan-c); color: var(--km-t0);
  border: 1px solid var(--km-ac); border-radius: 5px;
  text-decoration: none; font-size: .9375rem;
}
.km-saut:focus, .km-v-saut:focus { left: 1rem; top: 1rem; }

.km-vitrine h2 { margin: 0 0 1rem; }
.km-vitrine .km-section-tete { border-bottom: 0; padding-bottom: 0; margin-bottom: 1rem; }
.km-vitrine .km-lead { max-width: 62ch; }

/* ---------- La barre ---------- */

.km-barre {
  position: sticky; top: 0; z-index: 60;
  background: color-mix(in srgb, var(--km-fond) 92%, transparent);
  border-bottom: 1px solid transparent;
  transition: border-color var(--km-d-couleur) var(--km-e-couleur);
}
@supports not (background: color-mix(in srgb, red 50%, blue)) {
  .km-barre { background: var(--km-fond); }
}
.km-barre.km-vu, .km-barre[data-defile] { border-bottom-color: var(--km-l1); }
.km-barre-rang {
  display: flex; align-items: center; gap: 1.5rem;
  min-height: 68px;
}
.km-barre-marque {
  font-weight: 590; letter-spacing: -.014em; color: var(--km-t0);
  text-decoration: none; font-size: 1.0625rem;
}
.km-barre-marque:hover { color: var(--km-ac); text-decoration: none; }

.km-barre-menu { margin-left: auto; }
.km-barre-menu > summary { list-style: none; }
.km-barre-menu > summary::-webkit-details-marker { display: none; }
.km-barre-declencheur {
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 44px; padding: 0 .75rem; border-radius: 5px;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--km-t1); cursor: pointer;
}
.km-barre-declencheur:hover { color: var(--km-t0); background: var(--km-plan-b); }
.km-barre-panneau {
  position: absolute; right: 1.5rem; margin-top: .5rem;
  display: flex; flex-direction: column; gap: 1rem;
  padding: 1.25rem; min-width: 15rem;
  background: var(--km-plan-b); border: 1px solid var(--km-l1);
  border-radius: 5px; box-shadow: var(--km-ombre-2);
}
.km-barre-liens { display: flex; flex-direction: column; gap: .125rem; margin: 0; padding: 0; list-style: none; }
.km-barre-liens a {
  display: block; padding: .5rem 0; min-height: 44px; line-height: 28px;
  color: var(--km-t1); text-decoration: none; font-size: .9375rem;
}
.km-barre-liens a:hover, .km-barre-liens a.km-v-nav-lien-actif { color: var(--km-ac); text-decoration: none; }
.km-barre-actions { display: flex; flex-wrap: wrap; gap: .625rem; }
.km-barre-bascule {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; padding: 0;
  background: transparent; border: 0; border-radius: 5px;
  color: var(--km-t1); cursor: pointer;
}
.km-barre-bascule:hover { color: var(--km-t0); background: var(--km-plan-b); }

/* À partir de la tablette, le menu se déplie : plus de bouton, tout en ligne. */
@media (min-width: 900px) {
  .km-barre-menu { display: contents; }
  .km-barre-declencheur { display: none; }
  .km-barre-panneau {
    position: static; margin: 0 0 0 auto; padding: 0; min-width: 0;
    flex-direction: row; align-items: center; gap: 1.5rem;
    background: none; border: 0; box-shadow: none;
  }
  .km-barre-liens { flex-direction: row; gap: 1.5rem; }
  .km-barre-liens a { padding: 0; display: inline-flex; align-items: center; }
}

/* ---------- La langue du site ----------
   Le même dessin que le reste de la barre : pastille au filet --km-l1,
   panneau posé sur --km-plan-a, rayon de 5 px, code en Mono. Le rang courant
   porte le voile de safran — le motif des tableaux, pas une pastille neuve.
   Chaque rang fait 48 px de haut : la cible tactile de la maison. */
.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 {
  display: flex; align-items: center; gap: .75rem;
  min-height: 48px; padding: .375rem .75rem; border-radius: 4px;
  color: var(--km-t1); text-decoration: none;
}
/* « .km-vitrine li a » souligne tout lien de liste ; ces rangs n'en sont pas :
   la règle est répétée à spécificité supérieure pour l'emporter. */
.km-vitrine .km-langue-liste a { 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-t3); 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; }
@media (prefers-reduced-motion: reduce) {
  .km-langue-chevron { transition: none; }
}

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

.km-entree { padding-block: 4.5rem 3rem; }
.km-vitrine h1 { max-width: 18ch; margin: 1.25rem 0 0; }
.km-vitrine .km-entree .km-lead { margin-top: 1.25rem; }
.km-vitrine .km-ouverture-actions,
.km-appel-corps { display: flex; flex-wrap: wrap; gap: .875rem; margin-top: 2rem; }

/* ---------- La démonstration ---------- */

.km-preuve-cadre { margin-top: 2.5rem; }
.km-preuve-chapeau { max-width: 68ch; color: var(--km-t1); }
.km-preuve-figure { margin: 2rem 0 0; }
.km-preuve-svg { display: block; width: 100%; height: auto; overflow: visible; }
/* Un graphique au TRAIT : aucun aplat, aucun remplissage. C'était le défaut le
   plus visible — la courbe sortait en bloc noir. */
.km-preuve-svg * { fill: none; }
.km-preuve-svg text { fill: var(--km-t2); font-family: var(--km-mono); font-size: 11px; }
.km-preuve-grille line, .km-preuve-socle-trait { stroke: var(--km-l1); stroke-width: 1; }
.km-preuve-cran-haut { stroke: var(--km-l2); stroke-width: 1; }
.km-preuve-trait { stroke-width: 1.5; stroke-linejoin: miter; stroke-linecap: butt; }
.km-preuve-trait-kardox { stroke: var(--km-ac); }
.km-preuve-trait-marche { stroke: var(--km-t2); stroke-dasharray: 5 4; }
.km-preuve-bout { r: 3; }
.km-preuve-bout-kardox { fill: var(--km-ac) !important; stroke: none; }
.km-preuve-bout-marche { fill: var(--km-t1) !important; stroke: none; }
.km-preuve-saut { stroke: var(--km-l2); stroke-width: 1; stroke-dasharray: 3 3; }
.km-preuve-lecture { font-family: var(--km-mono); font-size: .75rem; }
.km-preuve-lecture-kardox { color: var(--km-ac); }
.km-preuve-lecture-marche { color: var(--km-t1); }
.km-preuve-legende { margin: 1.5rem 0 0; padding-left: 1.125rem; }
.km-preuve-legende li { margin-bottom: .375rem; color: var(--km-t1); font-size: .9375rem; }
.km-preuve-legende-note { max-width: 76ch; margin-top: .875rem; font-size: .8125rem; line-height: 1.375rem; color: var(--km-t2); }
.km-preuve-mesure { font-family: var(--km-mono); color: var(--km-t1); }
.km-preuve-mesure-forte { color: var(--km-ac); }
.km-preuve-tableau { margin-top: 2rem; }
.km-preuve-ecart { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 2rem; margin-top: 2.5rem; }
/* Le tracé se dessine à l'apparition ; sans script, il est déjà entier. */
/* Le tracé ne se cache QUE si le script a confirmé qu'il saura l'animer
   (« km-v-anime »), et il porte un filet de sûreté côté script. Mesuré :
   la version précédente dépendait d'une classe posée sur un ancêtre qui
   n'existe pas sur cette page — le trait restait invisible pour de bon. */
.km-v-anime .km-preuve-kardox { stroke-dasharray: 2000; stroke-dashoffset: 2000; }
.km-v-anime .km-preuve-kardox.km-trace {
  stroke-dashoffset: 0; transition: stroke-dashoffset 1600ms var(--km-e-entree);
}



/* ---------- Les tarifs ---------- */

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

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

#tarifs:has(#km-duree-m:checked)    .km-offre-jeu[data-duree="m"],
#tarifs:has(#km-duree-bia:checked)  .km-offre-jeu[data-duree="bia"],
#tarifs: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; }

/* ---------- Le comparatif ---------- */

.km-comparatif { margin-top: 4.5rem; }
.km-comparatif-titre { margin-bottom: 1.25rem; }
.km-tableau-defile, .km-v-tableau-cadre { overflow-x: auto; }
.km-comparatif table, .km-v-tableau { width: 100%; border-collapse: collapse; font-size: .9375rem; }
.km-comparatif caption, .km-v-tableau caption {
  caption-side: top; text-align: left; padding-bottom: .875rem;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--km-t2);
}
.km-comparatif th, .km-v-tableau th {
  padding: 0 1.25rem .75rem 0; text-align: left; vertical-align: bottom;
  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-comparatif td, .km-v-tableau td {
  padding: .8125rem 1.25rem .8125rem 0; vertical-align: top;
  border-bottom: 1px solid var(--km-l1); color: var(--km-t1);
}
.km-comparatif tbody th { color: var(--km-t0); border-bottom: 1px solid var(--km-l1); font-family: var(--km-sans); font-size: .9375rem; letter-spacing: -.006em; text-transform: none; }
.km-comparatif tbody tr:hover td, .km-comparatif tbody tr:hover th { color: var(--km-t0); }
.km-col-vedette { color: var(--km-t0) !important; }
.km-col-note, .km-comparatif-pied, .km-v-tableau-note {
  margin-top: 1rem; font-size: .8125rem; line-height: 1.375rem; color: var(--km-t2); max-width: 76ch;
}
.km-comparatif-releve { font-family: var(--km-mono); font-size: .75rem; color: var(--km-t2); }
.km-comparatif-mot { color: var(--km-t0); }
.km-comparatif-franchise, .km-comparatif-serment { max-width: 68ch; color: var(--km-t1); }

/* ---------- Les services ---------- */

.km-services-intro { max-width: 68ch; }
.km-services-grille, .km-v-inclus {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1.5rem; margin: 2.5rem 0 0; padding: 0; list-style: none;
}
.km-vitrine .km-tuile .km-icone { color: var(--km-ac); }
.km-titre-tuile { margin: .25rem 0 0; font-size: 1rem; font-weight: 510; letter-spacing: -.01em; color: var(--km-t0); max-width: none; }
.km-appui, .km-v-tuile-note { margin: 0; font-size: .875rem; line-height: 1.375rem; color: var(--km-t1); max-width: none; }
.km-services-duo { display: grid; grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); gap: 2rem; margin-top: 3rem; }
.km-services-encart, .km-v-tuile-absent {
  padding: 1.5rem; border: 1px solid var(--km-l1); border-radius: 5px; background: var(--km-plan-a);
}
.km-services-sous-titre { margin: 0 0 .75rem; font-size: 1.0625rem; font-weight: 510; color: var(--km-t0); }
.km-services-liste { margin: .875rem 0 0; padding: 0; list-style: none; }
.km-services-liste li { position: relative; padding-left: 1.125rem; margin-bottom: .5rem; font-size: .875rem; line-height: 1.375rem; color: var(--km-t1); }
.km-services-liste li::before { content: ""; position: absolute; left: 0; top: .625rem; width: 4px; height: 4px; background: var(--km-ac); }
.km-services-actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.25rem; }
.km-services-appui { font-size: .8125rem; color: var(--km-t2); }
/* Un point creux : ce qui n'est pas encore ouvert à la commande. */
.km-v-point-creux::before, .km-point-creux::before {
  content: ""; display: inline-block; width: 7px; height: 7px; margin-right: .5rem;
  border: 1px solid var(--km-t2); border-radius: 50%;
}

/* ---------- La confiance ---------- */

.km-confiance-tete { margin-bottom: 2.5rem; }
.km-argus { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); gap: 2rem; margin: 0; padding: 0; list-style: none; }
.km-argu { padding-top: 1.5rem; border-top: 1px solid var(--km-l1); }
.km-argu-titre { margin: .625rem 0 .5rem; font-size: 1.0625rem; font-weight: 510; color: var(--km-t0); }
.km-argu p { margin: 0; font-size: .875rem; line-height: 1.375rem; color: var(--km-t1); max-width: 44ch; }
.km-argu-mesure { margin-top: .625rem !important; font-family: var(--km-mono); font-size: .75rem; color: var(--km-ac); }
/* La marge visait le CADRE intérieur ; la section porte la même classe et
   l'héritait aussi — d'où un trou de 72 px de plus qu'ailleurs, mesuré. */
.km-comp-cadre { margin-top: 4.5rem; }
section.km-comparaison { margin-top: 0; }
.km-comp-groupe { color: var(--km-t2); }
.km-comp-groupe-nous { color: var(--km-ac); }
.km-comp-nb { font-family: var(--km-mono); }
.km-comp-tenu { color: var(--km-t0); }

/* ---------- Les questions ---------- */

.km-faq, .km-v-faq { margin-top: 2rem; border-top: 1px solid var(--km-l1); }
.km-q, .km-v-faq-item { border-bottom: 1px solid var(--km-l1); }
.km-q-titre {
  display: flex; align-items: flex-start; gap: 1rem;
  padding: 1.25rem 0; min-height: 44px; cursor: pointer;
  list-style: none; font-size: 1rem; line-height: 1.5rem;
  font-weight: 510; letter-spacing: -.008em; color: var(--km-t0);
}
.km-q-titre::-webkit-details-marker { display: none; }
.km-q-titre:hover { color: var(--km-ac); }
.km-q-signe {
  flex: none; position: relative; width: 12px; height: 12px; margin-top: .375rem;
  transition: transform var(--km-d-elev) var(--km-e-sortie);
}
.km-q-signe::before, .km-q-signe::after {
  content: ""; position: absolute; background: var(--km-ac);
}
.km-q-signe::before { left: 0; top: 5px; width: 12px; height: 1px; }
.km-q-signe::after  { left: 5px; top: 0; width: 1px; height: 12px;
  transition: opacity var(--km-d-micro) var(--km-e-micro); }
.km-q[open] .km-q-signe::after { opacity: 0; }
.km-q-corps { padding: 0 0 1.5rem 1.75rem; max-width: 72ch; }
.km-q-corps p { margin: 0 0 .75rem; font-size: .9375rem; line-height: 1.5rem; color: var(--km-t1); }
.km-q-corps p:last-child { margin-bottom: 0; }

/* ---------- L'appel final et le pied ---------- */

.km-appel { margin-top: 1rem; }
.km-pied, .km-v-pied {
  padding-block: 3rem 2.5rem; border-top: 1px solid var(--km-l1);
  font-size: .9375rem; color: var(--km-t1);
}
/* Le filet et la marge que portait la mention de droits sont montés d'un
   cran, sur la rangée du paiement : ici ils doubleraient le trait. */
.km-pied-droit, .km-v-pied-mention {
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--km-t2);
}
.km-v-liste-nue { list-style: none; margin: 0; padding: 0; }

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

@media (max-width: 767px) {
  .km-vitrine .km-section, .km-vitrine section[id] { padding-block: 3.5rem; }
  .km-entree { padding-block: 3rem 2rem; }
  .km-duree-rang { display: flex; width: 100%; }
  .km-duree-choix { flex: 1 1 auto; }
  .km-duree-btn { width: 100%; justify-content: center; }
}
@media (max-width: 575.98px) {
  .km-conteneur, .km-vitrine section[id] > * { padding-inline: 1.25rem; }
  .km-vitrine h1 { max-width: none; }
}

@media (prefers-reduced-motion: reduce) {
  .km-barre, .km-duree-btn, .km-duree-carre, .km-q-signe, .km-q-signe::after { transition: none; }
  .km-v-anime .km-preuve-kardox { stroke-dasharray: none; stroke-dashoffset: 0; transition: none; }
}

/* Les derniers groupes : conteneurs SVG et sections déjà réglées par leurs
   parents. On leur donne le peu qui manque, sans les surcharger. */
.km-preuve-titre { margin: 0 0 1rem; }
.km-preuve-appui { max-width: 68ch; color: var(--km-t1); }
/* Les deux tracés portent « km-preuve-kardox » et « km-preuve-marche » — pas
   les noms en « -trait- » que j'avais supposés. Mesuré au navigateur : sans
   ces deux règles, les chemins sortaient en « stroke: none », donc invisibles.
   Le nôtre est plein et en accent, celui du marché est pointillé et gris :
   la stabilité se lit avant même de lire les chiffres. */
.km-preuve-kardox {
  fill: none; stroke: var(--km-ac); stroke-width: 1.5;
  stroke-linejoin: miter; stroke-linecap: butt;
}
.km-preuve-marche {
  fill: none; stroke: var(--km-t2); stroke-width: 1.5;
  stroke-dasharray: 5 4; stroke-linejoin: miter; stroke-linecap: butt;
}
.km-preuve-bouts, .km-preuve-jalon { pointer-events: none; }
/* Les graduations du socle n'ont pas de classe : on les prend par leur parent. */
.km-preuve-socle line, .km-preuve-grille line { stroke: var(--km-l1); stroke-width: 1; }
.km-preuve-jalon line, line.km-preuve-jalon { stroke: var(--km-l2); stroke-width: 1; stroke-dasharray: 3 3; }
.km-preuve-axe-nom { fill: var(--km-t2) !important; font-family: var(--km-mono); font-size: 10px; letter-spacing: .1em; }
.km-preuve-saut-val { fill: var(--km-ac) !important; font-family: var(--km-mono); }
.km-preuve-donnees { margin-top: 1.5rem; }
.km-questions { scroll-margin-top: 5rem; }
.km-services-courrier { margin-top: 3rem; }
.km-flux-trait, .km-regle-crans line { stroke: var(--km-l2); stroke-width: 1; }
.km-flux-pointe { stroke: var(--km-ac); stroke-width: 1; fill: none; }

/* ==========================================================================
   CORRECTIFS DE MISE EN PAGE — relevés à l'écran
   ========================================================================== */

/* ---------- Les trois offres tiennent sur UNE ligne ----------
   Mesuré : « repeat(auto-fit, minmax(300px, 378px)) » se résolvait en
   « 378px 378px » dans un conteneur de 1216 px — deux colonnes, la troisième
   offre rejetée seule sur une deuxième ligne. Trois formules qui ne se
   comparent pas d'un coup d'œil, c'est une page de tarifs qui rate son seul
   travail. On impose donc trois colonnes égales tant qu'il y a la place, et
   on ne retombe qu'aux vraies ruptures. */
#tarifs .km-offres {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: stretch;
}
@media (max-width: 1100px) { #tarifs .km-offres { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 760px)  { #tarifs .km-offres { grid-template-columns: minmax(0, 1fr); } }

/* L'offre vedette ne dépasse plus de la rangée : elle se distingue par son
   filet et son plan, pas en poussant ses voisines vers le bas. */
#tarifs .km-offre { margin: 0; }
#tarifs .km-offre-vedette { border-color: var(--km-ac-bord); background: var(--km-plan-b); }

/* ---------- L'ouverture sur deux colonnes ----------
   La colonne de droite portait du vide. Elle reçoit la figure animée. */
@media (min-width: 1000px) {
  .km-entree .km-conteneur {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 30rem);
    gap: 4rem; align-items: center;
  }
  .km-entree-texte { min-width: 0; }
  .km-entree-figure { min-width: 0; }
}
.km-entree-figure { margin-top: 3rem; }
@media (min-width: 1000px) { .km-entree-figure { margin-top: 0; } }

/* ---------- La figure d'infrastructure ----------
   Un schéma d'ingénieur, pas une décoration : trois machines en Europe, la
   requête qui entre, la réponse qui repart, et le tarif qui ne bouge pas.
   Tout est au trait d'un pixel, tout est en jetons, rien ne clignote. */
.km-infra { display: block; width: 100%; height: auto; overflow: visible; }
.km-infra .km-i-lien   { fill: none; stroke: var(--km-l2); stroke-width: 1; }
.km-infra .km-i-noeud  { fill: var(--km-plan-b); stroke: var(--km-l3); stroke-width: 1; }
.km-infra .km-i-tarif  { fill: none; stroke: var(--km-ac); stroke-width: 1.5; }
.km-infra .km-i-txt    { fill: var(--km-t2); font-family: var(--km-mono); font-size: 9px; letter-spacing: .08em; }
.km-infra .km-i-txt-ac { fill: var(--km-ac); }
.km-infra .km-i-paquet { fill: var(--km-ac); }

/* Le mouvement : trois paquets qui remontent la ligne, décalés, en boucle.
   Rien ne s'arrête, rien ne saute — la durée est longue et la courbe douce,
   pour que ce soit une respiration, pas un clignotant. */
@keyframes km-i-course {
  0%   { offset-distance: 0%;   opacity: 0; }
  6%   { opacity: 1; }
  94%  { opacity: 1; }
  100% { offset-distance: 100%; opacity: 0; }
}
@keyframes km-i-souffle {
  0%, 100% { transform: scale(1);   opacity: .55; }
  50%      { transform: scale(1.9); opacity: 0; }
}
@keyframes km-i-veille {
  0%, 100% { stroke: var(--km-l3); }
  50%      { stroke: var(--km-ac); }
}
.km-infra .km-i-paquet {
  offset-path: path("M 44 150 L 128 150 L 128 92 L 214 92");
  offset-rotate: 0deg;
  animation: km-i-course 5.2s cubic-bezier(.45,0,.55,1) infinite;
}
.km-infra .km-i-paquet-2 {
  offset-path: path("M 44 150 L 128 150 L 128 150 L 214 150");
  animation-delay: 1.7s;
}
.km-infra .km-i-paquet-3 {
  offset-path: path("M 44 150 L 128 150 L 128 208 L 214 208");
  animation-delay: 3.4s;
}

/* Le trait du tarif se trace une fois, puis reste. */
@keyframes km-i-tracer { to { stroke-dashoffset: 0; } }
.km-infra .km-i-tarif {
  animation: km-i-tracer 1800ms var(--km-e-entree) 600ms forwards;
}

/* Qui demande moins de mouvement obtient le schéma, entier et immobile. */
@media (prefers-reduced-motion: reduce) {
  .km-infra .km-i-paquet, .km-infra .km-i-pouls,
  .km-infra .km-i-noeud-actif, .km-infra .km-i-tarif { animation: none; }
  .km-infra .km-i-tarif { transform: none; }
  .km-infra .km-i-paquet { opacity: 1; offset-distance: 62%; }
}

/* ==========================================================================
   LA FINITION — pied, barre, survols, rythme
   ========================================================================== */

/* ---------- Le pied ----------
   Mesuré : ses deux blocs faisaient 1280 px à partir de x=0. Le pied n'est pas
   un « section[id] », il ne recevait donc pas le conteneur, et la ligne de
   mentions sortait de l'écran par la droite. */
.km-pied > * {
  width: 100%; max-width: 76rem; margin-inline: auto; padding-inline: 1.5rem;
}
.km-pied-haut {
  display: grid; grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr));
  gap: 3rem 2.5rem;
}
.km-pied-marque .km-pied-nom { display: block; margin-bottom: .875rem; font-size: 1.0625rem; font-weight: 590; color: var(--km-t0); }
.km-pied-phrase { margin: 0 0 1.25rem; max-width: 34ch; font-size: .875rem; line-height: 1.375rem; color: var(--km-t1); }
.km-pied-col { display: flex; flex-direction: column; gap: .5rem; }
.km-pied-col > .km-etiquette { margin-bottom: .375rem; }
/* ---------- Le paiement, au pied ----------
   Rangée centrée de badges professionnels (jeu Datatrans, CC BY-SA 4.0,
   auto-hébergé). Les badges portent leurs couleurs de marque : c'est ainsi
   qu'on les reconnaît d'un coup d'œil, sur l'ardoise comme sur le papier.
   Un filet de la maison les cadre et le rayon reste celui des jetons. */
.km-pied-paiement {
  display: flex; flex-direction: column; align-items: center; gap: .875rem;
  margin-top: 2rem;
  text-align: center;
}
.km-paiement-moyens {
  display: flex; flex-wrap: wrap; justify-content: center; gap: .625rem;
  margin: 0; padding: 0; list-style: none;
}
.km-paiement-badge {
  display: block; width: auto; height: 2.375rem;
  border: 1px solid var(--km-l1); border-radius: 6px;
  background: #FFFFFF;
  transition: border-color var(--km-d-couleur) var(--km-e-couleur),
              transform var(--km-d-micro) var(--km-e-micro);
}
.km-paiement-moyens li:hover .km-paiement-badge {
  border-color: var(--km-l2); transform: translateY(-1px);
}
@media (prefers-reduced-motion: reduce) {
  .km-paiement-moyens li:hover .km-paiement-badge { transform: none; }
}
.km-paiement-note {
  display: inline-flex; align-items: flex-start; gap: .5rem;
  max-width: 58ch;
  font-size: .8125rem; line-height: 1.25rem; color: var(--km-t2);
  text-align: left;
}
.km-paiement-note .km-icone { color: var(--km-ac); flex: none; margin-top: .125rem; }
@media (max-width: 560px) {
  .km-pied-paiement { margin-top: 1.5rem; }
  .km-paiement-badge { height: 2.125rem; }
  .km-paiement-note { text-align: center; }
}

.km-pied-bas {
  display: flex; flex-wrap: wrap; align-items: center; gap: .75rem 2rem;
  margin-top: 3rem; padding-top: 1.5rem; padding-bottom: 0;
  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-bas .km-pied-lieu, .km-pied-bas > :last-child { margin-left: auto; }
@media (max-width: 860px) {
  .km-pied-haut { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .km-pied-bas > :last-child { margin-left: 0; }
}
@media (max-width: 560px) { .km-pied-haut { grid-template-columns: minmax(0, 1fr); gap: 2rem; } }

/* ---------- La barre : une vraie présence ---------- */
.km-barre-rang { min-height: 76px; }
.km-barre-marque {
  display: inline-flex; align-items: center; gap: .625rem;
  font-size: 1.125rem;
}
/* Le carré d'accent tenait la place du logo. Le vrai signe est posé dans le
   balisage : on retire le substitut, sinon les deux se disputent la place. */
.km-barre-liens a { position: relative; }
/* Le filet qui se trace sous le lien survolé — le motif de la maison. */
.km-barre-liens a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px;
  background: var(--km-ac); transform: scaleX(0); transform-origin: left;
  transition: transform var(--km-d-micro) var(--km-e-micro);
}
.km-barre-liens a:hover::after,
.km-barre-liens a[aria-current]::after { transform: scaleX(1); }
@media (max-width: 899.98px) { .km-barre-liens a::after { display: none; } }
.km-vitrine .km-tuile::before, .km-v-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-vitrine .km-tuile:hover, .km-v-tuile:hover {
  background: var(--km-plan-b); border-color: var(--km-l2); transform: translateY(-3px);
}
.km-vitrine .km-tuile:hover::before, .km-v-tuile:hover::before { transform: scaleX(1); }

/* Les lignes du tableau : un tiret d'ambre dans la gouttière, jamais un fond. */
.km-comparatif tbody tr, .km-v-tableau tbody tr { transition: color var(--km-d-micro) var(--km-e-micro); }
.km-comparatif tbody th { position: relative; padding-left: 1rem; }
.km-comparatif tbody th::before {
  content: ""; position: absolute; left: 0; top: 1.25rem; width: 0; height: 1px;
  background: var(--km-ac); transition: width var(--km-d-micro) var(--km-e-micro);
}
.km-comparatif tbody tr:hover th::before { width: 10px; }

/* Les questions : le filet qui se trace quand on ouvre. */
.km-q { position: relative; }
.km-q::after {
  content: ""; position: absolute; left: 0; bottom: -1px; height: 1px; width: 0;
  background: var(--km-ac); transition: width var(--km-d-elev) var(--km-e-sortie);
}
.km-q[open]::after { width: 100%; }

/* Les blocs d'argument : la barre d'accent qui monte au survol. */
.km-argu { position: relative; }
.km-argu::before {
  content: ""; position: absolute; left: 0; top: -1px; height: 1px; width: 0;
  background: var(--km-ac); transition: width var(--km-d-elev) var(--km-e-sortie);
}
.km-argu:hover::before { width: 4rem; }

/* ---------- Le rythme et la typographie ---------- */

/* Les titres de section : plus d'air au-dessus, moins en dessous — la phrase
   qui suit appartient au titre, elle ne doit pas en être séparée. */
.km-vitrine section[id] > * > .km-section-tete,
.km-vitrine .km-section-tete { margin-bottom: 1.25rem; }
.km-vitrine section[id] h2 {
  font-size: clamp(1.5rem, 2.6vw, 1.875rem);
  line-height: 1.16; letter-spacing: -.024em; max-width: 24ch;
}
.km-vitrine section[id] > * > p:first-of-type,
.km-vitrine .km-lead { font-size: 1.0625rem; line-height: 1.75rem; }
.km-vitrine .km-etiquette { display: inline-flex; align-items: center; gap: .5rem; }

/* Les faits de l'ouverture : deux colonnes qui respirent, filet à gauche. */
.km-faits {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1.75rem 2.5rem; margin: 3rem 0 0; padding: 0; list-style: none;
}
.km-fait {
  display: grid; grid-template-columns: auto 1fr; gap: .25rem .875rem;
  padding-left: 1.25rem; border-left: 1px solid var(--km-l1);
}
.km-fait i {
  grid-row: 1 / 3; align-self: start; font-style: normal;
  font-size: 1.5rem; line-height: 1.75rem; letter-spacing: -.02em; color: 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-t2);
}
.km-fait { font-size: .875rem; line-height: 1.375rem; color: var(--km-t1); }

/* Les grands moments de la page se séparent par le seul vide : les filets
   pleine largeur qui les soulignaient ont déplu, ils sont retirés. */

@media (prefers-reduced-motion: reduce) {
  .km-vitrine .km-tuile, .km-v-tuile, .km-vitrine .km-tuile::before, .km-v-tuile::before,
  .km-barre-liens a::after, .km-comparatif tbody th::before,
  .km-q::after, .km-argu::before { transition: none; }
}

/* Deux cibles mesurées sous 44 px : le bouton « petit » de la barre et le
   dépliant qui ouvre les données du graphique. Une cible se manipule au doigt
   autant qu'à la souris — la hauteur ne se négocie pas. */
.km-barre-actions .btn, .km-barre-actions .btn-sm { min-height: 44px; display: inline-flex; align-items: center; }
.km-preuve-donnees > summary {
  min-height: 44px; display: inline-flex; align-items: center; gap: .5rem;
  cursor: pointer; list-style: none;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--km-t2);
}
.km-preuve-donnees > summary::-webkit-details-marker { display: none; }
.km-preuve-donnees > summary:hover { color: var(--km-ac); }

/* ==========================================================================
   LES FILETS, POUR DE BON
   Mesuré à l'écran : un trait écrit « 1 px » dans un SVG à viewBox sortait à
   1,6 px sur le schéma (échelle 1,6) et 1,86 px sur le graphique (1,24), et
   le trait du tarif à 2,4 px. C'est pour cela que la page paraissait épaisse :
   la charte dit un pixel, le rendu en donnait presque trois demi.
   « non-scaling-stroke » découple l'épaisseur du trait de l'échelle du
   dessin : un pixel écrit devient un pixel affiché, quelle que soit la
   taille de la figure. C'est déjà ce que font nos icônes — elles mesuraient
   1,00 px, elles étaient les seules justes.
   ========================================================================== */

.km-infra *,
.km-preuve-svg *,
.km-frise-svg *,
.km-regle-svg *,
.km-flux-lien,
.km-flux-trait, .km-flux-pointe { vector-effect: non-scaling-stroke; }

/* Puisque le trait ne grossit plus, on peut revenir à l'épaisseur de la
   charte partout : un pixel. Seule la ligne du tarif garde un cheveu de plus
   — c'est la seule chose que la figure doit affirmer. */
.km-infra .km-i-tarif { stroke-width: 1.25; }
.km-preuve-kardox { stroke-width: 1.25; }
.km-preuve-marche { stroke-width: 1; }

/* Les graisses hors charte relevées à l'écran : le montant et le grand
   chiffre des faits sortaient en 500. La charte n'admet que 400, 510 et 590. */
.km-vitrine .km-offre-montant, .km-vitrine .km-fait i,
.km-vitrine .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; }

/* 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); }

/* ---------- Rien de tout cela pour qui demande moins de mouvement ---------- */
@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;
  }
  .km-offre-jeu, .km-offre-jeu .km-offre-economie { animation: none; }
  .km-duree-btn::after { transition: none; }
}

/* ==========================================================================
   AFFINAGE MESURÉ — suite, côté page de présentation
   ========================================================================== */

/* ---- Les trois offres : UNE surface découpée, pas trois objets ----
   Relevé : Linear, Vercel, Supabase et Railway ont tous une gouttière de ZÉRO
   entre leurs cartes de prix, et séparent par un filet d'un pixel. Sur trois
   cartes, notre gouttière de 32 px coûtait 64 px de largeur, et surtout
   faisait passer le nombre de segments de filet visibles de 6 à 12. La moitié
   du trait de la page était là. C'est cela, « trop épais ».
   Le cadre extérieur porte le rayon ; les cartes intérieures n'en ont plus. */
#tarifs .km-offres {
  gap: 0;
  border: 1px solid var(--km-l1);
  border-radius: 5px;
  overflow: hidden;
}
#tarifs .km-offre {
  border: 0; border-radius: 0;
  border-left: 1px solid var(--km-l1);
  background: transparent;
  padding: 2rem;                    /* 24 → 32 px : le filet s'éloigne du texte */
  transform: none;
}
#tarifs .km-offre:first-child { border-left: 0; }
/* L'offre retenue se distingue à l'arrêt, pas seulement au survol : un
   liseré de safran tracé en « outline » — il passe PAR-DESSUS les filets
   mitoyens de la surface soudée sans déplacer un seul pixel — et le voile
   descendant du spécimen de l'espace client. Le filet de tête reste posé. */
#tarifs .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;
}
#tarifs .km-offre-vedette::before { transform: scaleX(1); }
#tarifs .km-offre:hover { background: var(--km-plan-a); transform: none; }
#tarifs .km-offre-vedette:hover {
  background: linear-gradient(180deg, var(--km-ac-voile), transparent 42%), var(--km-plan-b);
}
/* Le halo radial des cartes de l'espace client n'a pas sa place sur une
   surface continue : il baverait d'une colonne à l'autre. */
#tarifs .km-offre::after { display: none; }

@media (max-width: 1100px) {
  #tarifs .km-offre:nth-child(3) { border-left: 0; border-top: 1px solid var(--km-l1); }
}
@media (max-width: 760px) {
  #tarifs .km-offre { border-left: 0; border-top: 1px solid var(--km-l1); padding: 1.5rem; }
  #tarifs .km-offre:first-child { border-top: 0; }
}

/* ---- Le nom d'offre reprend sa place dans la hiérarchie ----
   Mesuré : notre titre de carte était plus gros que celui de TOUS les sites
   relevés (Linear 24, Supabase 22, Railway 20, Stripe 18, Vercel 14).
   Le prix doit dominer, pas le nom. */
#tarifs .km-offre-titre { font-size: 1.5rem; line-height: 2rem; letter-spacing: -.012em; }
.km-preuve-grille line, .km-preuve-socle line { stroke-width: .75; }

@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;
  }
}

/* ==========================================================================
   L'ÉQUILIBRE DE LA PAGE — relevé à l'écran
   Deux défauts mesurés, tous deux justes :

   1. LE TEXTE FUYAIT À GAUCHE. Chaque « h2 » était plafonné à 432 px dans un
      conteneur de 1216, et chaque chapeau à 632. Les titres se serraient donc
      dans le premier tiers, laissant 780 px de vide à droite. Une largeur de
      lecture confortable est une bonne règle pour un PARAGRAPHE ; appliquée à
      l'en-tête d'une section, elle déséquilibre la page.
      Réponse : l'en-tête devient une composition en deux temps — l'étiquette
      et le titre à gauche, le chapeau en regard à droite. La largeur est
      occupée, la ligne de lecture reste courte.

   2. LE RYTHME ÉTAIT PLAT. Toutes les sections avaient 80 px en haut comme en
      bas, qu'elles fassent 545 px ou 2196 px de haut. Un même intervalle entre
      des masses très inégales se lit comme un désordre.
      Réponse : une respiration proportionnée — les sections denses reçoivent
      plus d'air, l'appel final en reçoit moins, et deux sections voisines ne
      cumulent plus 160 px de vide.
   ========================================================================== */

/* ---- L'en-tête de section, en deux temps ---- */
/* La grille à deux colonnes ne vaut que pour un CONTENEUR qui porte le titre
   ET le chapeau. Elle était aussi posée sur « .km-section-tete + .km-lead »,
   c'est-à-dire sur le PARAGRAPHE lui-même : son texte tombait en colonne 1 et
   la colonne 2 restait vide. C'est l'origine du grand vide à droite dans les
   sections « Tarifs » et « Inclus dans les trois formules ». Ces deux
   sections utilisent maintenant le même conteneur que les autres. */
.km-confiance-tete {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 1rem 4rem;
  align-items: end;
}
.km-confiance-tete > h2 { grid-column: 1; margin: 0; }
.km-confiance-tete > p, .km-confiance-tete > .km-lead { grid-column: 2; margin: 0; }

@media (max-width: 900px) {
  .km-confiance-tete { grid-template-columns: minmax(0, 1fr); gap: 1rem; }
  .km-confiance-tete > h2, .km-confiance-tete > p, .km-confiance-tete > .km-lead { grid-column: 1; }
}

/* Le titre respire : 24ch serrait le propos en trois lignes courtes. */
.km-vitrine section[id] h2 { max-width: 30ch; }
/* Le chapeau garde une ligne de lecture courte, mais dans SA colonne. */
.km-vitrine .km-lead, .km-vitrine .km-confiance-tete > p { max-width: 54ch; }

/* Les sections dont le chapeau est un vrai paragraphe autonome le laissent
   pleine largeur : forcer deux colonnes sur un texte seul ferait un trou. */
.km-vitrine section[id] > .km-lead:only-of-type { max-width: 62ch; }

/* ---- Le rythme vertical ---- */
/* Sans les filets, le vide sépare seul : les grandes respirations d'avant
   (jusqu'à 12,5 rem cumulés) devenaient des trous. Resserrées d'un tiers,
   mesure gardée : 7 rem entre deux sections, 8,5 rem après une dense. */
.km-vitrine section[id] { padding-block: 4.5rem; }
/* Le raccourci à IDENTIFIANT bat la règle des voisines : le haut se règle
   donc ici même, sinon ces deux sections gardent leur pleine respiration. */
#tarifs, #services { padding-block: 3rem 5.5rem; }
#commencer { padding-block: 2.5rem 4.5rem; margin-top: 0; }
#ouverture { padding-block: 4rem 4.5rem; }
.km-vitrine section[id] + section[id] { padding-top: 2.5rem; }
#tarifs + section[id], #services + section[id] { padding-top: 3rem; }

/* L'espace entre le titre d'une section et son contenu : constant, mesuré. */
.km-vitrine .km-confiance-tete { margin-bottom: 3rem; }
.km-vitrine section[id] > .km-section-tete { margin-bottom: 1rem; }

@media (max-width: 767px) {
  .km-vitrine section[id],
  #tarifs, #services, #commencer, #ouverture,
  .km-vitrine section[id] + section[id] { padding-block: 2.75rem; }
}

/* Les figures — schéma, graphique, frise — arrivent de la droite, comme si
   elles se posaient à côté du propos qu'elles illustrent. */

@media (prefers-reduced-motion: reduce) {
  }

/* ==========================================================================
   LE BOUTON « HAUT » et LA BASCULE
   ========================================================================== */

.km-haut {
  position: fixed; right: 1.5rem; bottom: 1.5rem; z-index: 70;
  display: inline-flex; align-items: center; justify-content: center;
  /* Un disque : la cible reste à 48 px, la flèche seule au centre. */
  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; }
/* Invisible, le disque ne doit pas non plus prendre le focus clavier :
   « visibility » le retire de l'ordre de tabulation. Le fondu d'entrée est
   conservé ; la sortie coupe court, personne ne la regarde en défilant. */
.km-haut:not(.km-visible) { visibility: hidden; }
.km-haut:hover { color: var(--km-ac); border-color: var(--km-ac-bord); text-decoration: none; }

/* La bascule clair/sombre : un trait de cheveu, comme le reste du dessin. */
.km-barre-bascule .km-icone { stroke-width: .9; }
.km-barre-bascule:hover { color: var(--km-ac); }

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

/* ==========================================================================
   LES CARTES — le détail que le commanditaire attend
   Chaque caractéristique porte désormais l'icône de ce dont elle parle : un
   serveur pour les sites, un disque pour l'espace, une enveloppe pour le
   courrier. Le marqueur carré disparaît — il ne disait rien.
   ========================================================================== */

#tarifs .km-offre-points { gap: .875rem; padding-top: 1.5rem; }
#tarifs .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);
}
/* Le carré de 4 px cède la place à l'icône : deux marqueurs feraient double. */
#tarifs .km-point-offre::before { content: none; }
#tarifs .km-point-icone { color: var(--km-t2); margin-top: .0625rem; transition: color var(--km-d-micro) var(--km-e-micro); }
#tarifs .km-offre:hover .km-point-icone,
#tarifs .km-offre-vedette .km-point-icone { color: var(--km-ac); }

/* ---- Le bloc de prix : la hiérarchie se voit ---- */
#tarifs .km-offre-prix { align-items: baseline; flex-wrap: wrap; gap: .5rem; margin-top: .25rem; }
#tarifs .km-offre-montant { font-size: 2.75rem; line-height: 1; letter-spacing: -.03em; color: var(--km-t0); }
#tarifs .km-offre-periode { font-size: .8125rem; color: var(--km-t2); }
#tarifs .km-offre-barre { margin-left: 0; font-size: .875rem; color: var(--km-t2); }
#tarifs .km-offre-barre s { text-decoration-color: var(--km-t2); }
/* L'économie devient une pastille sobre — un filet, pas un fond criard. */
#tarifs .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);
}
#tarifs .km-offre-economie-nulle { border-color: var(--km-l1); color: var(--km-t2); }
#tarifs .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);
}
#tarifs .km-offre-serment .km-icone { color: var(--km-ac); flex: none; margin-top: .125rem; }

/* ---- Repos et survol nettement distincts ----
   Le commanditaire les trouvait trop proches. Au repos la carte est nue ;
   au survol elle prend un plan, son filet d'accent se trace en tête, et son
   appel à l'action avance. Rien ne bouge de place — la surface reste soudée. */
#tarifs .km-offre { transition: background-color var(--km-d-elev) var(--km-e-couleur); }
#tarifs .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);
}
#tarifs .km-offre:hover::before { transform: scaleX(1); }
#tarifs .km-offre-appel { color: var(--km-t2); transition: color var(--km-d-micro) var(--km-e-micro); }
#tarifs .km-offre:hover .km-offre-appel,
#tarifs .km-offre-vedette .km-offre-appel { color: var(--km-ac); }
#tarifs .km-offre-appel::after { background: currentColor; }


/* ==========================================================================
   LE SCHÉMA DE L'OUVERTURE — version développée
   Reprise de la première figure, enrichie plutôt que remplacée : trafic dans
   les deux sens, jauges d'activité par machine, zone européenne bornée par
   ses coins, réglure de fond. Trait d'un pixel partout, boucles lentes et
   décalées pour que rien ne batte à l'unisson — un parc de machines respire,
   il ne clignote pas.
   ========================================================================== */

.km-infra { display: block; width: 100%; height: auto; overflow: visible; }
.km-infra * { vector-effect: non-scaling-stroke; }
.km-infra path, .km-infra rect, .km-infra circle { fill: none; }

.km-i-lien         { stroke: var(--km-l1); stroke-width: 1; }
.km-i-filet        { stroke: var(--km-l1); stroke-width: 1; }
.km-i-noeud        { fill: var(--km-plan-a); stroke: var(--km-l3); stroke-width: 1; }
.km-i-glyphe       { stroke: var(--km-t2); stroke-width: 1; }
.km-i-jauge        { stroke: var(--km-l2); stroke-width: 1; }
.km-i-diode        { fill: var(--km-ac); stroke: none; opacity: .3; }
.km-i-paquet       { fill: var(--km-ac); stroke: none; }
.km-i-tarif        { stroke: var(--km-ac); stroke-width: 1.25; }
.km-i-txt          { fill: var(--km-t2); font-family: var(--km-mono); font-size: 8px; letter-spacing: .11em; }
.km-i-txt-ac       { fill: var(--km-ac); }

/* ---- Le trafic ----
   L'aller emprunte les trois branches, le retour ne redescend que par deux :
   un parc n'est jamais sollicité uniformément, et un dessin trop régulier
   sonne faux. */
@keyframes km-i-file { 0% { offset-distance: 0%; opacity: 0; } 8% { opacity: 1; }
                       92% { opacity: 1; } 100% { offset-distance: 100%; opacity: 0; } }
.km-i-paquet { offset-rotate: 0deg; animation: km-i-file 6.4s cubic-bezier(.45,0,.55,1) infinite; }
.km-i-aller         { offset-path: path("M46 135 H108 V78 H196"); }
.km-i-aller-2       { offset-path: path("M46 135 H108 H196");      animation-delay: 2.1s; }
.km-i-aller-3       { offset-path: path("M46 135 H108 V192 H196"); animation-delay: 4.3s; }
/* Le retour part de la machine et redescend vers la visite. */
.km-i-retour        { offset-path: path("M196 78 H108 V135 H46");  animation-delay: 1.1s; }
.km-i-retour-2      { offset-path: path("M196 192 H108 V135 H46"); animation-delay: 3.5s; }
.km-i-retour        { opacity: .7; }

/* ---- Les jauges : chaque machine travaille à son rythme ---- */
@keyframes km-i-charge { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
.km-i-jauge   { animation: km-i-charge 4.8s var(--km-e-couleur) infinite; }

/* ---- La diode : la machine répond ---- */
@keyframes km-i-diode { 0%, 88%, 100% { opacity: .28; } 92% { opacity: 1; } }
.km-i-diode   { animation: km-i-diode 6.4s var(--km-e-couleur) infinite; }

/* ---- Le filet du contour de machine s'ambre quand elle sert ---- */

/* Le tracé du tarif est défini plus bas, en un seul endroit. Cette version
   au pointillé posait « stroke-dasharray » sur une classe moins spécifique :
   elle aurait continué de s'appliquer par-dessous la nouvelle règle, qui ne
   déclare plus de pointillé du tout. C'est ainsi qu'un défaut réparé
   réapparaît. */

/* ---- Sans mouvement : le schéma entier, immobile ---- */
@media (prefers-reduced-motion: reduce) {
  .km-i-paquet { animation: none; opacity: 1; offset-distance: 58%; }
  .km-i-jauge, .km-i-diode, .km-i-noeud-actif { animation: none; }
  .km-i-diode { opacity: 1; }
  .km-i-tarif { animation: none; }
}

/* ==========================================================================
   LE DÉFILEMENT DOUX — le complément CSS
   Le script anime lui-même avec la courbe de la maison ; ces deux lignes
   servent aux cas qu'il ne couvre pas (retour arrière, ancre à l'ouverture)
   et posent la marge sous la barre collante, pour qu'un titre visé ne se
   retrouve pas caché dessous.
   ========================================================================== */
/* LE DÉFILEMENT DOUX N'EST PAS DÉCLARÉ ICI QUAND LE SCRIPT EST LÀ.
   Défaut trouvé et mesuré : « scroll-behavior: smooth » s'appliquait au
   document PENDANT que le script animait lui-même le défilement en appelant
   « window.scrollTo() » à chaque trame. Le navigateur transformait alors
   CHACUN de ces appels en une animation douce de son cru — une nouvelle à
   chaque trame, aussitôt interrompue par la suivante. D'où le geste rapporté :
   le bouton « Haut » marque un temps d'arrêt, puis part d'un coup. Deux
   moteurs de défilement tiraient sur la même corde.
   Le script porte la classe « km-v-js » sur la racine. Tant qu'il est là,
   c'est lui qui anime, seul. S'il manque, la règle du navigateur reprend la
   main : sans JavaScript, le défilement reste doux. */
html:not(.km-v-js) { scroll-behavior: smooth; }
html { scroll-padding-top: 6rem; }
@media (prefers-reduced-motion: reduce) { html, html:not(.km-v-js) { scroll-behavior: auto; } }

/* ==========================================================================
   L'ENTRÉE — LA RÈGLE QUI TRANCHE
   Deux conflits mesurés à l'écran, tous deux de mon fait :
   · « #tarifs .km-offre { transform: none }

/* Les figures se posent depuis la droite, un peu plus lentement : ce sont
   des blocs, pas des vignettes. */

@media (prefers-reduced-motion: reduce) {
  }

@media (prefers-reduced-motion: reduce) {
  }


/* ==========================================================================
   L'ENTRÉE AU DÉFILEMENT — ÉTAT UNIQUE
   Les versions précédentes posaient l'état d'attente par « :not(.km-entre) »,
   en concurrence avec d'autres règles ; mesuré, la déclaration s'appliquait
   mais une autre l'emportait, et vingt éléments sur vingt-trois arrivaient
   déjà posés. Trois tours passés à arbitrer des spécificités : c'est deux de
   trop.
   Ici, un seul état, porté par une classe que le script ajoute au chargement
   et retire à l'entrée. Rien ne peut le contredire, et sans JavaScript la
   classe n'existe pas : la page est entière d'emblée.
   ========================================================================== */

.km-attend {
  opacity: .45 !important;
  transition: opacity var(--km-d-entree-el, 350ms) var(--km-e-sortie),
              transform var(--km-d-entree-el, 350ms) var(--km-e-sortie) !important;
}
.km-attend[data-entree="gauche"] { transform: translate3d(-20px, 0, 0) !important; }
.km-attend[data-entree="droite"] { transform: translate3d(20px, 0, 0) !important; }
.km-attend[data-entree="bas"]    { transform: translate3d(0, 16px, 0) !important; }
.km-attend.km-entree-figure, .km-attend.km-preuve-figure {
  transform: translate3d(24px, 0, 0) !important;
  transition-duration: var(--km-d-bloc, 600ms) !important;
}
/* La cascade : cent millisecondes, arrêtée au cinquième. */
.km-attend:nth-child(2) { transition-delay: 100ms !important; }
.km-attend:nth-child(3) { transition-delay: 200ms !important; }
.km-attend:nth-child(4) { transition-delay: 300ms !important; }
.km-attend:nth-child(n+5) { transition-delay: 400ms !important; }

@media (prefers-reduced-motion: reduce) {
  .km-attend, .km-attend[data-entree] {
    opacity: 1 !important; transform: none !important; transition: none !important;
  }
}

/* ==========================================================================
   LE RYTHME VERTICAL — UNE SEULE ÉCHELLE
   Mesuré entre blocs frères, section par section : 0, 0, 0, 0, 0, 16, 16, 16,
   16, 16, 17, 20, 21, 40, 40, 40, 48, 48, 48, 48, 48, 48, 72. Sept valeurs
   différentes sans système, cinq blocs collés l'un à l'autre et un écart de
   72 px isolé. C'est exactement ce que le commanditaire voyait.
   On impose trois rôles, et trois seulement :
     · SERRÉ     16 px — une étiquette et le titre qu'elle annonce
     · NORMAL    40 px — d'un bloc au suivant dans un même propos
     · SÉPARANT  64 px — d'un propos au suivant
   Toute autre valeur est une exception qui doit se justifier.
   ========================================================================== */

.km-vitrine section[id] > * + * { margin-top: 40px; }

/* Serré : l'étiquette appartient au titre qui suit. */
.km-vitrine section[id] > .km-section-tete + * { margin-top: 16px; }

/* Séparant : on change de propos. */
.km-vitrine section[id] > .km-offres + *,
.km-vitrine section[id] > .km-tuiles + *,
.km-vitrine section[id] > .km-services-grille + *,
.km-vitrine section[id] > .km-tableau-defile + *,
.km-vitrine section[id] > .km-faq + *,
.km-vitrine section[id] > .km-argus + *,
.km-vitrine section[id] > .km-comp-cadre + *,
.km-vitrine section[id] > .km-flux + *,
.km-vitrine section[id] > .km-services-duo + * { margin-top: 64px; }

/* Les notes de bas de bloc restent au contact de ce qu'elles commentent. */
.km-vitrine section[id] > .km-note,
.km-vitrine section[id] > .km-comparatif-pied,
.km-vitrine section[id] > .km-tableau-note { margin-top: 20px; }

/* On neutralise les marges internes qui s'ajoutaient à cette échelle et
   produisaient les 48 et les 72 relevés. */
.km-vitrine section[id] > .km-confiance-tete { margin-bottom: 0; }
.km-vitrine .km-comparatif, .km-vitrine .km-kb-trouves,
.km-vitrine .km-services-duo, .km-vitrine .km-services-courrier,
.km-vitrine .km-preuve-cadre, .km-vitrine .km-preuve-ecart,
.km-vitrine .km-frise, .km-vitrine .km-regle, .km-vitrine .km-flux { margin-top: 0; margin-bottom: 0; }
.km-vitrine .km-offres, .km-vitrine .km-tuiles, .km-vitrine .km-services-grille,
.km-vitrine .km-duree, .km-vitrine .km-argus { margin-top: 0; margin-bottom: 0; }

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

/* Un intitulé réservé aux lecteurs d'écran n'occupe pas le rythme : sans cela
   il consommait un cran de 40 px et laissait −1 px au bloc suivant. */
.km-vitrine section[id] > .km-lu-seul { margin-top: 0; }
.km-vitrine section[id] > .km-lu-seul + * { margin-top: 40px; }

/* ==========================================================================
   ARMER SANS ANIMER
   La mise en attente ne doit jamais se voir. Le script pose « km-fige » le
   temps d'écrire l'état, force le calcul, puis la retire : l'élément se remet
   en place instantanément, hors du champ, et seule son entrée s'anime.
   Sans cela on voyait les blocs s'effacer en remontant la page.
   ========================================================================== */
.km-fige, .km-fige * { transition: none !important; animation: none !important; }

/* Les distances d'entrée sont fixées plus bas, en un seul endroit : une
   génération de valeurs (28 / 22 / 36 px) traînait ici et n'était plus que
   du bruit dans la cascade. C'est ainsi que les conflits s'installent. */

/* Le trait reste un pixel, quelle que soit la taille du dessin.
   Le schéma est étiré de 340 unités à 480 pixels : sans cette règle, un trait
   déclaré à 1 est rendu à 1,41 px — et il grossit encore si la figure grandit.
   Le relevé des treize sites de référence n'a trouvé « non-scaling-stroke »
   que chez ceux qui, comme nous, étirent leurs SVG. C'est exactement le cas. */
.km-infra path, .km-infra rect, .km-infra circle, .km-infra line {
  vector-effect: non-scaling-stroke;
}

/* ==========================================================================
   L'ENTRÉE AU DÉFILEMENT — LA DURÉE ET LA COURSE
   Reproche reçu, et fondé : « ya yok ya çok hızlı ». Les valeurs en place
   étaient 350 ms pour 28 px. À cette vitesse et sur cette distance, le geste
   passe sous le seuil de perception : on ne voit pas une entrée, on voit un
   élément déjà posé. Une transition ne se remarque qu'au-delà d'environ un
   demi-tiers de seconde ET d'une course qui dépasse la hauteur d'une ligne.
   On double donc la durée et on multiplie la course par un peu plus d'un
   tiers. La courbe ne change pas — c'est toujours la sortie de la maison,
   qui part franchement et se pose longuement.
   L'opacité reste de 45 % à 100 % : c'est le rapport demandé.
   ========================================================================== */

.km-attend {
  opacity: .45 !important;
  transition: opacity 700ms var(--km-e-sortie),
              transform 700ms var(--km-e-sortie) !important;
}
.km-attend[data-entree="gauche"] { transform: translate3d(-44px, 0, 0) !important; }
.km-attend[data-entree="droite"] { transform: translate3d(44px, 0, 0) !important; }
.km-attend[data-entree="bas"]    { transform: translate3d(0, 34px, 0) !important; }

/* Les grandes pièces — figures et schémas — vont plus loin et plus longtemps :
   une masse importante qui se déplace vite paraît légère, donc bon marché. */
.km-attend.km-entree-figure, .km-attend.km-preuve-figure {
  transform: translate3d(56px, 0, 0) !important;
  transition-duration: 950ms !important;
}

/* La cascade : un cran de 110 ms par voisin, arrêtée au quatrième. Au-delà,
   le dernier de la rangée attendrait une demi-seconde pour rien. */
.km-attend:nth-child(2)    { transition-delay: 110ms !important; }
.km-attend:nth-child(3)    { transition-delay: 220ms !important; }
.km-attend:nth-child(4)    { transition-delay: 330ms !important; }
.km-attend:nth-child(n+5)  { transition-delay: 440ms !important; }

@media (prefers-reduced-motion: reduce) {
  .km-attend, .km-attend[data-entree],
  .km-attend.km-entree-figure, .km-attend.km-preuve-figure {
    opacity: 1 !important; transform: none !important; transition: none !important;
  }
}

/* ==========================================================================
   LE SCHÉMA DE L'ACCUEIL — RÉÉCRIT
   La version précédente était un organigramme clairsemé : trois rectangles et
   quelques traits dans beaucoup de vide. Reprise à zéro autour de deux idées,
   chacune avec la place qu'il lui faut :
     · en haut, LE PARC — une baie de huit unités, la visite qui y entre, la
       réponse qui en repart ;
     · en bas, LE TARIF — une droite sur trente-six mois, avec ses jalons.
   Tout est au trait d'un pixel réel, rien n'est rempli d'un aplat appuyé,
   rien ne clignote : ce qui bouge bouge lentement et en continu.
   ========================================================================== */

.km-infra { display: block; width: 100%; height: auto; overflow: visible; }
.km-infra path, .km-infra rect, .km-infra circle, .km-infra line { vector-effect: non-scaling-stroke; }

/* ---- Le lettrage ---- */
.km-infra .km-i-txt     { fill: var(--km-t2); font-family: var(--km-mono); font-size: 8px; letter-spacing: .11em; }
.km-infra .km-i-txt-fin { fill: var(--km-t3, var(--km-t2)); font-size: 7px; letter-spacing: .14em; }
.km-infra .km-i-txt-ac  { fill: var(--km-ac); }

/* ---- Les filets ---- */
.km-infra .km-i-filet  { fill: none; stroke: var(--km-l1); stroke-width: 1; }
.km-infra .km-i-grille { fill: none; stroke: var(--km-l0); stroke-width: 1; }
.km-infra .km-i-lien   { fill: none; stroke: var(--km-l1); stroke-width: 1; }
.km-infra .km-i-tick   { fill: none; stroke: var(--km-l1); stroke-width: 1; }

/* ---- La visite et le répartiteur ---- */
.km-infra .km-i-noeud  { fill: color-mix(in srgb, var(--km-plan-a) 60%, transparent); stroke: var(--km-l2); stroke-width: 1; }
.km-infra .km-i-glyphe { fill: none; stroke: var(--km-t2); stroke-width: 1; stroke-linecap: round; }

/* ---- La baie et ses unités ---- */
.km-infra .km-i-baie    { fill: none; stroke: var(--km-l2); stroke-width: 1; }
.km-infra .km-i-u-cadre { fill: none; stroke: var(--km-l1); stroke-width: 1; }
.km-infra .km-i-u-disque { fill: none; stroke: var(--km-l1); stroke-width: 1; }
.km-infra .km-i-u-dents  { fill: none; stroke: var(--km-l1); stroke-width: 1; opacity: .7; }
.km-infra .km-i-u-jauge { fill: none; stroke: var(--km-l2); stroke-width: 1;
                          transform-box: fill-box; transform-origin: left center; }
.km-infra .km-i-diode   { fill: var(--km-ac); stroke: none; opacity: .22; }
.km-infra .km-i-unite-active .km-i-u-cadre { stroke: var(--km-l2); }
.km-infra .km-i-unite-active .km-i-diode   { opacity: .5; }

/* Le balai : un trait qui descend la baie sans jamais s'arrêter. */
.km-infra .km-i-balai { fill: none; stroke: var(--km-ac); stroke-width: 1; opacity: 0; }

/* ---- L'état ---- */
.km-infra .km-i-etat { fill: var(--km-ac); stroke: none; }

/* Le cadenas du lien chiffré, et le trait en tirets de la résolution de nom :
   une étape préalable ne se dessine pas comme le chemin de la requête. */
.km-infra .km-i-cadenas-corps { fill: none; stroke: var(--km-ac); stroke-width: 1; }
.km-infra .km-i-cadenas-anse  { fill: none; stroke: var(--km-ac); stroke-width: 1; }
.km-infra .km-i-tirets { fill: none; stroke: var(--km-l1); stroke-width: 1; stroke-dasharray: 3 3; }
.km-infra .km-i-mono-fort { fill: var(--km-t1); font-size: 9px; letter-spacing: .06em; }

/* Le cadenas respire au rythme de la pastille d'état : la page est vivante,
   pas clignotante. */
.km-infra .km-i-tls { animation: km-i-etat 4.4s var(--km-e-couleur) infinite; }
@media (prefers-reduced-motion: reduce) { .km-infra .km-i-tls { animation: none; } }

/* ---- Le trafic ---- */
.km-infra .km-i-paquet { fill: var(--km-ac); stroke: none; offset-rotate: 0deg; }

/* ---- Le tarif ---- */
.km-infra .km-i-tarif { fill: none; stroke: var(--km-ac); stroke-width: 1.25; }
.km-infra .km-i-jalon { fill: var(--km-plan); stroke: var(--km-ac); stroke-width: 1; }

/* ==========================================================================
   CE QUI BOUGE
   Rien de plus rapide que trois secondes, rien qui clignote, et chaque
   élément décalé par rapport à son voisin : un parc où tout battrait au même
   rythme aurait l'air d'un gyrophare, pas d'un parc.
   ========================================================================== */

/* La diode de chaque unité, décalée par son rang. */
@keyframes km-i-diode { 0%, 84%, 100% { opacity: .18; } 90% { opacity: 1; } }
.km-infra .km-i-diode {
  animation: km-i-diode 7.2s var(--km-e-couleur) infinite;
  animation-delay: calc(var(--rang, 0) * 0.68s);
}

/* La jauge d'activité : elle s'allonge et se rétracte, elle ne saute pas. */
@keyframes km-i-jauge { 0%, 100% { transform: scaleX(.55); } 50% { transform: scaleX(1); } }
.km-infra .km-i-u-jauge {
  animation: km-i-jauge 6.4s var(--km-e-couleur) infinite;
  animation-delay: calc(var(--rang, 0) * -0.83s);
}

/* La façade ventilée respire très légèrement. */
@keyframes km-i-baies { 0%, 100% { opacity: .45; } 50% { opacity: .8; } }
.km-infra .km-i-u-dents {
  animation: km-i-baies 8.1s var(--km-e-couleur) infinite;
  animation-delay: calc(var(--rang, 0) * -0.51s);
}

/* Le balai descend la baie en sept secondes, invisible aux deux bouts. */
@keyframes km-i-balai {
  0%   { transform: translateY(0);     opacity: 0; }
  12%  {                               opacity: .5; }
  88%  {                               opacity: .5; }
  100% { transform: translateY(200px); opacity: 0; }
}
.km-infra .km-i-balai { animation: km-i-balai 7s cubic-bezier(.45,0,.55,1) infinite; }

/* La pastille d'état : une respiration lente, jamais un clignotement. */
@keyframes km-i-etat { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
.km-infra .km-i-etat { animation: km-i-etat 3.6s var(--km-e-couleur) infinite; }

/* Le trafic : trois requêtes montent, deux réponses redescendent. */
@keyframes km-i-file {
  0%   { offset-distance: 0%;   opacity: 0; }
  9%   {                        opacity: 1; }
  88%  {                        opacity: 1; }
  100% { offset-distance: 100%; opacity: 0; }
}
.km-infra .km-i-paquet { animation: km-i-file 6.8s cubic-bezier(.45,0,.55,1) infinite; }
/* Le tracé suit le bus : la requête descend jusqu'à x=140, puis emprunte
   l'amorce de son unité. Les ordonnées sont celles des unités 1, 4 et 7. */
.km-infra .km-i-aller    { offset-path: path("M30 130 H140 V47 H150"); }
.km-infra .km-i-aller-2  { offset-path: path("M30 130 H140 V119 H150"); animation-delay: 2.1s; }
.km-infra .km-i-aller-3  { offset-path: path("M30 130 H140 V191 H150"); animation-delay: 4.3s; }
.km-infra .km-i-retour   { offset-path: path("M150 71 H140 V130 H30");  animation-delay: 1.1s; opacity: .7; }
.km-infra .km-i-retour-2 { offset-path: path("M150 167 H140 V130 H30"); animation-delay: 3.5s; opacity: .7; }

/* La droite du tarif se trace une fois, puis reste entière : c'est la règle
   de la maison, un trait ne reste jamais à moitié dessiné. */
/* « km-i-tracer » : l'ancienne droite unique a été remplacée par les trois
   droites de formule. Motif conservé, plus aucun élément ne l'emploie. */
@keyframes km-i-tracer { from { transform: scaleX(0); } to { transform: scaleX(1); } }
/* L'état de repos est la droite ENTIÈRE, pas la droite absente. Si
   l'animation ne se joue jamais — mouvement réduit, onglet qui ne produit
   aucune trame, moteur qui refuse « transform-box » — le trait doit être là.
   « both » fait afficher l'état de départ pendant le retard, puis tenir
   l'état d'arrivée : on garde le tracé sans jamais risquer un trait absent.
   C'est la règle de la maison : un trait ne reste jamais à moitié dessiné. */
.km-infra .km-i-tarif {
  transform-box: fill-box; transform-origin: left center; transform: scaleX(1);
  animation: km-i-tracer var(--km-d-trace, 760ms) var(--km-e-entree) 400ms both;
}
@keyframes km-i-jalon { from { opacity: 0; transform: scale(.4); } to { opacity: 1; transform: none; } }
.km-infra .km-i-jalon {
  transform-box: fill-box; transform-origin: center; opacity: 0;
  animation: km-i-jalon 420ms var(--km-e-sortie) forwards;
}
/* Le rang est porté par le balisage : « nth-of-type » comptait aussi la
   pastille d'état et le nœud de la visite, qui sont des cercles eux aussi. */
.km-infra .km-i-jalon { animation-delay: calc(700ms + var(--jalon, 0) * 160ms); }

@media (prefers-reduced-motion: reduce) {
  .km-infra .km-i-diode, .km-infra .km-i-u-jauge, .km-infra .km-i-u-dents,
  .km-infra .km-i-balai, .km-infra .km-i-etat, .km-infra .km-i-paquet,
  .km-infra .km-i-tarif, .km-infra .km-i-jalon { animation: none; }
  .km-infra .km-i-diode { opacity: .5; }
  .km-infra .km-i-u-dents { opacity: .7; }
  .km-infra .km-i-u-jauge { transform: none; }
  .km-infra .km-i-balai { opacity: 0; }
  .km-infra .km-i-etat { opacity: 1; }
  .km-infra .km-i-paquet { opacity: 1; offset-distance: 58%; }
  .km-infra .km-i-tarif { transform: none; }
  .km-infra .km-i-jalon { opacity: 1; transform: none; }
}

/* ==========================================================================
   LA LUEUR SUR LES COMMANDES QUI NE SONT PAS DES « .btn »
   La règle de « kardox.css » ne vise que « .btn ». Le bouton « Haut », la
   bascule de thème et les choix de durée sont des commandes comme les autres :
   elles reçoivent le même geste, avec le même voile de safran.
   ========================================================================== */
/* « .km-haut » est EXCLU de cette règle. Il est « position: fixed » en bas à
   droite ; lui imposer « position: relative » l'a fait retomber dans le flux
   et atterrir en bas à GAUCHE de la page, hors de vue. Un élément fixé établit
   déjà son propre bloc conteneur : le voile en « ::after » s'y place sans
   qu'on ait à toucher à sa position.
   RÈGLE : on ne redéclare jamais « position » ni « display » sur un élément
   dont le placement est déjà décidé ailleurs. */
.km-vitrine .km-haut { overflow: hidden; }
.km-vitrine .km-barre-bascule,
.km-vitrine .km-duree-choix { position: relative; overflow: hidden; }

.km-vitrine .km-haut::after,
.km-vitrine .km-barre-bascule::after,
.km-vitrine .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-vitrine .km-haut:hover::after,
.km-vitrine .km-barre-bascule:hover::after,
.km-vitrine .km-duree-choix:hover::after { opacity: 1; }

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

/* ==========================================================================
   LA TAILLE DES CIBLES — QUARANTE-HUIT PIXELS, PAS QUARANTE-QUATRE
   Règle de la maison : toute cible d'activation fait au moins 48 px. Relevé
   sur la page : les liens de la barre, « Commander », la bascule de thème et
   les dépliants tenaient 44 px, « Nous écrire » 46. Quatre pixels manquants
   partout, et c'est aussi de la respiration en moins autour des commandes.
   Les liens EN LIGNE dans un paragraphe ne sont pas concernés : la règle
   d'accessibilité les excepte, et les grossir casserait l'interlignage.
   ========================================================================== */
.km-vitrine .btn,
.km-vitrine .km-barre-liens > li > a,
.km-vitrine .km-barre-bascule,
.km-vitrine .km-haut,
.km-vitrine .km-barre-declencheur,
.km-vitrine summary,
.km-vitrine .km-q {
  min-height: 48px;
}
.km-vitrine .km-barre-bascule { min-width: 48px; }
/* Le déclencheur du menu est EXCLU de cette règle : il est masqué au-delà de
   900 px par « display: none », et une déclaration de « display » écrite plus
   bas, même sans media, l'emporterait — le bouton « Menu » réapparaissait sur
   grand écran. On ne redéclare jamais « display » sur un élément dont
   l'affichage dépend d'un point de rupture. */
.km-vitrine .btn,
.km-vitrine .km-barre-liens > li > a,
.km-vitrine .km-barre-bascule,
.km-vitrine .km-haut {
  display: inline-flex; align-items: center; justify-content: center;
}

/* ==========================================================================
   LA TRAME DE FOND EN VARIANTE CLAIRE
   Sur l'ardoise, un filet clair sur fond sombre s'efface ; sur le papier, le
   même filet est SOMBRE sur fond clair, et l'œil l'accroche beaucoup plus.
   À maille de 52 px, cela fait un quadrillage qui passe devant le contenu au
   lieu de le porter. On agit sur les trois leviers à la fois :
     · la couleur     3,5 % → 1,6 % de noir
     · l'épaisseur    1 px → 0,5 px (un demi-pixel réel sur écran dense)
     · la maille      52 px → 68 px, donc un tiers de lignes en moins
   La variante sombre n'est pas touchée : elle a été validée telle quelle.
   ========================================================================== */
[data-bs-theme="light"] .km-vitrine {
  background-image:
    linear-gradient(rgba(14, 20, 24, .016) .5px, transparent .5px),
    linear-gradient(90deg, rgba(14, 20, 24, .016) .5px, transparent .5px);
  background-size: 68px 68px;
}

/* ==========================================================================
   L'ÉCHELLE TYPOGRAPHIQUE — REMISE AU CARRÉ
   Relevé sur les 373 éléments porteurs de texte de la page : quatorze corps
   différents, cinq graisses, et des interlignes fractionnaires sur TOUS les
   titres. Le détail qui compte :

     · interlignes 63,84 · 34,8 · 27,72 · 22,44 px — des multiplicateurs sans
       unité qui tombent entre deux pixels. Le texte se pose alors sur des
       demi-pixels, la ligne de base sort de la grille de 4, et l'ensemble
       paraît flou sans qu'on sache dire pourquoi. On repasse en valeurs
       entières, toutes multiples de 4.
     · 10 px pour « Le plus choisi » — sous le plus petit corps de la maison
       (11 px), donc hors échelle et à la limite du lisible.
     · 18 px pour la seule marque de la barre, quand 17 px existe déjà : un
       échelon pour un seul élément, et un écart que l'œil ne perçoit pas.
     · 12 px employé quatre fois, coincé entre 11 et 13 : un échelon de plus
       pour rien.
     · graisses 500 et 510 côte à côte : rigoureusement indiscernables.
     · en-têtes de tableau à 700, plus gras que n'importe quel titre de la
       page, dont le H1.

   L'échelle retenue, et rien d'autre :
     11 · 13 · 14 · 15 · 16 · 17 · 21 · 24 · 30 · 56
   ========================================================================== */

/* Les interlignes des titres, en valeurs entières sur la grille de 4.
   La portée « section[id] » est reprise ici : une règle plus spécifique
   (« .km-vitrine section[id] h2 { line-height: 1.16 } ») l'emportait sur une
   simple « .km-vitrine h2 », et les huit H2 gardaient leur 34,8 px. */
.km-vitrine h1, .km-vitrine .km-entree h1,
.km-vitrine section[id] h1 { line-height: 64px; }
.km-vitrine h2, .km-vitrine section[id] h2 { line-height: 36px; }
.km-vitrine h3, .km-vitrine section[id] h3 { line-height: 28px; }
.km-vitrine section[id] .km-services-sous-titre,
.km-vitrine section[id] .km-argu h3,
.km-vitrine section[id] h3.km-titre-tuile { line-height: 24px; }
.km-vitrine section[id] .km-offre h3 { line-height: 32px; }

/* Les échelons parasites, ramenés sur l'échelle. */
.km-vitrine .km-recommande { font-size: .6875rem; }   /* 10 → 11 px */
.km-vitrine .km-barre-marque { font-size: 1.0625rem; } /* 18 → 17 px */
.km-vitrine .km-flux-mesure { font-size: .8125rem; }   /* 12 → 13 px */
.km-vitrine .km-comparatif-releve { font-size: .6875rem; } /* 12 → 11 px, comme les autres étiquettes */

/* Une seule graisse moyenne : 510. */
.km-vitrine .km-nombre { font-weight: 510; }

/* Un en-tête de tableau n'est pas plus important qu'un titre de section : il
   prend la graisse des titres, pas davantage. */
.km-vitrine table th { font-weight: 590; }

/* ==========================================================================
   CINQ CORRECTIONS DE MISE EN PAGE, TOUTES MESURÉES
   ========================================================================== */

/* 1. « Pro » et sa pastille se lisaient « Prole plus choisi »
   Le balisage est « Pro<span class="km-col-note">le plus choisi</span> » et la
   pastille était en « display: inline » : les deux mots se suivaient sur la
   même ligne. Elle passe en bloc, sous le nom de la formule. */
.km-vitrine .km-comparatif thead .km-col-note {
  display: block; margin-top: .25rem;
  /* 11 px, pas 10 : le plus petit corps de la maison. En posant cette
     pastille j'avais réintroduit un échelon sous le plancher de l'échelle —
     exactement ce qui avait été retiré au passage précédent. */
  font-size: .6875rem; letter-spacing: .12em; line-height: 16px;
  color: var(--km-ac); text-transform: uppercase;
}

/* 2. Le bloc des écarts touchait la note qui le précède
   Mesuré : 0 px entre les deux. C'est ma propre règle de rythme qui avait mis
   « margin-top: 0 » sur « .km-preuve-ecart » pour normaliser les sections —
   en supprimant au passage une séparation voulue. On change de propos entre la
   note de méthode et les chiffres : c'est un écart séparant. */
.km-vitrine .km-preuve-ecart { margin-top: 64px; }
.km-vitrine .km-preuve-legende-note { max-width: 82ch; }

/* 3. La barre laissait 473 px de vide à sa droite
   Tout était tassé à gauche : marque, liens, boutons et bascule tenaient dans
   les 970 premiers pixels d'une barre de 1 440. Les liens restent près de la
   marque — c'est la navigation ; les actions et la bascule vont à droite,
   où l'on va chercher « Espace client » et « Commander ». */
@media (min-width: 900px) {
  /* On ne s'appuie plus sur « display: contents » pour la mise en page.
     Mesuré : le panneau avait bien « flex-grow: 1 » et restait à 610 px dans
     une barre de 1 216. En cause, la boîte interne « ::details-content » que
     les navigateurs récents interposent entre le « details » et son contenu :
     la croissance du panneau s'appliquait à CETTE boîte, pas à la barre.
     Le « details » devient donc lui-même l'élément souple de la barre, et son
     contenu s'étire à l'intérieur. */
  .km-vitrine .km-barre-menu { display: flex; flex: 1 1 auto; min-width: 0; margin: 0; }
  .km-vitrine .km-barre-menu::details-content { display: contents; }
  .km-vitrine .km-barre-panneau { margin: 0; flex: 1 1 auto; width: 100%; }
  .km-vitrine .km-barre-actions { margin-left: auto; }
  .km-vitrine .km-barre .km-conteneur { gap: 2rem; }
}

/* 4. Les quotas, ligne par ligne, avec leur icône
   Chaque intitulé porte désormais le même pictogramme que la carte de tarif
   correspondante : on relit la même chose avec le même signe. */
/* On NE fait PAS de la cellule un conteneur flex.
   Mesuré : avec « display: flex » sur le « th », la cellule cesse d'être une
   cellule de tableau — la disposition en colonnes ne la gouverne plus, et
   l'intitulé n'obtenait que 70 px dans une colonne qui en fait 329. Les dix
   intitulés se cassaient donc tous en deux lignes.
   L'icône reste en ligne, simplement calée sur la ligne de base du texte. */
.km-vitrine .km-comparatif tbody th[scope="row"] { text-align: left; }
.km-vitrine .km-quota-icone {
  color: var(--km-ac); opacity: .8;
  vertical-align: -.15em; margin-right: .5rem;
}

/* 5. Le tableau du tarif d'appel : des colonnes qui se tiennent
   Les quatre colonnes mesuraient 164, 340, 297 et 367 px — quatre largeurs
   sans rapport entre elles. On fixe la première, on égalise les trois autres,
   et les montants passent en chiffres tabulaires alignés à droite : deux
   nombres de même longueur doivent s'aligner à la virgule. */
.km-vitrine #comparaison table { table-layout: fixed; }
.km-vitrine #comparaison thead th:first-child { width: 22%; text-align: left; }
.km-vitrine #comparaison thead th:not(:first-child) { width: 26%; }
/* Un intitulé s'aligne sur ses valeurs, jamais l'inverse. La colonne « Durée
   payée d'avance » porte du texte (« 48 mois ») : elle est alignée à gauche,
   en-tête compris. Les deux colonnes de montants restent à droite, alignées
   sur la virgule. J'avais laissé l'en-tête à droite et les valeurs à gauche —
   une colonne qui se contredit elle-même. */
.km-vitrine #comparaison thead th:nth-child(2) { text-align: left; }
.km-vitrine #comparaison thead th:nth-child(3),
.km-vitrine #comparaison thead th:nth-child(4) { text-align: right; }
.km-vitrine #comparaison tbody th[scope="row"] { text-align: left; }
.km-vitrine #comparaison tbody td { text-align: right; font-variant-numeric: tabular-nums; }
.km-vitrine #comparaison tbody td:first-of-type { text-align: left; }

/* ==========================================================================
   LE TABLEAU DES QUOTAS OCCUPAIT LE TIERS GAUCHE
   Mesuré : 551 px de tableau dans un conteneur de 1 216. En « table-layout:
   auto », un tableau ne prend que la place que son contenu réclame — et ce
   contenu est fait de « 1 », « 5 », « 15 ». Résultat : tout se tassait à
   gauche et 665 px restaient vides à droite.
   On fixe la disposition : un intitulé large, trois colonnes de valeurs
   égales, et les valeurs centrées sous le nom de leur formule — c'est ainsi
   qu'un comparatif se lit, colonne par colonne.
   ========================================================================== */
.km-vitrine .km-comparatif {
  width: 100%;
  /* Mesuré : l'intitulé le plus long, « Bases de données MariaDB », demande
     194 px, plus 16 px d'icône, 10 px d'écart et 36 px de gouttières — soit
     256 px pour tenir sur UNE ligne. La colonne valant 40 %, le tableau ne
     doit jamais descendre sous 640 px, sinon les intitulés se cassent en deux,
     ce qui était le cas à 544 px (colonne à 214 px). */
  min-width: 40rem;
  /* Et il ne s'étale plus sur toute la largeur : dix lignes de trois valeurs
     n'ont pas besoin de 1 168 px. Plafonné, puis centré dans son conteneur. */
  max-width: 52rem;
  margin-inline: auto;
  table-layout: fixed;
}
.km-vitrine .km-comparatif thead th:first-child,
.km-vitrine .km-comparatif tbody th[scope="row"] { width: 40%; text-align: left; }
.km-vitrine .km-comparatif thead th:not(:first-child) { width: 20%; text-align: center; }
.km-vitrine .km-comparatif tbody td {
  text-align: center; font-variant-numeric: tabular-nums;
}
/* La colonne vedette se tient debout sur toute la hauteur du tableau. */
.km-vitrine .km-comparatif thead .km-col-vedette,
.km-vitrine .km-comparatif tbody td:nth-of-type(2) {
  background: color-mix(in srgb, var(--km-ac) 4%, transparent);
}

/* ==========================================================================
   LES DEUX NOTES SOUS LE TABLEAU DES QUOTAS
   Le tableau a été plafonné à 52 rem et centré ; ces deux lignes, elles, sont
   restées sur toute la largeur du conteneur. Mesuré : tableau x304→1136,
   notes x112→1328 — 192 px de débord de chaque côté. D'où l'impression
   qu'elles « restent à gauche » : elles ne sont pas décalées, c'est le
   tableau qui s'est resserré sans elles.
   Chaque note est donc CENTRÉE sur le même axe que le tableau. On ne la
   force pas à 52 rem : la seconde mesure 966 px d'un seul tenant, et la
   rétrécir la renverrait sur deux lignes — précisément ce qu'on corrige ici.
   Une note centrée plus large que le tableau se lit comme une légende ; une
   note coupée en deux se lit comme un défaut.

   Et le mot orphelin : « … se fait en un / clic. » tombait seul sur la
   deuxième ligne. « text-wrap: balance » répartit les lignes à peu près
   également au lieu de remplir la première jusqu'au bord — le navigateur
   choisit le point de coupe, on n'en pose aucun à la main.

   (Une largeur maximale a été essayée puis retirée : « .km-vitrine
   section[id] > * » impose déjà 76 rem avec une spécificité supérieure, la
   déclaration ne servait à rien. On ne laisse pas de règle morte.)
   ========================================================================== */
.km-vitrine .km-comparatif-serment,
.km-vitrine .km-comparatif-franchise {
  max-width: none;
  display: flex; align-items: baseline; justify-content: center;
  gap: .5rem; text-align: left;
}
.km-vitrine .km-comparatif-serment > span,
.km-vitrine .km-comparatif-franchise > span { text-wrap: balance; }
.km-vitrine .km-comparatif-serment > .km-icone,
.km-vitrine .km-comparatif-franchise > .km-icone { flex: 0 0 auto; }

/* ==========================================================================
   LES FINS DE PARAGRAPHE — PLUS DE MOT SEUL SUR LA DERNIÈRE LIGNE
   Relevé sur la page : cinq paragraphes finissaient sur une ligne quasi vide
   — 10 px de texte sur 368 disponibles pour l'un d'eux. C'est le même défaut
   que « … se fait en un / clic. » corrigé sous le tableau des quotas, et il
   se traite de la même façon : on laisse le navigateur choisir ses points de
   coupe au lieu de remplir chaque ligne jusqu'au bord.

     · « balance » pour les TITRES et les phrases courtes : lignes de
       longueurs voisines, ce qui compte quand il y en a deux ou trois.
     · « pretty » pour les PARAGRAPHES : le moteur évite spécifiquement le
       mot orphelin en fin de bloc, sans rééquilibrer tout le paragraphe.

   Aucun point de coupe n'est écrit à la main : un texte qui change de langue
   ou de largeur ne doit pas emporter la mise en page avec lui.
   ========================================================================== */
.km-vitrine p,
.km-vitrine li,
.km-vitrine dd,
.km-vitrine figcaption { text-wrap: pretty; }

.km-vitrine h1, .km-vitrine h2, .km-vitrine h3, .km-vitrine h4,
.km-vitrine .km-lead,
.km-vitrine .km-titre-tuile,
.km-vitrine .km-appui,
.km-vitrine .km-note,
.km-vitrine .km-argu-mesure,
.km-vitrine .km-doc-repere-val { text-wrap: balance; }

/* ==========================================================================
   LE TABLEAU DES DONNÉES DU GRAPHIQUE
   Il était livré nu : table par défaut, en-têtes qui se touchaient
   (« Kardox Media · Pro Indice Le marché · Premium Indice » se lisait d'une
   traite), chiffres non alignés, et les deux lignes de total noyées dans le
   corps. C'est pourtant la pièce justificative du graphique : elle doit se
   lire comme un relevé, pas comme un brouillon.
   Il reprend donc la grammaire des autres tableaux de la maison : intitulés
   en monospace capitales, filets d'un pixel, chiffres tabulaires alignés à
   droite, pied détaché par un filet plus marqué.
   ========================================================================== */
.km-vitrine .km-preuve-tableau { overflow-x: auto; margin-top: 1.25rem; }
.km-vitrine .km-preuve-tableau table {
  width: 100%; min-width: 30rem; border-collapse: collapse;
}
.km-vitrine .km-preuve-tableau caption {
  caption-side: top; text-align: left; padding-bottom: .875rem;
  font-family: var(--km-mono); font-size: .6875rem; letter-spacing: .11em;
  text-transform: uppercase; color: var(--km-t2);
}
.km-vitrine .km-preuve-tableau thead th {
  font-family: var(--km-mono); font-size: .6875rem; font-weight: 400;
  letter-spacing: .11em; text-transform: uppercase; color: var(--km-t2);
  text-align: right; padding: 0 .75rem .625rem; white-space: nowrap;
  border-bottom: 1px solid var(--km-l1);
}
.km-vitrine .km-preuve-tableau thead th:first-child { text-align: left; padding-left: 0; }
.km-vitrine .km-preuve-tableau thead th:last-child { padding-right: 0; }

.km-vitrine .km-preuve-tableau tbody th {
  font-family: var(--km-mono); font-weight: 400; font-size: .8125rem;
  color: var(--km-t2); text-align: left; padding: .5rem .75rem .5rem 0;
  border-bottom: 1px solid var(--km-l0);
}
.km-vitrine .km-preuve-tableau tbody td {
  text-align: right; font-size: .875rem; font-variant-numeric: tabular-nums;
  color: var(--km-t1); padding: .5rem .75rem;
  border-bottom: 1px solid var(--km-l0);
}
.km-vitrine .km-preuve-tableau tbody td:last-child { padding-right: 0; }

/* Le quarante-neuvième mois : c'est là que tout se joue. On le marque d'un
   filet de safran dans la gouttière — le motif des tableaux de la maison,
   pas une couleur de fond criarde. */
.km-vitrine .km-preuve-tableau tbody tr.km-bascule th,
.km-vitrine .km-preuve-tableau tbody tr.km-bascule td { color: var(--km-t0); }
.km-vitrine .km-preuve-tableau tbody tr.km-bascule th { position: relative; }
.km-vitrine .km-preuve-tableau tbody tr.km-bascule th::before {
  content: ""; position: absolute; left: -12px; top: 50%;
  width: 6px; height: 1px; background: var(--km-ac);
}

.km-vitrine .km-preuve-tableau tfoot th,
.km-vitrine .km-preuve-tableau tfoot td {
  border-top: 1px solid var(--km-l1); border-bottom: 0;
  padding-top: .75rem; font-weight: 510; color: var(--km-t0);
}
.km-vitrine .km-preuve-tableau tfoot th {
  font-family: var(--km-sans); font-size: .875rem; text-align: left; padding-left: 0;
}
.km-vitrine .km-preuve-tableau tfoot td {
  text-align: right; font-size: .875rem; font-variant-numeric: tabular-nums;
}
.km-vitrine .km-preuve-tableau tfoot td:last-child { padding-right: 0; }

/* ==========================================================================
   LES LIENS DANS LE TEXTE
   Ils n'étaient distingués que par la couleur : sur un paragraphe dense, un
   mot safran se repère mal, et la couleur seule ne suffit pas — un lecteur
   qui ne perçoit pas cette nuance n'a plus aucun indice.
   On rétablit le soulignement, mais à la manière de la maison : un filet fin,
   posé bas, dans une teinte atténuée du texte, qui s'affirme au survol.
   Les liens qui sont déjà des boutons ou des commandes en sont exclus.
   ========================================================================== */
.km-vitrine p a,
.km-vitrine li a,
.km-vitrine dd a,
.km-vitrine figcaption a,
.km-vitrine .km-note a,
.km-vitrine .km-lead a {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .18em;
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
  transition: text-decoration-color var(--km-d-micro) var(--km-e-micro),
              color var(--km-d-micro) var(--km-e-micro);
}
.km-vitrine p a:hover,
.km-vitrine li a:hover,
.km-vitrine dd a:hover,
.km-vitrine figcaption a:hover,
.km-vitrine .km-note a:hover,
.km-vitrine .km-lead a:hover { text-decoration-color: currentColor; }

/* Ce qui est déjà une commande garde son dessin. */
.km-vitrine p a.btn, .km-vitrine li a.btn,
.km-vitrine .km-barre-liens a, .km-vitrine .km-barre-actions a { text-decoration: none; }

/* ==========================================================================
   « QUATRE RAISONS » — DEUX PAR DEUX
   La grille était en « auto-fit, minmax(17rem, 1fr) » : à 1 216 px elle
   produisait trois colonnes, donc 3 + 1, et le quatrième bloc restait seul
   sur sa rangée. Un titre qui annonce quatre choses doit en montrer quatre
   d'un coup, en deux rangées égales. Même traitement pour « Ce qui se passe
   quand vous payez », qui compte aussi quatre blocs.
   Sous 900 px, une seule colonne : deux blocs côte à côte y seraient illisibles.
   ========================================================================== */
@media (min-width: 900px) {
  .km-vitrine #pourquoi .km-argus,
  .km-vitrine #commander .km-argus {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 3.5rem 4rem;
  }
}
@media (max-width: 899.98px) {
  .km-vitrine #pourquoi .km-argus,
  .km-vitrine #commander .km-argus { grid-template-columns: minmax(0, 1fr); gap: 2.5rem; }
}

/* Le bloc gagne en présence : l'icône dans un cartouche au trait, le titre à
   côté, et la mesure en bas précédée d'un tiret de safran — le même motif que
   la section courante d'un sommaire. Rien d'ajouté qui ne soit déjà dans la
   grammaire de la maison. */
.km-vitrine #pourquoi .km-argu,
.km-vitrine #commander .km-argu { padding-top: 1.75rem; }

.km-vitrine #pourquoi .km-argu .km-bloc-tete,
.km-vitrine #commander .km-argu .km-bloc-tete {
  display: flex; align-items: center; gap: .875rem; margin-bottom: .875rem;
}
.km-vitrine #pourquoi .km-argu .km-bloc-tete .km-icone,
.km-vitrine #commander .km-argu .km-bloc-tete .km-icone {
  flex: 0 0 auto; width: 38px; height: 38px; padding: 9px;
  border: 1px solid var(--km-l1); border-radius: 5px;
  color: var(--km-ac); background: color-mix(in srgb, var(--km-ac) 4%, transparent);
  transition: border-color var(--km-d-micro) var(--km-e-micro),
              background-color var(--km-d-micro) var(--km-e-micro);
}
.km-vitrine #pourquoi .km-argu:hover .km-bloc-tete .km-icone,
.km-vitrine #commander .km-argu:hover .km-bloc-tete .km-icone {
  border-color: var(--km-ac-bord);
  background: color-mix(in srgb, var(--km-ac) 9%, transparent);
}
.km-vitrine #pourquoi .km-argu h3,
.km-vitrine #commander .km-argu h3 { margin: 0; }

.km-vitrine #pourquoi .km-argu p,
.km-vitrine #commander .km-argu p { max-width: 52ch; }

.km-vitrine #pourquoi .km-argu-mesure,
.km-vitrine #commander .km-argu-mesure {
  position: relative; padding-left: 1.25rem; margin-top: .875rem !important;
}
.km-vitrine #pourquoi .km-argu-mesure::before,
.km-vitrine #commander .km-argu-mesure::before {
  content: ""; position: absolute; left: 0; top: .55em;
  width: 12px; height: 1px; background: var(--km-ac);
}

/* ==========================================================================
   LES RÉPONSES DE LA FOIRE AUX QUESTIONS
   Mesuré : la ligne de question fait 1 168 px, la réponse était plafonnée à
   72 ch — 691 px — et laissait près de 480 px vides à sa droite. La mesure
   était typographiquement correcte, mais elle ne tenait pas compte de la
   largeur du bloc qui l'entoure : à l'œil, la réponse paraît s'arrêter au
   milieu de la ligne qu'elle prolonge.
   On remonte le corps du texte au corps courant (16 px au lieu de 15) et on
   porte la mesure à 84 caractères. Le texte gagne en lisibilité ET occupe la
   place, sans jamais s'étirer au point de perdre le lecteur en fin de ligne.
   ========================================================================== */
.km-vitrine .km-q-corps { max-width: 96ch; padding-bottom: 1.75rem; }
.km-vitrine .km-q-corps p {
  font-size: 1rem; line-height: 1.625rem; margin-bottom: .875rem;
}

/* ==========================================================================
   LE BLOC FINAL — DEUX COLONNES, PAS UNE RANGÉE QUI DÉBORDE
   « .km-appel-corps » était une simple rangée flex avec retour à la ligne :
   la pastille, le titre, le chapeau, les deux boutons et la note s'y
   suivaient et se replaçaient au hasard de la largeur. D'où les boutons
   collés au milieu du chapeau, la note seule en bas à gauche, et un grand
   vide sous l'ensemble.
   Disposition explicite : le propos à gauche, les deux commandes à droite,
   alignées sur le centre du bloc. Chacun sait où il va.
   ========================================================================== */
@media (min-width: 900px) {
  .km-vitrine .km-appel-corps {
    display: grid;
    /* Deux colonnes de poids égal. La précédente version mettait « auto » et
       « justify-self: end » : les boutons partaient se coller au bord droit et
       laissaient un vide de cinq cents pixels entre le texte et eux. Ils sont
       maintenant calés au DÉBUT de la seconde colonne — assez à droite pour
       se détacher, assez près pour rester liés au propos. */
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas:
      "puce   actions"
      "titre  actions"
      "lead   actions"
      "note   actions";
    column-gap: 3rem; row-gap: .5rem;
    align-content: start;
  }
  .km-vitrine .km-appel-corps > .km-puce { grid-area: puce; }
  .km-vitrine .km-appel-corps > h2 { grid-area: titre; margin: .25rem 0 0; }
  .km-vitrine .km-appel-corps > .km-lead { grid-area: lead; margin: .5rem 0 0; max-width: 52ch; }
  .km-vitrine .km-appel-corps > .km-note { grid-area: note; margin: .75rem 0 0; }
  .km-vitrine .km-appel-corps > .km-ouverture-actions {
    grid-area: actions; align-self: center; justify-self: start;
    display: flex; gap: .875rem; flex-wrap: nowrap;
  }
}

/* Le grand vide sous le bloc : la section gardait la respiration d'une
   section pleine alors qu'elle n'a plus rien après elle. */
.km-vitrine #commencer { padding-bottom: 3rem; }

/* ==========================================================================
   L'ANIMATION D'ENTRÉE NE DOIT PAS ÉLARGIR LE DOCUMENT
   Mesuré à 768 px : « scrollWidth » valait 788 — vingt pixels de défilement
   horizontal, donc une barre en bas de l'écran sur tablette. En neutralisant
   toutes les transformations, le débordement disparaît : la cause est l'état
   d'attente lui-même. Un élément qui patiente à « translate3d(44px,0,0) »
   déborde de sa colonne, et un débordement transformé compte dans la largeur
   du document même s'il est invisible.
   « overflow-x: clip » — et non « hidden » : « clip » ne crée pas de
   conteneur de défilement, donc la barre supérieure reste « sticky ». C'est
   la seule forme qui règle le problème sans en créer un autre.
   ========================================================================== */
html { overflow-x: clip; }
.km-vitrine { overflow-x: clip; }

/* ==========================================================================
   LES TROIS FORMULES : JAMAIS DEUX PLUS UNE
   Relevé entre 761 et 1 100 px : la grille passait à DEUX colonnes, donc
   deux cartes en haut et une seule en dessous. C'est le même déséquilibre que
   « Quatre raisons » montrait en 3 + 1, et il est plus gênant encore ici :
   trois formules qui se comparent doivent se voir ensemble, ou pas du tout.
   Le calcul décide du seuil, pas le goût : à 1 024 px, trois colonnes laissent
   (1024 − 48 de gouttières extérieures − 48 d'écarts) / 3 = 309 px par carte,
   au-dessus du minimum de 300 px que la maquette impose. À 900 px il n'en
   resterait que 268 : trop peu. Le basculement se fait donc à 1 000 px, et en
   dessous les cartes s'empilent — une par ligne, entière, comparable.
   ========================================================================== */
@media (min-width: 1000px) {
  .km-vitrine #tarifs .km-offres { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 999.98px) {
  .km-vitrine #tarifs .km-offres { grid-template-columns: minmax(0, 1fr); }
}

/* La marque de la barre est un lien : elle doit offrir la même surface que
   les autres commandes. Mesurée à 125 × 26. */
.km-vitrine .km-barre-marque {
  display: inline-flex; align-items: center; min-height: 48px;
}

/* ==========================================================================
   LES CIBLES QUI RESTAIENT SOUS 48 px
   Relevé complet des liens de la page, en séparant deux familles :

     · les liens EN LIGNE dans un paragraphe (« écrivez-nous », « conditions
       générales », l'adresse de courriel) mesurent 20 à 22 px de haut. La
       règle d'accessibilité les excepte explicitement — les grossir casserait
       l'interlignage du texte qui les porte. On n'y touche pas.
     · les liens de NAVIGATION du pied de page (« Guides », « Questions
       fréquentes », « Conditions générales »…) ne sont pas dans du texte :
       ce sont des commandes en colonne, et ils tenaient 22 px. Ceux-là
       relèvent bien de la règle.
   ========================================================================== */
.km-vitrine .km-pied-col a,
.km-vitrine .km-pied-contact a {
  display: inline-flex; align-items: center;
  min-height: 48px;
}
/* La colonne ne doit pas doubler de hauteur pour autant : l'écart entre les
   liens est repris dans la hauteur de chaque cible. */
.km-vitrine .km-pied-col ul,
.km-vitrine .km-pied-col > nav { gap: 0; }
.km-vitrine .km-pied-col li { margin: 0; }

/* Un lien de la barre trop court pour la règle : « Tarifs » ne faisait que
   36 px de large. On lui donne de la marge intérieure plutôt qu'une largeur
   fixe, pour que le libellé continue de commander sa taille. */
.km-vitrine .km-barre-liens > li > a { padding-inline: .5rem; min-width: 48px; }

/* ==========================================================================
   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-vitrine .km-offre-groupe {
  display: block; margin-top: 1.25rem;
  padding-top: 1.25rem; border-top: 1px solid var(--km-l0);
}
.km-vitrine .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);
}

/* Ce qui manque porte son propre signe, et se lit en retrait — présent, mais
   sans crier. */
.km-vitrine .km-point-absent { color: var(--km-t2); }
.km-vitrine .km-point-absent .km-point-icone { color: var(--km-t3, var(--km-t2)); opacity: .75; }

/* 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-vitrine .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);
}

/* ---- La formule vedette, sans changer de couleur ----
   Elle était déjà signalée ; elle l'est maintenant franchement : un trait
   d'accent d'un pixel et demi, une élévation, et un léger débord vertical qui
   la fait passer devant ses voisines. Aucun aplat, aucune couleur de fond
   nouvelle — la palette ne bouge pas. */
@media (min-width: 1000px) {
  #tarifs .km-offre-vedette { position: relative; z-index: 1; }
}
/* Les cartes ne sont PAS des boîtes : « #tarifs .km-offre » met à zéro les
   bords haut, droit et bas, et ne garde qu'un filet à gauche. C'est le dessin
   validé, on ne le transforme pas en cadre. La formule vedette se signale
   donc par CE filet-là — porté à deux pixels et passé au safran — et non par
   un contour ajouté. Le sélecteur reprend l'identifiant, sinon la règle de
   « #tarifs » l'emporte : un identifiant bat deux classes. */
#tarifs .km-offre-vedette {
  border-left-color: var(--km-ac);
  border-left-width: 2px;
}
#tarifs .km-offre-vedette .km-offre-titre { color: var(--km-ac); }
#tarifs .km-offre-vedette:hover { border-left-color: var(--km-ac-h, var(--km-ac)); }

/* ==========================================================================
   LE SCHÉMA, DEUXIÈME PASSE — DENSITÉ ET VÉRITÉ
   Trois faiblesses relevées sur la capture :
     · les huit unités étaient rigoureusement identiques — une baie ne l'est
       jamais, et la répétition tue le dessin ;
     · trois traits partaient du répartiteur vers trois unités choisies au
       hasard, alors que la baie en compte huit : le schéma mentait sur son
       propre sujet ;
     · sous la droite du tarif, quarante-six unités de vide entre la ligne et
       son axe, sans rien pour les relier.
   Réponses : un BUS vertical qui dessert chaque unité par une amorce, des
   unités NUMÉROTÉES et de contenu variable (deux ou trois baies de disque),
   et des CHUTES en pointillé qui rattachent chaque jalon à l'axe.
   ========================================================================== */

/* Le bus et ses amorces */
.km-infra .km-i-bus     { fill: none; stroke: var(--km-l2); stroke-width: 1; }
.km-infra .km-i-amorce  { fill: none; stroke: var(--km-l1); stroke-width: 1; }

/* Le cadre d'une unité et son numéro */
.km-infra .km-i-boite-u { fill: none; stroke: var(--km-l1); stroke-width: 1; }
.km-infra .km-i-rang {
  fill: var(--km-t2); font-family: var(--km-mono); font-size: 7px;
  letter-spacing: .06em; opacity: .7;
}

/* L'axe du bas et les chutes qui y mènent */
.km-infra .km-i-axe   { fill: none; stroke: var(--km-l1); stroke-width: 1; }
.km-infra .km-i-chute { fill: none; stroke: var(--km-l1); stroke-width: 1; stroke-dasharray: 2 3; opacity: .8; }

/* La veille passe par le cadre de l'unité, comme avant. */
.km-infra .km-i-boite-u   { animation: km-i-eveil 6.4s var(--km-e-couleur) infinite; }
.km-infra .km-i-unite:nth-of-type(2) .km-i-boite-u { animation-delay: 2.1s; }
.km-infra .km-i-unite:nth-of-type(5) .km-i-boite-u { animation-delay: 4.3s; }

/* Le bus respire faiblement : le parc est vivant, il ne clignote pas. */
@keyframes km-i-bus { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
.km-infra .km-i-bus { animation: km-i-bus 7.6s var(--km-e-couleur) infinite; }

@media (prefers-reduced-motion: reduce) {
  .km-infra .km-i-boite-u, .km-infra .km-i-bus { animation: none; }
  .km-infra .km-i-bus { opacity: 1; }
}

/* ==========================================================================
   LES TROIS TARIFS, EN TROIS DROITES
   Le bas du schéma annonçait « TARIF · TRENTE-SIX MOIS » et ne montrait aucun
   montant : une promesse sans preuve, au milieu d'un dessin qui ne vit que de
   preuves. Les trois formules sont maintenant trois droites horizontales,
   chacune avec son montant au bout, sur un axe de mois commun.
   C'est la meilleure réclame possible parce que c'est un fait vérifiable :
   sur trente-six mois, aucune des trois ne monte. Les montants sont engendrés
   depuis « donnees.json » — ils ne peuvent pas diverger du catalogue.
   ========================================================================== */

.km-infra .km-i-plate-trait {
  fill: none; stroke: var(--km-l2); stroke-width: 1;
  transform-box: fill-box; transform-origin: left center;
}
.km-infra .km-i-plate-bout { fill: var(--km-plan); stroke: var(--km-l2); stroke-width: 1; }
.km-infra .km-i-plate-prix {
  fill: var(--km-t1); font-family: var(--km-mono); font-size: 10px;
  letter-spacing: .04em;
}

/* La formule la plus choisie porte le safran — le même signal que sur sa
   carte, pas un signal de plus. */
.km-infra .km-i-plate-vedette .km-i-plate-trait { stroke: var(--km-ac); stroke-width: 1.5; }
.km-infra .km-i-plate-vedette .km-i-plate-bout  { stroke: var(--km-ac); }
.km-infra .km-i-plate-vedette .km-i-plate-prix  { fill: var(--km-ac); }
.km-infra .km-i-plate-vedette .km-i-txt-fin     { fill: var(--km-ac); }

/* Les trois droites se tracent l'une après l'autre, de gauche à droite.
   L'état de repos est la droite ENTIÈRE : si l'animation ne se joue jamais,
   le trait est là. Un trait ne reste jamais à moitié dessiné. */
@keyframes km-i-plate { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.km-infra .km-i-plate-trait {
  transform: scaleX(1);
  animation: km-i-plate 640ms var(--km-e-entree) both;
  animation-delay: calc(420ms + var(--rang-t, 0) * 180ms);
}
@keyframes km-i-plate-bout { from { opacity: 0; } to { opacity: 1; } }
.km-infra .km-i-plate-bout, .km-infra .km-i-plate-prix {
  opacity: 1;
  animation: km-i-plate-bout 380ms var(--km-e-sortie) both;
  animation-delay: calc(940ms + var(--rang-t, 0) * 180ms);
}

@media (prefers-reduced-motion: reduce) {
  .km-infra .km-i-plate-trait, .km-infra .km-i-plate-bout, .km-infra .km-i-plate-prix {
    animation: none; transform: none; opacity: 1;
  }
}

/* ==========================================================================
   LE SOCLE COMMUN AUX TROIS FORMULES
   Ces cinq lignes étaient répétées à l'identique dans chacune des trois
   cartes — quinze lignes dont dix ne disaient rien de neuf, côte à côte.
   Énoncées une seule fois, sous les cartes, elles portent sur les trois à la
   fois et se lisent d'un coup. Les cartes y gagnent en hauteur, la page en
   franchise : ce qui est commun est dit comme tel.
   ========================================================================== */
.km-vitrine .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-vitrine .km-socle-tete {
  display: inline-flex; align-items: center; gap: .625rem; margin-bottom: 1rem;
}
.km-vitrine .km-socle-tete .km-icone { color: var(--km-ac); }
.km-vitrine .km-socle-liste {
  display: grid;
  /* Cinq éléments : la maille est calculée pour qu'ils tiennent sur UNE
     rangée à pleine largeur — 5 × 13 rem + 4 × 2 rem = 1 168 px, sous les
     1 216 disponibles. À 15 rem, on n'en logeait que quatre et le cinquième
     restait seul, comme les cartes le faisaient en 2 + 1. */
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: .75rem 1.5rem; margin: 0; padding: 0; list-style: none;
}
.km-vitrine .km-socle-liste li {
  display: flex; align-items: baseline; gap: .625rem;
  font-size: .9375rem; color: var(--km-t1);
}
.km-vitrine .km-socle-liste .km-point-icone { flex: 0 0 auto; color: var(--km-ac); opacity: .85; }

/* Cinq éléments, cinq colonnes : « auto-fit » retombait à quatre et laissait
   le cinquième seul sur sa rangée — le même « n + 1 » que partout ailleurs.
   Au-dessus de 1 100 px, on impose donc le compte exact. */
@media (min-width: 1100px) {
  .km-vitrine .km-socle-liste { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

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

/* ==========================================================================
   LE PIED DE PAGE — QUATRE COLONNES, ET UNE RESPIRATION TENUE
   Deux corrections.

   1. Le pied ne ramenait nulle part vers ce que la maison vend, et « /news »
      — qui existe et répond — n'était lié depuis aucune page. Une colonne
      « Nos offres » a été ajoutée, « Actualités » aussi, et le doublon de
      contact supprimé : « Nous écrire » et « Écrire à l'assistance » menaient
      au même formulaire.

   2. Les liens avaient reçu « min-height: 48px » pour respecter la règle de
      cible. C'est juste, mais la hauteur était prise sur du VIDE : la colonne
      se distendait et le pied paraissait flotter. La même surface est
      maintenant obtenue par du remplissage vertical, l'écart de grille étant
      ramené à zéro — la cible fait toujours 48 px, l'œil voit une liste
      serrée.
   ========================================================================== */
.km-vitrine .km-pied-col { gap: 0; }
/* Les liens sont désormais dans « .km-pied-liens » : le sélecteur en enfant
   direct de « .km-pied-col » ne les atteignait plus. */
.km-vitrine .km-pied-col > a,
.km-vitrine .km-pied-liens > a {
  min-height: 0;                 /* on annule la hauteur imposée plus haut… */
  padding-block: .8125rem;       /* …et on la reprend en remplissage : 13 + 22 + 13 = 48 */
  line-height: 1.375rem;
  min-width: 48px;               /* « Tarifs » ne mesurait que 47 px de large */
}
.km-vitrine .km-pied-contact a {
  min-height: 0; padding-block: .8125rem; line-height: 1.375rem;
}
.km-vitrine .km-pied-contact { display: flex; flex-direction: column; gap: 0; }

/* La marque garde son aération, les colonnes se resserrent. */
.km-vitrine .km-pied-adresse { margin: 0 0 .5rem; font-size: .875rem; line-height: 1.375rem; color: var(--km-t2); }

/* Cinq entrées dans « La société » : la colonne la plus longue donne sa
   hauteur au bloc, les autres s'alignent en haut. */
.km-vitrine .km-pied-haut { align-items: start; }

/* ==========================================================================
   LE PIED SUR TÉLÉPHONE
   Mesuré à 375 px : 1 425 px de haut, treize liens empilés en une colonne.
   Les trois groupes deviennent des dépliants — le même geste que le menu de
   la barre et que la foire aux questions, donc rien de nouveau à comprendre.
   Au-dessus de 560 px ils restent ouverts et le dessin ne change pas.
   ========================================================================== */
.km-vitrine .km-pied-col { display: flex; flex-direction: column; }
.km-vitrine .km-pied-col > summary { list-style: none; }
.km-vitrine .km-pied-col > summary::-webkit-details-marker { display: none; }
.km-vitrine .km-pied-liens { display: flex; flex-direction: column; }

@media (min-width: 560.02px) {
  /* Sur grand écran l'intitulé n'est pas une commande : il ne se survole pas,
     il ne prend pas le focus, il ne se clique pas. */
  .km-vitrine .km-pied-col > summary { pointer-events: none; cursor: default; }
}

@media (max-width: 560px) {
  .km-vitrine .km-pied-col > summary {
    display: flex; align-items: center; justify-content: space-between;
    min-height: 48px; cursor: pointer;
    border-top: 1px solid var(--km-l1);
  }
  /* Le signe d'ouverture : un trait qui devient une croix, comme ailleurs. */
  .km-vitrine .km-pied-col > summary::after {
    content: ""; flex: 0 0 auto; width: 11px; height: 11px;
    background:
      linear-gradient(var(--km-t2), var(--km-t2)) center/11px 1px no-repeat,
      linear-gradient(var(--km-t2), var(--km-t2)) center/1px 11px no-repeat;
    transition: transform var(--km-d-micro) var(--km-e-micro);
  }
  .km-vitrine .km-pied-col[open] > summary::after {
    background: linear-gradient(var(--km-ac), var(--km-ac)) center/11px 1px no-repeat;
  }
  .km-vitrine .km-pied-col[open] > summary .km-etiquette { color: var(--km-ac); }
  .km-vitrine .km-pied-liens { padding-bottom: .5rem; }
  .km-vitrine .km-pied-haut { gap: 0; }
  .km-vitrine .km-pied-marque { margin-bottom: 1.5rem; }
  .km-vitrine .km-pied-bas { margin-top: 1.5rem; gap: .5rem; }
}

/* ==========================================================================
   LA BARRE — CE QUI NE FONCTIONNAIT PAS, ET CE QUI MANQUAIT
   Relevé sur la page en ligne :
     · « Ce qui est inclus » pointait vers « #inclus » et « Comparer » vers
       « #comparer ». Ces deux ancres N'EXISTENT PAS — les sections sont
       « #services » et « #comparaison ». Deux liens de menu sur quatre ne
       menaient nulle part depuis la mise en ligne.
     · le script cherchait « .km-v-barre » et « .km-v-nav-lien » : zéro
       élément. L'état au défilement et le marquage de la section courante
       n'ont donc jamais fonctionné.
   Et ce qui manquait : la barre disait où l'on VA, rien ne disait où l'on EST.
   ========================================================================== */

/* La barre se pose quand la page défile : un filet apparaît sous elle. */
.km-vitrine .km-barre-posee, .km-vitrine .km-v-barre-posee {
  border-bottom-color: var(--km-l1);
}

/* La section courante : un trait de safran sous son intitulé — le motif du
   sommaire des documents, pas une pastille. */
.km-vitrine .km-barre-liens a[aria-current] { color: var(--km-t0); }
.km-vitrine .km-barre-liens a[aria-current]::after { transform: scaleX(1); }

/* Le filet de progression : un pixel, safran, sur toute la largeur. */
.km-vitrine .km-barre-progres {
  position: absolute; left: 0; bottom: -1px; height: 1px; width: 100%;
  transform: scaleX(var(--km-progres, 0)); transform-origin: left center;
  background: var(--km-ac);
  pointer-events: none;
}
.km-vitrine .km-barre { position: sticky; }

@media (prefers-reduced-motion: reduce) {
  .km-vitrine .km-barre-progres { display: none; }
}

/* ==========================================================================
   « OÙ SE TROUVE QUOI » — LA FIGURE DE LA SECTION « LA MAISON »
   Section la plus pauvre de la page : 95 mots, aucune figure. Plutôt qu'une
   photographie de banque d'images — qui pèserait à elle seule autant que la
   moitié du site et serait le seul élément générique d'une page qui n'en a
   aucun —, un repère dessiné dans la langue de la maison : réglure, trait
   d'un pixel, monospace, et rien qui vienne d'un autre domaine.
   Les coordonnées d'Agen sont publiques. La zone européenne est bornée par
   ses quatre coins, comme partout ailleurs sur ce site.
   ========================================================================== */
.km-vitrine .km-lieu-figure { margin: 0 0 2rem; }
.km-vitrine .km-lieu { display: block; width: 100%; height: auto; }
.km-vitrine .km-lieu path,
.km-vitrine .km-lieu rect,
.km-vitrine .km-lieu circle { vector-effect: non-scaling-stroke; }

.km-vitrine .km-lieu-reglure path { fill: none; stroke: var(--km-l0); stroke-width: 1; }
.km-vitrine .km-lieu-filet   { fill: none; stroke: var(--km-l1); stroke-width: 1; }
.km-vitrine .km-lieu-coins path { fill: none; stroke: var(--km-l2); stroke-width: 1; }
.km-vitrine .km-lieu-tirets  { fill: none; stroke: var(--km-l1); stroke-width: 1; stroke-dasharray: 3 3; }

.km-vitrine .km-lieu-txt {
  fill: var(--km-t2); font-family: var(--km-mono); font-size: 8px; letter-spacing: .11em;
}
.km-vitrine .km-lieu-txt-fin  { font-size: 7px; letter-spacing: .14em; }
.km-vitrine .km-lieu-txt-fort { fill: var(--km-ac); font-size: 11px; letter-spacing: .1em; }

/* Le point : une croix de relevé, un halo qui respire, un cœur plein. */
.km-vitrine .km-lieu-croix { fill: none; stroke: var(--km-l2); stroke-width: 1; }
.km-vitrine .km-lieu-halo  { fill: none; stroke: var(--km-ac); stroke-width: 1; opacity: .55; }
.km-vitrine .km-lieu-coeur { fill: var(--km-ac); stroke: none; }

.km-vitrine .km-lieu-boite { fill: none; stroke: var(--km-l1); stroke-width: 1; }
.km-vitrine .km-lieu-dents { fill: none; stroke: var(--km-l1); stroke-width: 1; opacity: .6; }
.km-vitrine .km-lieu-diode { fill: var(--km-ac); stroke: none; opacity: .3; }

.km-vitrine .km-lieu-legende {
  margin-top: 1rem; max-width: 62ch;
  font-size: .8125rem; line-height: 1.375rem; color: var(--km-t2);
  text-wrap: pretty;
}

/* Ce qui vit : le halo du relevé et les diodes, au rythme du reste du site. */
@keyframes km-lieu-halo { 0%, 100% { r: 11; opacity: .55; } 50% { r: 14; opacity: .15; } }
.km-vitrine .km-lieu-halo { animation: km-lieu-halo 4.2s var(--km-e-couleur) infinite; }
@keyframes km-lieu-diode { 0%, 86%, 100% { opacity: .22; } 92% { opacity: 1; } }
.km-vitrine .km-lieu-diode {
  animation: km-lieu-diode 6.8s var(--km-e-couleur) infinite;
  animation-delay: calc(var(--rang, 0) * 1.1s);
}
@media (prefers-reduced-motion: reduce) {
  .km-vitrine .km-lieu-halo, .km-vitrine .km-lieu-diode { animation: none; }
}

/* La figure occupe la moitié gauche, les repères la suivent. */
@media (min-width: 900px) {
  .km-vitrine #maison .km-lieu-figure { max-width: 34rem; }
}

/* ==========================================================================
   LE TABLEAU DE COMPARAISON SUR TÉLÉPHONE — DES INTITULÉS QUI SE CHEVAUCHENT
   Mesuré à 375 px : les quatre en-têtes portent « white-space: nowrap » dans
   un tableau à disposition fixe où chaque colonne ne fait que 87 px. « Durée
   payée d'avance » en réclame 150 : ne pouvant pas se couper, le texte sort
   de sa cellule et passe SOUS celui de la colonne voisine. Trois
   chevauchements relevés, tous là.

       « Durée payée d'avance » ⨯ « À la souscription »   89 × 15 px
       « À la souscription »    ⨯ « Au renouvellement »   63 × 15 px

   Sous 760 px les intitulés se coupent donc normalement, et le cadre devient
   défilant en dernier recours pour les écrans les plus étroits — le même
   dispositif que le tableau des quotas, déjà en place et déjà compris.
   ========================================================================== */
@media (max-width: 760px) {
  .km-vitrine #comparaison thead th,
  .km-vitrine #comparaison tbody th,
  .km-vitrine #comparaison tbody td {
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .km-vitrine #comparaison thead th { font-size: .625rem; line-height: 14px; }
  .km-vitrine #comparaison tbody td { font-size: .8125rem; }
  /* Filet de sûreté : sous 380 px, on laisse le cadre défiler plutôt que de
     comprimer les montants jusqu'à l'illisible. */
  .km-vitrine .km-comp-cadre { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .km-vitrine #comparaison table { min-width: 20rem; }
}

/* ==========================================================================
   SUR TÉLÉPHONE, L'ENTRÉE NE SE DÉPLACE PLUS LATÉRALEMENT
   C'est la cause du reproche « des blocs passent à droite ou à gauche de la
   page, surtout sur téléphone ». Ce n'est pas la mise en page : c'est l'état
   d'attente de l'animation, qui décale les blocs de 44 px à gauche ou à
   droite (56 px pour les figures) en attendant leur tour.

   Sur un écran de 1 440 px, 44 px sur une colonne de 389 représentent un
   onzième : le geste se lit comme un mouvement. Sur 375 px, la même
   translation déplace un bloc de PLEINE LARGEUR d'un huitième de l'écran —
   et tant que l'observateur n'a pas parlé, on voit une page mal alignée, pas
   une animation qui attend.

   Sous 760 px, l'entrée se fait donc uniquement par le bas et par l'opacité.
   Rien ne sort jamais de son axe.
   ========================================================================== */
@media (max-width: 760px) {
  .km-vitrine .km-attend[data-entree="gauche"],
  .km-vitrine .km-attend[data-entree="droite"],
  .km-vitrine .km-attend[data-entree="bas"],
  .km-vitrine .km-attend.km-entree-figure,
  .km-vitrine .km-attend.km-preuve-figure {
    transform: translate3d(0, 18px, 0) !important;
  }
}

/* ==========================================================================
   LA HIÉRARCHIE S'INVERSAIT SUR TÉLÉPHONE
   Mesuré à 375 px : le H1 tombe à 40 px pendant que les montants restent à
   44. Le prix devenait donc le plus gros caractère de la page, devant son
   titre. Sur grand écran l'ordre est juste (56 contre 44) ; c'est la
   réduction du titre qui l'a renversé.
   Les montants passent à 34 px sous 760 px : ils restent le second corps de
   la page, jamais le premier.
   ========================================================================== */
@media (max-width: 760px) {
  /* L'identifiant est repris : « #tarifs .km-offre-montant » porte 2,75 rem
     et un identifiant bat n'importe quel nombre de classes. Sans lui, la
     règle ne s'appliquait pas — vérifié, le montant restait à 44 px. */
  #tarifs .km-offre .km-valeur,
  #tarifs .km-offre-montant { font-size: 2.125rem; line-height: 40px; }
}

/* ==========================================================================
   LE GEL DOIT L'EMPORTER — ET IL DOIT RESTER LE DERNIER
   Défaut mesuré : « .km-fige { transition: none !important } » et
   « .km-attend { transition: … !important } » ont la MÊME spécificité et sont
   tous deux importants. Entre deux déclarations de force égale, c'est la
   dernière écrite qui gagne. En ajoutant le nouveau bloc « .km-attend » en fin
   de fichier, j'ai fait perdre le gel : la mise en attente s'animait de
   nouveau, et l'on revoyait les blocs s'effacer en remontant la page.
   Relevé sur la page : « getAnimations() » retournait « opacity running » au
   moment même de l'armement, ce qui ne doit jamais arriver.
   La classe est donc doublée — « .km-fige.km-fige », spécificité supérieure —
   et ce bloc reste le dernier du fichier. Rien ne doit être ajouté après.
   ========================================================================== */
.km-fige.km-fige, .km-fige.km-fige * {
  transition: none !important;
  animation: none !important;
}

/* ==========================================================================
   LA MARQUE
   Les fichiers viennent du dossier de remise (design_handoff_kardox_logos) et
   sont posés TELS QUELS, en <img>. Une image n'hérite d'aucun style : le
   basculement clair/sombre se fait donc par deux fichiers, montrés l'un ou
   l'autre selon « data-bs-theme », et non par currentColor.
   Rapport du verrouillage : 1094 / 206, soit 5,31:1.
   Le dossier de remise fixe une hauteur minimale de 24 px ; en dessous, il
   demande de n'employer que le monogramme du favicon — c'est ce que fait la
   règle des petites fenêtres, plus bas.
   ========================================================================== */
.km-logo,
.km-logo-mono {
  display: block;
  width: auto;
  flex: none;
  /* Le pied est une colonne en flex : sans cela l'image est étirée à la
     largeur de la colonne alors que sa hauteur reste fixe, et le dessin sort
     de son rapport (mesuré : 274x44, soit 6,23:1 au lieu de 5,31:1). */
  align-self: flex-start;
}
.km-logo { aspect-ratio: 1094 / 206; }
.km-logo-mono { aspect-ratio: 1 / 1; }

/* Le logo clair sert par défaut ; l'ardoise prend le fichier au texte blanc. */
.km-logo-sombre { display: none; }
[data-bs-theme="dark"] .km-logo-clair { display: none; }
[data-bs-theme="dark"] .km-logo-sombre { display: block; }

/* La barre. Le lien ne doit pas se laisser comprimer, sinon l'image rétrécit
   au lieu de tenir sa hauteur. */
.km-barre-marque { flex: none; }
.km-barre-marque .km-logo { height: 36px; }
@media (max-width: 620px) { .km-barre-marque .km-logo { height: 30px; } }

/* Le pied : un cran plus grand, et le nom reste pour les lecteurs d'écran. */
.km-logo-pied { height: 44px; margin-bottom: 1.125rem; }

/* Sous 400 px le verrouillage — cinq fois plus large que haut — pousserait la
   bascule de thème hors de l'écran. On sert alors le seul monogramme, comme le
   demande le dossier de remise. */
.km-logo-mono { display: none; }
@media (max-width: 400px) {
  .km-barre-marque .km-logo { display: none; }
  .km-barre-marque .km-logo-mono { display: block; height: 34px; }
}

/* Le nom reste dans le document pour les lecteurs d'écran et les moteurs,
   mais il n'est plus dessiné : le verrouillage le porte déjà. */
.km-hors-ecran {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ==========================================================================
   LE TÉLÉPHONE : la barre se resserre, la langue cesse d'être une pastille
   --------------------------------------------------------------------------
   Relevé sur un écran de 375 px : la barre pesait 76 px de haut, et le
   sélecteur de langue — pastille bordée, drapeau, code « FR » et chevron —
   faisait 95 px de large, deux fois la cible voisine. À côté du logo réduit
   au monogramme et du mot « Menu », il tirait tout l'œil.
   Le dessin du GRAND écran ne bouge pas : rien ici ne dépasse 899,98 px.
   ========================================================================== */

@media (max-width: 899.98px) {
  .km-barre-rang { min-height: 60px; gap: .25rem; }

  /* les trois commandes de la barre : trois carrés de 48 px, même dessin */
  .km-barre-declencheur,
  .km-barre-bascule,
  .km-langue-declencheur {
    height: 48px; min-height: 48px;
    border-radius: 5px;
  }
  .km-barre-bascule { width: 48px; }

  /* la langue : drapeau et chevron, sans pastille ni code — le nom complet
     reste dans le panneau, et l'aria-label dit déjà la langue en cours */
  .km-langue-declencheur {
    width: 48px; padding: 0; gap: .25rem;
    justify-content: center; border-color: transparent;
  }
  .km-langue-declencheur .km-langue-code { display: none; }
  .km-langue-declencheur .km-drapeau { width: 22px; height: auto; }
  .km-langue-declencheur:hover,
  .km-langue[open] .km-langue-declencheur { border-color: transparent; background: var(--km-plan-b); }

  /* Les deux panneaux tombent en pleine largeur, à gouttière égale.
     « .km-langue » cesse d'être le repère de position : large de 48 px, il
     réduisait son propre panneau à 16 px de large (mesuré à l'écran). Le
     repère devient la barre elle-même, qui est collante donc positionnée. */
  .km-langue { position: static; }
  .km-barre-panneau,
  .km-langue-panneau {
    position: absolute; left: 1rem; right: 1rem; width: auto;
    min-width: 0; max-width: none;
  }
  .km-langue-panneau { top: calc(100% + .5rem); }
  .km-barre-panneau { margin-top: .5rem; }
  .km-langue-choix { min-height: 48px; }

  /* le mot « Menu » cède la place sous 400 px : l'icône suffit */
  .km-barre-declencheur { padding-inline: .625rem; }
}

@media (max-width: 399.98px) {
  .km-barre-declencheur { width: 48px; padding: 0; justify-content: center; font-size: 0; }
  .km-barre-declencheur .km-icone { font-size: 1rem; }
}

/* La même gouttière pour le pied que pour le reste : 20 px, pas 24 —
   mesuré à 375 px, le pied était décalé de quatre pixels vers l'intérieur. */
@media (max-width: 575.98px) {
  .km-pied-haut, .km-pied-bas { padding-inline: 1.25rem; }
}

/* ---------- La page 404 : le même langage, en plus court ---------- */
.km-404 { min-height: 100svh; display: flex; flex-direction: column;
  justify-content: center; gap: 1.25rem; padding-block: 4rem; max-width: 44rem; }
.km-404 h1 { margin: 0; }
.km-404 .km-lead { margin: 0; }
.km-404-liens { display: flex; flex-wrap: wrap; gap: .5rem 1.75rem; margin-top: .5rem; }
.km-404-liens a { display: inline-flex; align-items: center; min-height: 48px;
  color: var(--km-t1); text-decoration: none; font-size: .9375rem; }
.km-404-liens a:hover { color: var(--km-ac); }
.km-404-marque { margin: 3rem 0 0; padding-top: 1.5rem; border-top: 1px solid var(--km-l1); }
.km-404-marque img { height: 26px; width: auto; }
@media (max-width: 575.98px) { .km-404 { padding-inline: 1.25rem; } }
