/*
 * Styles autonomes du plugin MS Groupe Occasions (préfixe .msg- partout).
 * Aucun framework : le thème charge Tailwind en CDN (cf. CLAUDE.md), ce CSS
 * doit rester indépendant de ça. Enqueue conditionnel : uniquement quand
 * [msg_occasions] est effectivement rendu (ListingShortcode::render()).
 */

/* === Listing [msg_occasions] ============================================ */

/* Le shortcode posé dans une PAGE du thème (BMW, MINI, Toutes nos occasions…)
   est rendu HORS du conteneur du thème : `page.php` n'enveloppe que le bandeau
   dans `.max-website.p-6` et sort the_content() à pleine largeur. Le legacy
   argus posait lui-même `max-website` dans son balisage ; sans équivalent, le
   catalogue collait aux bords de l'écran (relevé sur la démo le 2026-10-08).
   On reproduit donc `.max-website.p-6` (1440 px centrés, 1,5 rem de gouttière)
   pour s'aligner sur le bandeau — sauf là où le plugin fournit déjà le
   conteneur : l'archive (`.max-website.msg-archive`) et la fiche
   (`.max-website.msg-single`). D'où `:not(.max-website *)`, et non un test
   sur .msg-archive seul, qui avait décalé de 24 px la ligne LOM des fiches. */
.msg-listing:not(.max-website *) {
    box-sizing: border-box;
    max-width: 1440px;
    margin-inline: auto;
    padding-inline: 1.5rem;
}

/* La ligne LOM porte un filet supérieur : une gouttière INTÉRIEURE le laisserait
   courir d'un bord à l'autre de l'écran. Elle est donc rétrécie de l'extérieur,
   pour que le filet commence et finisse avec le bandeau et le catalogue. */
/* Même cas pour l'encart des mentions complètes, rendu par archive-listing.php
   APRÈS .msg-listing, au premier niveau du contenu de page : sur les pages de
   marque il partait d'un bord à l'autre de l'écran, fond et cadre compris
   (relevé par Fred le 2026-10-08). Il porte un cadre et un fond : rétréci de
   l'extérieur, comme la ligne LOM. La modale (`<dialog>`, hors conteneur elle
   aussi) a son propre gabarit et n'est pas concernée. */
.msg-legal--full:not(.max-website *):not(dialog *),
.msg-mobility:not(.max-website *) {
    box-sizing: border-box;
    width: calc(100% - 3rem);
    max-width: calc(1440px - 3rem);
    margin-inline: auto;
}

.msg-listing__empty {
    padding: 2rem 0;
    text-align: center;
    color: #4b5563;
}

.msg-listing__grid {
    display: grid;
    grid-template-columns: repeat(1, 1fr);
    gap: 1.5rem;
}

@media (min-width: 640px) {
    .msg-listing__grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 900px) {
    .msg-listing__grid {
        grid-template-columns: repeat(3, 1fr);
    }
}

@media (min-width: 1200px) {
    .msg-listing__grid {
        grid-template-columns: repeat(4, 1fr);
    }
}

/* `position: relative` : bloc contenant du pseudo-élément du LIEN ÉTIRÉ
   ci-dessous — sans lui, `inset: 0` se résoudrait sur le bloc englobant le
   plus proche (la grille, voire le viewport) et la zone cliquable déborderait
   de la carte. */
.msg-card {
    position: relative;
    background: #ffffff;
    border-radius: 0.5rem;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
    overflow: hidden;
    transition: box-shadow 0.15s ease-in-out;
}

.msg-card:hover {
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06);
}

.msg-card__link {
    display: block;
    color: inherit;
    text-decoration: none;
}

/*
 * ⚠ LIEN ÉTIRÉ. L'ancre n'entoure plus que le titre du véhicule
 * (templates/parts/vehicle-card.php) ; ce pseudo-élément lui rend la surface
 * cliquable de la carte entière.
 *
 * Pourquoi l'ancre a été resserrée : le modèle de contenu HTML interdit un
 * descendant interactif dans un `<a>` — le lien « ⓘ » des mentions du
 * financement ne pouvait donc pas exister à l'intérieur — et un lecteur
 * d'écran annonçait un lien unique avalant image, badges, prix, mensualité et
 * spécifications, là où il annonce désormais le nom du véhicule.
 *
 * Tout contrôle qui doit rester cliquable par-dessus cette surface se pose en
 * `position: relative; z-index: 1` (cf. .msg-card__legal-toggle).
 */
.msg-card__link::after {
    content: "";
    position: absolute;
    inset: 0;
}

/* Le contour de focus ne porte plus que sur le titre : sans cette règle, il
   dépendrait du style par défaut du navigateur, variable et parfois invisible
   sur fond blanc. Même traitement que les liens de mentions légales. */
.msg-card__link:focus-visible {
    outline: 2px solid #1D1D77;
    outline-offset: 2px;
}

.msg-card__img,
.msg-card__noimg {
    position: relative;
    width: 100%;
    aspect-ratio: 4 / 3;
    background: #e5e7eb;
}

/* Task 15 : PhotoResolver::mainImageHtml() ne pose plus de classe dédiée sur
   l'<img> (ni en mode local — get_the_post_thumbnail() sans attribut `class`
   — ni en mode remote depuis la revue qualité T15+T16) — ce sélecteur
   descendant couvre les deux modes (classes par défaut de WP en local :
   wp-post-image, attachment-*, size-*) sans avoir à les connaître. */
.msg-card__img img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.msg-card__body {
    padding: 1rem;
}

.msg-card__title {
    margin: 0 0 0.5rem;
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.3;
}

.msg-card__price {
    margin: 0 0 0.5rem;
    font-size: 1.125rem;
    font-weight: 700;
}

.msg-card__specs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.875rem;
    color: #4b5563;
}

.msg-card__spec:not(:last-child)::after {
    content: '\2022';
    margin-left: 0.5rem;
}

/* === Bloc financement de la carte (« Guide des mentions » BNP V1.1, p. 3) ==
   Mensualité, mentions ESSENTIELLES (TAEG, sa nature « fixe », montant total
   dû) et autres caractéristiques (produit, durée, apport), dans un même champ
   visuel — un renvoi par astérisque vers un pied de page n'y satisfait pas.
   Rendu par templates/parts/vehicle-card.php, et seulement quand
   VehicleFinancingFacts::forPost() rend un objet. */

/*
 * ⚠ HAUTEUR RÉSERVÉE, et ce n'est pas du confort : trois lignes, toujours, quel
 * que soit le contenu. Les libellés varient d'une carte à l'autre (un nom de
 * produit vide, un apport à 0, un montant qui passe à la ligne) ; sans plancher,
 * deux cartes voisines d'une même rangée n'auraient pas la même hauteur de bloc
 * et la grille serait en escalier.
 *
 * ⚠ CE PLANCHER NE PROTÈGE PAS DE L'INSERTION PAR teaser-live.js, et il ne le
 * peut pas : il vit sur `.msg-card__financing`, donc sur les cartes qui ont
 * DÉJÀ leur bloc. Une carte muette n'a aucun conteneur — « aucun montant sans
 * ses mentions » interdit le conteneur vide qui aurait pu garder la place en
 * amont. L'insertion décale donc bien la rangée de grille, ce que
 * `assets/js/teaser-live.js` assume explicitement : une carte à la fois, à
 * plusieurs secondes d'intervalle, ce que la file séquentielle étale d'elle-même.
 *
 * Interligne ABSOLU (--msg-card-financing-line), même raison que
 * .msg-legal--full plus bas : les trois lignes n'ont délibérément pas la même
 * taille de caractère, et un interligne relatif leur donnerait trois hauteurs
 * différentes — la somme réservée ci-dessous ne vaudrait alors plus rien.
 */
.msg-card__financing {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    margin: 0 0 0.75rem;
    min-height: calc(var(--msg-card-financing-line) * 3 + 0.5rem);

    /*
     * ⚠ UN ENCART, ET C'EST UNE EXIGENCE DU GUIDE AVANT D'ÊTRE UNE MAQUETTE. Le
     * « Guide des mentions » BNP (p. 3) veut les mentions essentielles « dans le
     * même champ visuel que la mensualité ». Empilées sans contenant, elles se
     * lisaient comme trois lignes indépendantes posées entre le prix et les
     * caractéristiques — rien ne disait que le TAEG et le montant total dû
     * DÉCRIVENT le montant du dessus. Le filet et le fond les réunissent en un
     * seul objet.
     *
     * ⚠ `box-sizing` LAISSÉ EN `content-box` (le défaut : la feuille ne pose
     * `border-box` que sur deux règles nommées). La hauteur RÉSERVÉE ci-dessus
     * vaut donc toujours exactement trois lignes de contenu, et le rembourrage
     * s'ajoute par-dessus au lieu de les rogner. Passer ce bloc en `border-box`
     * sans reprendre le `calc()` remettrait la grille en escalier — le défaut que
     * ce plancher existe pour empêcher.
     */
    padding: 0.5rem 0.625rem;
    border-left: 3px solid var(--color_primary, #1D1D77);
    border-radius: 0 0.375rem 0.375rem 0;
    background: #f4f5fb;
}

.msg-card__monthly {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    margin: 0;
    min-height: var(--msg-card-financing-line);
}

/* ⚠ La mensualité EST une mention essentielle : elle prend ici la taille
   normative (--msg-legal-essential), et non les 13 px de la règle `.msg-teaser`
   générique.
   ⚠ CETTE RÈGLE NE SERT PLUS SEULEMENT LES CARTES. L'accroche de la barre
   latérale de fiche est elle aussi enveloppée dans `.msg-card__monthly`
   (templates/single-msg_vehicule.php) : elle passe donc de 13 px à la taille
   essentielle — CHANGEMENT VISUEL ASSUMÉ, à vérifier en recette (§P13). Le
   sélecteur `.msg-sidebar__price-block .msg-teaser` (plus bas) ne le contredit
   pas : il ne porte qu'une marge.
   Le padding vertical passe à 0 : la hauteur du badge vient de l'interligne
   absolu, sinon elle dépasserait la hauteur réservée. */
.msg-card__monthly .msg-teaser {
    margin: 0;
    padding: 0 0.5rem;
    font-size: var(--msg-legal-essential);
    line-height: var(--msg-card-financing-line);
}

/*
 * ⚠ AU-DESSUS DU LIEN ÉTIRÉ. Sans `position: relative; z-index: 1`, le
 * pseudo-élément de .msg-card__link recouvrirait ce lien et le clic ouvrirait
 * la fiche au lieu des mentions.
 *
 * `min-width` : cible de pointage d'au moins 24 × 24 px (WCAG 2.2, 2.5.8) —
 * le glyphe seul n'en fait que ~16 de large.
 */
.msg-card__legal-toggle {
    position: relative;
    z-index: 1;
    flex: none;
    min-width: var(--msg-card-financing-line);
    font-size: var(--msg-legal-essential);
    line-height: var(--msg-card-financing-line);
    color: #1d4ed8;
    text-align: center;
    text-decoration: none;

    /*
     * Pastille ronde : le glyphe nu se confondait avec la ponctuation de la ligne
     * voisine. `inline-flex` + dimensions explicites parce que la cible de
     * pointage de 24 px (WCAG 2.2, 2.5.8) était portée par un `line-height` — or
     * un fond d'élément en ligne se peint sur la boîte de contenu, pas sur la
     * boîte de ligne : la pastille aurait été plus petite que la cible qu'elle
     * est censée montrer.
     */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--msg-card-financing-line);
    height: var(--msg-card-financing-line);
    border-radius: 50%;
    background: rgba(29, 78, 216, 0.09);
}

.msg-card__legal-toggle:hover {
    background: rgba(29, 78, 216, 0.18);
}

/*
 * ⚠ LE ⓘ DU SIMULATEUR EST UN `<button>`, ET LE THÈME LE REPREND ENTIÈREMENT.
 *
 * Les trois producteurs de ce balisage doivent rester IDENTIQUES (cf. « Mentions
 * par véhicule » du CLAUDE.md) : les cartes et la barre latérale rendent un `<a>`,
 * le simulateur un vrai `<button>` — il naît d'un résultat que seul JavaScript
 * produit et n'a aucune destination à offrir. Or `body.aladin .loop main button`
 * (0,2,3) impose à tout bouton de la boucle 48 px de haut, le bleu plein du thème,
 * « good-times » en capitales et 12 px. Mesuré : 34 × 48 px en bleu plein d'un
 * côté, 24 × 24 px en pastille claire de l'autre — le MÊME ⓘ, deux objets
 * différents selon l'endroit de la page.
 *
 * ⚠ `!important` CIBLÉ, et sur cette seule classe : la teinte que le thème impose
 * aux boutons du plugin reste un arbitrage produit assumé partout ailleurs (cf.
 * « Front vs thème parent »). Ce qui est corrigé ici n'est pas cette teinte, c'est
 * la DIVERGENCE entre deux rendus du même élément.
 */
button.msg-card__legal-toggle {
    width: var(--msg-card-financing-line) !important;
    height: var(--msg-card-financing-line) !important;
    min-width: var(--msg-card-financing-line) !important;
    min-height: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    border-radius: 50% !important;
    background: rgba(29, 78, 216, 0.09) !important;
    color: #1d4ed8 !important;
    font-family: inherit !important;
    font-size: var(--msg-legal-essential) !important;
    font-weight: 400 !important;
    letter-spacing: 0 !important;
    text-transform: none !important;
    cursor: pointer;
}

button.msg-card__legal-toggle:hover {
    background: rgba(29, 78, 216, 0.18) !important;
}

.msg-card__legal-toggle:focus-visible {
    outline: 2px solid #1D1D77;
    outline-offset: 2px;
}

.msg-card__financing-other,
.msg-card__financing-essential {
    display: flex;
    flex-wrap: wrap;
    gap: 0 0.375rem;
    margin: 0;
    padding: 0;
    list-style: none;
    line-height: var(--msg-card-financing-line);
}

/* « autres caractéristiques du financement » : produit, durée, apport. */
.msg-card__financing-other {
    font-size: var(--msg-legal-other);
    color: #4b5563;
}

/* ⚠ TAILLE NORMATIVE : les mentions essentielles doivent figurer « dans une
   taille de caractère nettement supérieure à celle utilisée pour les autres
   caractéristiques du financement ». C'est l'ÉCART qui est exigé — ne jamais
   descendre cette ligne à --msg-legal-other, ni monter la précédente à
   --msg-legal-essential. */
