/* ============================================================================
   KUABA — SOCLE PUBLIC
   ----------------------------------------------------------------------------
   Ce fichier est AUTOSUFFISANT : il ne dépend ni de Bootstrap, ni de jQuery UI,
   ni d'aucune fonte d'icônes. C'est tout son intérêt.

   🔑 POURQUOI UN SOCLE SÉPARÉ. Le gabarit hérité de l'éditeur charge 1,7 Mo de
   CSS et de JavaScript sur la page d'accueil, en 27 requêtes : Bootstrap,
   jQuery, jQuery UI, Slick, Odometer, Select2, Animate.css et DEUX fontes
   d'icônes. Sur un Android d'entrée de gamme en réseau lent, c'est plusieurs
   secondes avant le premier pixel utile. Aucun réglage ne rattrape cela ; il
   faut un autre socle.

   ⚠️ L'espace hôte et l'administration gardent l'ancien gabarit. Ils
   s'utilisent au bureau, sur des connexions correctes, et les réécrire n'aurait
   rien apporté à qui en a besoin.

   BUDGET : ce fichier vise 20 Ko non compressé. Le mesurer fait partie des
   sondes (`deploy/verifier-budget-public.php`) — un budget qu'on ne mesure pas
   est un vœu.
   ============================================================================ */

/* ─────────────────────────────────────────────────────────── 1. TYPOGRAPHIE

   Auto-hébergées, en variable, sous-ensembles latin et latin étendu.

   🔑 `font-display: swap` : le texte s'affiche IMMÉDIATEMENT dans la police de
   repli, puis bascule. Sur un réseau lent, l'alternative — `block` — laisse
   trois secondes de page blanche à quelqu'un qui cherche où il va dormir.

   ⚠️ Les deux sous-ensembles sont déclarés séparément avec leur `unicode-range` :
   le français tient presque entièrement dans « latin », et « latin étendu »
   (187 Ko à lui seul) ne sera donc quasiment jamais téléchargé. Fusionner les
   deux fichiers doublerait le coût réel pour ne servir personne.                */

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../fonts/inter-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                   U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                   U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../fonts/inter-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                   U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                   U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'Fraunces';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../fonts/fraunces-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                   U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                   U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Fraunces';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../fonts/fraunces-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                   U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                   U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ─────────────────────────────────────────────────────────── 2. JETONS

   ⚠️ AUCUNE COULEUR HORS DE CETTE LISTE. Six tons, pas un de plus. Une couleur
   ajoutée « juste pour ce cas » est celle qu'on retrouve ensuite partout.

   Les valeurs sont en composantes HSL sans la fonction, pour pouvoir écrire
   `hsl(var(--lagune) / .12)` sans déclarer une seconde variable par opacité.   */

:root {
    /* ── La palette. Le vert est dominant : c'est le vert Lagune de la marque. */
    --lagune:        149.5 43.7% 26.5%;   /* #266143 — en-tête, aplats, actions principales, confirmations */
    --lagune-fonce:  149.5 45.0% 18.3%;   /* #1A442E — survols, pied de page                               */
    --kaolin:         48.0 21.7% 95.5%;   /* #F6F5F1 — fond principal                                     */
    --nuit:          214.0 51.7% 11.4%;   /* #0E1B2C — texte et titres                                    */

    /* ⚠️ LE CHÂSSIS DE LA MAQUETTE DE TÉLÉPHONE, EN JETONS. Ces gris bleutés ne sont
       pas de la charte : ils dessinent un objet, pas l'interface. Ils restent
       néanmoins des jetons, parce qu'une couleur écrite en dur dans une règle est
       une couleur que personne ne retrouve le jour où le dessin change. */
    --metal-clair:   210.0 18.0% 46.0%;   /* la tranche vue de face                                       */
    --metal:         210.0 22.0% 26.0%;   /* le haut du corps                                             */
    --metal-sombre:  210.0 20.0% 20.0%;   /* le bas du corps                                              */
    --metal-bouton:  210.0 18.0% 40.0%;   /* volume et veille                                             */
    --creux:           0.0  0.0%  0.0%;   /* l'ombre intérieure de la lunette                            */
    --or:             40.7 55.6% 50.6%;   /* #C79A3B — accent RARE : badge Vérifié, garantie, chiffres    */
    --laterite:       13.2 58.9% 41.0%;   /* #A6462B — accent chaud PARCIMONIEUX : alertes                */

    /* Neutres dérivés du Nuit — jamais des gris arbitraires. */
    --texte:         213 20% 32%;
    --texte-doux:    213 14% 45%;   /* clarté calée sur 4.5:1 — voir CHARTE_SITE.md */
    --ligne:         213 16% 88%;
    --blanc:           0  0% 100%;

    /* ── Typographie. Le repli est nommé : il s'affiche avant la police web. */
    --titre: 'Fraunces', Georgia, 'Times New Roman', serif;
    --corps: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

    /* Échelle fluide : une seule valeur par palier, pas de points de rupture
       à maintenir. Les bornes sont calées sur 360 px (Android d'entrée) et
       1280 px. */
    --t-xs:   0.8125rem;
    --t-sm:   0.875rem;
    --t-base: 1rem;
    --t-lg:   clamp(1.0625rem, 0.99rem + 0.32vw, 1.1875rem);
    --t-xl:   clamp(1.25rem,  1.14rem + 0.48vw, 1.5rem);
    --t-2xl:  clamp(1.5rem,   1.31rem + 0.83vw, 2rem);
    --t-3xl:  clamp(1.875rem, 1.52rem + 1.55vw, 2.75rem);
    --t-4xl:  clamp(2.25rem,  1.66rem + 2.6vw,  3.5rem);

    /* ── LE TITRE DE LA SECTION D'OUVERTURE A SON PROPRE PAS ──────────────────
       🔑 IL EST SORTI DE L'ÉCHELLE GÉNÉRALE, ET C'EST TOUT L'OBJET. Le plus
       grand pas de l'échelle des titres (`--t-4xl`) plafonne à 56 px : correct
       pour un titre de section, trop petit pour une ouverture — le titre
       paraissait perdu dans l'espace qui lui était donné. Réutiliser ce pas ici
       reviendrait à faire dépendre l'ouverture d'une décision prise pour autre
       chose.

       Deux rampes plutôt qu'une : les paliers demandés ne sont pas alignés, et
       une seule interpolation linéaire manquait la cible de l'ordinateur d'environ
       trois points. Chacune porte son plancher et son plafond explicites.

         360 px →  40 px      768 px →  60 px      1440 px → 86 px
         480 px →  48 px     1024 px →  72 px      1500 px → 88 px (plafond)   */
    --t-hero: clamp(2.5rem, 1.606rem + 4.518vw, 4.5rem);

    /* L'accroche suit la même montée : 18 px sur mobile, 24 px sur ordinateur. */
    --t-hero-accroche: clamp(1.125rem, 1.0rem + 0.55vw, 1.5rem);

    /* ── Espacement : une échelle de 4 px, nommée par usage et non par taille. */
    --e-1: 0.25rem;  --e-2: 0.5rem;   --e-3: 0.75rem;  --e-4: 1rem;
    --e-5: 1.5rem;   --e-6: 2rem;     --e-7: 3rem;     --e-8: 4rem;
    --e-9: 6rem;

    --rayon:       14px;
    --rayon-petit:  8px;
    --rayon-pilule: 999px;

    /* Ombres portées : deux niveaux, pas davantage. */
    --ombre:      0 1px 2px hsl(var(--nuit) / .04), 0 18px 40px -28px hsl(var(--nuit) / .45);
    --ombre-haut: 0 2px 6px hsl(var(--nuit) / .06), 0 28px 56px -30px hsl(var(--nuit) / .5);

    --largeur:  1180px;

    /* 🔑 LE LOGO FAIT 64 px, LE DOUBLE DE CE QU'IL FAISAIT, À TOUTES LES LARGEURS.
       Il valait 32 px fixes : sur un écran de portable, la marque était plus petite
       que le libellé du bouton d'à côté.

       ⚠️ La barre grandit avec lui, elle ne le contient pas de force. Sur mobile
       elle se contente de 8 px de respiration au-dessus et en dessous — c'est
       serré, mais c'est ce qui laisse le pli de 640 points intact. */
    --entete-h:      80px;   /* mobile  */
    --entete-logo-h: 64px;
}

/* La seconde rampe du titre d'ouverture : de 72 px à 88 px. */
@media (min-width: 1024px) {
    :root { --t-hero: clamp(4.5rem, 2.344rem + 3.365vw, 5.5rem); }
}

@media (min-width: 768px) {
    /* Le logo ne bouge plus : seule la respiration autour de lui augmente. */
    :root { --entete-h: 96px; }
}

/* ─────────────────────────────────────────────────────────── 3. RÉINITIALISATION

   Minimale et volontairement courte. Une réinitialisation complète coûte plus
   de poids qu'elle n'en économise sur un site qui maîtrise ses propres styles. */

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

/**
 * 🔴 `hidden` DOIT GAGNER SUR TOUT LE RESTE.
 *
 * `[hidden]` vaut `display: none` dans la feuille du navigateur — donc la MÊME
 * spécificité qu'une classe, et n'importe quel `.k-machin { display: flex }`
 * écrit plus bas l'écrase en silence. Le panneau du concierge, marqué `hidden`
 * dans le HTML, occupait ainsi la place et INTERCEPTAIT LES CLICS du bouton
 * censé l'ouvrir : le bouton était visible, cliquable en apparence, et mort.
 *
 * ⚠️ Trouvé au navigateur, pas à la sonde : les deux éléments existaient, avec
 * les bons attributs, et le HTML était juste. C'est la mise en page qui mentait.
 */
[hidden] { display: none !important; }

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    /* Le décalage sous l'en-tête collant, pour que les ancres ne passent pas dessous. */
    scroll-padding-top: calc(var(--entete-h) + var(--e-4));
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
    margin: 0;
    font-family: var(--corps);
    font-size: var(--t-base);
    line-height: 1.6;
    color: hsl(var(--texte));
    background: hsl(var(--kaolin));
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
    margin: 0 0 var(--e-3);
    /* 🔴 UN MOT PLUS LARGE QUE L'ÉCRAN DÉBORDE TOUTE LA PAGE. « Appartement Angré 8e
       — DÉMONSTRATION » sortait de 27 px sur un écran de 320 points : le titre était
       coupé et la page entière défilait latéralement. Un titre est du texte, il a le
       droit de se casser ; c'est la page qui n'a pas le droit de déborder.

       ⚠️ `anywhere` ET NON `break-word`. `break-word` autorise la coupure mais laisse
       la largeur MINIMALE du bloc inchangée : le titre restait large de 331 px dans un
       écran de 320, et la page débordait exactement comme avant. Seul `anywhere`
       compte les coupures dans la largeur minimale. */
    overflow-wrap: anywhere;
    font-family: var(--titre);
    font-weight: 600;
    line-height: 1.15;
    color: hsl(var(--nuit));
    /* `opsz` : Fraunces est optiquement plus fine en grand corps. Sans cet axe,
       les titres paraissent lourds et les sous-titres maigres. */
    font-variation-settings: 'SOFT' 0, 'WONK' 0, 'opsz' 48;
    text-wrap: balance;
}
h1 { font-size: var(--t-4xl); }
h2 { font-size: var(--t-3xl); }
h3 { font-size: var(--t-xl); }
h4 { font-size: var(--t-lg); }

p { margin: 0 0 var(--e-4); text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: hsl(var(--lagune)); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: hsl(var(--lagune-fonce)); }

img, svg, video { max-width: 100%; height: auto; display: block; }

ul, ol { margin: 0 0 var(--e-4); padding-left: var(--e-5); }

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

/* 🔑 ACCESSIBILITÉ : un focus visible, partout, sans exception. `:focus-visible`
   ne l'affiche qu'au clavier — la souris ne déclenche pas le contour. */
:focus-visible {
    outline: 3px solid hsl(var(--lagune) / .55);
    outline-offset: 2px;
    border-radius: var(--rayon-petit);
}

/* Lien d'évitement : premier élément focalisable de chaque page. */
.k-skip {
    position: absolute; left: var(--e-4); top: calc(var(--e-4) * -4);
    z-index: 100; padding: var(--e-3) var(--e-4);
    background: hsl(var(--lagune)); color: hsl(var(--blanc));
    border-radius: var(--rayon-petit); text-decoration: none;
    transition: top .15s;
}
.k-skip:focus { top: var(--e-4); color: hsl(var(--blanc)); }

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

/* ─────────────────────────────────────────────────────────── 4. MISE EN PAGE

   Une grille maison de douze colonnes en `grid`. Bootstrap pèse 190 Ko pour
   servir ici l'équivalent de quarante lignes.                                  */

.k-wrap {
    width: 100%;
    max-width: var(--largeur);
    margin-inline: auto;
    padding-inline: var(--e-4);
}
@media (min-width: 768px) { .k-wrap { padding-inline: var(--e-5); } }

.k-section { padding-block: var(--e-7); }
@media (min-width: 768px) { .k-section { padding-block: var(--e-8); } }
.k-section--serre  { padding-block: var(--e-6); }
.k-section--teinte { background: hsl(var(--lagune) / .05); }
.k-section--pleine { background: hsl(var(--lagune)); color: hsl(var(--blanc) / .92); }
.k-section--pleine h2, .k-section--pleine h3 { color: hsl(var(--blanc)); }

.k-grille { display: grid; gap: var(--e-4); }
@media (min-width: 640px)  { .k-grille--2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px)  { .k-grille--3 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 900px)  { .k-grille--4 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .k-grille--4 { grid-template-columns: repeat(4, 1fr); } }

/* Grille ASYMÉTRIQUE : cartes hautes à gauche, cartes courtes à droite. Elle
   n'existe qu'à partir du grand écran ; en dessous tout s'empile, ce qui est
   l'ordre de lecture voulu. */
.k-grille--asym { gap: var(--e-4); }
@media (min-width: 900px) {
    .k-grille--asym { grid-template-columns: 1.35fr 1fr; align-items: start; }
}

/* ─────────────────────────────────────────────────────────── 5. TITRAGE */

.k-oeil {
    display: inline-block;
    margin-bottom: var(--e-2);
    font-family: var(--corps);
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: hsl(var(--lagune));
}
.k-section--pleine .k-oeil { color: hsl(var(--or)); }

.k-titre-section { max-width: 48ch; margin-bottom: var(--e-6); }
.k-titre-section p { color: hsl(var(--texte-doux)); font-size: var(--t-lg); }

/* ─────────────────────────────────────────────────────────── 6. ACTIONS */

/* 🔑 QUATRE NIVEAUX, ET UN SEUL PRIMAIRE PAR SECTION. Le défaut n'était pas
   l'absence de boutons mais l'absence de HIÉRARCHIE : quand tout a le même poids,
   le regard ne sait pas où aller et la section ne convertit pas.

     --plein      PRIMAIRE   l'action de la section. Jamais deux côte à côte.
     --contour    SECONDAIRE à côté d'un primaire, jamais seul.
     --lien       TERTIAIRE  engagement faible.
     --garantie   ACCENT     vérification et garantie SEULEMENT, une fois par page.

   ⚠️ 52 px sur ordinateur, 56 px sur mobile : au doigt, la cible est plus grande
   qu'à la souris, et c'est sur mobile que se prend la décision. */
.k-btn {
    display: inline-flex; align-items: center; justify-content: center;
    gap: var(--e-2);
    min-height: 52px;
    min-width: 44px;                       /* 44×44 minimum, y compris en icône seule */
    padding: var(--e-3) var(--e-6);        /* rembourrage horizontal généreux */
    border: 1px solid transparent;
    border-radius: var(--rayon-pilule);
    font-family: var(--corps);
    font-size: var(--t-sm);
    font-weight: 600;
    line-height: 1.2;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition: background-color .15s, color .15s, border-color .15s;
}
.k-btn--plein { background: hsl(var(--lagune)); color: hsl(var(--kaolin)); font-weight: 700; }
.k-btn--plein:hover { background: hsl(var(--lagune-fonce)); color: hsl(var(--kaolin)); }

.k-btn--contour { border-color: hsl(var(--lagune) / .35); color: hsl(var(--lagune)); background: transparent; }
.k-btn--contour:hover { border-color: hsl(var(--lagune)); background: hsl(var(--lagune) / .06); }

.k-btn--clair { background: hsl(var(--blanc)); color: hsl(var(--lagune)); }
.k-btn--clair:hover { background: hsl(var(--kaolin)); color: hsl(var(--lagune-fonce)); }

/* TERTIAIRE. Pas de cadre : le souligné n'apparaît qu'au survol, sinon il se
   confond avec un secondaire et l'on retombe à trois niveaux indistincts. */
.k-btn--lien {
    min-height: 44px; padding-inline: var(--e-2);
    background: transparent; border-color: transparent;
    color: hsl(var(--lagune)); font-weight: 600;
}
.k-btn--lien:hover { text-decoration: underline; color: hsl(var(--lagune-fonce)); }

/* ACCENT GARANTIE. ⚠️ RÉSERVÉ à la vérification et à la garantie, au maximum une
   fois par page. L'Or est le signal de la promesse ; l'employer pour une action
   ordinaire le vide de son sens, et il n'y a plus de signal du tout. */
.k-btn--garantie { background: hsl(var(--or)); color: hsl(var(--nuit)); font-weight: 700; }
.k-btn--garantie:hover { background: hsl(var(--or) / .85); color: hsl(var(--nuit)); }