.msg-card__financing-essential {
    font-size: var(--msg-legal-essential);
    font-weight: 600;
    /*
     * Bleu de marque plutôt que le quasi-noir : sur le fond clair de l'encart, il
     * rattache la ligne au filet qui la borde et cesse de disputer l'attention au
     * PRIX, qui est juste au-dessus et qui, lui, n'appartient pas au financement.
     * Mesuré : 12,9:1 sur #f4f5fb, très au-delà du seuil AA.
     *
     * ⚠ La TAILLE ne bouge pas : c'est l'écart avec `--msg-legal-other` de la
     * ligne précédente qui est normatif, pas la couleur.
     */
    color: var(--color_primary, #1D1D77);
}

/* Séparateur « · » en contenu généré, même idiome que .msg-card__spec : il
   reste une affaire de présentation et ne traîne pas dans le balisage. */
.msg-card__financing-item:not(:last-child)::after {
    content: '\00B7';
    margin-left: 0.375rem;
}

.msg-listing__pagination {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: center;
    margin-top: 2rem;
}

.msg-listing__pagination a,
.msg-listing__pagination span {
    padding: 0.375rem 0.75rem;
    border-radius: 0.375rem;
    border: 1px solid #6b7280;
    color: #111827;
    text-decoration: none;
    font-size: 0.875rem;
}

.msg-listing__pagination .current {
    background: #111827;
    border-color: #111827;
    color: #ffffff;
}

/* === Accroche mensualité (Financing\TeaserBadge, Task 10) =============== */

.msg-teaser {
    display: inline-block;
    margin: 0 0 0.5rem;
    padding: 0.125rem 0.5rem;
    border-radius: 0.25rem;
    background: #eff6ff;
    color: #1d4ed8;
    font-size: 0.8125rem;
    font-weight: 600;
}

.msg-teaser sup {
    font-weight: 400;
}

/* === Archive native /occasions/ (templates/archive-msg_vehicule.php) ==== */

.msg-archive {
    max-width: 1200px;
    margin: 0 auto;
    padding: 2rem 1rem;
}

/* Markup natif de the_posts_pagination() : <nav class="pagination"> +
   <span/a class="page-numbers"> (dont ".current" sur la page active) —
   styles alignés sur .msg-listing__pagination ci-dessus. */
.msg-archive .pagination {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: center;
    margin-top: 2rem;
}

.msg-archive .pagination .page-numbers {
    padding: 0.375rem 0.75rem;
    border-radius: 0.375rem;
    border: 1px solid #6b7280;
    color: #111827;
    text-decoration: none;
    font-size: 0.875rem;
}

.msg-archive .pagination .page-numbers.current {
    background: #111827;
    border-color: #111827;
    color: #ffffff;
}

/* === Fiche véhicule (templates/single-msg_vehicule.php) ================= */

.msg-single {
    max-width: 1200px;
    margin: 0 auto;
    padding: 2rem 1rem;
}

.msg-single__price {
    margin: 1rem 0 0.5rem;
    font-size: 1.5rem;
    font-weight: 700;
}

/* === Mentions légales crédit (Financing\LegalNotices, 3.0.0) ============ */

/*
 * ⚠ Deux tailles NORMATIVES, pas décoratives (« Guide des mentions » BNP V1.1,
 * p. 3) : les mentions essentielles doivent figurer « dans une taille de
 * caractère nettement supérieure à celle utilisée pour les autres
 * caractéristiques du financement », et la mention pédagogique « un pixel de
 * plus que l'affichage des mentions essentielles ».
 *
 * D'où une variable DÉRIVÉE de l'autre plutôt que deux valeurs indépendantes
 * qu'une retouche désynchroniserait — l'écart d'un pixel est la règle, pas une
 * coïncidence de maquette.
 */
:root {
    /*
     * ⚠ CE QUI EST NORMATIF ICI, C'EST L'ÉCART, PAS LA VALEUR.
     *
     * Le guide des mentions ne fixe AUCUNE taille absolue. Il impose deux
     * relations : les mentions essentielles dans « une taille de caractère
     * nettement supérieure à celle utilisée pour les autres caractéristiques du
     * financement », et la mention pédagogique « un pixel de plus que
     * l'affichage des mentions essentielles ». Un commentaire antérieur
     * présentait 16 px comme un plancher réglementaire : c'était faux, et le
     * corriger évite qu'on refuse un jour d'ajuster la maquette pour une raison
     * qui n'existe pas.
     *
     * 16 px reste le choix retenu, pour une raison précise : c'est la valeur que
     * BNP applique elle-même, en style inline, aux fragments essentiels de SON
     * bloc de mentions (TAEG, durée, mensualité, montant total dû). S'aligner
     * dessus est ce qui empêche les deux blocs de se contredire visuellement.
     *
     * `max(16px, 1rem)` plutôt que `16px` : la valeur suit la préférence de
     * taille de police de l'utilisateur au-delà. Sinon, chez quelqu'un qui règle
     * son navigateur à 20 px, le texte environnant (en rem) grandit tandis que
     * les mentions restent figées — elles deviennent RELATIVEMENT plus petites
     * que les autres caractéristiques, ce qui attaque l'exigence d'écart.
     */
    --msg-legal-essential: max(16px, 1rem);
    --msg-legal-pedago: calc(var(--msg-legal-essential) + 1px);

    /*
     * Dérivée VERS LE BAS, même logique que --msg-legal-pedago vers le haut :
     * « taille de caractère nettement supérieure à celle utilisée pour les
     * autres caractéristiques du financement ». 3 px d'écart et non 2 —
     * « nettement » ne se plaide pas à un point.
     *
     * ⚠ TOUTE caractéristique du financement affichée HORS du tableau BNP
     * (montants d'assurance, valeurs des curseurs) prend cette taille et ne
     * doit jamais la dépasser.
     */
    --msg-legal-other: calc(var(--msg-legal-essential) - 3px);

    /*
     * Interligne du bloc financement de carte (.msg-card__financing) : ABSOLU,
     * pour que les trois lignes aient la même hauteur malgré leurs deux tailles
     * de caractère — c'est ce qui rend la hauteur du bloc calculable, donc
     * réservable. Déclaré ici, avec les deux tailles dont il dérive, plutôt que
     * sur le bloc lui-même : ses descendants le liraient alors sans repli hors
     * de ce contexte.
     */
    --msg-card-financing-line: calc(var(--msg-legal-essential) * 1.5);
}

/*
 * 13 px / #4b5563 et non 12 px / #6b7280 : l'ancien couple donnait 4,62:1 sur
 * le fond gris du bloc, soit 0,12 de marge au-dessus du seuil AA de 4,5:1 —
 * le moindre changement de fond dans le thème parent faisait basculer en
 * non-conformité. #4b5563 monte à 7,2:1. Aucune contrainte réglementaire
 * n'impose 12 px ici : le plancher de 16 px porte sur les mentions
 * ESSENTIELLES, servies par --msg-legal-essential.
 */
.msg-legal {
    margin: 0.5rem 0 1.5rem;
    font-size: 0.8125rem;
    line-height: 1.6;
    color: #4b5563;
}

/* Visible sans scroller : elle est rendue par le bandeau collant de tête
   (templates/parts/legal-pedago-banner.php) sur le listing, l'archive ET la
   fiche, plus dans la modale des mentions. ⚠ Elle n'est PLUS en tête de
   sidebar : le CSS y empilait la colonne latérale sous toute la page en
   dessous de 1024 px, donc sous plusieurs mensualités — « sans avoir à cliquer
   ou à scroller » n'y était pas tenu. */
.msg-legal--pedago {
    margin: 0 0 0.75rem;
    font-size: var(--msg-legal-pedago);
    font-weight: 600;
    line-height: 1.35;
    color: #111827;
}

/*
 * ⚠ LE BLOC `MENT_PEDAGO` EST UN FRAGMENT, PAS UNE PHRASE : BNP l'envoie sous la
 * forme `<div><p>Un crédit vous engage…</p></div>`. La taille réglementaire posée
 * sur `.msg-legal--pedago` ne descendait donc pas jusqu'au texte — le thème parent
 * sert ses propres valeurs à tout `<p>` (`font: 0.9em`, `font-weight: lighter`,
 * mesuré à 18 px / 100 le 2026-09-18), avec une spécificité (0,2,2) qui bat la
 * (0,1,0) de la règle ci-dessus.
 *
 * `!important` CIBLÉ, même discipline que les boutons du plugin (cf. la section
 * « Front vs thème parent » du CLAUDE.md) : deux propriétés, sur les seuls
 * descendants du bandeau.
 *
 * ⚠ `:not([style*="font-size"])` / `:not([style*="font-weight"])` — LA MÊME
 * PRÉCAUTION QUE `.msg-legal--full [style*="font-size"]`, et pour la même raison.
 * BNP porte l'exigence de taille de caractère dans des styles INLINE que
 * l'assainisseur conserve exprès. `MENT_PEDAGO` n'en porte aucun aujourd'hui,
 * mais un `!important` sans cette réserve écraserait silencieusement ceux qu'un
 * bloc futur apporterait — et c'est précisément la conformité qu'il détruirait.
 */
.msg-legal--pedago :is(p, div, span):not([style*="font-size"]) {
    font-size: inherit !important;
}

.msg-legal--pedago :is(p, div, span):not([style*="font-weight"]) {
    font-weight: inherit !important;
}

/* Le fragment de BNP apporte les marges par défaut de son `<p>` : la hauteur du
   bandeau est portée par son propre `padding`, pas par celles-ci. */
.msg-legal--pedago :is(p, div) {
    margin: 0;
    color: inherit;
    line-height: inherit;
}

/*
 * ⚠ INTERLIGNE ABSOLU, et c'est tout le point de cette règle.
 *
 * BNP place SIX fragments en `font-size: 16px` inline au milieu de ce bloc —
 * le TAEG, la durée, la mensualité, le montant total dû, la date de validité.
 * Ce sont les mentions essentielles À L'INTÉRIEUR de l'exemple représentatif :
 * la banque applique elle-même la règle d'écart de taille dans son HTML, et il
 * n'est pas question de les neutraliser.
 *
 * Avec un `line-height` RELATIF, chaque ligne contenant un de ces fragments
 * devient plus haute que ses voisines : le paragraphe part en escalier et donne
 * l'impression de tailles « extrêmement différentes » dans un même bloc.
 * Signalé en relecture visuelle le 2026-09-09.
 *
 * Un interligne en unité ABSOLUE rend toutes les lignes identiques quelle que
 * soit la taille du texte qu'elles contiennent : l'emphase de BNP redevient une
 * emphase, et non une rupture de rythme. 24 px accommode le plus grand fragment
 * (16 px) sans serrer le corps de base.
 *
 * La base passe de 12 à 13 px : à 12 px le saut vers les 16 px de BNP faisait
 * 33 %. Et #4b5563 plutôt que #6b7280, qui ne tenait le seuil de contraste AA
 * qu'à 0,12 près sur ce fond.
 */
.msg-legal--full {
    font-size: 0.8125rem;
    line-height: 24px;
    color: #4b5563;

    /*
     * ⚠ UN ENCART, PAS UN MUR. Le bloc fait 5,4 Ko de texte assaini : posé à nu
     * en pied de page, il se lisait comme la fin de la page plutôt que comme un
     * document à part. Le cadre, le fond et le rembourrage en font un objet
     * délimité, et c'est la condition pour que le filet de séparation de la ligne
     * de mobilité, juste en dessous, veuille encore dire quelque chose : on ne
     * distingue pas deux choses dont l'une n'a pas de bord.
     */
    padding: 1.25rem 1.5rem;
    border: 1px solid #e3e6ef;
    border-radius: 0.5rem;
    background: #f8f9fb;
}

/*
 * ⚠ LE BLOC DE LA MODALE NE REPREND PAS LE CADRE. Il partage `.msg-legal--full`
 * avec les pieds de page, mais il est DÉJÀ dans un `<dialog>` encadré : un encart
 * dans un encart, avec son propre titre au-dessus du titre de la modale.
 */
.msg-legal-dialog .msg-legal--full {
    padding: 0;
    border: 0;
    background: none;
}

/*
 * Intitulé de section. ⚠ `!important` CIBLÉ, même discipline que les boutons du
 * plugin (cf. « Front vs thème parent » du CLAUDE.md) : le thème parent gonfle
 * les titres de bloc du plugin jusqu'à ~40 px en capitales « good-times », ce qui
 * est son identité et reste assumé ailleurs — mais pas au-dessus d'un bloc de
 * mentions à 13 px, où le titre pèserait trois fois le texte qu'il annonce.
 *
 * ⚠ Ce titre est le SEUL texte du bloc qui nous appartienne. Tout ce qui suit
 * vient de l'API et n'est jamais réécrit.
 */
.msg-legal__heading {
    margin: 0 0 0.75rem !important;
    font-size: 1rem !important;
    font-weight: 700 !important;
    line-height: 1.4 !important;
    letter-spacing: 0 !important;
    text-transform: none !important;
    color: var(--color_primary, #1D1D77) !important;
}

/* Les paragraphes du bloc de BNP arrivent collés les uns aux autres : sans
   respiration, l'exemple représentatif, les assurances, les bornes et les
   mentions du financeur forment un seul pavé. */
.msg-legal--full p {
    margin: 0 0 0.75rem;
}

.msg-legal--full p:last-child {
    margin-bottom: 0;
}

/*
 * ⚠ GRAISSE NORMALE RÉTABLIE SUR LES SEULS PARAGRAPHES, et cette restriction est
 * tout le soin de la règle.
 *
 * Le thème parent applique `font-weight: lighter` à tout `<p>` de la boucle, en
 * (0,2,2) : mesuré au navigateur, les mentions du financeur et la date de
 * validité de l'offre — un fragment que BNP met pourtant à 16 px — s'affichaient
 * en graisse 100, filiformes sur un fond gris.
 *
 * ⚠ LE SÉLECTEUR S'ARRÊTE À `p`. Le réflexe serait d'ajouter `span`, et ce serait
 * un défaut de conformité : BNP emboîte des `<span>` NUS dans des `<span>` qu'elle
 * met en gras — `<span style='font-weight: bold'>… <span>5,68</span> %</span>`.
 * Une règle atteignant les spans sans style inline ramènerait l'enfant à 400 au
 * milieu d'une mention essentielle mise en avant par la banque. Les `<p>`, eux, ne
 * peuvent par construction être imbriqués dans aucun fragment en gras.
 *
 * `:not([style*="font-weight"])` : même réserve que partout ailleurs — on ne
 * touche jamais à ce que BNP a décidé elle-même.
 */
.msg-legal--full p:not([style*="font-weight"]) {
    font-weight: 400 !important;
}

/*
 * L'exemple représentatif du pied de LISTING est calculé sur UN véhicule de la
 * page, nommé ici. Sans relief, cette phrase se confondait avec les mentions
 * qu'elle qualifie — or c'est elle qui empêche le visiteur de rattacher le
 * montant à n'importe laquelle des douze cartes.
 *
 * ⚠ `p.msg-legal__scope` et non `.msg-legal__scope` seul : il faut (0,2,1) pour
 * passer devant la règle de graisse ci-dessus, qui vient d'être posée en
 * `!important` sur tous les paragraphes du bloc. Ce libellé est le nôtre, pas
 * celui de BNP — le mettre en avant ne touche à aucune mention reçue.
 */
.msg-legal--full p.msg-legal__scope {
    margin: 0 0 0.75rem;
    padding-bottom: 0.75rem;
    border-bottom: 1px dashed #d5d9e6;
    font-weight: 600 !important;
    color: #374151;
}

/* Les fragments que BNP met en avant restent plus grands, mais n'emportent
   plus la hauteur de ligne avec eux. */
.msg-legal--full [style*="font-size"] {
    line-height: inherit;
}

/*
 * ⚠ SOULIGNEMENT OBLIGATOIRE. `color: inherit` rend le lien exactement de la
 * même couleur que le texte qui l'entoure : sans soulignement, il n'est pas
 * « distingué par la couleur seule », il n'est pas distingué DU TOUT. Le lien
 * concerné est celui du registre ORIAS, dans les mentions du financeur.
 */
/*
 * ⚠ SOULIGNEMENT TOUJOURS OBLIGATOIRE — la couleur ne suffit jamais seule. Le
 * lien concerné est celui du registre ORIAS, dans les mentions du financeur : il
 * est dans la liste blanche de l'assainisseur précisément pour rester cliquable,
 * et il doit donc aussi rester TROUVABLE.
 *
 * `color: inherit` cède la place au bleu de marque : dans un encart gris de
 * 5,4 Ko, un lien de la couleur exacte du texte qui l'entoure ne se repère qu'en
 * passant la souris dessus. Mesuré 7,3:1 sur le fond de l'encart, au-delà du
 * seuil AA — et le soulignement reste, il n'est pas remplacé par la couleur.
 */
.msg-legal--full a {
    color: #1d4ed8;
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

.msg-legal--full a:hover {
    color: var(--color_primary, #1D1D77);
}

.msg-legal--full a:focus-visible {
    outline: 2px solid #1D1D77;
    outline-offset: 2px;
}

/*
 * Cible du lien ⓘ des cartes de listing (templates/parts/vehicle-card.php →
 * {permalien}#mentions-financement, posé sur le bloc de mentions complètes en
 * pied de fiche) : sans marge de défilement, le bloc se colle au bord haut du
 * viewport, sous l'en-tête du thème.
 *
 * ⚠ LA MARGE SUIT LA HAUTEUR DU BANDEAU, elle n'est plus un forfait. Mesuré au
 * navigateur après la refonte du bandeau pédagogique : à 2 rem, l'intitulé du
 * bloc atterrissait 42 px SOUS la bande collante — donc invisible, précisément
 * au terme du geste censé l'amener à l'écran. Le bandeau ayant gagné en hauteur
 * et surtout en opacité, un nombre écrit une fois pour toutes ne pouvait plus
 * convenir.
 *
 * `--msg-pedago-banner-height` est redéfinie en dessous de 1024 px, où la mention
 * tient sur trois lignes au lieu d'une : c'est ce qui rend cette seule
 * déclaration juste sur les deux largeurs.
 */
#mentions-financement {
    scroll-margin-top: calc(var(--msg-pedago-banner-height) + 2rem);
}

/* Étiquette du récapitulatif : c'est un intitulé de SECTION, pas une
   caractéristique du financement — la règle de taille ne le concerne donc pas,
   et il peut descendre à 11 px. */
/* === Encart assurance emprunteur (3.0.1) ================================= */

/*
 * Ouverture/fermeture par `grid-template-rows: 0fr → 1fr` : aucune hauteur
 * calculée en JS, aucun `max-height` arbitraire à re-régler quand le contenu
 * change. L'encart reste TOUJOURS monté dans le DOM — le démonter ferait
 * sauter la page au cochage et casserait le lien programmatique.
 *
 * Le clip porte `overflow: hidden`, l'inner porte marge et padding : sinon la
 * marge fuit hors du clip et l'encart fermé occupe encore de la place.
 */
.msg-simulate__insurance {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 200ms ease;
}

.msg-simulate.has-insurance .msg-simulate__insurance {
    grid-template-rows: 1fr;
}

.msg-simulate__insurance-clip {
    overflow: hidden;
    min-height: 0;
}

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

/* Barre latérale du MÊME bleu que l'accent-color de la case à cocher : c'est
   l'une des quatre accroches qui relient la case aux montants qu'elle fait
   apparaître (avec la légende sous la mensualité, la reprise littérale du
   libellé en titre, et le lien aria-labelledby). */
.msg-simulate__insurance-inner {
    margin: 0.75rem 0 0;
    padding: 0.625rem 0.875rem;
    border-left: 3px solid #1d4ed8;
    border-radius: 0 0.375rem 0.375rem 0;
    background: #eff6ff;
    font-size: var(--msg-legal-other);
    color: #4b5563;
}

/* Même raison que l'étiquette du récapitulatif : le thème parent impose
   `body.aladin .loop main p { font: 0.9em "source-sans-pro"; font-weight:
   lighter }` en (0,2,2), qui écrasait la graisse et la taille de tous les
   paragraphes du bloc. */
.msg-simulate .msg-simulate__insurance-title {
    margin: 0 0 0.375rem;
    font-size: var(--msg-legal-other) !important;
    font-weight: 700 !important;
    color: #1d4ed8;
}

.msg-simulate .msg-simulate__monthly-breakdown,
.msg-simulate .msg-simulate__field-hint {
    font-size: var(--msg-legal-other) !important;
    font-weight: 400 !important;
}

.msg-simulate__insurance-row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
}

.msg-simulate__insurance-row + .msg-simulate__insurance-row {
    margin-top: 0.25rem;
}

.msg-simulate__insurance-row span:last-child {
    font-weight: 700;
    color: #1D1D77;
    font-variant-numeric: tabular-nums;
}

/* Indicateur de focus : occasions.css en définissait pour .msg-filters,
   .msg-chip et .msg-lightbox, mais AUCUN pour .msg-simulate — alors que le
   thème parent applique un reset global très spécifique sur les contrôles. */
.msg-simulate :is(input, button, a):focus-visible {
    outline: 3px solid #1D1D77;
    outline-offset: 2px;
    border-radius: 0.25rem;
}

/*
 * ⚠ `!important` CIBLÉ, même discipline que les boutons du plugin (cf. la
 * section « Front vs thème parent » du CLAUDE.md).
 *
 * Le thème parent applique `body.aladin .loop main h3 { font: normal normal
 * normal 1.3em/150% "good-times"; text-transform: uppercase; }` — spécificité
 * (0,2,3) contre (0,1,0) pour une simple classe. Sans ces `!important`, cette
 * étiquette de section se rendait en capitales « good-times » de 1,3em, plus
 * grosse que la mensualité qu'elle est censée introduire.
 *
 * Le `font` du thème étant une propriété RACCOURCIE, il faut redéclarer
 * family, size et weight séparément : ne pas en retirer un en croyant
 * simplifier.
 */
.msg-simulate .msg-simulate__recap-title {
    margin: 1.25rem 0 0.5rem !important;
    font-family: inherit !important;
    font-size: 0.75rem !important;
    font-weight: 700 !important;
    line-height: 1.4 !important;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #4b5563 !important;
}

/*
 * Récapitulatif renvoyé par BNP, dans le même champ visuel que la mensualité.
 *
 * ⚠ DEUX SURFACES, UNE SEULE DÉCLARATION : le même tableau est rendu par le
 * simulateur de fiche (`.msg-simulate__recap`) et par la modale des mentions
 * (`.msg-legal-dialog__recap`, point 3 de l'ordre du guide). Sa taille de
 * caractère est NORMATIVE — la dupliquer, c'est se donner deux valeurs à
 * maintenir et une divergence réglementaire à découvrir en audit.
 *
 * ⚠ `font-size` NORMATIF : ne jamais le réduire, et ne jamais le compenser par
 * `transform: scale()` ou `zoom` — un auditeur lit la déclaration CSS, pas le
 * rendu.
 *
 * ⚠ `overflow: visible`, JAMAIS `auto` ni `scroll`. Un défilement interne
 * rendrait les dernières lignes accessibles « en scrollant », ce que le guide
 * interdit au même titre qu'un accordéon. Le tableau doit REPLIER, pas
 * défiler — d'où `overflow-wrap: anywhere` sur les cellules.
 *
 * Fond blanc dans la carte grise : le bloc se lit comme une feuille jointe,
 * ce qu'il est — un document fourni par un tiers.
 */
.msg-simulate__recap,
.msg-legal-dialog__recap {
    margin: 0;
    overflow: visible;
    font-size: var(--msg-legal-essential);
    background: #ffffff;
    border: 1px solid #e5e7eb;
    border-radius: 0.5rem;
    padding: 0.25rem 0.875rem;
}

.msg-simulate__recap table,
.msg-legal-dialog__recap table {
    width: 100%;
    border-collapse: collapse;
    table-layout: auto;
}

/* Filet intérieur seulement : un quadrillage complet ou des règles verticales,
   c'est ce qui fait « formulaire administratif ». */
.msg-simulate__recap tr + tr td,
.msg-legal-dialog__recap tr + tr td {
    border-top: 1px solid #f3f4f6;
}

/* 0.35rem : compromis mesuré. À 0.15rem le tableau faisait un mur, à 0.5rem
   l'air s'ajoutait à des lignes déjà hautes de trois à quatre lignes de texte
   et aggravait la masse au lieu de l'alléger. Une fois le débordement réglé
   (cf. td:last-child ci-dessous), 0.35rem suffit à aérer. */
.msg-simulate__recap td,
.msg-legal-dialog__recap td {
    padding: 0.35rem 0;
    vertical-align: baseline;
    line-height: 1.35;
}

/* La hiérarchie passe par la COULEUR et la GRAISSE, jamais par la taille :
   celle-ci reste uniforme à --msg-legal-essential comme l'exige le guide. */
.msg-simulate__recap td:first-child,
.msg-legal-dialog__recap td:first-child {
    color: #4b5563;
    padding-right: 1rem;
    overflow-wrap: anywhere;
    hyphens: auto;
}

/*
 * ⚠ PAS de `width: 1%` sur la colonne de valeur. L'idée — « colonne au plus
 * juste, libellés au large » — est bonne pour un tableau dont les valeurs sont
 * courtes. Ici elle est ruineuse : BNP répète le qualificatif dans la VALEUR
 * (« 417,16 € (hors assurance facultative) »), si bien que comprimer cette
 * colonne faisait déborder les onze lignes sur trois à quatre lignes chacune.
 *
 * Mesuré sur une colonne de 351 px : 612 px de haut avec `width: 1%`, 455 px
 * sans, à taille de police identique. C'est le premier levier, et il ne coûte
 * rien réglementairement.
 */
.msg-simulate__recap td:last-child,
.msg-legal-dialog__recap td:last-child {
    text-align: right;
    font-weight: 600;
    color: #1D1D77;
    font-variant-numeric: tabular-nums;
}

.msg-simulate__field--check {
    margin: 0.75rem 0 0;
}

/* 44 px de hauteur minimale et une case de 24 px : la ligne faisait ~19 px,
   sous le seuil de 24 px du critère « taille de cible (minimum) ». */
.msg-simulate__field--check label {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    min-block-size: 2.75rem;
    padding-block: 0.25rem;
    font-size: 0.9375rem;
    line-height: 1.4;
    cursor: pointer;
}

.msg-simulate__field--check input {
    inline-size: 1.5rem;
    block-size: 1.5rem;
    margin: 0;
    flex: 0 0 auto;
    accent-color: #1d4ed8;
}

.msg-simulate__product {
    margin: 0 0 0.75rem;
    font-size: var(--msg-legal-essential);
    font-weight: 700;
}

/* === Bloc simulation de financement (Task 10) ============================ */

.msg-simulate {
    max-width: 32rem;
    margin: 1.5rem 0;
    padding: 1.25rem 1.5rem;
    border: 1px solid #6b7280;
    border-radius: 0.5rem;
    background: #f9fafb;
}

.msg-simulate h2 {
    margin: 0 0 1rem;
    font-size: 1.125rem;
    font-weight: 600;
}

.msg-simulate__form {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 1rem;
}

.msg-simulate__field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.875rem;
}

.msg-simulate__field label {
    color: #374151;
    font-weight: 500;
}

.msg-simulate__field select,
.msg-simulate__field input {
    padding: 0.375rem 0.5rem;
    border: 1px solid #6b7280;
    border-radius: 0.375rem;
    font-size: 0.875rem;
}

/* === Sliders Durée/Apport (référence client Legrand/BNP, revue navigateur
   2026-07-30) — remplacent l'ancien <select> Durée et l'ancien
   <input type="number"> Apport, cf. docblock de
   templates/single-msg_vehicule.php. Le formulaire n'est plus
   `align-items: end` en ligne (ne fait plus sens avec des sliders pleine
   largeur) : chaque `.msg-simulate__field--range` prend toute la largeur
   disponible et empile son en-tête (label + valeur courante) au-dessus du
   slider. ========================================================== */

.msg-simulate__form {
    align-items: stretch;
}

.msg-simulate__field--range {
    width: 100%;
    flex: 1 1 100%;
}

.msg-simulate__field-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
}