.k-btn--large { width: 100%; }
.k-btn[disabled], .k-btn[aria-disabled="true"] { opacity: .55; pointer-events: none; }

/* 🔑 FOCUS VISIBLE AU CLAVIER. `:focus-visible` et non `:focus` : le second
   dessinerait un anneau après chaque clic à la souris, ce que les intégrateurs
   finissent par supprimer — et le clavier perd son repère avec. */
.k-btn:focus-visible {
    outline: 2px solid hsl(var(--lagune));
    outline-offset: 3px;
}
.k-btn--garantie:focus-visible { outline-color: hsl(var(--nuit)); }

/* CHARGEMENT DANS LE BOUTON, pas à côté. Un indicateur posé ailleurs oblige à
   chercher où en est l'action qu'on vient de déclencher. Le libellé RESTE lisible :
   le remplacer par « Chargement… » efface ce qu'on était en train de faire. */
.k-btn[data-chargement="1"] { pointer-events: none; opacity: .8; }
.k-btn[data-chargement="1"]::before {
    content: ''; width: 1em; height: 1em; flex: none;
    border: 2px solid currentColor; border-right-color: transparent;
    border-radius: 50%;
    animation: k-tourne .7s linear infinite;
}
@keyframes k-tourne { to { transform: rotate(360deg); } }
/* ⚠️ Respecte le réglage système : une rotation permanente déclenche des malaises
   chez qui a demandé moins d'animation. */
@media (prefers-reduced-motion: reduce) {
    .k-btn[data-chargement="1"]::before { animation: none; opacity: .6; }
}

@media (max-width: 767px) {
    .k-btn { min-height: 56px; }
    .k-btn--lien { min-height: 44px; }
}

/* ── Barre d'action fixe, mobile, pages de conversion ────────────────────

   🔑 ELLE APPARAÎT AU DÉFILEMENT, PAS AU CHARGEMENT. Posée d'emblée, elle
   masquerait le contenu avant qu'on ait lu de quoi il s'agit — on demande d'agir
   avant d'avoir dit quoi. Elle sort une fois le premier écran passé.

   ⚠️ Elle n'existe QUE sous 768 px. Sur ordinateur, l'action de la section est
   déjà visible et une barre fixe ne ferait que voler de la hauteur. */
.k-action-mobile { display: none; }

@media (max-width: 767px) {
    .k-action-mobile {
        display: block;
        position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
        padding: var(--e-3) var(--e-4);
        /* `env(safe-area-inset-bottom)` : sans lui, la barre passe sous le trait
           de navigation des iPhone récents et devient à moitié intouchable. */
        padding-bottom: calc(var(--e-3) + env(safe-area-inset-bottom, 0px));
        background: hsl(var(--blanc) / .97);
        backdrop-filter: blur(8px);
        border-top: 1px solid hsl(var(--ligne));
        transform: translateY(110%);
        transition: transform .18s ease-out;
    }
    .k-action-mobile.est-visible { transform: none; }
    @media (prefers-reduced-motion: reduce) {
        .k-action-mobile { transition: none; }
    }
    /* La barre recouvre le bas de page : on rend la hauteur au document, sinon
       le dernier lien du pied de page reste inatteignable. */
    body:has(.k-action-mobile) { padding-bottom: 88px; }
}

/* ⚠️ LA BARRE PASSE À DEUX LIGNES PLUTÔT QUE D'ÉCRASER SON TEXTE. Sans base
   minimale, « 33 440 F CFA / nuit, taxes comprises » se réduisait à une colonne de
   cinquante pixels pendant que le bouton gardait sa largeur : le prix devenait
   illisible juste à côté du bouton qui le facture. */
.k-action-mobile__inner { display: flex; align-items: center; gap: var(--e-3); flex-wrap: wrap; }
.k-action-mobile__quoi { flex: 1 1 9rem; min-width: 0; line-height: 1.2; }
.k-action-mobile__quoi strong { display: block; font-size: var(--t-sm); }
.k-action-mobile__quoi span { font-size: var(--t-xs); color: hsl(var(--texte-doux)); }

/* ─────────────────────────────────────────────────────────── 7. SURFACES */

.k-carte {
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon);
    padding: var(--e-5);
    box-shadow: var(--ombre);
}
.k-carte--plate { box-shadow: none; }

/* ─────────────────────────────────────────────────────────── 8. BADGES

   🔑 L'OR EST RÉSERVÉ À LA PREUVE. Le badge Vérifié, la garantie, les chiffres
   clés — rien d'autre. C'est ce qui lui garde son sens : une couleur d'accent
   employée partout n'accentue plus rien.                                       */

.k-badge {
    display: inline-flex; align-items: center; gap: var(--e-1);
    padding: 2px var(--e-2);
    border-radius: var(--rayon-pilule);
    font-size: var(--t-xs); font-weight: 600; line-height: 1.5;
    white-space: nowrap;
}
.k-badge--verifie  { background: hsl(var(--or) / .14);      color: hsl(38 62% 34%); }
/* ⚠️ NEUTRE, PAS ALARMANTE. « Pas encore visité » est un FAIT, pas un avertissement :
   en rouge, elle ferait fuir d'une offre que Kuaba assume de proposer et couvre par sa
   garantie. En gris sourd, elle se lit sans crier — et elle se distingue au premier
   coup d'œil du doré du badge, ce qui est tout ce qu'on lui demande. */
.k-badge--attente  { background: hsl(var(--nuit) / .07);    color: hsl(var(--texte-doux)); }
.k-badge--declare  { background: hsl(var(--texte) / .07);   color: hsl(var(--texte-doux)); }
.k-badge--neutre   { background: hsl(var(--lagune) / .1);   color: hsl(var(--lagune-fonce)); }
.k-badge--alerte   { background: hsl(var(--laterite) / .12);color: hsl(var(--laterite)); }

/* ─────────────────────────────────────────────────────────── 9. ÉTAT VIDE

   ⚠️ Un état vide n'est pas une erreur : c'est une page qui dit la vérité. Il
   est soigné parce qu'on le verra longtemps — la place de marché n'a qu'un seul
   logement au moment où ces lignes sont écrites.                               */

.k-vide {
    padding: var(--e-7) var(--e-5);
    text-align: center;
    border: 1px dashed hsl(var(--ligne));
    border-radius: var(--rayon);
    background: hsl(var(--blanc) / .6);
}
.k-vide h3 { margin-bottom: var(--e-2); }
.k-vide p  { max-width: 46ch; margin-inline: auto; color: hsl(var(--texte-doux)); }

/* ────────────────────────────────────────────────────────── 10. UTILITAIRES

   Le strict nécessaire. Une bibliothèque d'utilitaires complète pèse plus que
   les styles qu'elle remplace.                                                 */

.k-flex   { display: flex; gap: var(--e-3); }

/* 🔴 DEUX CHAMPS CÔTE À CÔTE DÉBORDAIENT L'ÉCRAN À 390 POINTS. Un enfant de flex a
   `min-width: auto` : il refuse de descendre sous la largeur intrinsèque de son
   contenu, et un `<input type=number>` en réclame environ 180. Deux d'entre eux plus
   l'espacement font 565 points dans un cadre de 390 — le relevé de terrain, l'écran
   d'un agent debout devant un portail, défilait latéralement.
   🔑 La règle se pose sur l'utilitaire, pas sur la rangée qui a été vue déborder :
   toutes les autres rangées de champs ont le même défaut, elles ne l'avaient pas
   encore montré. */
.k-flex > * { min-width: 0; }
.k-flex--centre { align-items: center; }

/* Sous 40 rem : une rangee .k-flex qui ne peut pas retrecir ses enfants (un input
   enveloppe dans un groupe etiquette garde sa largeur intrinseque) et un .k-badge en
   nowrap (une alerte-phrase « sans code — ne peut pas se connecter ») debordaient le
   telephone. On empile et on plie. */
@media (max-width: 40rem) {
  .k-flex  { flex-wrap: wrap; }
  .k-badge { white-space: normal; }
}
.k-flex--entre  { justify-content: space-between; }
.k-flex--wrap   { flex-wrap: wrap; }
.k-centre { text-align: center; }
.k-doux   { color: hsl(var(--texte-doux)); }
.k-petit  { font-size: var(--t-sm); }
.k-xs     { font-size: var(--t-xs); }
.k-gras   { font-weight: 600; }
.k-mt-4   { margin-top: var(--e-4); }
.k-mt-5   { margin-top: var(--e-5); }
.k-mb-0   { margin-bottom: 0; }
.k-liste-nue { list-style: none; padding: 0; margin: 0; }

/* ────────────────────────────────────────────────────────── 11. EN-TÊTE

   Collant, compact au défilement. `position: sticky` plutôt que `fixed` : il ne
   se superpose pas au contenu au chargement, donc pas de décalage de mise en
   page à corriger ensuite.                                                     */

.k-entete {
    position: sticky; top: 0; z-index: 50;
    background: hsl(var(--blanc) / .92);
    backdrop-filter: blur(8px);
    border-bottom: 1px solid transparent;
    transition: border-color .2s, box-shadow .2s;
}
.k-entete--compact { border-bottom-color: hsl(var(--ligne)); box-shadow: 0 1px 12px hsl(var(--nuit) / .05); }

.k-entete__barre {
    display: flex; align-items: center; gap: var(--e-5);
    min-height: var(--entete-h);
}
/* ⚠️ ZONE CLIQUABLE D'AU MOINS 44 px : le logo est le lien vers l'accueil, et
   c'est la cible la plus visée d'une barre. Le plancher reste écrit même si le
   logo le dépasse aujourd'hui — c'est la règle qui protège, pas la valeur. */
.k-entete__logo {
    flex: none;
    display: flex;
    align-items: center;
    min-height: 44px;
}
.k-entete__logo img,
.k-entete__logo svg {
    height: var(--entete-logo-h);
    width: auto;
}

/* 🔑 À L'ÉTAT RÉDUIT, LA BARRE SE CONTRACTE ET LE LOGO NE BOUGE PAS. Il rapetissait
   de six pixels au défilement — la marque maigrissait au moment précis où l'on
   parcourt la page. La barre seule se resserre. */
.k-entete--compact .k-entete__barre { min-height: 76px; }

.k-entete__nav { display: none; flex: 1; }
/* ⚠️ L'ESPACEMENT DES LIENS AUGMENTE AVEC LE LOGO, il ne le compense pas. Un logo
   agrandi rend la navigation serrée ; la réponse est d'aérer les liens, jamais de
   rapetisser le logo — c'est lui qui porte la marque. */
.k-entete__liens { display: flex; align-items: center; gap: var(--e-5); }
@media (min-width: 1100px) { .k-entete__liens { gap: var(--e-6); } }
/* ⚠️ Et la barre elle-même s'aère là où il y a la place. À 992 px, un logo de
   160 px de large ne laisse que 24 px entre « Ressources » et « Se connecter » :
   les deux groupes se lisent comme un seul. En dessous de 1100 px la place manque
   pour davantage — c'est la navigation qui se serre, jamais le logo. */
@media (min-width: 1100px) { .k-entete__barre { gap: var(--e-6); } }
.k-entete__liens > li > a,
.k-menu > summary {
    display: inline-flex; align-items: center; gap: var(--e-1);
    /* ⚠️ UN LIBELLÉ DE NAVIGATION NE SE COUPE PAS. « Comment ça marche » passé sur
       deux lignes désaligne toute la barre et se lit comme deux entrées. S'il n'y a
       plus la place, c'est le menu qui prend le relais — pas le mot qui se plie. */
    white-space: nowrap;
    padding: var(--e-2) 0;
    font-size: var(--t-sm); font-weight: 500;
    color: hsl(var(--nuit)); text-decoration: none;
    cursor: pointer;
}
.k-entete__liens > li > a:hover, .k-menu > summary:hover { color: hsl(var(--lagune)); }
/* La page courante est signalée par un trait, pas seulement par une couleur :
   une différence de teinte seule n'est pas perceptible par tout le monde. */
.k-entete__liens > li > a[aria-current="page"] {
    color: hsl(var(--lagune));
    box-shadow: inset 0 -2px 0 hsl(var(--lagune));
}

.k-entete__actions { display: none; align-items: center; gap: var(--e-4); margin-left: auto; }
/* ⚠️ « Se connecter » et le bouton principal ne se coupent pas non plus. Sur les
   pages au titre long, « Se / connecter » passait sur deux lignes et déséquilibrait
   toute la barre — le même défaut que les libellés de navigation, à l'autre bout. */
.k-entete__secondaire { font-size: var(--t-sm); font-weight: 500; color: hsl(var(--nuit)); text-decoration: none; white-space: nowrap; }
.k-entete__actions .k-btn { white-space: nowrap; }
.k-entete__secondaire:hover { color: hsl(var(--lagune)); }

/* 🔴 LE SEUIL DU MENU SUIT LE LOGO. Il valait 992 px quand le logo faisait 105 px
   de large. À 160 px, la navigation complète demande 1 035 px : à 992 elle sortait
   de la page, et lui interdire de se couper a rendu ce débordement visible au lieu
   de le cacher sous un libellé plié en deux. C'est la navigation qui passe dans le
   menu, jamais le logo qui rétrécit.

   ⚠️ 1 024 px, et c'est la BARRE qui a décidé, pas l'inverse. À cinq entrées elle
   réclamait 1 180 px — soit toute la largeur de contenu — et disparaissait donc
   derrière un menu burger sur un portable de 1 100 ou 1 152 px, c'est-à-dire chez
   une bonne part des visiteurs. À quatre entrées, mesurée dans le navigateur :
   logo 160 + écart 32 + liens 386 + écart 32 + actions 317 + marges 48 = 975 px.
   1 024 laisse 49 px et rend la barre complète aux petits portables et à la
   tablette en paysage.

   ⚠️ Toucher aux libellés sans refaire cette mesure remettrait le débordement :
   c'est la somme ci-dessus qui justifie le nombre, pas une valeur ronde. */
@media (min-width: 1024px) {
    .k-entete__nav, .k-entete__actions { display: flex; }
    .k-burger { display: none; }
}

/* Menu déroulant : `<details>` natif, donc ouvrable sans JavaScript. */
.k-menu { position: relative; }
.k-menu > summary { list-style: none; }
.k-menu > summary::-webkit-details-marker { display: none; }
.k-menu__fleche {
    width: 0; height: 0; margin-top: 2px;
    border: 4px solid transparent; border-top-color: currentColor;
    transition: transform .15s;
}
.k-menu[open] .k-menu__fleche { transform: rotate(180deg); margin-top: -4px; }
.k-menu__panneau {
    position: absolute; top: calc(100% + var(--e-2)); left: calc(var(--e-4) * -1);
    min-width: 232px; padding: var(--e-2);
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon);
    box-shadow: var(--ombre-haut);
}
.k-menu__panneau a {
    display: block; padding: var(--e-2) var(--e-3);
    border-radius: var(--rayon-petit);
    font-size: var(--t-sm); color: hsl(var(--nuit)); text-decoration: none;
}
.k-menu__panneau a:hover { background: hsl(var(--lagune) / .07); color: hsl(var(--lagune)); }