.msg-simulate__field-value {
    font-weight: 700;
    color: #1d4ed8;
    font-variant-numeric: tabular-nums;
}

/* Reset du style natif + piste/curseur cohérents avec le reste du plugin
   (bleu #1d4ed8, cf. .msg-simulate__submit historique) sur les moteurs qui
   exposent ces pseudo-éléments (WebKit/Blink/Firefox) — un slider natif
   sans ce reset reste utilisable (progressive enhancement), juste avec
   l'apparence par défaut du navigateur. */
/* 44 px : un input[type=range] non stylé fait 16 à 20 px de haut selon le
   moteur, sous le seuil de 24 px. La piste reste fine, seule la zone de saisie
   grandit.

   ⚠ NE PAS remplacer ces curseurs natifs par une implémentation JS : le range
   natif satisfait sans effort le critère « mouvements de glissement » (un clic
   sur la piste positionne la valeur) et offre une alternative clavier
   complète. Une réimplémentation casserait les deux. */
.msg-simulate__field--range input[type="range"] {
    width: 100%;
    block-size: 2.75rem;
    margin: 0.25rem 0 0;
    accent-color: #1d4ed8;
    cursor: pointer;
    touch-action: manipulation;
}

/* Bornes et pas : ce texte est utile à tout le monde, il est donc VISIBLE et
   non masqué hors écran. Aucun lecteur d'écran n'annonce systématiquement
   min/max/step d'un curseur. */
.msg-simulate__field-hint {
    margin: 0.25rem 0 0;
    font-size: var(--msg-legal-other);
    color: #4b5563;
}

/* Repli no-JS (docblock de fichier) : uniquement rendu par un navigateur
   sans JavaScript (contenu <noscript>, jamais parsé sinon). */
/* Ni rouge ni injonctif : l'utilisateur n'a souvent pas la main sur
   l'activation de JavaScript, et le récapitulatif rendu côté serveur reste
   affiché — la page est conforme, seule la personnalisation manque. */
.msg-simulate__noscript {
    margin: 1rem 0 0.5rem;
    font-size: var(--msg-legal-other);
    color: #4b5563;
}

.msg-simulate__submit {
    padding: 0.5rem 1.25rem;
    border: none;
    border-radius: 0.375rem;
    background: #1d4ed8;
    color: #ffffff;
    font-size: 0.875rem;
    font-weight: 600;
    cursor: pointer;
}

.msg-simulate__submit:hover {
    background: #1D1D77;
}

.msg-simulate__submit:disabled {
    background: #9ca3af;
    cursor: not-allowed;
}

/* État de chargement (recalcul en cours, cf. assets/js/simulate.js
   setLoading()) : plus de bouton à désactiver une fois JS actif (repli
   no-JS retiré dans un <noscript>), donc l'indicateur passe par une classe
   sur la section — opacité réduite + interactions désactivées le temps de
   la requête ajax, pour ne pas laisser l'utilisateur re-déclencher un
   glisser pendant qu'un calcul est déjà en vol. */
/*
 * ⚠ NI `opacity`, NI `pointer-events: none`, et les trois raisons comptent :
 *
 * 1. `pointer-events: none` ne bloque QUE la souris. Le clavier passait au
 *    travers, si bien qu'un utilisateur clavier pouvait lancer deux cotations
 *    concurrentes — désormais séquencées par AbortController côté JS, ce qui
 *    est la vraie correction.
 * 2. La règle portait sur toute la <section>, donc aussi sur le bouton
 *    « Demander ce financement », inerte pendant le premier appel BNP sans
 *    aucune explication visible.
 * 3. `opacity: .6` ramenait le texte de détail à 2,8:1 sur le fond du bloc,
 *    sous le seuil AA de 4,5:1, pendant toute la durée de la requête.
 *
 * L'attente est signalée par `aria-busy` (posé par setLoading) et, si besoin,
 * par un indicateur qui ne touche pas au contraste.
 */
.msg-simulate[aria-busy="true"] .msg-simulate__monthly {
    transition: opacity 120ms ease;
}

.msg-simulate__result {
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-top: 1px solid #e5e7eb;
}

/* Mensualité mise en évidence en très grand (référence Legrand) : c'est le
   seul chiffre que la majorité des visiteurs vient chercher. Le TAEG, le coût
   total et le montant total dû ne sont PLUS redonnés ici — ils sont dans le
   tableau BNP juste en dessous, qui est la source normative.

   Ce corps de 40 px n'entorse pas la règle de taille : le montant des
   échéances EST l'une des mentions essentielles. La règle interdit d'afficher
   les AUTRES caractéristiques plus gros qu'elles, pas d'afficher une
   essentielle très gros. */
.msg-simulate__monthly {
    margin: 0 0 0.25rem;
    display: flex;
    align-items: baseline;
    /* `wrap` + `clamp` : à 320 px, après les marges de page et le padding du
       bloc, il reste ~250 px — « 1 234,56 € » en 40 px gras débordait, et un
       flex sans wrap ne rétrécit pas un texte. */
    flex-wrap: wrap;
    column-gap: 0.375rem;
    color: #111827;
}

.msg-simulate__monthly strong {
    font-size: clamp(1.75rem, 9vw, 2.5rem);
    line-height: 1.05;
    font-weight: 800;
    color: #1d4ed8;
}

.msg-simulate__monthly-suffix {
    font-size: 1rem;
    font-weight: 500;
    color: #4b5563;
}

/* Légende sous la mensualité : la seule chose que le tableau BNP ne peut pas
   expliquer, c'est-à-dire POURQUOI le gros chiffre vaut 316,14 et non 295,27.
   Remplace la ligne « Mensualité hors assurance » de l'ancienne liste maison,
   dont le montant figure de toute façon dans le tableau. */
.msg-simulate__monthly-breakdown {
    margin: 0 0 0.75rem;
    font-size: var(--msg-legal-other);
    color: #4b5563;
}

.msg-simulate__error {
    margin-top: 1rem;
    color: #b91c1c;
    font-size: 0.875rem;
}

/* === Grille financement (LOA | simulation), Task 3 plan 3 ================ */
/* Append only : ne pas réorganiser les sections existantes ci-dessus (T5
   ajoute aussi des styles à lui dans ce même fichier). */

/* align-items: stretch (valeur par défaut de CSS Grid) — PAS "start" comme
   avant : exigence produit (revue navigateur, 2026-07-30) que les deux
   blocs « Demande de LOA » et « Simulez votre financement » aient TOUJOURS
   la même hauteur, quel que soit celui des deux qui a le plus de contenu.
   Écrite explicitement (plutôt que simplement retirée) pour que l'intention
   reste visible si quelqu'un est tenté de réintroduire "start" plus tard. */
/* Une colonne par défaut, deux seulement quand la COLONNE PRINCIPALE de la
   fiche (conteneur `msg-main`, cf. .msg-single__main plus bas) dépasse 50rem —
   et non plus quand l'ÉCRAN dépasse 768 px. La grille vit à côté de la
   sidebar : à 1200 px d'écran elle n'a que ~670 px, deux blocs de ~320 px où
   les titres se coupaient au milieu des mots et où les champs du formulaire
   de location débordaient de la carte (relevé en production le 2026-10-08,
   demande de Fred). 50rem = deux blocs de ~390 px, la largeur sous laquelle
   le formulaire de location ne tient plus ses paires de champs. */
.msg-financing-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.5rem;
    align-items: stretch;
    margin: 1.5rem 0;
}

.msg-single__main {
    container: msg-main / inline-size;
}

@container msg-main (min-width: 50rem) {
    .msg-financing-grid {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }
}