/* Menu mobile */
.k-burger { margin-left: auto; }
.k-burger > summary { list-style: none; cursor: pointer; padding: var(--e-2); }
.k-burger > summary::-webkit-details-marker { display: none; }
.k-burger__traits { display: block; width: 22px; }
.k-burger__traits i {
    display: block; height: 2px; margin: 4px 0;
    background: hsl(var(--nuit)); border-radius: 2px;
}
.k-burger__panneau {
    position: absolute; left: 0; right: 0; top: var(--entete-h);
    padding: var(--e-5) var(--e-4) var(--e-6);
    background: hsl(var(--blanc));
    border-bottom: 1px solid hsl(var(--ligne));
    box-shadow: var(--ombre);
    /* ⚠️ Onze liens et un bouton dépassent un écran de 640 points : sans ceci, le
       bas du tiroir n'est atteignable par AUCUN geste — la page derrière défile,
       le tiroir non. */
    max-height: calc(100dvh - var(--entete-h));
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* 🔴 LE BANDEAU COOKIES RECOUVRAIT LES DEUX ACTIONS DU TIROIR. Il est en
   `z-index: 60`, l'en-tête en 50 : « Se connecter » et « Mettre mon logement »
   — le bas de la liste, donc ce qui compte — disparaissaient derrière lui sur
   téléphone. L'en-tête ouvrant un contexte d'empilement, aucun z-index posé sur
   le tiroir lui-même ne pouvait en sortir : c'est l'EN-TÊTE qu'il faut lever.

   ⚠️ On ne masque pas le bandeau, on le passe dessous le temps du menu : il
   revient dès la fermeture, et le consentement reste demandé. */
.k-entete:has(.k-burger[open]) { z-index: 70; }
.k-burger__panneau a {
    display: block; padding: var(--e-3) 0;
    border-bottom: 1px solid hsl(var(--ligne));
    color: hsl(var(--nuit)); text-decoration: none; font-weight: 500;
}
.k-burger__panneau .k-btn { border-bottom: 0; color: hsl(var(--blanc)); }

/* ⚠️ UN INTITULÉ, PAS UN LIEN. Il ne se clique pas et ne doit pas en avoir l'air :
   plus petit, en capitales espacées, en gris. La marge haute est ce qui fait la
   séparation — sans elle, il se lirait comme la première entrée du bloc. */
.k-burger__intitule {
    margin: var(--e-5) 0 0;
    padding-top: var(--e-3);
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: hsl(var(--texte) / .55);
}

/* ────────────────────────────────────────────────────────── 12. PIED DE PAGE */

.k-pied {
    background: hsl(var(--lagune-fonce));
    color: hsl(var(--blanc) / .78);
    padding-block: var(--e-7) var(--e-5);
    margin-top: var(--e-8);
}
.k-pied a { color: hsl(var(--blanc) / .78); text-decoration: none; }
.k-pied a:hover { color: hsl(var(--blanc)); text-decoration: underline; }

/* 🔑 DEUX COLONNES DÈS LE TÉLÉPHONE. Empilées une par une, les quatre listes
   faisaient 624 px à elles seules et le pied entier 1 320 — deux écrans de tunnel
   après chaque page. Les intitulés sont courts : deux colonnes tiennent largement
   dans 358 px utiles, et ramènent ces 624 px à 388.

   ⚠️ Pas d'accordéon. Il aurait mieux compacté, mais il met chaque lien derrière
   un geste de plus — et sur `<details>`, garder la version bureau dépliée sans
   JavaScript repose sur un contournement que les navigateurs récents referment.
   Une grille ne demande ni mécanisme ni exception. */
.k-pied__haut { display: grid; gap: var(--e-6) var(--e-5); grid-template-columns: repeat(2, 1fr); }

/* ⚠️ Le bloc de marque porte le logo, la phrase et deux pastilles d'application :
   sur deux colonnes il serait illisible. Il prend toute la largeur tant que la
   grille n'a pas sa forme bureau. */
.k-pied__marque { grid-column: 1 / -1; }

@media (min-width: 992px) {
    .k-pied__haut { grid-template-columns: 1.4fr repeat(4, 1fr); gap: var(--e-5); }
    .k-pied__marque { grid-column: auto; }
}

.k-pied__marque img { filter: brightness(0) invert(1); opacity: .92; height: 30px; width: auto; }
.k-pied__wa {
    display: inline-block; margin-top: var(--e-4);
    font-weight: 600; color: hsl(var(--blanc)) !important;
}
.k-pied__titre {
    font-family: var(--corps); font-size: var(--t-xs); font-weight: 600;
    letter-spacing: .08em; text-transform: uppercase;
    color: hsl(var(--or)); margin-bottom: var(--e-3);
}
.k-pied__col li { margin-bottom: var(--e-2); font-size: var(--t-sm); }

.k-pied__bas {
    display: flex; flex-wrap: wrap; gap: var(--e-3) var(--e-5);
    align-items: center; justify-content: space-between;
    margin-top: var(--e-7); padding-top: var(--e-4);
    border-top: 1px solid hsl(var(--blanc) / .14);
}
.k-pied__legal { display: flex; flex-wrap: wrap; gap: var(--e-4); font-size: var(--t-xs); }

/* 🔴 LE BANDEAU COOKIES RECOUVRAIT LA LIGNE LÉGALE. Mesuré : 61 px du bloc
   `.k-pied__bas` passaient dessous sur 1 280 px — c'est-à-dire les liens
   « Mentions légales », « Confidentialité » et « Cookies » eux-mêmes. Un avis de
   consentement qui cache les mentions légales est précisément ce qu'il ne doit
   pas faire.

   🔑 ON RÉSERVE LA PLACE PLUTÔT QUE DE DÉPLACER LE BANDEAU. `remove()` le retire
   du DOM au clic sur « J'ai compris » : la réserve disparaît avec lui, sans une
   ligne de script de plus. Et il n'est même pas rendu quand le choix est déjà
   fait.

   ⚠️ Les deux valeurs sont MESURÉES, pas arrondies au hasard : le bandeau fait
   85 px sur bureau et 172 px sur téléphone (deux lignes de texte). Changer sa
   formulation change sa hauteur — la sonde vérifie qu'il reste de la marge. */
body:has(.k-cookies) .k-pied { padding-bottom: 200px; }
@media (min-width: 768px) {
    body:has(.k-cookies) .k-pied { padding-bottom: 110px; }
}
.k-pied__sep { opacity: .5; margin-inline: var(--e-1); }

/* ────────────────────────────────────────────────────────── 13. COOKIES */

.k-cookies {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
    background: hsl(var(--blanc));
    border-top: 1px solid hsl(var(--ligne));
    box-shadow: 0 -8px 30px -20px hsl(var(--nuit) / .4);
    padding-block: var(--e-4);
}
.k-cookies__inner {
    display: flex; flex-wrap: wrap; gap: var(--e-4);
    align-items: center; justify-content: space-between;
}
.k-cookies p { max-width: 62ch; }

/* ────────────────────────────────────────────────────────── 14. CONTACT

   WhatsApp d'abord : c'est le canal réel de ces utilisateurs, pas une option.
   Le formulaire vient après, et le courriel en repli.                          */

.k-contact { display: grid; gap: var(--e-6); align-items: start; }
@media (min-width: 900px) { .k-contact { grid-template-columns: 1fr 1fr; gap: var(--e-7); } }

.k-wa {
    padding: var(--e-6);
    background: hsl(var(--lagune));
    color: hsl(var(--blanc) / .92);
    border-radius: var(--rayon);
}
.k-wa h2 { color: hsl(var(--blanc)); margin-bottom: var(--e-2); }
.k-wa__numero {
    display: block; margin-block: var(--e-4) var(--e-2);
    font-family: var(--corps); font-size: var(--t-2xl); font-weight: 700;
    color: hsl(var(--blanc)); text-decoration: none;
    letter-spacing: .01em;
}
.k-wa__numero:hover { color: hsl(var(--or)); }
.k-wa__delai {
    display: inline-flex; align-items: center; gap: var(--e-2);
    font-size: var(--t-sm); color: hsl(var(--or));
}
.k-wa__delai::before {
    content: ''; width: 8px; height: 8px; border-radius: 50%;
    background: hsl(var(--or));
}

/* Fil de conversation SIMULÉ. ⚠️ Il est explicitement présenté comme un exemple
   dans le texte : une capture qui se ferait passer pour un échange réel serait
   de la preuve sociale fabriquée. */
.k-fil { margin-top: var(--e-5); display: grid; gap: var(--e-2); }
.k-fil__bulle {
    max-width: 84%; padding: var(--e-3) var(--e-4);
    border-radius: var(--rayon);
    font-size: var(--t-sm); line-height: 1.5;
}
.k-fil__bulle--eux {
    background: hsl(var(--blanc) / .14); color: hsl(var(--blanc));
    border-bottom-left-radius: var(--rayon-petit);
}
.k-fil__bulle--nous {
    background: hsl(var(--blanc)); color: hsl(var(--nuit));
    margin-left: auto; border-bottom-right-radius: var(--rayon-petit);
}
.k-fil__note { font-size: var(--t-xs); color: hsl(var(--blanc) / .6); margin-top: var(--e-2); }

/* ────────────────────────────────────────────────────────── 15. FORMULAIRES */

.k-champ { margin-bottom: var(--e-4); }
.k-champ > label {
    display: block; margin-bottom: var(--e-2);
    font-size: var(--t-sm); font-weight: 600; color: hsl(var(--nuit));
}
.k-champ__aide { display: block; font-weight: 400; color: hsl(var(--texte-doux)); font-size: var(--t-xs); }
.k-input, .k-select, .k-textarea {
    width: 100%;
    min-height: 46px;
    padding: var(--e-3) var(--e-4);
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon-petit);
    font-size: var(--t-base);
    color: hsl(var(--nuit));
}
.k-textarea { min-height: 128px; resize: vertical; }
.k-input:hover, .k-select:hover, .k-textarea:hover { border-color: hsl(var(--lagune) / .5); }
/* L'erreur est signalée par la couleur ET par un texte : la couleur seule
   n'informe pas qui ne la distingue pas. */
.k-input[aria-invalid="true"], .k-textarea[aria-invalid="true"], .k-select[aria-invalid="true"] {
    border-color: hsl(var(--laterite));
    background: hsl(var(--laterite) / .04);
}
.k-erreur {
    display: block; margin-top: var(--e-2);
    font-size: var(--t-sm); color: hsl(var(--laterite));
}
.k-succes {
    padding: var(--e-4);
    border-left: 3px solid hsl(var(--lagune));
    background: hsl(var(--lagune) / .07);
    border-radius: var(--rayon-petit);
    color: hsl(var(--lagune-fonce));
}

/* ────────────────────────────────────────────────────────── 16. RECHERCHE

   Elle s'empile sur mobile et s'aligne à partir de la tablette. Les champs sont
   des éléments NATIFS : le sélecteur de dates du navigateur est celui que la
   personne connaît, il est accessible au clavier, et il ne coûte pas un octet.  */

.k-recherche {
    display: grid; gap: var(--e-3);
    padding: var(--e-4);
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon);
    box-shadow: var(--ombre);
}
@media (min-width: 860px) {
    .k-recherche {
        grid-template-columns: 1.5fr 1fr 1fr .9fr auto;
        align-items: end;
        gap: var(--e-4);
        padding: var(--e-4) var(--e-5);
        border-radius: var(--rayon-pilule);
    }
}
.k-recherche__champ { display: grid; gap: var(--e-1); min-width: 0; }
.k-recherche__champ > label {
    font-size: var(--t-xs); font-weight: 600;
    letter-spacing: .04em; text-transform: uppercase;
    color: hsl(var(--texte-doux));
}
.k-recherche__saisie {
    width: 100%; min-height: 44px;
    padding: var(--e-2) var(--e-3);
    background: transparent;
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon-petit);
    font-size: var(--t-base); color: hsl(var(--nuit));
}
@media (min-width: 860px) {
    /* Sur une ligne, les séparateurs remplacent les bordures : moins de bruit
       visuel pour la même lisibilité. */
    .k-recherche__saisie { border: 0; padding-inline: 0; }
    .k-recherche__champ + .k-recherche__champ { padding-left: var(--e-4); border-left: 1px solid hsl(var(--ligne)); }
}
.k-recherche__action { white-space: nowrap; }
@media (max-width: 859px) {
    .k-recherche__action { width: 100%; }
}
/* ⚠️ À PARTIR DE 360 px SEULEMENT. Sous cette largeur, deux colonnes donnaient
   des colonnes de 146 px : `input[type=date]` a une largeur minimale intrinsèque
   supérieure et DÉBORDAIT la page de douze pixels — un défilement horizontal sur
   toute la page pour gagner une ligne. En dessous, les champs restent empilés. */
@media (min-width: 360px) and (max-width: 859px) {
    /* 🔑 ARRIVÉE ET DÉPART SE PARTAGENT UNE LIGNE. Empilés, les quatre champs et
       le bouton faisaient 416 px : le bouton « Rechercher » tombait sous la ligne
       de flottaison d'un écran de 640 points. Deux dates côte à côte tiennent
       largement dans 360 px — ce sont les champs les plus étroits du formulaire. */
    .k-recherche { grid-template-columns: 1fr 1fr; gap: var(--e-2); padding: var(--e-2) var(--e-3); }
    .k-recherche > * { grid-column: 1 / -1; }
    .k-recherche__champ--date { grid-column: auto; }
}

/* Variante « barre persistante » : plus compacte, collée sous l'en-tête. */
.k-recherche--barre { box-shadow: none; }
.k-barre-collante {
    position: sticky; top: var(--entete-h); z-index: 40;
    padding-block: var(--e-3);
    background: hsl(var(--kaolin) / .96);
    backdrop-filter: blur(8px);
    border-bottom: 1px solid hsl(var(--ligne));
}

/* ────────────────────────────────────────────────────────── 17. OUVERTURE */

/* 🔑 UN GRAND TITRE A BESOIN DE VIDE AUTOUR DE LUI. Serré dans une section basse,
   il paraît plus petit qu'un titre moyen bien aéré : la taille seule ne suffit pas.
   ⚠️ Aucune hauteur MAXIMALE n'est posée : elle couperait le contenu au lieu de le
   contenir. La contrainte « ne pas dépasser la fenêtre » est tenue par la marge et
   la longueur du texte, pas par un rognage. */
.k-hero {
    padding-top: var(--e-7);
    padding-bottom: var(--e-6);
    background:
        radial-gradient(900px 420px at 82% -8%, hsl(var(--lagune) / .10), transparent 62%),
        hsl(var(--kaolin));
}
@media (min-width: 1024px) {
    .k-hero {
        min-height: 70vh;
        display: flex;
        flex-direction: column;
        justify-content: center;
        padding-top: var(--e-8);
        padding-bottom: var(--e-8);
    }
}
/* L'en-tête du hero prend toute la largeur : c'est ce qui laisse au titre la place
   de tenir sa taille sans se couper là où on ne l'a pas décidé. */
.k-hero__entete { margin-bottom: var(--e-5); }
@media (min-width: 1024px) { .k-hero__entete { margin-bottom: var(--e-6); } }

.k-hero__grille { display: grid; gap: var(--e-6); align-items: center; }

/* 🔴 SUR MOBILE, LE CHAMP DE RECHERCHE ÉTAIT SOUS LA MAQUETTE DE TÉLÉPHONE — donc
   à deux écrans du titre. Quelqu'un qui arrive cherche un logement pour des dates :
   lui faire faire défiler un visuel de sept cents pixels avant de pouvoir taper,
   c'est perdre ceux dont la connexion hésite.

   `display: contents` fait disparaître la grille en tant que boîte : ses deux
   enfants deviennent frères de la recherche dans la colonne, et `order` décide.
   ⚠️ Une boîte en `display: contents` perd son `gap` : c'est la colonne qui le
   porte. */
@media (max-width: 991.98px) {
    /* ⚠️ CES TROIS VALEURS SONT CE QUI PAIE LE LOGO DE 64 px. La barre a pris seize
       pixels ; ils sont repris ici, dans le blanc, pas dans le titre. */
    .k-hero            { padding-top: var(--e-3); }
    .k-hero > .k-wrap  { display: flex; flex-direction: column; gap: var(--e-3); }
    .k-hero__entete    { order: 1; margin-bottom: 0; }
    .k-hero__grille,
    .k-hero__texte     { display: contents; }
    .k-hero__accroches { order: 2; }
    /* ⚠️ L'espacement vient du `gap` du conteneur : la marge propre du champ
       s'ajouterait par-dessus et rendrait l'écart deux fois trop grand. */
    .k-hero__recherche { order: 3; margin-top: 0; }
    .k-hero__apres     { order: 4; }
    .k-hero__visuel    { order: 5; }
}
@media (min-width: 992px) {
    /* 🔴 `align-items: center` CENTRAIT L'ACCROCHE CONTRE LE VISUEL. Le titre étant
       remonté en pleine largeur, la colonne de gauche ne contient plus que
       l'accroche et les actions : centrée face à une maquette de téléphone haute
       de 700 px, elle se retrouvait à trois cents pixels du titre, séparée par du
       vide. Elle doit commencer là où le titre finit. */
    .k-hero__grille { grid-template-columns: 1.08fr 1fr; gap: var(--e-7); align-items: start; }
}

/* ── LE TITRE D'OUVERTURE ────────────────────────────────────────────────────
   ⚠️ INTERLIGNAGE SERRÉ. Un titre de 86 px avec l'interlignage d'un paragraphe
   paraît mou : les lignes flottent au lieu de faire bloc.
   ⚠️ APPROCHE RESSERRÉE AUX GRANDES TAILLES seulement — appliquée sur mobile, elle
   collerait les lettres.
   ⚠️ LARGEUR LIMITÉE : environ quatorze mots par ligne au maximum, pour obtenir
   deux ou trois lignes plutôt qu'une seule très longue.
   ⚠️ JAMAIS CENTRÉ : l'œil doit retrouver le même bord gauche du surtitre à
   l'accroche. */
.k-hero__titre {
    font-size: var(--t-hero);
    line-height: 1.04;
    font-weight: 800;
    letter-spacing: -0.015em;
    text-align: left;
    text-wrap: balance;          /* aucune veuve : jamais un mot seul en dernière ligne */
    margin-bottom: 0;

    /* ⚠️ ENVIRON QUATORZE MOTS PAR LIGNE AU MAXIMUM. C'est un plafond, pas une
       consigne de coupure : les retours voulus sont dans le contenu, cette largeur
       n'est là que pour empêcher une ligne interminable si quelqu'un écrit un titre
       sans barre verticale. */
    max-width: 28ch;
}
@media (min-width: 768px)  { .k-hero__titre { letter-spacing: -0.02em;  max-width: 34ch; } }
@media (min-width: 1024px) { .k-hero__titre { letter-spacing: -0.025em; max-width: 100%; } }

.k-hero__accent { color: hsl(var(--lagune)); }

/* 🔑 LE RETOUR À LA LIGNE EST DÉCIDÉ DANS LE CONTENU, PAS PAR LE NAVIGATEUR — et
   seulement à partir de la tablette. En dessous, la place manque et un retour
   imposé laisserait des lignes d'un seul mot ; le texte se répartit librement.
   Un `<br>` en `display: none` ne provoque aucune coupure : c'est exactement ce
   qu'on veut sous le seuil. */
.k-br { display: none; }
/* 🔑 LA COUPURE NE VAUT QUE LÀ OÙ LE TITRE EST EN COLONNE. Entre 768 et 991 px, la
   section d'ouverture est encore une seule colonne large : y appliquer une coupure
   pensée pour une colonne de 560 px donnerait trois lignes courtes perdues dans du
   blanc. Au-delà de 992 px, le titre partage la largeur avec le visuel et la coupure
   devient ce qui l'empêche de se couper n'importe où. */