/* Les deux blocs enfants en colonne flex + height:100% : le stretch du
   grid donne déjà aux <section> la hauteur de la ligne, mais c'est ce
   display:flex qui permet à leur propre contenu (garanties de LOA,
   formulaire de simulation) de s'étirer jusqu'en bas plutôt que de laisser
   un vide non maîtrisé sous un contenu plus court. */
.msg-financing-grid > .msg-loa,
.msg-financing-grid > .msg-simulate {
    display: flex;
    flex-direction: column;
    margin: 0;
    box-sizing: border-box;
    /* .msg-simulate porte un max-width: 32rem pensé pour un simulateur seul ;
       dans la grille, chaque bloc occupe sa cellule entière (sinon, empilé,
       il s'arrêtait aux deux tiers de la largeur sous le formulaire). */
    max-width: none;
}

/* Même hauteur pour les deux blocs seulement quand ils sont côte à côte ;
   empilés, chacun garde la sienne. */
@container msg-main (min-width: 50rem) {
    .msg-financing-grid > .msg-loa,
    .msg-financing-grid > .msg-simulate {
        height: 100%;
    }
}

/* === Formulaire de demande de LOA (Leads\LoaFormRenderer, Task 3) ========= */

.msg-loa {
    padding: 1.25rem 1.5rem;
    border: 1px solid #6b7280;
    border-radius: 0.5rem;
    background: #ffffff;
}

.msg-loa h2 {
    margin: 0 0 0.5rem;
    font-size: 1.125rem;
    font-weight: 600;
}

.msg-loa__intro {
    margin: 0 0 1rem;
    font-size: 0.875rem;
    color: #4b5563;
}

.msg-loa {
    container: msg-loa / inline-size;
}

.msg-loa__form {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 1rem;
}

/* Bloc étroit (mobile) : un champ par ligne plutôt que deux de ~140 px.
   20rem de largeur utile : deux blocs côte à côte (~350 px utiles) gardent
   leurs paires de champs (~165 px chacun), un téléphone de 390 px passe à un
   champ par ligne. */
@container msg-loa (max-width: 20rem) {
    .msg-loa__form {
        grid-template-columns: minmax(0, 1fr);
    }
}

.msg-loa__field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.875rem;
}

/* Champ occupant les deux colonnes (concession) : il ouvre le formulaire seul,
   ce qui aligne ensuite les paires prénom + nom, e-mail + téléphone,
   durée + kilométrage. */
.msg-loa__field--wide {
    grid-column: 1 / -1;
}

.msg-loa__field label {
    color: #374151;
    font-weight: 500;
}

.msg-loa__field select,
.msg-loa__field input {
    /* Sans largeur explicite, un <input> garde sa largeur par défaut (~20
       caractères) et débordait de sa cellule, puis de la carte. */
    box-sizing: border-box;
    width: 100%;
    min-width: 0;
    padding: 0.375rem 0.5rem;
    border: 1px solid #6b7280;
    border-radius: 0.375rem;
    font-size: 0.875rem;
}

/* Concession verrouillée (Leads\LoaFormRenderer::lockedConcessionField()) :
   le champ reste un <input> pour ne pas casser l'alignement de la grille,
   mais son fond grisé signale qu'il n'y a rien à y choisir — le véhicule
   n'est en stock que dans cette concession. */
.msg-loa__field input[readonly] {
    background: #f3f4f6;
    color: #374151;
    cursor: default;
}

.msg-loa__field-error {
    color: #b91c1c;
    font-size: 0.75rem;
    min-height: 1em;
}

.msg-loa__submit {
    grid-column: 1 / -1;
    padding: 0.5rem 1.25rem;
    border: none;
    border-radius: 0.375rem;
    background: #1d4ed8;
    color: #ffffff;
    font-size: 0.875rem;
    font-weight: 600;
    cursor: pointer;
    justify-self: start;
}

.msg-loa__submit:hover {
    background: #1D1D77;
}

.msg-loa__submit:disabled {
    background: #9ca3af;
    cursor: not-allowed;
}

.msg-loa__success {
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid #e5e7eb;
    color: #15803d;
    font-weight: 600;
    font-size: 0.875rem;
}

.msg-loa__error {
    margin-top: 1rem;
    color: #b91c1c;
    font-size: 0.875rem;
}

/* (L'ancien passage à une colonne sous 480 px d'écran est assuré par la
   requête de conteneur `msg-loa`, plus haut, qui suit la largeur du bloc.) */

/* Honeypot anti-spam (champ `website`) : masqué hors écran, PAS
   `display:none` seul (cf. docblock LoaFormRenderer::honeypotField()). */
.msg-hp {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* === Filtres serveur du listing (templates/parts/listing-filters.php,
   Task 5, plan 3) — formulaire GET partagé entre le shortcode
   [msg_occasions] (archive-listing.php) et l'archive native /occasions/
   (archive-msg_vehicule.php). ============================================ */

.msg-filters {
    margin-bottom: 1.5rem;
    padding: 1rem;
    background: #f9fafb;
    border: 1px solid #e5e7eb;
    border-radius: 0.5rem;
}

/* Zone 1 : les huit champs de filtrage, GRILLE RÉGULIÈRE de 2 rangées de 4
   (la recherche libre est SORTIE de la grille le 2026-09-01 — sans quoi
   « Année min » restait seule sur une troisième rangée)
   (Task 7 bis, arbitrage utilisateur 2026-08-31 — le <form> lui-même n'est
   plus la boîte flex, il empile désormais la grille de filtres puis la barre
   de résultats .msg-filters__results plus bas).

   Rangée 1 = les quatre critères principaux (Recherche, Type, Marque,
   Concession), rangée 2 = les quatre paliers (Carburant, Prix max,
   Kilométrage max, Année min) — l'ordre du DOM, donc l'ordre de tabulation,
   est celui-là à TOUTES les tailles.

   Pourquoi une largeur unique plutôt que huit largeurs calées sur le contenu
   (ce que proposait la maquette) : la raison est STRUCTURELLE. Sur ~1120 px,
   quatre colonnes font ~260 px chacune — de quoi afficher « Toutes les
   concessions » sans calibrage — là où huit flex-basis ajustés au stock
   D'AUJOURD'HUI seraient à refaire dès qu'une concession au nom plus long
   entre dans le flux CSV.

   ⚠ minmax(0, 1fr) et NON 1fr : une piste de grille a `auto` pour largeur
   minimale, si bien qu'un <select> contenant « BMW MINI HONDA DUPONT
   ORLEANS » élargirait sa colonne au-delà de sa part, ferait déborder la
   grille et scroller le body horizontalement. Le minmax(0, …) — plus le
   min-width:0 des champs et le width:100% des contrôles ci-dessous — est ce
   qui force le select à se contraindre. */
.msg-filters__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: end;
    gap: 0.75rem 0.875rem;
}

@media (min-width: 640px) {
    .msg-filters__grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 1024px) {
    .msg-filters__grid {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

.msg-filters__field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    min-width: 0;
}

/* Zone 2 : barre de résultats (Task 7 bis) — compteur à gauche,
   « Réinitialiser », puis « Trier par » (et « Filtrer » en repli sans JS) à
   droite. Sépare visuellement deux gestes distincts : restreindre la liste,
   puis l'ordonner. ⚠ Le select `tri` reste DANS le <form> .msg-filters, cf.
   le docblock de templates/parts/listing-filters.php. */
.msg-filters__results {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.875rem;
    padding-top: 0.875rem;
    border-top: 1px solid #e5e7eb;
}

/* Le compteur garde .msg-listing__count (déjà stylé plus bas) : seule sa
   marge basse, héritée de son ancien rendu en bloc autonome par les deux
   gabarits d'archive, n'a plus lieu d'être dans une barre flex. */
.msg-filters__results .msg-listing__count {
    margin: 0;
}

.msg-filters__label {
    font-size: 0.8125rem;
    font-weight: 600;
    color: #374151;
}

.msg-filters__select {
    width: 100%;
    min-width: 0;
    padding: 0.375rem 0.5rem;
    border-radius: 0.375rem;
    border: 1px solid #6b7280;
    background: #ffffff;
    color: #111827;
    font-size: 0.875rem;
}

.msg-filters__submit {
    padding: 0.5rem 1.25rem;
    border: none;
    border-radius: 0.375rem;
    background: #1D1D77;
    color: #ffffff;
    font-size: 0.875rem;
    font-weight: 600;
    cursor: pointer;
}

.msg-filters__submit:hover {
    background: #1e3a8a;
}

.msg-filters__reset {
    font-size: 0.8125rem;
    color: #4b5563;
    text-decoration: underline;
}

.msg-filters__reset:hover {
    color: #111827;
}

/* === Fiche véhicule : galerie + caractéristiques (Task 4, plan 3) ========
   RETOUCHÉ (lot « parité Legrand » P2, docs/ANALYSE-LEGRAND.md §A) :
   .msg-single__layout/.msg-single__info (2 colonnes limitées à la hauteur de
   la galerie) sont remplacées par .msg-single__shell/.msg-single__main +
   .msg-sidebar (2 colonnes sur TOUTE la hauteur de la fiche — c'est ce qui
   permet une sidebar réellement sticky, cf. docblock de
   templates/single-msg_vehicule.php). ==================================== */

.msg-single__shell {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    gap: 2rem;
    align-items: start;
}

@media (max-width: 1023px) {
    /* Sidebar empilée SOUS la colonne principale en mobile/tablette (spec :
       sticky ≥1024px seulement) — cf. .msg-sidebar ci-dessous pour le seuil
       symétrique côté position:sticky. */
    .msg-single__shell {
        grid-template-columns: 1fr;
    }
}

.msg-single__main {
    min-width: 0;
}

/* --- Galerie (templates/parts/gallery.php) ------------------------------ */

.msg-gallery__main {
    width: 100%;
    aspect-ratio: 4 / 3;
    background: #e5e7eb;
    border-radius: 0.5rem;
    overflow: hidden;
}

/* Lightbox (revue navigateur, 2026-07-30) : l'image principale est
   maintenant enveloppée dans un lien (templates/parts/gallery.php,
   data-msg-gallery-open) — curseur zoom-in pour signaler l'agrandissement,
   display:block pour que le lien épouse exactement les dimensions de
   .msg-gallery__main (sinon l'espace inline sous l'image resterait
   cliquable en dehors du cadre visuel). */
.msg-gallery__main-link {
    display: block;
    width: 100%;
    height: 100%;
    cursor: zoom-in;
}

.msg-gallery__main-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.msg-gallery__count {
    margin: 0.5rem 0;
    font-size: 0.8125rem;
    color: #6b7280;
}

.msg-gallery__thumbs {
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    padding-bottom: 0.25rem;
    scrollbar-width: thin;
}

.msg-gallery__thumb {
    flex: 0 0 auto;
    width: 4.5rem;
    height: 3.375rem;
    border-radius: 0.375rem;
    overflow: hidden;
    border: 2px solid transparent;
    display: block;
}

.msg-gallery__thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.msg-gallery__thumb.is-active {
    border-color: #1d4ed8;
}

/* --- Caractéristiques (templates/parts/vehicle-specs.php) --------------- */

.msg-specs {
    width: 100%;
    margin-top: 1rem;
    border-collapse: collapse;
    font-size: 0.875rem;
}

.msg-specs__row:not(:last-child) {
    border-bottom: 1px solid #e5e7eb;
}

.msg-specs__label,
.msg-specs__value {
    padding: 0.5rem 0;
    text-align: left;
    font-weight: 400;
}

/* === Bloc concessionnaire (templates/parts/dealer-card.php, Feature 2) ===
   Append only. =========================================================== */

.msg-dealer {
    margin-top: 1.5rem;
    padding-top: 1rem;
    border-top: 1px solid #e5e7eb;
}

.msg-dealer__title {
    margin: 0 0 0.375rem;
    font-size: 0.9375rem;
    font-weight: 600;
    color: #374151;
}

/* Le thème parent impose `body.aladin .loop main h2 { font: 2.2em "good-times";
   text-transform: uppercase; color: primaire }` (Aladin-main-child/assets/scss/
   _typo.scss, spécificité (0,2,3)) : cet intitulé de quatre mots s'affichait en
   ~40 px capitales sur trois lignes dans la sidebar (relevé en production le
   2026-10-08, demande de Fred). Reprise ciblée par !important, même discipline
   que les boutons plus bas — jamais une règle générale sur les h2 du plugin. */
/* Titres des deux blocs de financement (« Demandez un devis en location »,
   « Simulez votre financement ») : la même règle h2 du thème les portait à
   ~40 px, et « FINANCEMENT », mot insécable, se coupait en « FINANCE / MENT »
   dans un bloc de ~320 px (relevé en production le 2026-10-08). Seule la
   TAILLE est reprise : police good-times, capitales et couleur du thème sont
   conservées, c'est l'identité du site. */
body.aladin .msg-loa h2,
body.aladin .msg-simulate h2 {
    font-size: 1.5rem !important;
    line-height: 1.25 !important;
}

body.aladin .msg-dealer__title {
    font: normal normal 600 0.9375rem/1.4 "source-sans-pro", sans-serif !important;
    color: #374151 !important;
    text-transform: none !important;
}

.msg-dealer__name {
    margin: 0 0 0.25rem;
    font-size: 1rem;
    font-weight: 700;
    color: #111827;
}

.msg-dealer__phone,
.msg-dealer__address {
    margin: 0 0 0.125rem;
    font-size: 0.875rem;
    color: #4b5563;
}

.msg-dealer__phone a {
    color: #1d4ed8;
    text-decoration: none;
}

.msg-dealer__phone a:hover {
    text-decoration: underline;
}

/* Lot « parité Legrand » P2 : e-mail (lien mailto:) même style que le
   téléphone ; SIRET/TVA discret, plus petit — parité fiche legacy. */
.msg-dealer__email {
    margin: 0 0 0.125rem;
    font-size: 0.875rem;
    color: #4b5563;
}

.msg-dealer__email a {
    color: #1d4ed8;
    text-decoration: none;
}

.msg-dealer__email a:hover {
    text-decoration: underline;
}

.msg-dealer__siret {
    margin: 0.375rem 0 0;
    font-size: 0.75rem;
    color: #9ca3af;
}

.msg-specs__label {
    color: #6b7280;
    width: 45%;
    white-space: nowrap;
}

.msg-specs__value {
    color: #111827;
    font-weight: 600;
}

/* === Lightbox galerie (assets/js/gallery.js, revue navigateur 2026-07-30) =
   Append only. Markup entièrement généré par JS (docblock gallery.js) —
   ces règles ciblent uniquement les classes/attributs posés par ce script,
   rien ici n'est rendu côté PHP. `html.msg-lightbox-open` bloque le scroll
   de fond pendant que l'overlay est ouvert. ===================== */

html.msg-lightbox-open {
    overflow: hidden;
}

.msg-lightbox {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 2rem;
    box-sizing: border-box;
    background: rgba(0, 0, 0, 0.9);
}

.msg-lightbox.is-open {
    display: flex;
}

.msg-lightbox__img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    display: block;
}

.msg-lightbox__close,
.msg-lightbox__prev,
.msg-lightbox__next {
    position: absolute;
    border: none;
    border-radius: 9999px;
    background: rgba(255, 255, 255, 0.1);
    color: #ffffff;
    font-size: 1.75rem;
    line-height: 1;
    padding: 0.5rem 0.875rem;
    cursor: pointer;
}

.msg-lightbox__close:hover,
.msg-lightbox__prev:hover,
.msg-lightbox__next:hover {
    background: rgba(255, 255, 255, 0.25);
}

/* Contraste clavier sur fond noir (spec accessibilité, revue navigateur 2026-07-30). */
.msg-lightbox__close:focus-visible,
.msg-lightbox__prev:focus-visible,
.msg-lightbox__next:focus-visible {
    outline: 2px solid #ffffff;
    outline-offset: 2px;
}

.msg-lightbox__close {
    top: 1rem;
    right: 1rem;
}

.msg-lightbox__prev {
    left: 1rem;
    top: 50%;
    transform: translateY(-50%);
}

.msg-lightbox__next {
    right: 1rem;
    top: 50%;
    transform: translateY(-50%);
}

.msg-lightbox__counter {
    position: absolute;
    bottom: 1rem;
    left: 50%;
    transform: translateX(-50%);
    margin: 0;
    color: #ffffff;
    font-size: 0.875rem;
}

@media (max-width: 480px) {
    .msg-lightbox {
        padding: 1rem;
    }

    .msg-lightbox__close,
    .msg-lightbox__prev,
    .msg-lightbox__next {
        font-size: 1.375rem;
        padding: 0.375rem 0.625rem;
    }
}

/* === Demande de financement depuis le simulateur (Leads\CreditRequestRenderer,
   Feature 1) — sous .msg-simulate__result/.msg-simulate__error. Append only.
   ========================================================================= */

.msg-credit-request {
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-top: 1px solid #e5e7eb;
}

.msg-credit-request__toggle {
    padding: 0.5rem 1.25rem;
    border: 1px solid #1d4ed8;
    border-radius: 0.375rem;
    background: #ffffff;
    color: #1d4ed8;
    font-size: 0.875rem;
    font-weight: 600;
    cursor: pointer;
}

.msg-credit-request__toggle:hover {
    background: #eff6ff;
}

.msg-credit-request__intro {
    /* Enfant direct de la grille 2 colonnes du formulaire : sans cette
       occupation pleine largeur, l'intro consomme la première cellule et
       décale TOUS les champs d'un cran (prénom seul à droite, puis nom/e-mail
       appariés, téléphone orphelin). Les paires attendues sont
       prénom + nom, puis e-mail + téléphone. */
    grid-column: 1 / -1;
    margin: 0 0 1rem;
    font-size: 0.8125rem;
    color: #4b5563;
}

.msg-credit-request__form {
    margin-top: 1rem;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
}

.msg-credit-request__field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.875rem;
}

.msg-credit-request__field label {
    color: #374151;
    font-weight: 500;
}

.msg-credit-request__field input {
    padding: 0.375rem 0.5rem;
    border: 1px solid #6b7280;
    border-radius: 0.375rem;
    font-size: 0.875rem;
}

.msg-credit-request__field-error {
    color: #b91c1c;
    font-size: 0.75rem;
    min-height: 1em;
}

.msg-credit-request__submit {
    grid-column: 1 / -1;
    padding: 0.5rem 1.25rem;
    border: none;
    border-radius: 0.375rem;
    background: #1d4ed8;
    color: #ffffff;
    font-size: 0.875rem;
    font-weight: 600;
    cursor: pointer;
    justify-self: start;
}

.msg-credit-request__submit:hover {
    background: #1D1D77;
}

.msg-credit-request__submit:disabled {
    background: #9ca3af;
    cursor: not-allowed;
}

.msg-credit-request__success {
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid #e5e7eb;
    color: #15803d;
    font-weight: 600;
    font-size: 0.875rem;
}

.msg-credit-request__error {
    margin-top: 1rem;
    color: #b91c1c;
    font-size: 0.875rem;
}

@media (max-width: 480px) {
    .msg-credit-request__form {
        grid-template-columns: 1fr;
    }
}

/* === Auto-application des filtres (assets/js/listing-filters.js, Task ?,
   plan 3, demande utilisateur) — append only. ============================
   Le bouton « Filtrer » reste dans le DOM (repli sans JS + accessibilité,
   cf. docblock du script).

   ⚠ La règle qui le masquait sous `.js-enabled` a été RETIRÉE le 2026-09-01 :
   il n'était masqué que parce que l'auto-submit rendait le clic superflu. Les
   quatre filtres multi-valeurs sont désormais des menus à cases à cocher, sur
   lesquels l'auto-submit provoquerait un rechargement par case cochée — le
   bouton redevient donc le mode nominal de validation, comme sur le site
   actuel. Le remettre en display:none rendrait la multi-sélection
   inutilisable. */

/* === Tri (select « Trier par », Task ?, plan 3, REVU Task 7 bis) =========
   Le tri n'est plus un champ de la grille de filtres : il occupe la droite de
   la barre de résultats (.msg-filters__results), label EN LIGNE devant le
   select — ce n'est pas un critère de filtrage et il ne doit plus en avoir
   l'air. Il reste néanmoins DANS le <form> .msg-filters (auto-submit au
   `change` + add_args de la pagination), cf. le docblock de
   templates/parts/listing-filters.php.
   Avant Task 7 bis : `.msg-filters__field--sort { margin-left: auto }` — le
   select prenait alors toute la largeur d'une deuxième ligne, pesant autant
   que les huit filtres réunis. */
.msg-filters__sort {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-left: auto;
}

/* Le select de tri n'est plus étiré par une colonne flex : largeur calée sur
   son contenu (« Kilométrage croissant » est la plus longue option). */
.msg-filters__sort .msg-filters__select {
    width: auto;
    min-width: 190px;
}

/* Label en ligne, jamais coupé au milieu de « Trier par ». */
.msg-filters__sort .msg-filters__label {
    white-space: nowrap;
}

/* === Bloc équipements (templates/parts/vehicle-equipment.php, parité fiche
   legacy — équipements de série/options, séparateur pipe legacy). Append
   only. ==================================================================== */

.msg-equipment {
    margin-top: 2rem;
    padding-top: 1.5rem;
    border-top: 1px solid #e5e7eb;
}

.msg-equipment__heading {
    margin: 0 0 0.75rem;
    font-size: 1.25rem;
    font-weight: 700;
}

.msg-equipment__subheading {
    margin: 1.5rem 0 0.75rem;
    font-size: 1rem;
    font-weight: 600;
    color: #374151;
}

.msg-equipment__list {
    margin: 0;
    padding: 0;
    list-style: none;
    columns: 2;
    column-gap: 1.5rem;
}

.msg-equipment__item {
    padding: 0.25rem 0;
    font-size: 0.875rem;
    color: #374151;
    break-inside: avoid;
}

.msg-equipment__details summary::-webkit-details-marker {
    color: #1d4ed8;
}

.msg-equipment__summary {
    cursor: pointer;
    font-weight: 600;
    color: #1d4ed8;
    margin-bottom: 0.5rem;
}

@media (min-width: 768px) {
    .msg-equipment__list {
        columns: 3;
    }
}

/* === Lot « parité Legrand » P1b (docs/ANALYSE-LEGRAND.md §A) : badges de
   carte, prix barré, compteur, fil d'ariane, recherche libre. Append only.
   ========================================================================= */

/* Badges (Inventory\CardBadges::for(), templates/parts/vehicle-card.php) :
   overlay coin haut-gauche, empilés — .msg-card__img/.msg-card__noimg sont
   passés en `position: relative` ci-dessus (seule modification d'une règle
   existante de ce fichier, nécessaire pour ancrer cet overlay). */
.msg-card__badges {
    position: absolute;
    top: 0.5rem;
    left: 0.5rem;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.25rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.msg-badge {
    padding: 0.125rem 0.5rem;
    border-radius: 0.25rem;
    background: #111827;
    color: #ffffff;
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.msg-badge--drop {
    background: #b91c1c;
}

.msg-badge--lowkm {
    background: #1d4ed8;
}

.msg-badge--energy {
    background: #15803d;
}

/* Prix barré (templates/parts/vehicle-card.php) : _msg_prix_precedent >
   _msg_prix. Le prix actuel reste en gras (.msg-card__price est déjà en
   font-weight: 700 par défaut) — --drop se contente d'une couleur d'accent. */
.msg-card__price-previous {
    margin: 0;
    font-size: 0.8125rem;
    color: #6b7280;
}

.msg-card__price-previous del {
    text-decoration: line-through;
}

.msg-card__price--drop {
    color: #b91c1c;
}

/* Compteur « {N} véhicules/voitures/motos en vente »
   (ListingShortcode::vehicleCountNoun(), templates/archive-msg_vehicule.php
   et templates/archive-listing.php). */
.msg-listing__count {
    margin: 0 0 1.5rem;
    color: #4b5563;
    font-size: 0.9375rem;
}

/* Fil d'ariane (ListingShortcode::breadcrumbItems(), archive uniquement —
   pas la fiche, cf. brief). */
.msg-breadcrumb {
    margin-bottom: 1rem;
}

.msg-breadcrumb__list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.8125rem;
    color: #6b7280;
}

.msg-breadcrumb__item:not(:last-child)::after {
    content: '\203A';
    margin-left: 0.375rem;
}

.msg-breadcrumb__item a {
    color: #1D1D77;
    text-decoration: none;
}

.msg-breadcrumb__item a:hover {
    text-decoration: underline;
}

.msg-breadcrumb__item span[aria-current='page'] {
    color: #111827;
    font-weight: 600;
}

/* Recherche libre (templates/parts/listing-filters.php, champ `q` en tête du
   formulaire) : même look que .msg-filters__select. Sa largeur n'est PLUS
   réglée ici — depuis Task 7 bis, les huit champs de la grille partagent les colonnes
   régulières de .msg-filters__grid (cf. plus haut). Une règle de largeur
   rescapée à cet endroit, PLUS BAS dans le fichier, écraserait
   silencieusement la disposition (même spécificité, dernière règle
   gagnante). */
.msg-filters__input {
    width: 100%;
    min-width: 0;
    padding: 0.375rem 0.5rem;
    border-radius: 0.375rem;
    border: 1px solid #6b7280;
    background: #ffffff;
    color: #111827;
    font-size: 0.875rem;
}

/* === Lot « parité Legrand » P2 (docs/ANALYSE-LEGRAND.md §A) : sidebar
   sticky, icônes-clés, pastille Crit'Air, étiquette CO₂, véhicules
   similaires. Append. ===================================================== */

/* --- Sidebar sticky (templates/single-msg_vehicule.php) ----------------- */

.msg-sidebar {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    padding: 1.25rem 1.5rem;
    border: 1px solid #6b7280;
    border-radius: 0.5rem;
    background: #ffffff;
    align-self: start;
}

/* Sticky à partir de 1024px seulement (spec) — même seuil que le retour à 1
   colonne de .msg-single__shell ci-dessus (symétrique : la sidebar n'est
   jamais "collée" quand elle est empilée sous la colonne principale). */
@media (min-width: 1024px) {
    .msg-sidebar {
        position: sticky;
        top: 90px;
    }
}

.msg-sidebar__ref {
    margin: 0 0 0.25rem;
    text-align: right;
    font-size: 0.75rem;
    color: #9ca3af;
}

.msg-sidebar__title {
    margin: 0;
    font-size: 1.375rem;
    font-weight: 700;
    line-height: 1.25;
}

/* Rangée de 4 icônes-clés (année/km/énergie/boîte) — grille responsive, une
   icône omise (valeur vide) ne laisse pas de trou disproportionné grâce à
   auto-fit. */
.msg-sidebar__icons {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(6rem, 1fr));
    gap: 0.75rem;
    margin: 0;
    padding: 0.75rem 0;
    list-style: none;
    border-top: 1px solid #e5e7eb;
    border-bottom: 1px solid #e5e7eb;
}

.msg-sidebar__icon {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    color: #374151;
    font-size: 0.8125rem;
    font-weight: 600;
}

.msg-sidebar__icon svg {
    flex: 0 0 auto;
    color: #1d4ed8;
}