@media (min-width: 992px) { .k-br { display: inline; } }

.k-hero__accroche {
    max-width: 60ch;
    font-size: var(--t-hero-accroche);
    line-height: 1.5;
    color: hsl(var(--texte));
}

/* 🔑 SUR PETIT ÉCRAN, C'EST L'ACCROCHE QUI RACCOURCIT, JAMAIS LE TITRE QUI
   RÉTRÉCIT. Sur 360 × 640, le titre, l'accroche et le champ de recherche doivent
   tenir sans défiler ; la seule variable d'ajustement est le texte d'accroche. */
.k-hero__accroche--longue  { display: none; }
.k-hero__accroche--courte  { display: block; }
@media (min-width: 768px) {
    .k-hero__accroche--longue { display: block; }
    .k-hero__accroche--courte { display: none; }
}
.k-hero__actions { display: flex; flex-wrap: wrap; gap: var(--e-3); margin-top: var(--e-5); }

/* Pastilles de catégories */
.k-pastilles { display: flex; flex-wrap: wrap; gap: var(--e-2); margin-top: var(--e-5); }
.k-pastille {
    display: inline-block;
    padding: var(--e-2) var(--e-4);
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon-pilule);
    font-size: var(--t-sm); color: hsl(var(--nuit)); text-decoration: none;
}
.k-pastille:hover { border-color: hsl(var(--lagune)); color: hsl(var(--lagune)); }

/* Visuel produit et cartes de preuve flottantes */
.k-hero__visuel { position: relative; }
.k-hero__visuel img {
    width: 100%; border-radius: var(--rayon);
    box-shadow: var(--ombre-haut); object-fit: cover;
}
.k-hero__visuel-vide {
    /* Rapport 4:3 réservé : la place du visuel est tenue même sans image, donc
       aucun décalage le jour où une vraie photo arrive. */
    aspect-ratio: 4 / 3;
    border-radius: var(--rayon);
    border: 1px dashed hsl(var(--ligne));
    background:
        linear-gradient(135deg, hsl(var(--lagune) / .07), transparent 60%),
        hsl(var(--blanc) / .5);
}
.k-preuve-flottante {
    position: absolute;
    padding: var(--e-3) var(--e-4);
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon-petit);
    box-shadow: var(--ombre-haut);
    max-width: 230px;
}
.k-preuve-flottante--haut { top: var(--e-5); left: calc(var(--e-5) * -1); }
.k-preuve-flottante--bas  { bottom: var(--e-5); right: calc(var(--e-4) * -1); }
/* ⚠️ Masquées sous 992 px : superposées à un visuel étroit, elles le rendent
   illisible — et leur contenu est repris en clair par la bande de preuves. */
@media (max-width: 991px) { .k-preuve-flottante { display: none; } }

.k-hero__recherche { margin-top: var(--e-6); }

/* ────────────────────────────────────────────────────────── 18. PREUVES */

.k-preuves { gap: var(--e-5); }
.k-preuve {
    padding-left: var(--e-4);
    border-left: 3px solid hsl(var(--or));
}
.k-preuve__titre { font-size: var(--t-lg); margin-bottom: var(--e-2); }
.k-preuve__lien {
    display: inline-flex; align-items: center; gap: var(--e-1);
    font-size: var(--t-sm); font-weight: 600; text-decoration: none;
}
.k-preuve__lien:hover { text-decoration: underline; }

/* ────────────────────────────────────────────────────────── 19. LOGEMENT */

.k-logement {
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon);
    overflow: hidden;
    transition: border-color .15s, box-shadow .15s, transform .15s;
}
.k-logement:hover { border-color: hsl(var(--lagune) / .45); box-shadow: var(--ombre-haut); }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
    .k-logement:hover { transform: translateY(-2px); }
}
/* La carte entière est cliquable, mais le lien reste UN seul élément focalisable :
   un titre et une image cliquables séparément doublent les arrêts au clavier. */
.k-logement__lien { display: block; color: inherit; text-decoration: none; }
.k-logement__lien:focus-visible { outline-offset: -3px; }

.k-logement__image { position: relative; aspect-ratio: 4 / 3; background: hsl(var(--kaolin)); }
.k-logement__image img { width: 100%; height: 100%; object-fit: cover; }
.k-logement__image-vide {
    width: 100%; height: 100%;
    background: linear-gradient(135deg, hsl(var(--lagune) / .08), hsl(var(--kaolin)));
}
.k-logement__badge {
    position: absolute; left: var(--e-3); bottom: var(--e-3);
    background: hsl(var(--blanc));
    box-shadow: 0 1px 6px hsl(var(--nuit) / .12);
}

.k-logement__corps { padding: var(--e-4); }
.k-logement__titre {
    font-size: var(--t-lg); margin-bottom: var(--e-1);
    /* Deux lignes au maximum : au-delà, les cartes d'une grille se désalignent. */
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
}
.k-logement__prix {
    margin-top: var(--e-3); margin-bottom: 0;
    font-size: var(--t-lg); font-weight: 700; color: hsl(var(--nuit));
}
.k-logement__prix span { font-weight: 400; }

/* ────────────────────────────────────────────────────────── 20. PARCOURS

   Étapes numérotées 01→05, chacune avec une maquette d'interface montrant des
   DONNÉES CONCRÈTES plutôt qu'une illustration.                                */

.k-etapes { display: grid; gap: var(--e-6); counter-reset: etape; }
.k-etape { display: grid; gap: var(--e-4); align-items: center; }
@media (min-width: 900px) {
    .k-etape { grid-template-columns: 1fr 1fr; gap: var(--e-7); }
    /* Une étape sur deux inverse l'ordre : le regard zigzague au lieu de
       descendre en colonne, ce qui tient l'attention sur cinq étapes. */
    .k-etape:nth-child(even) .k-etape__texte { order: 2; }
}
.k-etape__num {
    display: inline-block; margin-bottom: var(--e-2);
    font-family: var(--titre); font-size: var(--t-2xl); font-weight: 600;
    color: hsl(var(--or));
    font-variation-settings: 'opsz' 24;
}
.k-etape__titre { font-size: var(--t-xl); }

/* Maquette : un cadre d'interface, pas une illustration. */
.k-maquette {
    padding: var(--e-4);
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon);
    box-shadow: var(--ombre);
    font-size: var(--t-sm);
}
.k-maquette__barre {
    display: flex; gap: var(--e-1); margin-bottom: var(--e-4);
}
.k-maquette__barre i {
    width: 8px; height: 8px; border-radius: 50%;
    background: hsl(var(--ligne));
}
.k-maquette__ligne {
    display: flex; justify-content: space-between; gap: var(--e-4);
    padding-block: var(--e-2);
    border-bottom: 1px solid hsl(var(--ligne));
}
.k-maquette__ligne:last-child { border-bottom: 0; }
.k-maquette__ligne--total { font-weight: 700; color: hsl(var(--nuit)); }

/* ────────────────────────────────────────────────────────── 21. PRIX */

.k-prix { display: grid; gap: 0; }
.k-prix__ligne {
    display: flex; justify-content: space-between; align-items: baseline; gap: var(--e-4);
    padding-block: var(--e-3);
    border-bottom: 1px solid hsl(var(--ligne));
    font-size: var(--t-sm);
}
.k-prix__ligne span:first-child { display: grid; }
.k-prix__ligne--total {
    border-bottom: 0;
    padding-top: var(--e-4);
    font-size: var(--t-lg); font-weight: 700; color: hsl(var(--nuit));
}

/* ────────────────────────────────────────────────────────── 22. TÉMOIGNAGE */

.k-temoignage { margin: 0; }
.k-temoignage p {
    font-family: var(--titre); font-size: var(--t-lg); line-height: 1.45;
    color: hsl(var(--nuit));
    font-variation-settings: 'opsz' 20;
}
.k-temoignage footer { margin-top: var(--e-3); }

/* ────────────────────────────────────────────────────────── 23. BROUILLON */

.k-brouillon {
    display: grid; gap: var(--e-2);
    margin-bottom: var(--e-6);
    padding: var(--e-4) var(--e-5);
    /* Latérite : l'accent chaud, réservé aux alertes. Une seule section
       d'emphase par page — celle-ci l'est. */
    background: hsl(var(--laterite) / .07);
    border-left: 4px solid hsl(var(--laterite));
    border-radius: var(--rayon-petit);
    color: hsl(var(--laterite));
}

/* ────────────────────────────────────────────────────────── 24. GALERIE */

.k-galerie {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 88%;
    gap: var(--e-3);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    /* La barre de défilement reste visible : sans repère, on ne devine pas
       qu'il y a d'autres photos à droite. */
    scrollbar-width: thin;
    padding-bottom: var(--e-2);
    border-radius: var(--rayon);
}
@media (min-width: 768px) { .k-galerie { grid-auto-columns: 62%; } }
@media (min-width: 1100px) { .k-galerie { grid-auto-columns: 48%; } }
.k-galerie__vue { margin: 0; scroll-snap-align: start; }
.k-galerie__vue img {
    width: 100%; aspect-ratio: 3 / 2; object-fit: cover;
    border-radius: var(--rayon); background: hsl(var(--kaolin));
}

/* ────────────────────────────────────────────────────────── 25. PLACE DE MARCHÉ */

.k-marche { display: grid; gap: var(--e-5); align-items: start; }
@media (min-width: 992px) { .k-marche { grid-template-columns: 268px 1fr; gap: var(--e-6); } }

/* Filtres : `<details>` natif. Ouverts sur grand écran, repliés sur mobile pour
   ne pas repousser les résultats sous la ligne de flottaison. */
.k-filtres {
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon);
}
.k-filtres > summary {
    display: flex; align-items: baseline; gap: var(--e-2);
    padding: var(--e-4); cursor: pointer;
    border-radius: var(--rayon);
}
.k-filtres > summary::marker { color: hsl(var(--lagune)); }
.k-filtres__corps { padding: 0 var(--e-4) var(--e-4); }
.k-filtres__bloc {
    margin: 0 0 var(--e-4); padding: 0 0 var(--e-4);
    border: 0; border-bottom: 1px solid hsl(var(--ligne));
}
.k-filtres__bloc:last-of-type { border-bottom: 0; }
.k-filtres__bloc legend {
    padding: 0; margin-bottom: var(--e-3);
    font-size: var(--t-xs); font-weight: 600;
    letter-spacing: .06em; text-transform: uppercase;
    color: hsl(var(--texte-doux));
}
.k-filtres__actions { display: grid; gap: var(--e-2); }

.k-coche {
    display: flex; align-items: flex-start; gap: var(--e-3);
    padding-block: var(--e-2); cursor: pointer;
    font-size: var(--t-sm);
}
/* Cible tactile confortable : une case de 13 px se rate une fois sur trois. */
.k-coche input { width: 20px; height: 20px; margin: 2px 0 0; accent-color: hsl(var(--lagune)); flex: none; }
.k-coche span { display: grid; }

@media (min-width: 992px) {
    /* Sur grand écran les filtres restent visibles pendant qu'on parcourt les
       résultats : les rouvrir à chaque essai décourage de filtrer. */
    .k-filtres { position: sticky; top: calc(var(--entete-h) + 88px); }
}

.k-carte-toggle > summary { list-style: none; display: inline-flex; }
.k-carte-toggle > summary::-webkit-details-marker { display: none; }
.k-carte-zone {
    margin-top: var(--e-4); padding: var(--e-4);
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon);
}

.k-pagination { margin-top: var(--e-6); }
.k-pagination__liste {
    display: flex; align-items: center; justify-content: center;
    gap: var(--e-3); flex-wrap: wrap;
}
.k-pagination__lien {
    display: inline-flex; align-items: center; min-height: 44px;
    padding: var(--e-2) var(--e-4);
    border: 1px solid hsl(var(--ligne)); border-radius: var(--rayon-pilule);
    font-size: var(--t-sm); font-weight: 600; text-decoration: none;
    background: hsl(var(--blanc));
}
.k-pagination__lien:hover { border-color: hsl(var(--lagune)); }
.k-pagination__lien--inactif { opacity: .45; pointer-events: none; }
.k-pagination__etat { font-size: var(--t-sm); color: hsl(var(--texte-doux)); }

/* ────────────────────────────────────────────────────────── 26. FICHE LOGEMENT */

.k-fil-ariane {
    display: flex; gap: var(--e-2); align-items: center; flex-wrap: wrap;
    margin-bottom: var(--e-4);
    font-size: var(--t-sm); color: hsl(var(--texte-doux));
}
.k-fil-ariane a { text-decoration: none; }
.k-fil-ariane a:hover { text-decoration: underline; }

.k-fiche { display: grid; gap: var(--e-6); align-items: start; }
@media (min-width: 992px) { .k-fiche { grid-template-columns: 1fr 360px; gap: var(--e-7); } }
.k-fiche__corps > section { margin-bottom: var(--e-7); }
.k-fiche__corps > section:last-child { margin-bottom: 0; }

/* Confort : le vérifié et le déclaré ne se ressemblent jamais. */
.k-confort__famille { margin-bottom: var(--e-5); }
.k-confort__famille h3 { font-size: var(--t-lg); margin-bottom: var(--e-2); }
.k-confort__ligne {
    display: flex; justify-content: space-between; align-items: flex-start;
    gap: var(--e-4);
    padding-block: var(--e-3);
    border-bottom: 1px solid hsl(var(--ligne));
}
.k-confort__ligne > span:first-child { display: grid; gap: 2px; }
.k-confort__declares { display: flex; flex-wrap: wrap; gap: var(--e-2); }

.k-regles { display: grid; gap: var(--e-2); }
.k-regles li {
    display: flex; justify-content: space-between; gap: var(--e-4);
    padding-block: var(--e-2);
    border-bottom: 1px solid hsl(var(--ligne));
    font-size: var(--t-sm);
}
.k-hote-fiche {
    display: flex; align-items: center; gap: var(--e-4);
    padding: var(--e-4);
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon);
}
.k-avis { display: grid; gap: var(--e-3); }

/* ── Bloc de réservation ──────────────────────────────────────────────────
   Collant sur ordinateur, barre fixe sur mobile. Le prix reste sous les yeux
   pendant qu'on lit : le faire remonter chercher fait renoncer.              */

.k-reservation__carte {
    padding: var(--e-5);
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon);
    box-shadow: var(--ombre);
}
.k-reservation__prix {
    margin-bottom: var(--e-4);
    font-size: var(--t-2xl); font-weight: 700; color: hsl(var(--nuit));
}
.k-reservation__prix span { font-weight: 400; display: block; }

@media (min-width: 992px) {
    .k-reservation { position: sticky; top: calc(var(--entete-h) + var(--e-4)); }
    /* ⚠️ `.k-reservation__barre` a été retirée : la fiche utilise désormais la
       barre d'action commune, qui apparaît au défilement au lieu de recouvrir le
       contenu dès le chargement. La marge basse, elle, reste nécessaire. */
    .k-fiche { padding-bottom: var(--e-8); }
}

/* ────────────────────────────────────────────────────────── 27. COMPTE */

.k-compte { display: grid; place-items: start center; }
.k-compte__carte {
    width: 100%; max-width: 480px;
    padding: var(--e-6);
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon);
    box-shadow: var(--ombre);
}
/* La candidature hôte demande onze champs : à 480 px ils s'empilent en colonne
   unique et la page devient un couloir. Elle seule a besoin de cette largeur. */
.k-compte__carte--ample { max-width: 720px; }
.k-champ__legende {
    padding: 0; margin-bottom: var(--e-3);
    font-size: var(--t-sm); font-weight: 600; color: hsl(var(--nuit));
}
.k-profil { border: 0; padding: 0; margin: 0 0 var(--e-5); }
.k-profil__choix {
    display: flex; align-items: flex-start; gap: var(--e-3);
    padding: var(--e-4);
    margin-bottom: var(--e-2);
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon-petit);
    cursor: pointer;
}
.k-profil__choix:has(input:checked) {
    border-color: hsl(var(--lagune));
    background: hsl(var(--lagune) / .05);
}
.k-profil__choix input { width: 20px; height: 20px; margin: 2px 0 0; accent-color: hsl(var(--lagune)); flex: none; }
.k-profil__choix > span { display: grid; }

/* Le champ de code : large, espacé, en chiffres tabulaires. On le saisit une
   fois, souvent en le lisant sur un autre écran. */
.k-input--code {
    font-size: var(--t-2xl);
    letter-spacing: .4em;
    text-align: center;
    font-variant-numeric: tabular-nums;
    padding-left: .4em;   /* compense l'espacement sur le dernier caractère */
}

.k-repli { margin-top: var(--e-5); padding-top: var(--e-4); border-top: 1px solid hsl(var(--ligne)); }
.k-repli > summary { cursor: pointer; font-size: var(--t-sm); color: hsl(var(--texte-doux)); }

/* ────────────────────────────────────────────────────────── 28. BLOC HÔTE */

.k-hote-bloc { display: grid; gap: var(--e-6); align-items: center; }
@media (min-width: 992px) { .k-hote-bloc { grid-template-columns: 1.15fr 1fr; gap: var(--e-7); } }
.k-hote-bloc__points { display: grid; gap: var(--e-4); margin-top: var(--e-5); }
.k-hote-bloc__points li { display: grid; gap: 2px; }
.k-hote-bloc__points strong { color: hsl(var(--blanc)); }