.msg-sidebar__icon-value {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.msg-sidebar__price-block {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

.msg-sidebar__price-block .msg-single__price {
    margin: 0;
}

.msg-sidebar__price-block .msg-teaser {
    margin: 0;
}

.msg-sidebar__financing-link {
    font-size: 0.8125rem;
    font-weight: 600;
    color: #1d4ed8;
    text-decoration: none;
}

.msg-sidebar__financing-link:hover {
    text-decoration: underline;
}

.msg-sidebar__contact {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding-top: 1rem;
    border-top: 1px solid #e5e7eb;
}

.msg-sidebar__contact-btn {
    display: inline-block;
    padding: 0.5rem 1.25rem;
    border: 1px solid #1d4ed8;
    border-radius: 0.375rem;
    background: #ffffff;
    color: #1d4ed8;
    font-size: 0.875rem;
    font-weight: 600;
    text-decoration: none;
    text-align: center;
    cursor: pointer;
}

.msg-sidebar__contact-btn:hover {
    background: #eff6ff;
}

/* .msg-dealer (templates/parts/dealer-card.php) vit maintenant DANS la
   sidebar : neutralise sa bordure/marge de séparation propres (déjà posées
   par .msg-sidebar__contact ci-dessus), évite un double filet visuel. */
.msg-sidebar__contact .msg-dealer {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

/* --- Bloc « Me faire rappeler » (Leads\CallbackRequestRenderer) --------- */

.msg-callback {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 1rem;
    border: 1px solid #6b7280;
    border-radius: 0.375rem;
    background: #f9fafb;
}

.msg-callback__title {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
}

.msg-callback__intro {
    margin: 0;
    font-size: 0.8125rem;
    color: #4b5563;
}

.msg-callback__form {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.msg-callback__field {
    flex: 1 1 10rem;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.msg-callback__field input {
    padding: 0.5rem 0.625rem;
    border: 1px solid #6b7280;
    border-radius: 0.375rem;
    font-size: 0.875rem;
}

.msg-callback__field-error {
    color: #b91c1c;
    font-size: 0.75rem;
    min-height: 1em;
}

.msg-callback__submit {
    flex: 0 0 auto;
    padding: 0.5rem 1.25rem;
    border: none;
    border-radius: 0.375rem;
    background: #1d4ed8;
    color: #ffffff;
    font-size: 0.875rem;
    font-weight: 600;
    cursor: pointer;
}

.msg-callback__submit:hover {
    background: #1D1D77;
}

.msg-callback__submit:disabled {
    background: #9ca3af;
    cursor: not-allowed;
}

.msg-callback__success {
    margin: 0;
    color: #15803d;
    font-weight: 600;
    font-size: 0.8125rem;
}

.msg-callback__error {
    margin: 0;
    color: #b91c1c;
    font-size: 0.8125rem;
}

/* --- Pastille Crit'Air (Inventory\CritairBadge) -------------------------- */
/* Mapping couleur (spec) : 0/E vert foncé, 1 violet, 2 jaune, 3 orange,
   4 bordeaux, 5 gris. */

.msg-critair {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.1875rem 0.625rem;
    border-radius: 9999px;
    color: #ffffff;
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1.4;
}

.msg-critair--0 {
    background: #14532d; /* vert foncé */
}

.msg-critair--1 {
    background: #6d28d9; /* violet */
}

.msg-critair--2 {
    background: #ca8a04; /* jaune (assombri pour le contraste texte blanc) */
}

.msg-critair--3 {
    background: #ea580c; /* orange */
}

.msg-critair--4 {
    background: #9f1239; /* bordeaux */
}

.msg-critair--5 {
    background: #6b7280; /* gris */
}

/* --- Étiquette CO₂ (Inventory\Co2Label) ---------------------------------- */
/* Barème A→G (cf. docblock de Co2Label), dégradé vert → rouge, forme
   "flèche" via clip-path (repli rectangle simple sur les moteurs qui ne le
   supportent pas — dégradation propre, aucune perte d'information). */

.msg-co2 {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.1875rem 0.75rem 0.1875rem 0.625rem;
    clip-path: polygon(0 0, 88% 0, 100% 50%, 88% 100%, 0 100%);
    color: #ffffff;
    font-size: 0.75rem;
    line-height: 1.4;
}

.msg-co2__letter {
    font-weight: 800;
    font-size: 0.875rem;
}

.msg-co2__value {
    font-weight: 500;
}

.msg-co2--a {
    background: #15803d;
}

.msg-co2--b {
    background: #65a30d;
}

.msg-co2--c {
    background: #ca8a04;
}

.msg-co2--d {
    background: #d97706;
}

.msg-co2--e {
    background: #ea580c;
}

.msg-co2--f {
    background: #dc2626;
}

.msg-co2--g {
    background: #991b1b;
}

/* --- Véhicules similaires (templates/parts/similar-vehicles.php) -------- */

.msg-similar {
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid #e5e7eb;
}

.msg-similar__header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1rem;
}

.msg-similar__heading {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 700;
}

.msg-similar__more {
    font-size: 0.8125rem;
    font-weight: 600;
    color: #1d4ed8;
    text-decoration: none;
    white-space: nowrap;
}

.msg-similar__more:hover {
    text-decoration: underline;
}

/* Le nombre de colonnes suit la largeur de la SECTION, pas celle de l'écran
   (requête de conteneur) : la grille vit dans la colonne principale de la
   fiche, ~60 % de la largeur à côté de la sidebar. L'ancienne bascule sur la
   largeur d'écran (4 colonnes dès 1024 px) laissait, à 1200 px d'écran, quatre
   cartes de 153 px dans 673 px de grille : « dès 253,50 €/mois » cassé sur
   trois lignes (relevé en production le 2026-10-08, demande de Fred).
   Quatre colonnes seulement à partir de 56rem de section, soit ~210 px par
   carte, la largeur qu'il faut au bloc de financement pour tenir sa mensualité
   et son ⓘ sur une ligne ; deux colonnes en dessous, jamais trois (la
   quatrième carte resterait seule sur sa rangée).
   ⚠ Dans la fiche, la section plafonne à ~826 px même sur un écran de
   1920 px (largeur max de la page) : c'est donc en pratique un 2 × 2 partout
   sur ordinateur, et c'est voulu. Mesuré : forcées à 4 colonnes, les cartes
   font 191 px et « dès 311,63 €/mois » repasse sur deux lignes (bloc de
   financement à 192 px de haut). Ne pas baisser le seuil pour « retrouver »
   les 4 colonnes. */
.msg-similar {
    container-type: inline-size;
}

.msg-similar__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.25rem;
}

@container (min-width: 56rem) {
    .msg-similar__grid {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

/* Mobile : scroll horizontal plutôt qu'un empilement 1 colonne (spec) —
   cartes de largeur fixe dans une piste défilante. */
@media (max-width: 640px) {
    .msg-similar__grid {
        display: flex;
        overflow-x: auto;
        gap: 1rem;
        padding-bottom: 0.5rem;
        scroll-snap-type: x proximity;
    }

    .msg-similar__grid > .msg-card {
        flex: 0 0 80%;
        scroll-snap-align: start;
    }
}

/* === Anti-chevauchement fiche (bug utilisateur 2026-07-30 21:59) =========
   Un track `1fr` ne rétrécit jamais sous la largeur min-content de son
   contenu : les titres display du thème (« SIMULEZ VOTRE FINANCEMENT »,
   mot insécable en grand corps) imposaient une min-content > track, la
   grille LOA/simulateur débordait alors SOUS la sidebar sticky (fiche,
   1024-1300px) au lieu de se compresser. minmax(0, 1fr) autorise le track
   à rétrécir ; min-width: 0 fait pareil pour les colonnes du shell ;
   overflow-wrap: anywhere césure les mots insécables en dernier recours
   (utile aussi en vrai mobile ≤ 480px).
   Depuis le 2026-10-08 les pistes de la grille sont déclarées en minmax(0, 1fr)
   à la source (requête de conteneur `msg-main`, plus haut) : la règle
   `@media (min-width: 769px)` qui les redéclarait ici a été retirée — elle
   imposait deux colonnes selon la largeur d'ÉCRAN et l'emportait sur le
   conteneur. */
.msg-financing-grid > .msg-loa,
.msg-financing-grid > .msg-simulate {
    min-width: 0;
}

.msg-single__main,
.msg-sidebar {
    min-width: 0;
}

.msg-loa h2,
.msg-simulate h2,
.msg-callback__title,
.msg-dealer__title,
.msg-sidebar__title,
.msg-single__title {
    overflow-wrap: anywhere;
}

/* === Harmonisation hauteur input/bouton, bloc « Me faire rappeler »
   (bug utilisateur 2026-07-30, revue navigateur) ===========================
   Aladin-main-child/assets/scss/_btns.scss pose un reset global très
   spécifique sur TOUT <button> du site : `body.aladin .loop main button,
   input[type=button], .form_btn, .btn { height: 48px; padding: 12px 16px;
   font: 12px/20px "good-times"; ... }` — spécificité (0,2,3). Nos propres
   règles `.msg-*__submit` ci-dessus, simple sélecteur de classe (0,1,0), ne
   gagnent jamais contre ce sélecteur composé, quel que soit l'endroit du DOM
   où le gabarit/shortcode est rendu (pas de sélecteur d'ancêtre fiable à lui
   opposer). Conséquence : le bouton ENVOYER prend la hauteur fixe 48px du
   thème pendant que le champ téléphone suit notre propre CSS (~39px, cf.
   .msg-callback__field input plus haut) — l'écart visible signalé par
   l'utilisateur. Correctif volontairement MINIMAL : seul le padding
   vertical (donc la hauteur) est repris en main, PAS le fond/la police/les
   majuscules du thème — l'identité visuelle (bleu marine, police display)
   est hors périmètre de cette revue (cf. brief : « ne pas toucher aux
   couleurs/l'identité »). !important nécessaire pour battre la spécificité
   du thème sans dupliquer les sélecteurs de classe.
   .msg-filters__submit reçoit le même correctif par cohérence (même
   sélecteur de thème) : bouton masqué en usage normal une fois le JS actif
   à côté du champ de recherche — même écart potentiel. Il est visible dans
   tous les cas depuis le 2026-09-01 (cf. plus haut).
   2026-10-08 (relevé en production, demande de Fred) : les trois boutons du
   parcours financement rejoignent la liste. « DEMANDER CE FINANCEMENT », en
   capitales good-times dans une colonne étroite, passe sur deux lignes ; la
   hauteur fixe de 48 px du thème coupait alors la seconde ligne hors du fond
   du bouton. Même correctif minimal : hauteur et padding vertical seulement. */
.msg-callback__submit,
.msg-filters__submit,
.msg-credit-request__toggle,
.msg-credit-request__submit,
.msg-loa__submit {
    height: auto !important;
    padding-top: 0.5rem !important;
    padding-bottom: 0.5rem !important;
}

/* .msg-callback__form empile un champ (label en screen-reader-text + input +
   message d'erreur réservé, cf. .msg-callback__field) et un bouton sur une
   même ligne flex ; align-items:stretch (valeur par défaut) étirait le
   bouton — hauteur désormais auto, cf. règle ci-dessus — jusqu'à la hauteur
   TOTALE du champ (réserve d'erreur comprise), reproduisant le même écart de
   hauteur par un autre mécanisme. flex-start aligne le bouton sur le HAUT du
   champ : le label étant masqué visuellement (screen-reader-text, hauteur
   nulle), l'input démarre déjà en haut du champ. */
.msg-callback__form {
    align-items: flex-start;
}

/* === Cibles tactiles lightbox ≥ 44px en mobile (checklist accessibilité,
   revue navigateur 2026-07-30) ==============================================
   Le @media (max-width: 480px) plus haut réduit padding/font-size des
   boutons close/prev/next de la lightbox — mesuré ~26-34px de côté (device
   tools), sous le minimum recommandé pour une cible tactile (44px,
   WCAG 2.5.5 AAA / recommandation Apple-HIG et Material Design). Ce sont
   les SEULS moyens de fermer/naviguer la lightbox sur mobile (pas de swipe
   alternatif visible, uniquement une fermeture au clic sur l'overlay en
   plus). min-width/min-height forcent la zone cliquable à 44px SANS changer
   la taille visuelle de l'icône (display:inline-flex + centrage) — desktop
   non touché (déjà ~42-44px sans ce correctif, cf. règles de base plus
   haut). */
@media (max-width: 480px) {
    .msg-lightbox__close,
    .msg-lightbox__prev,
    .msg-lightbox__next {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 44px;
        min-height: 44px;
    }
}

/* === Cible tactile du repli équipements ≥ 44px (checklist accessibilité,
   revue navigateur 2026-07-30) ==============================================
   .msg-equipment__summary (déclenche le <details> « Voir les N équipements »
   au-delà de 20 items, cf. vehicle-equipment.php) n'a aucun padding vertical
   propre : sa hauteur cliquable se limite à la ligne de texte (~20px mesuré,
   device tools) — sous le minimum recommandé pour une cible tactile (44px).
   La largeur pleine (bloc de liste) reste inchangée, seul le padding
   vertical est ajouté ; le marqueur natif <summary> (triangle, cf. règle
   ::-webkit-details-marker plus haut) suit le padding sans ajustement
   supplémentaire. */
.msg-equipment__summary {
    padding: 0.75rem 0;
}

/* === Titres longs de carte (polish backlog, revue navigateur 2026-07-30) ==
   Les titres de véhicule sans limite de lignes (ex. « HONDA CRF CRF 1100 L
   AFRICA TWIN ADVENTURE SPORTS DCT SE 2025 ») poussent le prix/les specs
   plus bas que les cartes voisines de la même rangée de grille — aucun
   chevauchement (chaque carte garde sa propre hauteur, la grille n'impose
   pas d'égalité), mais un désalignement visuel du prix d'une carte à
   l'autre. line-clamp à 2 lignes borne la hauteur du titre sans toucher à
   sa taille/graisse/couleur (line-height:1.3 déjà défini plus haut) ;
   -webkit-line-clamp requis pour Safari, line-clamp (standard) pour les
   moteurs récents — les deux sont nécessaires, aucun n'est encore
   suffisant seul sur l'ensemble des navigateurs ciblés. */
.msg-card__title {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* === Prix barré sur la fiche (baisse mémorisée, 2026-07-31) ==============
   Mêmes codes visuels que la carte (.msg-card__price-previous /
   .msg-card__price--drop) : ancien prix barré discret au-dessus, prix
   courant en rouge sombre (contraste AA sur fond blanc). */
.msg-single__price-previous {
    margin: 0 0 -0.25rem;
    font-size: 0.95rem;
    color: #6b7280;
}

.msg-single__price--drop {
    color: #b91c1c;
}

/* === Couleur des titres de véhicule (retour client Arpeggio 2026-08-31) ===
   Le client a signalé, captures à l'appui, que le titre de sa fiche de démo
   était gris là où le site en production l'affiche en bleu marine.

   Ce qui était réellement en cause : le titre de FICHE (`.msg-sidebar__title`,
   un `<h1>`). Le thème pose bien `color: var(--color_primary)` sur les h2/h3
   (`body.aladin .loop main h3`, main.css) — mais PAS sur les h1, qui
   héritaient donc du gris de corps d'Aladin (`--color_secondary: #464646`).
   Mesuré : #464646 sans cette règle, #1D1D77 avec.

   `.msg-card__title` (un `<h3>`) est déjà bleu SANS nous, par la règle de
   thème ci-dessus — de spécificité (0,2,3), qu'un simple sélecteur de classe
   ne bat pas. La ligne est conservée quand même : le plugin est autonome du
   thème (cf. en-tête de ce fichier) et doit rendre ses titres à la couleur de
   marque hors contexte Aladin (autre thème, page d'aperçu). En contexte
   Aladin, elle ne change rien — ne pas la lire comme le correctif du bug.

   `var(--color_primary, #1D1D77)` et pas la valeur en dur : la variable est
   déclarée par le thème enfant (Aladin-main-child/assets/css/main.css, :root)
   — le jour où MS Groupe change son bleu, les fiches suivent sans nouvelle
   version du plugin. Le littéral ne sert que de repli.

   `.msg-card__link` pose `color: inherit` sur l'ancre qui ENVELOPPE le titre
   (lien étiré), pas sur le titre lui-même : la règle ci-dessous s'applique
   bien à l'élément, et l'emporte donc sur ce qu'il hériterait de l'ancre. */
.msg-card__title,
.msg-sidebar__title,
.msg-single__title {
    color: var(--color_primary, #1D1D77);
}

/* === Titres du carrousel « Véhicules similaires » (2026-08-31) ===========
   Effet de bord de la cascade de paliers (SimilarVehicles) : les similaires
   étant désormais du MÊME modèle, la partie discriminante du titre est la
   finition et la motorisation — « 218d 150ch Business Design » — précisément
   ce que `-webkit-line-clamp: 2` coupait. Les 4 cartes affichaient toutes
   « BMW SÉRIE 2… », indistinguables. Tant que les similaires étaient
   hétéroclites, le premier mot suffisait à les différencier ; ce n'est plus
   le cas.

   Deux leviers, uniquement dans le carrousel (la grille du listing, sur 4
   colonnes pleine largeur, n'a pas ce problème) : 4 lignes au lieu de 2, et
   un corps réduit — les cartes y font ~160 px de large, coincées à 4 colonnes à côté
   de la sidebar de fiche, et le thème les rend en `1.3em` (23,4 px mesurés)
   de police display majuscules.

   ⚠ `!important` sur la SEULE font-size, et c'est nécessaire : la règle de
   thème `body.aladin header h3, body.aladin .loop main h3` (main.css) a une
   spécificité de (0,2,3) que `.msg-similar__grid .msg-card__title` (0,2,0)
   ne bat pas — 0.8125rem était calculée à 23,4 px, la règle sans effet.
   Même situation, même remède que le reset des boutons du thème documenté
   plus haut dans ce fichier ; l'alternative (préfixer nos sélecteurs de
   `body.aladin .loop main`) coupleraient le plugin au thème. Le line-clamp,
   lui, n'a besoin de rien : le thème ne le pose pas.

   Pourquoi 4 et pas plus : mesuré sur la fiche témoin, 3 lignes laissent
   « 218d 150ch Business Design » et « 218d 150ch Luxury » coupés au MÊME
   endroit — deux cartes identiques à l'œil, soit le bug non corrigé ; 4
   lignes rendent 3 titres sur 4 entiers pour +20 px de hauteur de carte.
   Le clamp n'est pas supprimé pour autant : il borne la hauteur du titre et
   aligne les prix d'une carte à l'autre (motif d'origine, plus haut dans ce
   fichier), ce dont les titres moto les plus longs — « HONDA CRF CRF 1100 L
   AFRICA TWIN ADVENTURE SPORTS DCT SE 2025 » — ont toujours besoin.

   Hors du carrousel mobile (≤ 640px) : les cartes y passent en piste
   défilante à 80 % de largeur, où le titre respire déjà — le corps réduit y
   serait une perte de lisibilité sans contrepartie. */
@media (min-width: 641px) {
    .msg-similar__grid .msg-card__title {
        font-size: 0.8125rem !important;
        -webkit-line-clamp: 4;
        line-clamp: 4;
    }
}


/* Recherche libre, hors grille et pleine largeur (2026-09-01) : c'est le
   raccourci de tous les critères, pas un critère parmi neuf. */
.msg-filters__search {
    margin-bottom: 1rem;
}

.msg-filters__search .msg-filters__input {
    max-width: 32rem;
}

/* Le focus n'était nulle part défini sur les contrôles de filtre : ils
   héritaient du contour par défaut du navigateur, variable et parfois
   invisible sur fond clair. */
.msg-filters :is(input, select, button, a):focus-visible {
    outline: 2px solid #1D1D77;
    outline-offset: 2px;
}

/* La cible de l'ancre porte tabindex="-1" : sans cette règle, le navigateur
   lui dessine un contour de focus au chargement, ce qui n'a pas de sens sur
   un conteneur. */
.msg-filters__results:focus {
    outline: none;
}

/* Recherche interne à un panneau long (Modèle : 77 options). Injectée par
   le JavaScript, donc absente sans lui — la liste complète reste alors
   fonctionnelle. */
.msg-dropdown__search {
    position: sticky;
    top: 0;
    z-index: 1;
    margin: -0.5rem -0.5rem 0.5rem;
    padding: 0.5rem;
    background: #ffffff;
    border-bottom: 1px solid #e5e7eb;
}

.msg-dropdown__search-input {
    width: 100%;
    padding: 0.3125rem 0.5rem;
    border: 1px solid #6b7280;
    border-radius: 0.375rem;
    font-size: 0.8125rem;
}

.msg-dropdown__status {
    margin: 0.25rem 0 0;
    font-size: 0.75rem;
    color: #4b5563;
}

.msg-dropdown__status:empty {
    display: none;
}

/* === Étiquettes de filtres actifs (2026-09-01) ===========================
   Le manque que les trois revues du 2026-09-01 ont placé en tête : depuis que
   les facettes sont repliées en menus, l'état du filtrage est invisible — le
   bouton dit « 2 marques », pas lesquelles.

   ⚠ Ce sont des <a>, jamais des <button> : le thème parent impose à tout
   <button> du listing 48 px, les majuscules « good-times » et son marine. Un
   lien est de toute façon la sémantique juste pour une navigation GET. */
.msg-filters__active {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 1rem;
}

.msg-filters__active-label {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #4b5563;
}

.msg-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.25rem 0.5rem 0.25rem 0.625rem;
    border: 1px solid #c7c7de;
    border-radius: 999px;
    background: #f2f2f8;
    color: #1D1D77;
    font-size: 0.8125rem;
    line-height: 1.4;
    text-decoration: none;
}

.msg-chip:hover,
.msg-chip:focus-visible {
    border-color: #1D1D77;
    background: #e8e8f3;
    text-decoration: none;
}

.msg-chip__text strong {
    font-weight: 700;
}

.msg-chip__remove {
    font-size: 1rem;
    line-height: 1;
    color: #6b7280;
}

.msg-chip:hover .msg-chip__remove,
.msg-chip:focus-visible .msg-chip__remove {
    color: #1D1D77;
}

/* === Deux garde-fous que le plugin ne peut pas déléguer ==================

   1. `[hidden]`. Le partial de menu rend son bouton d'ouverture avec
   l'attribut `hidden` : c'est le JavaScript qui le révèle, et sans JS le
   fieldset déplié doit rester seul. Or la feuille du NAVIGATEUR déclare
   `[hidden] { display: none }` en règle NORMALE, quand `.msg-dropdown__toggle`
   ci-dessous doit passer en `display: flex !important` pour battre le reset
   global du thème parent sur les <button>. En cascade CSS, une déclaration
   AUTEUR `!important` l'emporte sur la feuille du navigateur : le bouton
   redevenait visible sans JavaScript — quatre boutons morts et sans nom
   accessible au-dessus des panneaux. Régression introduite le 2026-09-01 en
   harmonisant l'apparence, trouvée en revue d'accessibilité le jour même.
   Cette règle rétablit l'invariant, et doit rester AVANT les règles du menu.

   2. `.screen-reader-text`. Le plugin l'utilise (libellés d'options, labels de
   formulaire) sans l'avoir jamais définie : elle ne fonctionnait que parce que
   WordPress charge le CSS de la bibliothèque de blocs, que tout plugin de
   performance peut déprogrammer. Le listing en compte plus de cent
   occurrences — la dépendance implicite n'est pas tenable. */
[hidden] {
    display: none !important;
}

.msg-filters .screen-reader-text,
.msg-dropdown .screen-reader-text {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* === Menus déroulants à cases à cocher (2026-09-01) ======================
   Demande client : « sur le site actuel l'internaute avait la possibilité de
   filtrer dans le filtre. Ex : sélectionner MINI et BMW et pas le reste ».

   ⚠ Le panneau est DÉPLIÉ par défaut : c'est le rendu sans JavaScript, et il
   doit rester utilisable tel quel. Seule la classe
   `.msg-dropdown--collapsible`, posée par assets/js/listing-filters.js,
   autorise le repli. Masquer par défaut priverait de tout filtre un visiteur
   sans JavaScript.

   ⚠ SPÉCIFICITÉ ET !important — ce n'est pas de la paresse. Le thème parent
   pose `body.aladin .loop main button, .btn { … }` (spécificité (0,2,3)) qui
   impose à TOUT <button> du listing une hauteur de 48 px, la fonte
   « good-times » en majuscules et le marine du thème. Le bouton d'ouverture
   d'un menu de filtre s'affichait donc comme un CTA principal, massif à côté
   des <select> voisins (retour utilisateur 2026-09-01, « les nouvelles
   sélections sont trop massives »). Ces déclarations le ramènent à
   l'apparence exacte de .msg-filters__select, avec lequel il partage sa
   rangée. Piège déjà documenté au CLAUDE.md du plugin, section « Front vs
   parent theme ». */
.msg-dropdown {
    position: relative;
}

/* Calqué sur .msg-filters__select, à l'identique — les deux se côtoient dans
   la même grille et doivent être indiscernables. */
.msg-filters .msg-dropdown__toggle {
    display: flex !important;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    width: 100%;
    min-width: 0;
    height: auto !important;
    min-height: 0 !important;
    margin: 0 !important;
    padding: 0.375rem 0.5rem !important;
    border: 1px solid #6b7280 !important;
    border-radius: 0.375rem !important;
    background: #ffffff !important;
    color: #111827 !important;
    font-family: inherit !important;
    font-size: 0.875rem !important;
    font-weight: 400 !important;
    letter-spacing: normal !important;
    text-transform: none !important;
    text-align: left;
    line-height: 1.5;
    cursor: pointer;
}

.msg-filters .msg-dropdown__toggle:hover {
    border-color: #9ca3af !important;
}

/* Chevron, repris du rendu natif d'un <select>. */
.msg-dropdown__toggle::after {
    content: "";
    flex: 0 0 auto;
    width: 0.45rem;
    height: 0.45rem;
    margin-left: auto;
    border-right: 1.5px solid #6b7280;
    border-bottom: 1.5px solid #6b7280;
    transform: translateY(-0.15em) rotate(45deg);
    transition: transform 0.15s ease;
}

.msg-dropdown--open .msg-dropdown__toggle::after {
    transform: translateY(0.1em) rotate(-135deg);
}

/* Sélection active : discrète, une pastille de comptage plutôt qu'un gras qui
   ferait sauter la ligne de base par rapport aux selects voisins. */
.msg-filters .msg-dropdown--active .msg-dropdown__toggle {
    border-color: #111827 !important;
}

.msg-dropdown__panel {
    margin: 0.25rem 0 0;
    padding: 0.5rem;
    border: 1px solid #6b7280;
    border-radius: 0.375rem;
    background: #ffffff;
    max-height: 16rem;
    overflow-y: auto;
}

.msg-dropdown--collapsible .msg-dropdown__panel {
    display: none;
}

.msg-dropdown--collapsible.msg-dropdown--open .msg-dropdown__panel {
    display: block;
    position: absolute;
    z-index: 30;
    left: 0;
    right: 0;
    box-shadow: 0 8px 20px rgba(17, 24, 39, 0.12);
}

.msg-dropdown__group {
    margin: 0.5rem 0 0.25rem;
    padding: 0 0.25rem;
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #9ca3af;
}

.msg-dropdown__group:first-child {
    margin-top: 0;
}

/* ⚠ `user-select: none` n'est PAS cosmétique : sans lui, cliquer le libellé
   ne coche pas la case, alors que cliquer la case fonctionne — signalé le
   2026-09-01.

   Le balisage est pourtant correct (un <label for> contenant son <input>) et
   un clic programmatique sur le libellé, sur le texte ou sur le compteur
   produit bien UN seul `change` — vérifié. La différence tient au vrai clic
   souris : dès qu'il dérape d'un ou deux pixels SUR DU TEXTE, le navigateur
   l'interprète comme le début d'une sélection et n'active pas le libellé. La
   case à cocher, elle, ne porte aucun texte — d'où l'asymétrie constatée.

   Le thème parent applique la même parade à ses propres lignes à cocher
   (`.checkbox { user-select: none }`), c'est la convention du projet.

   La rangée est aussi rendue plus haute : 32 px de cible au lieu de 27,
   au-dessus du minimum de 24 px de WCAG 2.5.8 et plus confortable au doigt. */
.msg-dropdown__option {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4375rem 0.375rem;
    border-radius: 0.25rem;
    font-size: 0.875rem;
    color: #111827;
    cursor: pointer;
    -webkit-user-select: none;
    user-select: none;
}

.msg-dropdown__option:hover {
    background: #f3f4f6;
}

.msg-dropdown__option input[type="checkbox"] {
    flex: 0 0 auto;
    margin: 0;
    accent-color: #111827;
}

.msg-dropdown__option-label {
    flex: 1 1 auto;
    min-width: 0;
}

.msg-dropdown__count {
    flex: 0 0 auto;
    font-size: 0.75rem;
    /* #9ca3af donnait 2,54:1 sur blanc, sous le seuil WCAG AA de 4,5:1 — et
       c'est l'information même autour de laquelle le composant est construit.
       #4b5563 donne 7,2:1. Relevé en revue d'accessibilité le 2026-09-01. */
    color: #4b5563;
    font-variant-numeric: tabular-nums;
}

/* Option sans aucun véhicule : grisée et non cochable. Une option COCHÉE n'a
   JAMAIS cette classe, même à zéro — sinon elle deviendrait impossible à
   décocher et l'internaute serait prisonnier de la page. */
.msg-dropdown__option--empty {
    cursor: not-allowed;
    color: #c4c8ce;
}

.msg-dropdown__option--empty:hover {
    background: transparent;
}

.msg-dropdown__option--empty .msg-dropdown__count {
    color: #d8dbdf;
}

/* === Modale des mentions légales (templates/parts/legal-notices-dialog.php,
   assets/js/legal-notices.js) ============================================= */

/*
 * ⚠ LA MISE EN PAGE EST SCOPÉE À `[open]`, ET CE N'EST PAS UN RAFFINEMENT.
 * La feuille de style du navigateur rend `dialog:not([open])` en
 * `display: none`. Poser `display: flex` sur `.msg-legal-dialog` tout court
 * écraserait cette règle (même spécificité, notre feuille passe après) et
 * afficherait le conteneur, ouvert ou non, en haut de chaque page de listing.
 *
 * ⚠ `padding: 0` SUR LE `<dialog>` LUI-MÊME : la marge intérieure est portée
 * par `__head` et `__body`. C'est ce qui rend fiable la fermeture au clic sur
 * le voile (`event.target === dialog` dans legal-notices.js) — avec un padding
 * ici, un clic dans la marge du dialogue fermerait la modale par surprise.
 */
.msg-legal-dialog {
    /*
     * ⚠ `margin: auto` EXPLICITE, ET IL N'EST PAS REDONDANT. Une `<dialog>`
     * ouverte en `showModal()` est centrée par la feuille de style du
     * NAVIGATEUR, qui lui pose `position: fixed; inset: 0; margin: auto` : le
     * centrage se fait par marges automatiques, pas par `transform` ni par
     * flexbox. Or le thème parent charge Tailwind v4 au runtime
     * (`@tailwindcss/browser@4`, Aladin-main-child/includes/configTheme.php),
     * dont le preflight écrit `margin: 0` sur `*, ::after, ::before,
     * ::backdrop, ::file-selector-button`. Le `inset: 0` survit, le `auto`
     * meurt — et la modale se colle dans le COIN SUPÉRIEUR GAUCHE.
     *
     * Mesuré au navigateur le 2026-09-18 avant correction : `margin: 0px`,
     * rectangle à (0, 0) au lieu de (24, 61) dans une fenêtre de 500 x 812.
     * Aucune règle du plugin n'était en cause — nous ne déclarions simplement
     * pas ce que le navigateur fournissait déjà. Ne pas retirer cette ligne en
     * la croyant superflue : elle ne l'est que sur une page sans reset global.
     */
    margin: auto;
    width: min(42rem, 92vw);
    /* Deux déclarations, pas une coquille : `dvh` suit la barre d'adresse
       mobile qui se rétracte, `vh` sert de repli aux navigateurs qui l'ignorent
       (la seconde écrase la première là où elle est comprise). */
    max-height: 85vh;
    max-height: 85dvh;
    padding: 0;
    border: 0;
    border-radius: 0.75rem;
    box-shadow: 0 24px 48px rgba(17, 24, 39, 0.24);
    background: #ffffff;
    color: #111827;
}

.msg-legal-dialog[open] {
    display: flex;
    flex-direction: column;
}

.msg-legal-dialog::backdrop {
    background: rgba(17, 24, 39, 0.6);
}

/* `flex: none` : l'en-tête ne défile pas, seul le corps le fait. La zone de
   fermeture reste donc atteignable en permanence, y compris au milieu des
   ~5 000 caractères du bloc légal sur un écran de téléphone. */
.msg-legal-dialog__head {
    display: flex;
    flex: none;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid #e5e7eb;
}

/* Famille, taille, graisse et interligne redéclarés : le thème parent stylise
   ses titres par la propriété RACCOURCIE `font`, et un seul de ces axes laissé
   au thème suffit à faire déborder un titre de modale — leçon de
   `.msg-simulate__recap-title`, plus haut dans cette feuille. */
.msg-legal-dialog__title {
    margin: 0;
    font-family: inherit;
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.3;
    letter-spacing: normal;
    text-transform: none;
    color: #111827;
}

.msg-legal-dialog__dismiss {
    flex: none;
    margin: 0;
}

/* 2,75 rem de haut : cible de pointage confortable, bien au-delà du minimum de
   24 px de WCAG 2.5.8 — c'est le seul contrôle de la modale. */
.msg-legal-dialog__close {
    min-height: 2.75rem;
    padding: 0.5rem 0.875rem;
    border: 1px solid #d1d5db;
    border-radius: 0.375rem;
    background: #ffffff;
    font: inherit;
    font-size: 0.875rem;
    color: #111827;
    cursor: pointer;
}

.msg-legal-dialog__close:hover {
    background: #f3f4f6;
}

.msg-legal-dialog__close:focus-visible {
    outline: 2px solid #1D1D77;
    outline-offset: 2px;
}

/*
 * ⚠ DÉFILEMENT INTERNE ASSUMÉ ICI, alors que `.msg-simulate__recap` l'INTERDIT
 * plus haut dans cette feuille. Les deux règles sont justes ; lire la
 * différence avant d'« harmoniser » :
 *
 * - le récapitulatif du simulateur est affiché SANS action du visiteur, dans le
 *   champ visuel de la mensualité : des dernières lignes accessibles « en
 *   scrollant » y équivaudraient à un accordéon, que le guide refuse ;
 * - cette modale est déjà, par construction, derrière un clic — c'est le mode
 *   de consultation prévu pour les mentions COMPLÈTES. La mention pédagogique,
 *   elle, reste rendue en tête de listing par le gabarit, sans clic ni
 *   défilement.
 *
 * Sur un téléphone, 5 000 caractères ne tiennent dans aucune hauteur d'écran :
 * l'alternative au défilement interne n'est pas « tout voir d'un coup », c'est
 * une modale plus haute que l'écran dont la fermeture devient inatteignable.
 */
.msg-legal-dialog__body {
    flex: 1 1 auto;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 1rem 1.25rem 1.5rem;
}

/* 1. Nom du produit financier, en titre (ordre du guide BNP, p. 1). */
.msg-legal-dialog__product {
    margin: 0 0 0.75rem;
    font-family: inherit;
    font-size: 1.125rem;
    font-weight: 700;
    line-height: 1.3;
    letter-spacing: normal;
    text-transform: none;
    color: #111827;
}

/*
 * 2. Mention pédagogique. ⚠ SA TAILLE VIENT DE `.msg-legal--pedago`
 * (`--msg-legal-pedago`, soit essentiel + 1 px), classe posée par le script en
 * même temps que celle-ci : NE JAMAIS la redéclarer ici.
 *
 * Le bloc affiché juste en dessous porte des `style="font-size:16px"` INLINE
 * imposés par BNP. Rendue à la taille de base de la modale, cette mention
 * serait donc plus PETITE que des mentions essentielles voisines — violation
 * directe de la règle du pixel supplémentaire (guide p. 3), et dans le champ
 * visuel le plus dense de la page. Cette règle-ci ne fait que l'espacement.
 */
.msg-legal-dialog__pedago {
    margin: 0 0 1rem;
}

/* 3. Récapitulatif chiffré : tableau BNP, stylé avec celui du simulateur —
   déclaration unique, cf. `.msg-simulate__recap`. */
.msg-legal-dialog__recap {
    margin: 0 0 1rem;
}

/* 4. Exemple représentatif, assurances, bornes, financeur, rétractation.
   `.msg-legal--full` porte déjà l'interligne ABSOLU sans lequel les fragments
   de 16 px de BNP mettent le paragraphe en escalier. */
.msg-legal-dialog__full {
    margin: 0;
}

.msg-legal-dialog__loading {
    margin: 0;
    font-size: 0.875rem;
    color: #4b5563;
}

.msg-legal-dialog__unavailable p {
    margin: 0 0 0.75rem;
    font-size: 0.875rem;
    color: #4b5563;
}

.msg-legal-dialog__unavailable a {
    font-size: 0.875rem;
    color: #1d4ed8;
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

/* ⓘ CONSTRUIT EN `<button>` par simulate.js — son SEUL usager aujourd'hui.
   ⚠ `legal-notices.js` NE REHAUSSE PLUS RIEN : il est passé à une écoute
   déléguée sur le document (commit `5e5ceda`), justement pour ne plus dépendre
   de l'instant de naissance d'un ⓘ, et les ⓘ des cartes et de la barre latérale
   restent donc les `<a>` qu'ils sont. Reste le ⓘ du simulateur, né d'un
   résultat que seul JavaScript produit : sans destination à offrir, il est un
   vrai bouton, et il reprend la classe du ⓘ de carte pour garder partout le
   même aspect.
   D'où cette remise à zéro : sans elle, le navigateur lui ajouterait son fond
   gris, sa bordure et sa police système, et le même geste aurait deux aspects
   dans la même page. */
button.msg-card__legal-toggle {
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: var(--msg-legal-essential);
    line-height: var(--msg-card-financing-line);
    cursor: pointer;
}

/* Téléphone : la modale prend toute la largeur utile et monte à 92 % de la
   hauteur — le bloc légal y fait plusieurs écrans de haut de toute façon, et
   chaque point de marge gagné est une ligne de texte de plus. */
@media (max-width: 30rem) {
    .msg-legal-dialog {
        width: 96vw;
        max-height: 92vh;
        max-height: 92dvh;
        border-radius: 0.5rem;
    }

    .msg-legal-dialog__head {
        padding: 0.75rem 1rem;
    }

    .msg-legal-dialog__body {
        padding: 0.75rem 1rem 1.25rem;
    }
}

/* === Ligne de promotion des mobilités (arrêté du 28 décembre 2021) =======
 *
 * Obligation DISTINCTE de celles du guide BNP : elle porte sur la publicité
 * d'un véhicule, pas sur une offre de crédit (cf. `Inventory\MobilityNotice`).
 *
 * ⚠ SÉPARATION VISUELLE NORMATIVE. L'arrêté veut le message « clairement
 * distingué de la publicité ET DE TOUTE AUTRE MENTION OBLIGATOIRE » : le filet
 * et l'espace ci-dessous détachent la ligne du bloc `.msg-legal--full` qui la
 * précède sur les trois gabarits. Les réduire pour gagner de la place fait
 * retomber la ligne au contact des mentions BNP — c'est exactement ce que le
 * texte interdit.
 *
 * ⚠ TAILLE VOLONTAIREMENT INDÉPENDANTE de `--msg-legal-essential`, dont elle
 * partage aujourd'hui la valeur par coïncidence et non par dérivation : les
 * deux obligations viennent de sources différentes (Journal officiel d'un côté,
 * guide BNP de l'autre) et n'ont aucune raison de bouger ensemble. Un
 * `var(--msg-legal-essential)` ici ferait suivre silencieusement la ligne de
 * mobilité au premier réglage de la maquette de financement.
 *
 * ⚠ AUCUNE ANIMATION, ni `animation`, ni `transition`, ni `@keyframes` : la
 * rotation des trois messages est une alternance entre AFFICHAGES (cf. le
 * docblock de la classe), pas un mouvement dans la page — WCAG 2.2.2.
 */
.msg-mobility {
    /* Marge basse non nulle : la ligne est le DERNIER élément rendu par les
       trois gabarits, elle se retrouverait sinon collée au pied de page du
       thème. */
    margin: 2.5rem 0 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid #d1d5db;
    font-size: max(16px, 1rem);
    line-height: 1.5;

    /*
     * ⚠ VERT, ET C'EST LA SÉPARATION NORMATIVE QUI LE DEMANDE. L'arrêté veut le
     * message « clairement distingué de la publicité ET DE TOUTE AUTRE MENTION
     * OBLIGATOIRE » : le filet et l'espace le détachent du bloc BNP, une FAMILLE
     * DE COULEUR distincte du bleu de marque achève de dire que ce n'est pas la
     * dernière ligne des mentions de financement. Mesuré 7,68:1 sur blanc.
     *
     * ⚠ Le vert est une couleur, pas une information : le message reste
     * intégralement lisible en monochrome, et le pictogramme ci-dessous est
     * décoratif. Rien ici n'est « distingué par la couleur seule ».
     */
    color: #065f46;

    /* `!important` CIBLÉ, même discipline que partout ailleurs face au thème
       parent : `body.aladin .loop main p { font-weight: lighter }` ramenait la
       ligne à la graisse 100, mesuré — un message légal filiforme, exactement ce
       que « clairement distingué » interdit. */
    font-weight: 500 !important;

    /* Le pictogramme se pose comme premier élément de la ligne, sans entrer dans
       le balisage — le partiel ne rend qu'un `<p>`, et le texte de l'arrêté doit
       y rester seul. */
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
}

/*
 * ⚠ PICTOGRAMME DÉCORATIF, en CSS et non dans le gabarit. La feuille de mobilité
 * est un message légal : son élément ne doit contenir que le texte de l'arrêté et
 * son mot-dièse, sans quoi un lecteur d'écran annoncerait une image au milieu
 * d'une mention obligatoire. Une feuille plutôt qu'un bus : les trois
 * formulations de l'arrêté alternent entre la marche, le covoiturage et les
 * transports en commun, et seul `#SeDéplacerMoinsPolluer` leur est commun.
 *
 * ⚠ AUCUNE ANIMATION ICI NON PLUS (WCAG 2.2.2) — la règle vaut pour le
 * pseudo-élément comme pour son hôte.
 */
.msg-mobility::before {
    content: '';
    flex: none;
    width: 1.375rem;
    height: 1.375rem;
    /* Aligne la feuille sur la première ligne de texte plutôt que sur le haut
       de la boîte, dont l'interligne dépasse le glyphe. */
    margin-top: 0.0625rem;
    background: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23065f46'%20stroke-width='1.9'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M11%2020A7%207%200%200%201%209.8%206.1C15.5%205%2017%204.48%2019%202c1%202%202%204.18%202%208%200%205.5-4.78%2010-10%2010z'/%3E%3Cpath%20d='M2%2021c0-3%201.85-5.36%205.08-6C9.5%2014.52%2012%2013%2013%2012'/%3E%3C/svg%3E") no-repeat center / contain;
}

/* === Bandeau pédagogique collant ========================================
 *
 * « Un crédit vous engage et doit être remboursé… » doit rester visible « sans
 * avoir à cliquer ou à scroller » dès qu'une mensualité est affichée (guide des
 * mentions BNP, p. 3). Un paragraphe en tête du flux ne tenait cette promesse
 * qu'au chargement : au premier défilement il sortait de l'écran, tandis que
 * les mensualités des cartes, elles, continuaient de défiler.
 */

:root {
    /*
     * ⚠ DÉCALAGE VERTICAL DU BANDEAU — LA SEULE VALEUR À CHANGER EN RECETTE.
     *
     * Le thème parent Aladin rend son `<header>` COLLANT au défilement vers le
     * haut : `Aladin-main-child/assets/js/argus_main.js` lui ajoute alors les
     * classes Tailwind `sticky w-full top-0 z-99` (et les retire au défilement
     * vers le bas). Deux éléments collants à `top: 0` se superposent — et
     * celui du thème, à `z-index: 99`, passe devant : le bandeau disparaîtrait
     * derrière l'en-tête, sans la moindre erreur pour le signaler.
     *
     * Repli à 0 : c'est la valeur juste tant que l'en-tête n'est pas collant,
     * c'est-à-dire au chargement et pendant tout défilement vers le bas.
     *
     * ⚠ La valeur de recette n'a PAS été mesurée : elle reste à régler au
     * navigateur, sur listing, archive et fiche, en desktop ET en mobile — la
     * hauteur de l'en-tête n'y est pas la même. Premier candidat : 90px, la
     * garde que `.msg-sidebar` s'est déjà donnée face au même en-tête (cf.
     * plus haut).
     *
     * ⚠ Ne pas croire qu'il faudrait attendre quoi que ce soit pour la
     * mesurer : le bandeau ne dépend PAS des cartes. `legal-pedago-banner.php`
     * ne se garde que sur `LegalNoticesStore::current()` — il s'affiche donc
     * dès que des mentions ont été reçues dans cet environnement, même sur un
     * listing dont aucune carte n'affiche de mensualité.
     *
     * Se règle d'une ligne, ici ou depuis le thème :
     *     :root { --msg-pedago-banner-offset: 90px; }
     *
     * ⚠ SUR LA FICHE, RELEVER AUSSI `.msg-sidebar { top }` DU MÊME NOMBRE. La
     * sidebar est collante à partir de 1024 px, à `top: 90px` : un bandeau
     * décalé à 90px viendrait se poser exactement sur elle et, portant un
     * `z-index`, la recouvrirait. Les deux valeurs doivent s'empiler, pas se
     * croiser — bandeau à H, sidebar à H + hauteur du bandeau.
     */
    --msg-pedago-banner-offset: 0px;

    /*
     * ⚠ HAUTEUR MESURÉE DE L'EN-TÊTE DU THÈME, et le seul endroit où le plugin
     * connaît un nombre appartenant à Aladin. Relevée au navigateur le
     * 2026-09-18 sur msgroup.ddev.site : 108 px au-delà de 1024 px, 96 px en
     * dessous. Elle ne sert QUE dans la règle conditionnelle ci-dessous, donc
     * uniquement pendant les instants où l'en-tête est réellement collant.
     *
     * Un thème qui changerait la hauteur de son en-tête décalerait le bandeau
     * d'autant — c'est le prix à payer pour que la mention reste visible, et
     * c'est une valeur à revérifier au navigateur après toute refonte du thème.
     */
    --msg-theme-header-height: 108px;

    /*
     * Hauteur réservée au bandeau lui-même quand il faut empiler la barre
     * latérale de fiche EN DESSOUS de lui (cf. la règle conditionnelle). Mesurée
     * sur une mention tenant en une ligne, cas de tous les écrans ≥ 1024 px.
     */
    --msg-pedago-banner-height: 3.25rem;
}

@media (max-width: 1023px) {
    :root {
        --msg-theme-header-height: 96px;

        /* La mention passe de une à trois lignes à cette largeur : mesuré 95 px
           de bandeau, contre 52 au-delà de 1024 px. */
        --msg-pedago-banner-height: 6rem;
    }
}

/*
 * ⚠ `z-index` DÉLIBÉRÉMENT INFÉRIEUR au 99 de l'en-tête du thème. Le faire
 * passer devant recouvrirait le menu du site par une bande de texte légal : ce
 * n'est pas une guerre de plans qu'il faut gagner, c'est le décalage vertical
 * ci-dessus qu'il faut régler. 5 suffit à passer devant les cartes, qui n'ont
 * pas de `z-index` propre.
 *
 * ⚠ Le panneau d'un filtre ouvert (`.msg-dropdown__panel`, `z-index: 30`) passe
 * donc DEVANT le bandeau, et c'est le bon sens de lecture : les filtres sont
 * rendus juste sous lui, et un panneau tranché par une bande de texte légal
 * serait inutilisable. Le bandeau revient dès la fermeture du panneau —
 * l'exigence du guide porte sur ce que le visiteur voit SANS cliquer.
 *
 * ⚠ FOND OPAQUE OBLIGATOIRE. Un bandeau translucide laisserait les cartes
 * défiler sous le texte : la mention deviendrait illisible exactement quand
 * elle doit être lue.
 *
 * ⚠ `position: sticky` est neutralisé par tout ancêtre en `overflow: hidden`
 * ou `auto`. Aucun de nos conteneurs (`.msg-listing`, `.msg-archive`,
 * `.msg-single`) n'en pose ; à contrôler côté thème si le bandeau ne collait
 * pas, plutôt que d'incriminer cette règle.
 */
.msg-pedago-banner {
    position: sticky;
    top: var(--msg-pedago-banner-offset, 0px);
    z-index: 5;
    margin: 0 0 1.25rem;
    /* Réserve à gauche pour la silhouette, posée en fond (cf. plus bas). */
    padding: 0.875rem 1.5rem 0.875rem 5.25rem;
    border-radius: 0.5rem;
    color: #ffffff;
    text-align: center;

    /*
     * ⚠ FOND OPAQUE, EN DEUX DÉCLARATIONS, ET L'ORDRE EST LA DÉGRADATION.
     *
     * La première est une couleur pleine : c'est elle qui tient la promesse
     * d'opacité — un bandeau translucide laisserait les cartes défiler sous le
     * texte, et la mention deviendrait illisible exactement quand elle doit être
     * lue. La seconde la remplace là où `color-mix()` est compris ; là où il ne
     * l'est pas, la déclaration entière est invalide et la première tient.
     *
     * `var(--color_primary, #1D1D77)` et non le littéral : même convention que
     * `.msg-card__title` plus bas — la variable est déclarée par le thème enfant,
     * le jour où MS Groupe change son bleu le bandeau suit sans nouvelle version
     * du plugin, et le littéral n'est qu'un repli hors contexte Aladin.
     */
    background: var(--color_primary, #1D1D77);
    background:
        url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2064%2026'%3E%3Cg%20fill='%23ffffff'%20fill-opacity='.92'%3E%3Cpath%20d='M3.2%2019.4h3.1a5.6%205.6%200%200%200%2011.2%200h21.9a5.6%205.6%200%200%200%2011.2%200h4.2a2.2%202.2%200%200%200%202.2-2.2v-3.6a4.4%204.4%200%200%200-3.4-4.3l-9.3-2.2-6.2-4.2A7.7%207.7%200%200%200%2033.8.7H22.4a7.7%207.7%200%200%200-6.1%203L11.7%209.8%204.4%2011.5A4.4%204.4%200%200%200%201%2015.8v1.4a2.2%202.2%200%200%200%202.2%202.2z'/%3E%3Ccircle%20cx='11.9'%20cy='19.4'%20r='3.6'/%3E%3Ccircle%20cx='44.8'%20cy='19.4'%20r='3.6'/%3E%3C/g%3E%3C/svg%3E") no-repeat 1.5rem center / 3rem auto,
        linear-gradient(
            100deg,
            color-mix(in srgb, var(--color_primary, #1D1D77) 72%, #000000) 0%,
            var(--color_primary, #1D1D77) 55%,
            color-mix(in srgb, var(--color_primary, #1D1D77) 88%, #ffffff) 100%
        );
    box-shadow: 0 2px 12px rgba(17, 24, 39, 0.18);
}

/*
 * ⚠ LE BANDEAU DOIT S'EFFACER SOUS L'EN-TÊTE DU THÈME, JAMAIS PASSER DEVANT.
 *
 * Mesuré au navigateur le 2026-09-18, et c'est le défaut que la règle corrige :
 * `Aladin-main-child/assets/js/argus_main.js` ajoute `sticky w-full top-0 z-99`
 * à l'en-tête AU DÉFILEMENT REMONTANT (et les retire en descendant). Deux
 * éléments collants à `top: 0`, celui du thème à `z-index: 99` — le bandeau
 * disparaissait INTÉGRALEMENT derrière un en-tête de 108 px, sans la moindre
 * erreur pour le signaler, exactement pendant le geste où le visiteur remonte
 * vers les mensualités.
 *
 * ⚠ CONDITIONNELLE, ET C'EST TOUT LE POINT. Un décalage CONSTANT — la piste que
 * le commentaire précédent proposait — serait juste pendant le défilement
 * remontant et faux le reste du temps : au chargement et pendant tout
 * défilement descendant, l'en-tête n'est pas collant, et le bandeau laisserait
 * une bande de 108 px de cartes défiler à découvert au-dessus de lui. Le
 * `:has()` fait porter le décalage exactement sur les instants où il est dû.
 *
 * ⚠ `body:has(header.sticky)` et non `.loop:has(…)` : le plugin reste autonome
 * du thème (cf. l'en-tête de ce fichier). Hors contexte Aladin, ou le jour où le
 * thème cesse de poser cette classe, le sélecteur ne s'apparie simplement jamais
 * et le bandeau retrouve son comportement à `top: 0`.
 */
body:has(header.sticky) .msg-pedago-banner {
    top: calc(var(--msg-pedago-banner-offset, 0px) + var(--msg-theme-header-height));
}

/*
 * ⚠ LA BARRE LATÉRALE DE FICHE S'EMPILE SOUS LE BANDEAU, ELLE NE LE CROISE PAS.
 *
 * Corollaire obligatoire de la règle ci-dessus : la sidebar est collante à
 * `top: 90px` à partir de 1024 px, le bandeau décalé passerait exactement sur
 * elle et, portant un `z-index`, la recouvrirait d'une bande bleue opaque. Les
 * deux valeurs doivent s'empiler — bandeau à H, sidebar à H + hauteur du
 * bandeau.
 *
 * ⚠ MÊME CONDITION, ET PAS UNE AUTRE : hors défilement remontant, la sidebar
 * reprend ses 90 px. Le décaler en permanence la ferait démarrer 200 px plus bas
 * que la colonne principale.
 */
@media (min-width: 1024px) {
    body:has(header.sticky) .msg-sidebar {
        top: calc(var(--msg-theme-header-height) + var(--msg-pedago-banner-height));
    }
}

/* La marge basse du bloc est portée par le bandeau : la laisser ici creuserait
   un blanc à l'intérieur de la bande collante. */
.msg-pedago-banner .msg-legal--pedago {
    margin: 0;
    /* Blanc sur bleu nuit — 10,1:1 au point le plus clair du dégradé, mesuré. */
    color: #ffffff;
    /* Le registre demandé par le client : une mention qui SE VOIT. La taille,
       elle, reste celle de `--msg-legal-pedago` — normative, jamais décorative. */
    font-weight: 700;
    line-height: 1.4;
    text-wrap: balance;
}

/*
 * Sous 600 px, la silhouette cède la place au texte : la mention fait trois
 * lignes à cette largeur, et 5,25 rem de réserve à gauche lui en coûteraient une
 * quatrième — dans un bandeau collant, donc autant de hauteur d'écran en moins
 * sur le support majoritaire.
 */
@media (max-width: 599px) {
    .msg-pedago-banner {
        padding: 0.75rem 1rem;

        /*
         * ⚠ LA SURCHARGE REPASSE PAR LE RACCOURCI `background`, ET PAS PAR
         * `background-image` SEUL. Le raccourci de la règle de base décrit DEUX
         * couches et fixe donc `background-size`, `-position` et `-repeat` à deux
         * valeurs chacun — dont `3rem auto`, `1.5rem center` et `no-repeat` pour
         * la silhouette. Ne remplacer que l'image laisse ces longhands en place :
         * le dégradé hérite alors de la taille de l'icône et se peint en une
         * bande de 3 rem à gauche, le reste du bandeau restant clair avec du
         * texte BLANC dessus — illisible, et constaté à l'écran le 2026-09-18
         * avant correction.
         */
        background: var(--color_primary, #1D1D77);
        background: linear-gradient(
            100deg,
            color-mix(in srgb, var(--color_primary, #1D1D77) 72%, #000000) 0%,
            var(--color_primary, #1D1D77) 55%,
            color-mix(in srgb, var(--color_primary, #1D1D77) 88%, #ffffff) 100%
        );
    }
}