/* Bande WhatsApp de l'accueil : même bloc, disposition horizontale. */
.k-wa--bande { display: grid; gap: var(--e-5); align-items: center; }
@media (min-width: 768px) { .k-wa--bande { grid-template-columns: 1.4fr 1fr; } }

/* ────────────────────────────────────────────────────────── 29. DESTINATION */

.k-destination {
    display: grid; gap: var(--e-1);
    padding: var(--e-4);
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon);
    text-decoration: none;
    transition: border-color .15s;
}
.k-destination:hover { border-color: hsl(var(--lagune)); }
.k-destination__nom { font-weight: 600; color: hsl(var(--nuit)); }

/* ────────────────────────────────────────────────────────── 30. ONGLETS

   🔑 Sans JavaScript, et sans masquer le contenu à un moteur de recherche. Deux
   boutons radio visuellement cachés pilotent l'affichage : les deux panneaux
   sont dans le document, donc indexés, donc lisibles même si le style ne charge
   pas.                                                                          */

.k-onglets__barre {
    display: flex; gap: var(--e-2); flex-wrap: wrap;
    margin-bottom: var(--e-6);
    border-bottom: 1px solid hsl(var(--ligne));
}
.k-onglets__bouton {
    display: inline-flex; align-items: center; min-height: 46px;
    padding: var(--e-3) var(--e-5);
    border-bottom: 2px solid transparent;
    font-size: var(--t-sm); font-weight: 600;
    color: hsl(var(--texte-doux)); cursor: pointer;
}
.k-onglets__bouton:hover { color: hsl(var(--lagune)); }

#onglet-voyageur:checked ~ .k-onglets__barre label[for="onglet-voyageur"],
#onglet-hote:checked     ~ .k-onglets__barre label[for="onglet-hote"] {
    color: hsl(var(--lagune));
    border-bottom-color: hsl(var(--lagune));
}
/* Le focus clavier doit se voir sur le LABEL, l'input étant hors écran. */
#onglet-voyageur:focus-visible ~ .k-onglets__barre label[for="onglet-voyageur"],
#onglet-hote:focus-visible     ~ .k-onglets__barre label[for="onglet-hote"] {
    outline: 3px solid hsl(var(--lagune) / .55); outline-offset: 2px;
}

.k-onglets__panneau { display: none; }
#onglet-voyageur:checked ~ #panneau-voyageur,
#onglet-hote:checked     ~ #panneau-hote { display: block; }
/* ⚠️ Si le style ne charge pas, les DEUX panneaux s'affichent — verbeux, mais
   complet. L'inverse (tout masqué) serait une page vide. */

/* ────────────────────────────────────────────────────────── 31. PROSE

   Le contenu éditorial venant du gestionnaire de contenu : on lui impose la
   largeur de lecture et les espacements, sans quoi il arrive avec les siens.    */

.k-prose { max-width: 68ch; }
.k-prose h2 { margin-top: var(--e-6); font-size: var(--t-xl); }
.k-prose h3 { margin-top: var(--e-5); }
.k-prose img { border-radius: var(--rayon); margin-block: var(--e-4); }
.k-prose ul, .k-prose ol { margin-bottom: var(--e-4); }
.k-prose li { margin-bottom: var(--e-2); }

/* ─────────────────────────────────────────── 30. MAQUETTES DE TÉLÉPHONE

   🔑 AUCUNE IMAGE. Le cadre est dessiné en CSS et l'écran contient de VRAIS
   composants Kuaba, avec les vrais jetons. Une capture d'écran importée ment
   deux fois : elle vieillit sans qu'on s'en aperçoive, et elle ne prouve pas
   que l'interface existe — celle-ci se rend, donc elle existe.

   🔑 TOUT EST EN `em`, ET LA TAILLE DE POLICE DU CADRE PORTE L'ÉCHELLE. C'est
   ce qui rend le téléphone fluide sans `transform: scale()` : une mise à
   l'échelle par transformation laisse la boîte de mise en page à sa taille
   d'origine et creuse un trou blanc sous le visuel. Ici la boîte suit. */

.k-tel {
    /* 390 points de large, ratio 9:19.5 → 845 de haut. `min()` fait le reste :
       sur un écran étroit le téléphone rétrécit, il ne déborde jamais. */
    /* ⚠️ `largeur × 16 / 390`, PAS `largeur / 390 × 16px` : diviser une longueur
       par un nombre donne une longueur, la multiplier ensuite par `16px` donne
       des px² — `calc()` invalide, et la règle entière est jetée en silence. */
    --tel-large: min(390px, 72vw);
    font-size: calc(var(--tel-large) * 16 / 390);
    width: var(--tel-large);
    aspect-ratio: 9 / 19.5;
    position: relative;
    margin-inline: auto;
    /* 🔴 LE CADRE NE RESSEMBLAIT PAS À UN TÉLÉPHONE. Une bordure épaisse, un écran
       à peine arrondi, aucun bouton, aucune tranche : le résultat se lisait comme un
       rectangle noir autour d'une page web. Ce qui fait un appareil, ce sont trois
       choses, toutes dessinées : une tranche métallique fine, une lunette RÉGULIÈRE
       sur les quatre côtés, et des boutons sur le côté. */
    padding: 0.42em;
    background: linear-gradient(160deg, hsl(var(--metal)), hsl(var(--nuit)) 38%, hsl(var(--nuit)) 70%, hsl(var(--metal-sombre)));
    border-radius: 3.1em;
    box-shadow:
        var(--ombre-haut),
        0 0 0 0.055em hsl(var(--metal-clair) / .9),      /* la tranche, claire  */
        0 0 0 0.11em  hsl(var(--nuit)),           /* le corps            */
        inset 0 0 0.4em hsl(var(--creux) / .5);
    flex: none;
}

/* Les boutons : volume à gauche, veille à droite. Ils ne font rien — ils situent. */
.k-tel::after {
    content: '';
    position: absolute; top: 22%; right: -0.13em;
    width: 0.13em; height: 8%;
    border-radius: 0 0.1em 0.1em 0;
    background: hsl(var(--metal-bouton));
}

/* L'encoche. Dessinée, pas photographiée. */
/* L'îlot d'écran, dessiné : une pastille posée SUR l'écran, comme les appareils
   récents — l'encoche découpée dans la lunette est une génération plus ancienne. */
.k-tel::before {
    content: '';
    position: absolute; top: 1.15em; left: 50%;
    transform: translateX(-50%);
    width: 5.2em; height: 1.5em;
    background: hsl(var(--nuit));
    border-radius: 999px;
    z-index: 3;
}

.k-tel__ecran {
    height: 100%;
    position: relative;
    overflow: hidden;
    display: flex; flex-direction: column;
    background: hsl(var(--blanc));
    /* La courbure de l'écran suit celle du cadre moins la lunette : sans quoi on voit
       du noir dans les coins, et c'est ce qui trahit une maquette. */
    border-radius: 2.7em;
    font-size: 1em;
}

/* ── Le bandeau d'état ──────────────────────────────────────────────────────
   ⚠️ L'heure est la VRAIE heure du serveur : une heure inventée est un détail qu'on
   remarque. Aucun opérateur n'est nommé — la marque d'un tiers dans une maquette
   engage Kuaba sur ce qu'elle ne contrôle pas. */
.k-tel__etat {
    flex: none; height: 2.9em;
    display: flex; align-items: center; justify-content: space-between;
    padding: 0 1.7em;
    background: hsl(var(--blanc));
    position: relative; z-index: 2;
}
.k-tel__heure { font-size: 0.72em; font-weight: 700; color: hsl(var(--nuit)); letter-spacing: .01em; }
.k-tel__signaux { display: flex; align-items: flex-end; gap: 0.16em; margin-left: auto; margin-right: 0.5em; }
.k-tel__signaux i { width: 0.22em; height: 0.4em; border-radius: 1px; background: hsl(var(--nuit) / .8); }
.k-tel__signaux i:nth-child(2) { height: 0.6em; }
.k-tel__signaux i:nth-child(3) { height: 0.8em; }
.k-tel__pile {
    width: 1.3em; height: 0.62em;
    border: 0.09em solid hsl(var(--nuit) / .6); border-radius: 0.18em;
    position: relative;
}
.k-tel__pile::before {
    content: ''; position: absolute; inset: 0.09em; right: 0.35em;
    background: hsl(var(--nuit) / .8); border-radius: 0.06em;
}
.k-tel__pile::after {
    content: ''; position: absolute; top: 0.18em; right: -0.2em;
    width: 0.09em; height: 0.26em; border-radius: 0 0.06em 0.06em 0;
    background: hsl(var(--nuit) / .5);
}

/* La barre de retour à l'accueil : deux pixels qui séparent un téléphone d'un
   rectangle. Elle FLOTTE au-dessus du contenu, comme sur l'appareil. */
.k-tel__accueil {
    position: absolute; bottom: 0.55em; left: 50%;
    transform: translateX(-50%);
    width: 8.5em; height: 0.28em;
    border-radius: 999px;
    background: hsl(var(--nuit) / .28);
    z-index: 3;
}

.k-tel__corps { flex: 1; overflow: hidden; padding: 1em; }
/* Le cadre embarqué occupe tout : c'est une page, pas un fragment. */
.k-tel__corps--cadre { padding: 0; }

/* ── Variantes ───────────────────────────────────────────────────────── */

/* Perspective LÉGÈRE. Au-delà, le texte de l'écran devient illisible et le
   visuel cesse de montrer le produit pour ne montrer que lui-même. */
.k-tel--incline { transform: perspective(1400px) rotateY(-11deg) rotate(-1.5deg); }

/* ⚠️ `isolation` et des z-index POSITIFS. Un `z-index: -1` fait passer le second
   téléphone DERRIÈRE le fond de la première section teintée qu'il rencontre — il
   ne recule pas, il disparaît. */
.k-tel-duo { position: relative; display: flex; justify-content: center; isolation: isolate; }
.k-tel-duo .k-tel:nth-child(1) { z-index: 2; }
.k-tel-duo .k-tel:nth-child(2) {
    position: absolute; top: 3.5em; left: 50%;
    transform: translateX(-18%) scale(.86);
    z-index: 1;
    filter: saturate(.9) brightness(.98);
}

/* ⚠️ JAMAIS DE DUO SUR MOBILE. Deux téléphones sur 360 points ne montrent plus
   qu'un empilement de rectangles : le second disparaît, il ne rétrécit pas. */
@media (max-width: 767px) {
    .k-tel-duo .k-tel:nth-child(2) { display: none; }
    .k-tel--incline { transform: none; }
}

/* ── Fragments d'interface réutilisés dans les écrans ────────────────── */

.k-tel-carte {
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: 0.9em;
    overflow: hidden;
}
/* Emplacement de photographie. ⚠️ Ce n'est PAS une image décorative : c'est un
   emplacement en attente d'une vraie photo de logement vérifié. Un aplat se
   reconnaît comme tel, une photo de catalogue se ferait passer pour vraie. */
.k-tel-photo {
    aspect-ratio: 4 / 3;
    background:
        repeating-linear-gradient(-45deg,
            hsl(var(--lagune) / .07) 0 0.8em,
            hsl(var(--lagune) / .04) 0.8em 1.6em);
    display: grid; place-items: center;
    color: hsl(var(--lagune) / .5);
    font-size: 0.62em;
    letter-spacing: .06em;
    text-transform: uppercase;
}
.k-tel-corps { padding: 0.85em; }
.k-tel-titre { font-family: var(--titre); font-size: 1.05em; line-height: 1.25; margin: 0 0 0.15em; }
.k-tel-lieu  { font-size: 0.72em; color: hsl(var(--texte-doux)); margin: 0 0 0.7em; }

.k-tel-agent { display: flex; align-items: center; gap: 0.55em; margin-bottom: 0.7em; }
.k-tel-agent__vignette {
    width: 2.1em; height: 2.1em; flex: none;
    border-radius: 50%;
    display: grid; place-items: center;
    background: hsl(var(--lagune) / .12);
    color: hsl(var(--lagune-fonce));
    font-size: 0.8em; font-weight: 700;
}
.k-tel-agent__nom { font-size: 0.74em; line-height: 1.3; }
.k-tel-agent__role { display: block; color: hsl(var(--texte-doux)); font-size: 0.92em; }

.k-tel-prix {
    display: flex; align-items: baseline; justify-content: space-between;
    padding-top: 0.7em; border-top: 1px solid hsl(var(--ligne));
}
.k-tel-prix__montant { font-family: var(--titre); font-size: 1.15em; }
.k-tel-prix__unite   { font-size: 0.7em; color: hsl(var(--texte-doux)); }

/* Le badge Or dans l'écran : la vérification est le seul endroit où l'Or paraît. */
.k-tel-badge {
    display: inline-flex; align-items: center; gap: 0.35em;
    padding: 0.3em 0.65em;
    border-radius: var(--rayon-pilule);
    background: hsl(var(--or) / .16);
    color: hsl(38 62% 26%);
    font-size: 0.66em; font-weight: 700;
}

.k-tel-bouton {
    display: block; width: 100%;
    margin-top: 0.8em; padding: 0.75em;
    border: 0; border-radius: var(--rayon-pilule);
    background: hsl(var(--lagune)); color: hsl(var(--blanc));
    font-family: var(--corps); font-size: 0.78em; font-weight: 600;
    text-align: center;
}

/* ── Le berceau : téléphone + cartes de preuve flottantes ───────────── */

.k-tel-scene { position: relative; display: flex; justify-content: center; padding-block: var(--e-4); }

/* ── Fragments des écrans E2 à E6 ────────────────────────────────────── */

.k-tel-entete { font-family: var(--titre); font-size: 0.95em; margin: 0 0 0.7em; }
/* 🔴 UNE TAILLE D'ILLUSTRATION SERVIE COMME TEXTE RÉEL, DANS TRENTE-TROIS VUES.
   `0.72em` a du sens à l'intérieur du téléphone DESSINÉ des pages publiques : c'est une
   maquette, son texte doit paraître petit. Mais la même classe porte les lignes
   « étiquette → valeur » de l'espace hôte, de l'espace voyageur, de l'administration et
   du reçu d'agent — et le 11/09/2026 le solde d'un hôte, « 125 000 F CFA », était
   RENDU À 11,5 POINTS sur son propre écran.

   🔑 LA MINIATURE RESTE MINIATURE LÀ OÙ ELLE EST UNE IMAGE. La règle de taille descend
   donc dans le cadre du téléphone dessiné ; partout ailleurs, la ligne prend la taille
   du texte courant. Trois fichiers `partials/ecrans/*` dessinent ce téléphone ; les
   trente-trois autres montrent de vrais chiffres à de vraies personnes. */
.k-tel-ligne {
    display: flex; align-items: center; justify-content: space-between; gap: 0.5em;
    padding: 0.5em 0; font-size: var(--t-sm);
    border-bottom: 1px solid hsl(var(--ligne));
}
.k-tel .k-tel-ligne,
.k-tel-carte .k-tel-ligne,
.k-tel-scene .k-tel-ligne { font-size: 0.72em; }
.k-tel-ligne:last-child { border-bottom: 0; }
.k-tel-ligne__fort { font-weight: 700; color: hsl(var(--nuit)); }

/* Jauge d'épargne. ⚠️ `aria-hidden` sur tout le cadre : la valeur est reprise en
   clair à côté du visuel, une barre seule n'énonce rien. */
.k-tel-jauge { height: 0.55em; border-radius: var(--rayon-pilule); background: hsl(var(--ligne)); overflow: hidden; }
.k-tel-jauge > span { display: block; height: 100%; background: hsl(var(--lagune)); border-radius: inherit; }

/* Pastilles de filtre. L'état actif se lit à la couleur ET au contour : la
   couleur seule n'informe pas qui ne la distingue pas. */
.k-tel-pastilles { display: flex; flex-wrap: wrap; gap: 0.35em; margin-bottom: 0.7em; }
.k-tel-pastille {
    padding: 0.3em 0.6em; border-radius: var(--rayon-pilule);
    border: 1px solid hsl(var(--ligne));
    background: hsl(var(--blanc)); color: hsl(var(--texte-doux));
    font-size: 0.62em; white-space: nowrap;
}
.k-tel-pastille--active {
    border-color: hsl(var(--lagune)); background: hsl(var(--lagune) / .1);
    color: hsl(var(--lagune-fonce)); font-weight: 700;
}

.k-tel-recherche {
    display: flex; align-items: center; gap: 0.4em;
    padding: 0.6em 0.8em; margin-bottom: 0.7em;
    background: hsl(var(--blanc)); border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon-pilule); font-size: 0.7em; color: hsl(var(--texte-doux));
}

/* Fil de conversation SUR FOND CLAIR. ⚠️ `.k-fil` existe déjà mais il est calé sur
   une section sombre (texte blanc sur blanc translucide) : le réutiliser ici
   donnerait du blanc sur blanc. Deux contextes, deux jeux — la structure est la
   même, les couleurs ne peuvent pas l'être. */
.k-tel-fil { display: grid; gap: 0.4em; }
.k-tel-fil__bulle {
    max-width: 86%; padding: 0.5em 0.7em;
    border-radius: 0.8em; font-size: 0.68em; line-height: 1.45;
    background: hsl(var(--blanc)); color: hsl(var(--nuit));
    border: 1px solid hsl(var(--ligne));
}
.k-tel-fil__bulle--nous {
    margin-left: auto;
    background: hsl(var(--lagune) / .12); border-color: hsl(var(--lagune) / .25);
}
.k-tel-fil__meta { font-size: 0.58em; color: hsl(var(--texte-doux)); }

/* Vignette vidéo : un emplacement, pas une image. Même raison que la photo. */
.k-tel-video {
    aspect-ratio: 16 / 9; border-radius: 0.5em; margin-top: 0.4em;
    background: repeating-linear-gradient(-45deg,
        hsl(var(--nuit) / .1) 0 0.7em, hsl(var(--nuit) / .06) 0.7em 1.4em);
    display: grid; place-items: center;
    color: hsl(var(--nuit) / .45); font-size: 0.85em;
}

/* Calendrier du mois. Les nuits occupées se distinguent par le fond ET par le
   poids : deux signaux, pas un. */
.k-tel-cal { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.18em; }
.k-tel-cal span {
    aspect-ratio: 1; display: grid; place-items: center;
    border-radius: 0.3em; font-size: 0.55em; color: hsl(var(--texte-doux));
}
.k-tel-cal .occ { background: hsl(var(--lagune) / .16); color: hsl(var(--lagune-fonce)); font-weight: 700; }

/* Indicateur de pays d'un paiement. ⚠️ DES LETTRES, PAS DE DRAPEAU : un drapeau est
   un asset importé, et il désigne un État là où l'on veut désigner l'origine d'un
   virement. Le code ISO dit exactement cela, sans rien importer. */
.k-tel-pays {
    padding: 0.15em 0.4em; border-radius: 0.3em;
    background: hsl(var(--nuit) / .07); color: hsl(var(--texte-doux));
    font-size: 0.85em; font-weight: 700; letter-spacing: .04em;
}

/* ─────────────────────── 31. DISPONIBILITÉ MOBILE — SECTION SUPPRIMÉE

   ⛔ LES PASTILLES « BIENTÔT SUR ANDROID / IPHONE » N'EXISTENT PLUS. Elles
   annonçaient une application publiée nulle part ; il ne reste que la capture
   « préviens-moi à la sortie », qui elle ne promet rien qu'on ne puisse tenir.

   🔑 LA RÈGLE, ELLE, RESTE ET S'EST ÉLARGIE. Aucun artwork Google Play ou App
   Store nulle part sur le site : leurs chartes le réservent aux applications
   publiées, et ce serait à la fois un usage non autorisé de leur marque et une
   promesse fausse. `verifier-maquettes.php` l'affirme désormais sur TOUTES les
   vues publiques, plus seulement sur le composant qui portait les pastilles. */

/* ── Pont pour les badges d'état des modèles ──────────────────────────────

   ⚠️ `Coffre::badgeEtat()` et `Part::badgeEtat()` émettent `badge badge--warning`
   et consorts. Ces libellés sont la SOURCE UNIQUE de l'état d'un coffre : les
   recopier dans la vue en ferait une seconde version, qui divergerait au premier
   statut ajouté. On habille donc leur sortie plutôt que de la réécrire. */
.k-etats .badge {
    display: inline-flex; align-items: center;
    padding: .2em .6em;
    border-radius: var(--rayon-pilule);
    font-size: var(--t-xs); font-weight: 700;
    background: hsl(var(--nuit) / .07); color: hsl(var(--texte-doux));
}
.k-etats .badge--success { background: hsl(var(--lagune) / .12); color: hsl(var(--lagune-fonce)); }
.k-etats .badge--warning { background: hsl(var(--or) / .16);    color: hsl(38 62% 26%); }
.k-etats .badge--info    { background: hsl(var(--lagune) / .08); color: hsl(var(--lagune-fonce)); }
.k-etats .badge--danger  { background: hsl(var(--laterite) / .12); color: hsl(var(--laterite)); }

/* Tableau simple, lisible sur 390 points : il défile plutôt que de se comprimer. */
/* ⚠️ LA ZONE DÉFILE, LE TABLEAU NE S'ÉCRASE PAS. Sans largeur minimale, un tableau
   de cinq colonnes dans une carte étroite comprimait ses en-têtes jusqu'à couper les
   mots (« SÉJOU », « VILL ») au lieu d'utiliser le défilement que cette zone lui
   offre. Une colonne illisible n'est pas une colonne. */
.k-tableau-zone { overflow-x: auto; }

.k-tableau { width: 100%; min-width: 30rem; border-collapse: collapse; font-size: var(--t-sm); }
.k-tableau th, .k-tableau td { padding: var(--e-3) var(--e-2); text-align: left; vertical-align: top; }
/* ⚠️ UN EN-TÊTE DE COLONNE NE SE COUPE PAS EN DEUX. « SÉJOURS » rendu « SÉJOU / RS »
   n'est plus un libellé : la colonne se lit de travers pour économiser dix pixels.
   S'il n'y a pas la place, c'est la zone qui défile. */
.k-tableau th { font-size: var(--t-xs); text-transform: uppercase; letter-spacing: .05em; color: hsl(var(--texte-doux)); white-space: nowrap; }
.k-tableau tbody tr { border-top: 1px solid hsl(var(--ligne)); }

/* ════════════════════════════════════════════════════════════════════════════════
   LE TABLEAU N'EST PAS RÉTRÉCI À 390 POINTS : IL EST REMPLACÉ.

   🔴 QUATRE-VINGT-SEIZE VUES PARTAGENT CE TABLEAU, et `min-width: 30rem` lui donne
   480 points dans un cadre de 390. Sur la file de vérifications, il compte CINQ
   colonnes ; l'administrateur qui la consulte depuis son téléphone doit défiler
   latéralement dans une boîte, geste qu'aucun pouce ne trouve seul.

   🔑 RÉDUIRE LA POLICE OU AJOUTER UN POINT DE RUPTURE AURAIT GARDÉ LE TABLEAU. La
   consigne du 10/09/2026 est explicite : « N'ajoute pas de points de rupture à un
   tableau : remplace-le. Ne réduis pas la taille de police pour faire entrer du
   contenu. » Sous 40 rem, chaque ligne devient donc une FICHE, et chaque cellule une
   ligne étiquette → valeur : deux colonnes, jamais plus, quel que soit le nombre de
   colonnes du tableau d'origine.

   ⚠️ L'ÉTIQUETTE VIENT DE `data-libelle`, posé à l'exécution depuis le `<thead>` par
   `components/k/tableaux-empiles`. Sans script, on retombe sur le tableau qui défile —
   l'ancien comportement, pas un écran cassé.
   ════════════════════════════════════════════════════════════════════════════════ */
@media (max-width: 40rem) {
  .k-tableau-zone { overflow-x: visible; }
  .k-tableau      { min-width: 0; display: block; }

  /* Les en-têtes ne disparaissent pas : ils redescendent dans chaque fiche. */
  .k-tableau thead { display: none; }
  .k-tableau tbody, .k-tableau tbody tr, .k-tableau tbody td { display: block; }

  .k-tableau tbody tr {
    border: 1px solid hsl(var(--ligne));
    border-radius: 10px;
    padding: var(--e-2) var(--e-3);
    margin-top: var(--e-3);
  }

  .k-tableau tbody td {
    display: grid;
    grid-template-columns: minmax(6.5rem, 38%) 1fr;
    gap: var(--e-2);
    align-items: baseline;
    padding: .3rem 0;
    white-space: normal;
  }

  .k-tableau tbody td::before {
    content: attr(data-libelle);
    font-size: var(--t-xs);
    text-transform: uppercase;
    letter-spacing: .05em;
    color: hsl(var(--texte-doux));
  }

  /* Une cellule qui tient toute la ligne — « Aucune visite en cours » — n'a pas
     d'étiquette à porter : elle parle déjà d'elle-même. */
  .k-tableau tbody td[colspan] { grid-template-columns: 1fr; }
  .k-tableau tbody td[colspan]::before { content: none; }
}

/* ─────────────────────────────────────── 28. ESPACE VOYAGEUR — DEUX COLONNES

   🔴 CE BLOC S'APPELAIT `.k-compte`, ET CE NOM ÉTAIT DÉJÀ PRIS. `.k-compte` habille
   depuis toujours les pages d'IDENTIFICATION — connexion, inscription, mot de passe
   oublié, dans les trois espaces — avec `place-items: start center` et une carte
   centrée. Lui donner ici une grille à deux colonnes a transformé dix-neuf écrans de
   connexion en formulaires tassés dans une colonne de 240 px. Aucune erreur nulle
   part : les deux règles étaient justes, c'est le NOM qui était partagé.

   🔑 MENU À GAUCHE, CONTENU À DROITE. Le menu horizontal en haut de page mettait sur
   la même ligne sept entrées et le titre de la page : à sept entrées on ne lit plus
   un menu, on le subit. En colonne, l'entrée courante se repère d'un coup d'œil et
   la place ne manque plus quand une entrée s'ajoute.

   ⚠️ SOUS LA TABLETTE, LA COLONNE REDEVIENT UNE BARRE QUI DÉFILE. Empilée, elle
   repousserait le contenu sous le pli — et c'est le contenu qu'on vient chercher. */

/* ⚠️ `min-width: 0` SUR LES DEUX COLONNES. Un élément de grille refuse par défaut de
   passer sous sa largeur MINIMALE de contenu : la barre de navigation, faite d'entrées
   qui ne se coupent pas, élargissait donc la page de dix pixels sur un téléphone — son
   `overflow-x` ne servait à rien puisqu'elle n'était jamais contrainte. */
.k-espace { display: grid; gap: var(--e-5); }
/* ⚠️ ET `justify-self: stretch`. Un `justify-items: center` hérité d'un conteneur
   parent dimensionne l'élément sur son CONTENU au lieu de la colonne, et le centre :
   la barre débordait alors des deux côtés, et `min-width: 0` n'y pouvait rien —
   « centré » veut dire « à la taille de ce qu'il contient ». */
.k-espace > * { min-width: 0; justify-self: stretch; }
@media (min-width: 900px) {
    .k-espace { grid-template-columns: 15rem 1fr; gap: var(--e-7); align-items: start; }
}

.k-espace__contenu { min-width: 0; }
@media (min-width: 900px) { .k-espace__contenu { max-width: 52rem; } }

/* La colonne de gauche COLLE au défilement : sur une longue liste de séjours, un menu
   qui part vers le haut oblige à remonter toute la page pour changer de rubrique. */
@media (min-width: 900px) {
    .k-espace__nav { position: sticky; top: calc(var(--entete-h) + var(--e-4)); }
}

.k-espace__groupe {
    margin: var(--e-5) 0 var(--e-2);
    font-size: var(--t-xs); font-weight: 600;
    letter-spacing: .08em; text-transform: uppercase;
    color: hsl(var(--texte-doux));
}
.k-espace__groupe:first-child { margin-top: 0; }

.k-espace__lien {
    display: block;
    padding: .5rem var(--e-3);
    margin-left: calc(var(--e-3) * -1);
    border-radius: var(--rayon-petit);
    color: hsl(var(--nuit));
    text-decoration: none;
    font-size: var(--t-sm);
    border-left: 2px solid transparent;
}
.k-espace__lien:hover { background: hsl(var(--lagune) / .06); color: hsl(var(--lagune-fonce)); }

/* L'entrée courante se signale par un TRAIT autant que par la couleur : une
   différence de teinte seule n'est pas perceptible par tout le monde. */
.k-espace__lien[aria-current="page"] {
    color: hsl(var(--lagune-fonce)); font-weight: 600;
    background: hsl(var(--lagune) / .08);
    border-left-color: hsl(var(--lagune));
}

.k-espace__sortie { margin-top: var(--e-6); padding-top: var(--e-4); border-top: 1px solid hsl(var(--ligne)); }
.k-espace__sortie .k-btn { color: hsl(var(--laterite)); padding-inline: 0; }

@media (max-width: 899.98px) {
    /* Une barre qui défile, comme la navigation héritée le faisait déjà. */
    .k-espace__nav { overflow-x: auto; border-bottom: 1px solid hsl(var(--ligne)); padding-bottom: var(--e-3); }
    .k-espace__nav ul { display: flex; gap: var(--e-2); }
    .k-espace__groupe { display: none; }   /* deux intertitres dans une barre : du bruit */
    /* ⚠️ La marge négative sert à aligner le fond de l'entrée courante sur le texte
       DANS LA COLONNE. Dans la barre, elle fait simplement sortir le premier élément
       de la page — dix pixels de défilement horizontal sur tout le site. */
    .k-espace__lien { white-space: nowrap; margin-left: 0; border-left: 0; border-bottom: 2px solid transparent; }
    .k-espace__lien[aria-current="page"] { border-left: 0; border-bottom-color: hsl(var(--lagune)); }
    .k-espace__sortie { margin-top: var(--e-3); padding-top: var(--e-3); }
}

/* ── Navigation de l'espace voyageur ─────────────────────────────────────

   Elle défile horizontalement sur mobile plutôt que de s'empiler : six entrées
   empilées repoussent le contenu sous le pli, et c'est le contenu qu'on vient
   chercher, pas le menu. */
.k-nav-compte { margin-bottom: var(--e-5); border-bottom: 1px solid hsl(var(--ligne)); }
.k-nav-compte ul {
    display: flex; gap: var(--e-4);
    overflow-x: auto; scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}
.k-nav-compte ul::-webkit-scrollbar { display: none; }
.k-nav-compte a {
    display: block; padding: var(--e-3) 0;
    white-space: nowrap;
    font-size: var(--t-sm); font-weight: 600;
    color: hsl(var(--texte-doux)); text-decoration: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}
.k-nav-compte a:hover { color: hsl(var(--lagune)); }
/* L'entrée courante se marque par la couleur ET par le trait : la couleur seule
   n'informe pas qui ne la distingue pas. */
.k-nav-compte a[aria-current="page"] {
    color: hsl(var(--lagune-fonce));
    border-bottom-color: hsl(var(--lagune));
}

/* ── Pont pour les partiels PARTAGÉS ─────────────────────────────────────

   🔑 `partials.kuaba_score` et `partials.kuaba_identite` servent l'espace voyageur,
   l'espace hôte ET l'administration. Les réécrire pour le socle public casserait les
   deux autres ; en faire une copie en créerait une seconde version qui divergerait.
   On habille donc leur sortie, comme pour `<x-viser-form>`.

   ⚠️ Ce pont est un PIS-ALLER assumé, pas un modèle : il traduit des classes
   Bootstrap. Le jour où ces partiels sont refaits, il se retire. */
.k-pont .card {
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon);
    margin-bottom: var(--e-4);
    overflow: hidden;
}
.k-pont .card-header {
    padding: var(--e-4);
    border-bottom: 1px solid hsl(var(--ligne));
    background: hsl(var(--kaolin) / .6);
}
.k-pont .card-title { margin: 0; font-size: var(--t-sm); font-weight: 700; }
.k-pont .card-body, .k-pont .card-footer { padding: var(--e-4); }
.k-pont .text-muted { color: hsl(var(--texte-doux)); }
.k-pont .text--success { color: hsl(var(--lagune-fonce)); }
.k-pont .text--danger  { color: hsl(var(--laterite)); }
.k-pont .small, .k-pont small { font-size: var(--t-xs); }
.k-pont .progress { height: 8px; border-radius: var(--rayon-pilule); background: hsl(var(--ligne)); overflow: hidden; }
.k-pont .progress-bar { height: 100%; background: hsl(var(--lagune)); }
.k-pont .alert {
    padding: var(--e-4); border-radius: var(--rayon-petit);
    border-left: 3px solid hsl(var(--or)); background: hsl(var(--or) / .08);
    font-size: var(--t-sm);
}
.k-pont .form--control, .k-pont .form-control, .k-pont select, .k-pont input:not([type=checkbox]):not([type=radio]) {
    width: 100%; min-height: 46px; padding: var(--e-3) var(--e-4);
    background: hsl(var(--blanc)); border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon-petit); font-size: var(--t-base); color: hsl(var(--nuit));
}
.k-pont .form--label, .k-pont label {
    display: block; margin-bottom: var(--e-2);
    font-size: var(--t-sm); font-weight: 600; color: hsl(var(--nuit));
}
.k-pont .btn {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 52px; padding: var(--e-3) var(--e-6);
    border: 1px solid transparent; border-radius: var(--rayon-pilule);
    font-size: var(--t-sm); font-weight: 700; text-decoration: none; cursor: pointer;
}
.k-pont .btn--base { background: hsl(var(--lagune)); color: hsl(var(--kaolin)); }
.k-pont .btn-outline-danger { border-color: hsl(var(--laterite) / .4); color: hsl(var(--laterite)); background: transparent; }
.k-pont .w-100 { width: 100%; }

/* ── Grille et divers, pour le pont ──────────────────────────────────────

   ⚠️ Les deux pages de détail de réservation portent trois formulaires qui touchent
   à l'argent et aux litiges. Les réécrire aurait fait courir un risque hors de
   proportion avec le gain : elles sont ENVELOPPÉES, pas refaites. Il leur faut donc
   le minimum de grille pour ne pas s'effondrer en une colonne illisible. */
.k-pont .row { display: grid; gap: var(--e-4); }
@media (min-width: 768px) {
    .k-pont .row { grid-template-columns: repeat(12, 1fr); }
    .k-pont [class*="col-lg-"], .k-pont [class*="col-md-"], .k-pont [class*="col-sm-"] { grid-column: span 12; }
    .k-pont .col-lg-8, .k-pont .col-md-8 { grid-column: span 8; }
    .k-pont .col-lg-7, .k-pont .col-md-7 { grid-column: span 7; }
    .k-pont .col-lg-6, .k-pont .col-md-6 { grid-column: span 6; }
    .k-pont .col-lg-5, .k-pont .col-md-5 { grid-column: span 5; }
    .k-pont .col-lg-4, .k-pont .col-md-4 { grid-column: span 4; }
    .k-pont .col-lg-3, .k-pont .col-md-3 { grid-column: span 3; }
}
.k-pont .d-flex { display: flex; }
.k-pont .justify-content-between { justify-content: space-between; }
.k-pont .align-items-center { align-items: center; }
.k-pont .flex-wrap { flex-wrap: wrap; }
.k-pont .text-end { text-align: right; }
.k-pont .text-center { text-align: center; }
.k-pont .gap-2 { gap: var(--e-2); }
.k-pont .mb-0 { margin-bottom: 0; }
.k-pont .mb-2, .k-pont .mb-3 { margin-bottom: var(--e-3); }
.k-pont .mt-2, .k-pont .mt-3 { margin-top: var(--e-3); }
.k-pont .mt-4, .k-pont .mb-4 { margin-block: var(--e-4); }
.k-pont ul { list-style: none; padding: 0; }
.k-pont table { width: 100%; border-collapse: collapse; font-size: var(--t-sm); }
.k-pont th, .k-pont td { padding: var(--e-3) var(--e-2); text-align: left; }
.k-pont tbody tr { border-top: 1px solid hsl(var(--ligne)); }
.k-pont img { max-width: 100%; height: auto; border-radius: var(--rayon-petit); }
.k-pont .btn--sm { min-height: 44px; padding: var(--e-2) var(--e-4); font-size: var(--t-xs); }
.k-pont .btn-outline--secondary, .k-pont .btn--dark {
    border-color: hsl(var(--lagune) / .35); color: hsl(var(--lagune)); background: transparent;
}
.k-pont textarea { min-height: 96px; }
/* ⚠️ Le squelette de chargement du gabarit hérité anime un fond gris. Sans son JS,
   il resterait gris pour toujours : on le neutralise. */
.k-pont .skeleton { animation: none; background: none; }

/* ── Onglets génériques ──────────────────────────────────────────────────────
   ⚠️ Les onglets historiques du socle (`#onglet-voyageur` / `#onglet-hote`) sont
   en CSS pur et restent tels quels. Ceux-ci sont pilotés par `kuaba-socle.js` et
   fonctionnent partout, avec n'importe quel nombre d'onglets.                  */
[data-k-onglets] .k-onglets__bouton[aria-selected="true"] {
    color: hsl(var(--lagune-fonce));
    border-bottom-color: hsl(var(--lagune));
    font-weight: 600;
}
[data-k-onglets] .k-onglets__bouton { background: none; border-top: 0; border-inline: 0; cursor: pointer; }


/* ─────────────────────────────────────────────── 27. BLOCS DE RÉPONSE

   🔑 CE NE SONT PAS DES QUESTIONS FRÉQUENTES REPLIÉES. Chaque bloc est ouvert, dans
   le fil de la page : la question fait le titre, la réponse suit. Un accordéon
   demanderait un clic pour lire ce qu'on est venu lire — et laisserait croire que
   ces réponses sont secondaires, alors qu'elles sont le corps de la page.

   ⚠️ Une réponse se lit HORS de sa page. La mesure de ligne est donc celle d'un
   paragraphe autonome, pas celle d'une colonne de mise en page.                   */

.k-reponses {
    display: grid;
    gap: var(--e-6);
    margin-block: var(--e-7);
    max-width: 62ch;
}
.k-reponse__question {
    font-size: var(--t-xl);
    line-height: 1.2;
    margin-bottom: var(--e-3);
}
/* ⚠️ PAS DE GRIS. Une réponse est le corps de la page, pas une légende : la passer
   en texte doux la faisait lire comme une note de bas de page — et les trois quarts
   des réponses d'Assinie devenaient plus pâles que la liste de liens en dessous. */
.k-reponse__texte { margin: 0; }
/* La première porte la question qui décide de tout le reste. Elle se distingue par
   la TAILLE seulement : la couleur d'alerte est déjà prise par l'état de la zone. */
.k-reponse:first-child .k-reponse__texte { font-size: var(--t-lg); }

/* 🔑 LES LISTES DE LIENS NE SONT PAS DES SECTIONS DE MÊME RANG. « Quand venir »,
   « Sur la route », « À côté » sont de la navigation ; rendues à la taille d'un `h2`
   plein, elles écrasaient les questions, qui sont le corps de la page. Le rang
   sémantique reste le même, le poids visuel non. */
.k-titre-liste { font-size: var(--t-lg); margin-top: var(--e-6); margin-bottom: var(--e-3); }


/* ═══════════════════════════════ 29. LES SECTIONS D'EXCLUSIVITÉ

   🔴 QUATRE SECTIONS BÂTIES SUR LE MÊME GABARIT REDEVIENNENT UNE LISTE. La cohérence
   vient des jetons — palette, échelle, mesure de ligne — jamais de la répétition d'une
   mise en page. Chacune a donc sa propre composition, et deux sections consécutives
   n'ont jamais la même.

   ⚠️ UNE SEULE COULEUR D'ACCENT PAR SECTION. L'Or est réservé à Vérifié et Garantie —
   ce sont les deux qui parlent de confiance ; l'employer ailleurs le dilue.          */

/* ⛔ LA BANDE D'ANNONCE N'EXISTE PLUS — treize règles retirées avec elle. Elle
   listait les quatre exclusivités au-dessus des quatre sections qui les montrent,
   à 254 pixels de la première : un sommaire dont on voit la cible en même temps que
   l'entrée. Les sections font le travail. */

/* ── Le rapport de visite ───────────────────────────────────────────────────
   Il doit se lire comme un DOCUMENT, pas comme une carte marketing : chasse
   fixe pour les valeurs, filets fins, aucune ombre, aucun arrondi généreux. */

.k-rapport {
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--nuit) / .16);
    border-top: 3px solid hsl(var(--or));
    border-radius: var(--rayon-petit);
    padding: var(--e-5) var(--e-5) var(--e-4);
}
.k-rapport__entete { margin-bottom: var(--e-4); padding-bottom: var(--e-3); border-bottom: 1px solid hsl(var(--ligne)); }
.k-rapport__quoi {
    margin: 0 0 var(--e-1);
    font-size: var(--t-xs); font-weight: 700;
    letter-spacing: .1em; text-transform: uppercase;
    color: hsl(38 62% 34%);
}
.k-rapport__ref { display: block; font-weight: 500; letter-spacing: 0; text-transform: none;
                  font-size: var(--t-sm); color: hsl(var(--nuit)); margin-top: var(--e-1); }
.k-rapport__qui { margin: 0; font-size: var(--t-sm); color: hsl(var(--texte-doux)); }

.k-rapport__lignes { margin: 0; display: grid; }
.k-rapport__ligne {
    display: grid; grid-template-columns: 1fr auto; gap: var(--e-3);
    align-items: baseline;
    padding-block: var(--e-3);
    border-bottom: 1px dotted hsl(var(--ligne));
}
.k-rapport__ligne:last-child { border-bottom: 0; }
.k-rapport__ligne dt { color: hsl(var(--nuit)); font-size: var(--t-sm); }
.k-rapport__ligne dd { margin: 0; text-align: right; }

.k-rapport__valeur {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: hsl(var(--lagune-fonce));
    font-size: var(--t-sm);
}
/* Une divergence entre le déclaré et le constaté est ce que la visite a servi à
   établir : elle se voit, sans crier. */
.k-rapport__ecart {
    display: block; margin-top: 2px;
    font-size: var(--t-xs); color: hsl(var(--laterite));
}
.k-rapport__exemple {
    margin: var(--e-4) 0 0; padding-top: var(--e-3);
    border-top: 1px solid hsl(var(--ligne));
    font-size: var(--t-xs); color: hsl(var(--texte-doux));
}

/* ── Composition « document à gauche, propos à droite » ─────────────────────
   L'INVERSE du hero, et c'est le point : deux sections qui se suivent ne
   partagent pas leur direction. */

.k-exclu { padding-block: var(--e-8); }
.k-exclu__grille { display: grid; gap: var(--e-6); align-items: center; }
@media (min-width: 900px) {
    .k-exclu__grille--doc { grid-template-columns: 1.15fr 1fr; gap: var(--e-7); }
}
.k-exclu__propos { display: grid; gap: var(--e-4); align-content: center; }
.k-exclu__propos > * { max-width: 34ch; }

/* 🔑 LE MOMENT TYPOGRAPHIQUE. Une phrase courte, très grande, qui porte l'idée à elle
   seule : c'est ce qui reste quand le visiteur ne lit que les titres. Elle n'emprunte
   pas le pas du hero — deux titres de même taille sur une page se disputent. */
.k-exclu__moment {
    font-family: var(--titre);
    font-size: clamp(1.75rem, 1.25rem + 2.2vw, 2.75rem);
    line-height: 1.08;
    letter-spacing: -.02em;
    font-weight: 700;
    margin: 0;
    text-wrap: balance;
}
.k-exclu__moment em { font-style: normal; color: hsl(var(--or)); }


/* ── Kuaba Coffre : le simulateur ───────────────────────────────────────────
   Pleine largeur, centré, TRÈS aéré : c'est la seule section de la page où l'on
   agit, et l'action doit avoir de la place autour d'elle. */

.k-coffre {
    display: grid; gap: var(--e-6);
    background: hsl(var(--blanc));
    border: 1px solid hsl(var(--ligne));
    border-radius: var(--rayon);
    padding: var(--e-6);
    box-shadow: var(--ombre);
}
@media (min-width: 900px) {
    .k-coffre { grid-template-columns: 1fr 1fr; gap: var(--e-7); align-items: center; padding: var(--e-7); }
}

/* 🔑 LE SIMULATEUR À DROITE DE SON ARGUMENT. Le texte prend un peu moins de place :
   il tient en 34ch par `.k-exclu__propos`, et c'est la démonstration qui mérite la
   largeur. */
@media (min-width: 900px) {
    .k-exclu__grille--coffre { grid-template-columns: .8fr 1fr; gap: var(--e-7); align-items: center; }

    /* 🔴 ET LA CARTE REPASSE SUR UNE COLONNE. Ses deux colonnes internes se déclenchent
       sur la largeur de l'ÉCRAN, pas sur la sienne : dans une demi-page, la saisie et
       le résultat se seraient serrés à trois cents pixels chacun, avec un montant en
       très grands chiffres au milieu. La règle qui la met en deux colonnes est juste
       tant qu'elle occupe toute la largeur — elle ne l'occupe plus. */
    .k-exclu__grille--coffre .k-coffre { grid-template-columns: 1fr; gap: var(--e-5); padding: var(--e-6); }
}
.k-coffre__saisie { display: grid; gap: var(--e-4); align-content: start; }
.k-coffre__resultat { display: grid; gap: var(--e-3); }

/* 🔑 LE MOMENT TYPOGRAPHIQUE DE LA SECTION : le montant, qui change sous les doigts.
   C'est lui qu'on regarde, pas le formulaire. */
.k-coffre__montant {
    margin: 0;
    font-family: var(--titre);
    font-size: clamp(2.5rem, 1.6rem + 4vw, 4rem);
    line-height: 1; letter-spacing: -.025em; font-weight: 700;
    color: hsl(var(--lagune-fonce));
    font-variant-numeric: tabular-nums;
}
.k-coffre__unite { font-size: var(--t-lg); font-weight: 500; color: hsl(var(--texte-doux)); }
.k-coffre__quoi { margin: 0; color: hsl(var(--texte-doux)); font-size: var(--t-sm); }

/* ── Kuaba Ensemble : le fil de partage ─────────────────────────────────────
   La SEULE section sombre de la page. Elle tranche avec ses deux voisines sans
   rien coûter — ni image, ni requête. */

.k-exclu--nuit { background: hsl(var(--nuit)); color: hsl(var(--blanc) / .92); }
.k-exclu--nuit h2, .k-exclu--nuit .k-exclu__moment { color: hsl(var(--blanc)); }
.k-exclu--nuit .k-oeil { color: hsl(var(--or)); }
.k-exclu--nuit .k-doux { color: hsl(var(--blanc) / .7); }
.k-exclu--nuit .k-exclu__moment em { color: hsl(var(--or)); }
@media (min-width: 900px) {
    /* 35 / 65 : le propos est court, la démonstration a besoin de place. */
    .k-exclu__grille--fil { grid-template-columns: .55fr 1fr; gap: var(--e-7); align-items: start; }
}

/* 🔴 UNE CARTE CLAIRE DANS UNE SECTION SOMBRE REPREND SES PROPRES COULEURS. Sans
   cela, le `.k-doux` de la section — blanc à 70 % pour le fond nuit — s'appliquait au
   texte posé sur la carte blanche : « sur 120 000 F CFA » était rendu en blanc sur
   blanc, donc invisible. Une couleur héritée d'un contexte qu'on a quitté est le
   défaut le plus discret d'une page à sections. */
.k-fil-part .k-doux { color: hsl(var(--texte-doux)); }

.k-fil-part {
    background: hsl(var(--blanc));
    border-radius: var(--rayon);
    padding: var(--e-5);
    color: hsl(var(--nuit));
    display: grid; gap: var(--e-4);
}
.k-fil-part__lien {
    display: flex; align-items: center; gap: var(--e-3); flex-wrap: wrap;
    margin: 0; padding: var(--e-3);
    background: hsl(var(--kaolin)); border-radius: var(--rayon-petit);
}
.k-fil-part__url {
    flex: 1 1 10rem; min-width: 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: var(--t-sm); color: hsl(var(--texte-doux));
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.k-btn--petit { padding: .35rem .9rem; min-height: 34px; font-size: var(--t-sm); }

.k-fil-part__fil { display: grid; gap: var(--e-3); }
.k-fil-part__bulle {
    display: grid; grid-template-columns: 1fr auto; gap: var(--e-1) var(--e-3);
    padding: var(--e-3) var(--e-4);
    background: hsl(var(--kaolin));
    border-radius: var(--rayon-petit);
    /* La forme d'un fil, jamais les couleurs d'une messagerie tierce. */
    border-left: 2px solid hsl(var(--lagune) / .35);
}
.k-fil-part__qui { margin: 0; font-weight: 600; font-size: var(--t-sm); }
.k-fil-part__ou {
    font-weight: 400; color: hsl(var(--texte-doux)); font-size: var(--t-xs);
    margin-left: var(--e-2);
}
.k-fil-part__texte { grid-column: 1; margin: 0; font-size: var(--t-sm); color: hsl(var(--texte-doux)); }
.k-fil-part__montant {
    grid-column: 2; grid-row: 1 / span 2; align-self: center;
    margin: 0; font-weight: 700; white-space: nowrap;
    font-variant-numeric: tabular-nums; color: hsl(var(--lagune-fonce)); font-size: var(--t-sm);
}
.k-fil-part__total { display: grid; gap: var(--e-2); padding-top: var(--e-3); border-top: 1px solid hsl(var(--ligne)); }
.k-fil-part__somme {
    margin: 0; font-family: var(--titre); font-size: var(--t-xl);
    font-variant-numeric: tabular-nums;
}
.k-fil-part__somme .k-doux { font-family: var(--corps); font-size: var(--t-sm); }
.k-fil-part__exemple { margin: 0; font-size: var(--t-xs); color: hsl(var(--texte-doux)); }

/* ── Kuaba Garantie : la chaîne de recours ──────────────────────────────────
   La section la PLUS aérée de la page : c'est ce qui la fait lire comme un
   engagement et non comme une promesse. Aucun mouvement. */

.k-recours { display: grid; gap: var(--e-7); }
.k-recours__temps { display: grid; gap: var(--e-6); }
@media (min-width: 780px) {
    .k-recours__temps { grid-template-columns: repeat(3, 1fr); gap: var(--e-7); }
}
.k-recours__temps-item { display: grid; gap: var(--e-2); align-content: start; }
.k-recours__rang {
    font-family: var(--titre); font-size: var(--t-lg); font-weight: 700;
    color: hsl(var(--or)); line-height: 1;
}
.k-recours__quand { margin: 0; font-family: var(--titre); font-size: var(--t-lg); }
.k-recours__quoi  { margin: 0; color: hsl(var(--texte-doux)); font-size: var(--t-sm); max-width: 34ch; }

.k-recours__delai {
    display: flex; align-items: baseline; gap: var(--e-4); flex-wrap: wrap;
    margin: 0; padding-top: var(--e-5); border-top: 1px solid hsl(var(--ligne));
}
.k-recours__heures {
    font-family: var(--titre);
    font-size: clamp(2.75rem, 1.8rem + 4vw, 4.5rem);
    line-height: 1; letter-spacing: -.03em; font-weight: 700;
    color: hsl(var(--or)); font-variant-numeric: tabular-nums;
}
.k-recours__engagement { color: hsl(var(--texte-doux)); max-width: 32ch; }

/* ── La comparaison ─────────────────────────────────────────────────────────
   ⚠️ Un mot, pas une coche : « oui » et « non » se lisent au lecteur d'écran,
   une icône verte ou rouge ne dit rien à qui ne distingue pas les deux. */

.k-comparaison th[scope="row"] { font-weight: 500; color: hsl(var(--nuit)); text-transform: none;
                                 letter-spacing: 0; font-size: var(--t-sm); }
.k-comparaison td { text-align: center; }
.k-comparaison__nous { background: hsl(var(--lagune) / .05); }
.k-comparaison th.k-comparaison__nous { color: hsl(var(--lagune-fonce)); }
.k-comparaison__oui    { font-weight: 700; color: hsl(var(--lagune)); }
.k-comparaison__non    { color: hsl(var(--texte-doux)); }
.k-comparaison__nuance { color: hsl(var(--texte-doux)); font-style: italic; }


/* 🔴 SUR UN TÉLÉPHONE, LE TABLEAU SE DÉPLIE. À 390 px, trois colonnes obligeaient à
   faire défiler pour atteindre la colonne Kuaba — c'est-à-dire la seule qu'on est venu
   lire. Chaque ligne devient un bloc : la question, puis les trois réponses étiquetées.
   Le `data-col` du gabarit redevient l'étiquette. */
@media (max-width: 779.98px) {
    .k-comparaison { min-width: 0; }
    .k-comparaison thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
    .k-comparaison tbody tr {
        display: grid; gap: var(--e-1);
        padding: var(--e-4) 0; border-top: 1px solid hsl(var(--ligne));
    }
    .k-comparaison th[scope="row"] {
        padding: 0 0 var(--e-2); font-weight: 600; font-size: var(--t-base);
    }
    .k-comparaison td {
        display: flex; justify-content: space-between; align-items: baseline; gap: var(--e-3);
        padding: .3rem 0; text-align: right; border: 0;
    }
    .k-comparaison td::before {
        content: attr(data-col);
        text-align: left; color: hsl(var(--texte-doux)); font-size: var(--t-sm);
    }
    /* La ligne Kuaba se distingue par un liseré, pas par un fond : un fond sur une
       ligne dépliée baverait sur toute la largeur de l'écran. */
    .k-comparaison td.k-comparaison__nous {
        background: none; border-left: 2px solid hsl(var(--lagune)); padding-left: var(--e-3);
    }
    .k-comparaison td.k-comparaison__nous::before { color: hsl(var(--lagune-fonce)); font-weight: 600; }
}


/* ── L'affirmation d'antériorité ────────────────────────────────────────────

   ⚠️ CE N'EST PAS UNE PASTILLE. Une pastille se lit comme un autocollant posé sur la
   page — et un autocollant, on n'y croit pas. C'est une ligne de texte, précédée d'un
   filet court, à la même hauteur que le propos qu'elle accompagne.

   ⚠️ Elle prend l'accent de SA section : l'Or dans Vérifié, la Lagune dans Coffre et
   Ensemble. Une couleur propre en ferait un cinquième élément de langage.            */

/* ⚠️ `p.k-premiere` ET NON `.k-premiere` : dans un `.k-titre-section`, la règle
   `.k-titre-section p` a une spécificité supérieure et repeignait l'affirmation en
   gris — la seule des trois qui perdait sa couleur, et rien ne le signalait. Le
   sélecteur d'élément rétablit l'égalité ; l'ordre du fichier fait le reste. */
p.k-premiere {
    display: flex; align-items: center; gap: var(--e-3);
    /* ⚠️ Une respiration au-dessus : collée au titre, elle se lisait comme sa
       quatrième ligne. Elle accompagne le propos, elle ne le prolonge pas. */
    margin: var(--e-3) 0 0;
    font-size: var(--t-sm); font-weight: 600;
    letter-spacing: .01em;
    color: hsl(var(--lagune-fonce));
}
p.k-premiere + p { margin-top: var(--e-3); }
.k-premiere__trait {
    flex: none; width: 2rem; height: 2px; border-radius: 1px;
    background: currentColor; opacity: .55;
}
/* Dans une section sombre, le contraste vient de l'Or, pas d'un vert qui s'éteint. */
.k-exclu--nuit .k-premiere { color: hsl(var(--or)); }
/* Dans la section Vérifié, l'accent est l'Or : l'affirmation le suit. */
#verifie .k-premiere { color: hsl(38 62% 34%); }

/* ═══════════════════════════════════════════════════════════════════════════
   MESSAGES DU SERVEUR
   🔴 Le socle n'avait aucune manière de dire non. Une action refusée revenait
   sur une page identique et silencieuse — le défaut se lit « rien ne se passe ».
   ⚠️ La couleur ne porte pas seule le sens : chaque message garde un liseré à
   gauche ET un fond, pour rester distinguable sans perception des couleurs.
   ═══════════════════════════════════════════════════════════════════════════ */
.k-messages { display: grid; gap: var(--e-2); margin-top: var(--e-5); }
.k-message {
    margin: 0;
    padding: var(--e-3) var(--e-4);
    border-radius: var(--rayon-petit, 8px);
    border-left: 4px solid;
    font-size: var(--t-sm);
}
.k-message--error   { background: hsl(var(--laterite) / .08); border-color: hsl(var(--laterite)); color: hsl(var(--laterite)); }
.k-message--success { background: hsl(var(--lagune) / .08);   border-color: hsl(var(--lagune));   color: hsl(var(--lagune-fonce)); }
.k-message--warning { background: hsl(var(--or) / .12);       border-color: hsl(var(--or));       color: hsl(var(--nuit)); }
.k-message--info    { background: hsl(var(--nuit) / .06);     border-color: hsl(var(--nuit));     color: hsl(var(--nuit)); }

/* ═══════════════════════════════════════════════════════════════════════════
   PASTILLES D'ÉTAT HÉRITÉES
   ⚠️ Les modèles de l'éditeur (`statusBadge`, `priorityBadge`) renvoient du HTML
   avec les classes Bootstrap `badge badge--*`. Les réécrire à la main dans
   chaque vue du socle aurait donné deux libellés d'état pour un même objet, et
   c'est le genre d'écart qui finit par se contredire. On habille les classes
   plutôt que de recopier les libellés.
   ═══════════════════════════════════════════════════════════════════════════ */
.badge {
    display: inline-block; padding: .15em .6em; border-radius: 999px;
    font-size: var(--t-xs); font-weight: 600; line-height: 1.6;
    background: hsl(var(--nuit) / .08); color: hsl(var(--nuit));
}
.badge--success { background: hsl(var(--lagune) / .10); color: hsl(var(--lagune-fonce)); }
.badge--primary { background: hsl(var(--nuit) / .08);   color: hsl(var(--nuit)); }
.badge--warning { background: hsl(var(--or) / .16);     color: hsl(var(--nuit)); }
.badge--danger  { background: hsl(var(--laterite) / .10); color: hsl(var(--laterite)); }
.badge--dark    { background: hsl(var(--nuit) / .12);   color: hsl(var(--nuit)); }

/* Coquille de compte servie à un visiteur : une seule colonne, pas de menu. */
.k-espace--seul { grid-template-columns: 1fr; }

/* ═══════════════════════════════════════════════════════════════════════════
   LE MODE DE RÉSERVATION, SUR LA FICHE
   🔑 Deux traitements distincts, parce que ce sont deux promesses distinctes :
   l'une est acquise, l'autre est une attente. Les habiller pareil laisserait
   croire à la première quand c'est la seconde.
   ═══════════════════════════════════════════════════════════════════════════ */
.k-mode-resa {
    display: grid; gap: .2rem;
    margin: var(--e-3) 0 0;
    padding: var(--e-2) var(--e-3);
    border-radius: var(--rayon-petit);
    font-size: var(--t-sm); font-weight: 600;
}
.k-mode-resa--instantane        { background: hsl(var(--lagune) / .08); color: hsl(var(--lagune-fonce)); }
.k-mode-resa--sous_confirmation { background: hsl(var(--or) / .12);     color: hsl(var(--nuit)); }
.k-mode-resa .k-xs { font-weight: 400; }

/* ═══════════════════════════════════════════════════════════════════════════
   LE DESCRIPTEUR DE CATÉGORIE — le premier des trois niveaux de l'ouverture
   🔑 Trois informations, trois niveaux : ce que c'est (ici), pourquoi eux
   (le titre), la preuve (l'accroche). Aucun ne répète l'autre.
   ⚠️ IL EST PLUS GRAND QUE `.k-oeil`, et en casse normale. L'œil est une
   étiquette de section, en capitales et très espacée : il se REGARDE, il ne
   se LIT pas. Le descripteur doit se lire d'un coup, c'est sa seule tâche —
   le composer comme un œil l'aurait rendu décoratif, donc sauté.
   ═══════════════════════════════════════════════════════════════════════════ */
.k-hero__descripteur {
    margin: 0 0 var(--e-3);
    font-family: var(--corps);
    font-size: var(--t-sm);
    font-weight: 500;
    line-height: 1.4;
    color: hsl(var(--texte-doux));
    /* Il ne se coupe pas en trois lignes sur mobile : au-delà, il cesse d'être
       lu d'un coup d'œil, ce qui est tout ce qu'on lui demande. */
    max-width: 34ch;
}
@media (min-width: 62em) {
    /* ⚠️ ASSEZ LARGE POUR TENIR SUR UNE LIGNE. À 44ch il se coupait avant
       « Côte d'Ivoire », et un descripteur en deux lignes cesse d'être lu d'un
       coup d'œil — ce qui est la seule chose qu'on lui demande. */
    .k-hero__descripteur { font-size: var(--t-base); max-width: 60ch; }
}

/* ───────────────────────────────────────────────────── 26. LE CONCIERGE

   Le seul élément flottant du site avec le bandeau de consentement. Il reste
   discret tant qu'on ne l'ouvre pas : un panneau qui s'impose sur une fiche de
   logement fait fuir la personne qu'il prétend aider.

   ⚠️ `.k-fil` existe déjà mais il est dessiné pour un fond SOMBRE — ses bulles
   utilisent `--blanc` avec de l'alpha. Le panneau du concierge est clair : il
   lui faut ses propres bulles, pas un remplacement du fil existant. */

.k-conc-ouvrir {
    position: fixed; right: var(--e-4); bottom: var(--e-4); z-index: 60;
    display: inline-flex; align-items: center; gap: var(--e-2);
    padding: var(--e-3) var(--e-4);
    border: 0; border-radius: 999px; cursor: pointer;
    background: hsl(var(--lagune)); color: hsl(var(--blanc));
    font-family: var(--corps); font-size: var(--t-sm); font-weight: 600;
    box-shadow: 0 6px 20px hsl(var(--nuit) / .22);
}
.k-conc-ouvrir:hover { background: hsl(var(--lagune-fonce)); }
.k-conc-ouvrir svg { width: 1.15em; height: 1.15em; flex: none; }

.k-conc {
    position: fixed; right: var(--e-4); bottom: var(--e-4); z-index: 61;
    width: min(24rem, calc(100vw - var(--e-4) * 2));
    max-height: min(34rem, calc(100vh - var(--e-4) * 2));
    display: flex; flex-direction: column;
    background: hsl(var(--blanc)); color: hsl(var(--texte));
    border: 1px solid hsl(var(--ligne)); border-radius: var(--rayon);
    box-shadow: 0 12px 40px hsl(var(--nuit) / .26);
    overflow: hidden;
}

.k-conc__entete {
    display: flex; align-items: center; justify-content: space-between; gap: var(--e-3);
    padding: var(--e-3) var(--e-4);
    background: hsl(var(--lagune)); color: hsl(var(--blanc));
}
.k-conc__titre { font-family: var(--titre); font-size: var(--t-base); margin: 0; }
.k-conc__sous  { font-size: var(--t-xs); opacity: .82; margin: 0; }
.k-conc__fermer {
    background: none; border: 0; cursor: pointer; padding: var(--e-1);
    color: inherit; font-size: 1.3rem; line-height: 1;
}

.k-conc__fil {
    flex: 1; min-height: 8rem; overflow-y: auto;
    padding: var(--e-4); display: grid; gap: var(--e-3); align-content: start;
}
.k-conc__bulle {
    max-width: 88%; padding: var(--e-3) var(--e-4);
    border-radius: var(--rayon); font-size: var(--t-sm); line-height: 1.55;
}
.k-conc__bulle--lui {
    background: hsl(var(--kaolin)); color: hsl(var(--nuit));
    border-bottom-left-radius: var(--rayon-petit);
}
.k-conc__bulle--moi {
    background: hsl(var(--lagune)); color: hsl(var(--blanc));
    margin-left: auto; border-bottom-right-radius: var(--rayon-petit);
}
/* Une réponse qui passe la main se distingue : elle n'est pas une réponse. */
.k-conc__bulle--main {
    background: hsl(var(--kaolin)); color: hsl(var(--nuit));
    border-left: 3px solid hsl(var(--or));
    border-bottom-left-radius: var(--rayon-petit);
}
.k-conc__source {
    font-size: var(--t-xs); color: hsl(var(--texte-doux)); margin-top: var(--e-1);
}

.k-conc__pistes { display: flex; flex-wrap: wrap; gap: var(--e-2); padding: 0 var(--e-4) var(--e-3); }
.k-conc__piste {
    border: 1px solid hsl(var(--ligne)); background: hsl(var(--blanc));
    color: hsl(var(--lagune)); cursor: pointer;
    border-radius: 999px; padding: .3rem .7rem;
    font-family: var(--corps); font-size: var(--t-xs); text-align: left;
}
.k-conc__piste:hover { border-color: hsl(var(--lagune)); background: hsl(var(--kaolin)); }

.k-conc__saisie {
    display: flex; gap: var(--e-2); padding: var(--e-3) var(--e-4);
    border-top: 1px solid hsl(var(--ligne));
}
.k-conc__saisie input {
    flex: 1; min-width: 0; font-family: var(--corps); font-size: var(--t-sm);
    padding: var(--e-2) var(--e-3);
    border: 1px solid hsl(var(--ligne)); border-radius: var(--rayon-petit);
    background: hsl(var(--blanc)); color: hsl(var(--texte));
}
.k-conc__saisie input:focus-visible { outline: 2px solid hsl(var(--lagune)); outline-offset: 1px; }
.k-conc__saisie button {
    border: 0; border-radius: var(--rayon-petit); cursor: pointer;
    background: hsl(var(--lagune)); color: hsl(var(--blanc));
    padding: var(--e-2) var(--e-4); font-family: var(--corps); font-weight: 600; font-size: var(--t-sm);
}
.k-conc__saisie button[disabled] { opacity: .55; cursor: default; }

/* Les trois points d'attente. Discrets : ce n'est pas un spectacle. */
.k-conc__attente span {
    display: inline-block; width: .4em; height: .4em; margin-right: .18em;
    border-radius: 50%; background: hsl(var(--texte-doux));
    animation: k-conc-pulse 1.1s infinite;
}
.k-conc__attente span:nth-child(2) { animation-delay: .16s; }
.k-conc__attente span:nth-child(3) { animation-delay: .32s; }
@keyframes k-conc-pulse { 0%, 60%, 100% { opacity: .25; } 30% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
    .k-conc__attente span { animation: none; opacity: .55; }
}

/* ─────────────────────────────────────────────────── LA COUCHE DÉCOUVERTE

   🔑 TROIS RÈGLES, PAS UN COMPOSANT DE PLUS. La carte de lieu réutilise
   `.k-carte` ; il ne reste ici que ce qu'elle ajoute — l'image en tête, la
   liste de faits, et la ligne d'origine. Un composant complet aurait dupliqué
   bordures, rayons et ombres, qui auraient divergé à la première retouche.

   ⚠️ AUCUNE COULEUR EN DUR : tout passe par les jetons, comme le reste de la
   feuille. `deploy/verifier-budget-public.php` refuse le contraire.            */

.k-carte-lieu { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.k-carte-lieu img { width: 100%; height: auto; display: block; object-fit: cover; aspect-ratio: 4 / 3; }
.k-carte-lieu__corps { padding: var(--e-4); display: flex; flex-direction: column; gap: var(--e-2); }
.k-carte-lieu__corps h3 { margin: 0; font-size: var(--t-lg); }
.k-carte-lieu__corps p  { margin: 0; }

/* La ligne d'origine : le badge et sa date se lisent d'un seul tenant. */
.k-lieu-origine { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-2); font-size: var(--t-sm); }

/* Les faits datés d'une fiche. Chaque ligne existe ou n'existe pas ; aucune
   n'est remplie par défaut, donc aucune ne doit réserver de place vide. */
.k-faits { display: grid; gap: var(--e-3); margin: 0; }
.k-faits dt { font-weight: 600; color: hsl(var(--nuit)); }
.k-faits dd { margin: 0; color: hsl(var(--texte)); }
.k-faits dd .k-doux { display: block; font-size: var(--t-sm); }

@media (min-width: 40rem) {
    .k-faits { grid-template-columns: 14rem 1fr; align-items: baseline; }
    .k-faits dt { grid-column: 1; }
    .k-faits dd { grid-column: 2; }
}

/* Le visuel de remplacement : deux aplats de la charte, aucune image.
   🔴 Il ne représente rien. Une photo générique légendée du nom d'un lieu serait
   une fausse information — et c'est la seule promesse que Kuaba fasse. */
.k-image-absente {
    aspect-ratio: 4 / 3;
    display: grid;
    place-items: center;
    background: linear-gradient(135deg, hsl(var(--lagune) / .10), hsl(var(--kaolin)));
    border-bottom: 1px solid hsl(var(--ligne));
}
.k-image-absente span {
    font-family: var(--titre);
    font-size: clamp(2rem, 8vw, 3.5rem);
    font-weight: 600;
    color: hsl(var(--lagune) / .35);
    line-height: 1;
}
