/* Core Bridge — Frontend CSS */
/* ─── Variables ──────────────────────────────────────────────────────────── */
:root {
  --crb-primary:       #2271b1;
  --crb-premium:       #f0a500;
  --crb-premium-dark:  #c47f00;
  --crb-danger:        #c00;
  --crb-success:       #0a0;
  --crb-bg:            #f6f7f7;
  --crb-surface:       #fff;
  --crb-border:        #dde0e3;
  --crb-text:          #1e1e1e;
  --crb-text-muted:    #6b7280;
  --crb-radius:        8px;
  --crb-radius-sm:     6px;
  --crb-radius-lg:     12px;
  --crb-radius-pill:   999px;   /* pills / avatars / dots */
  /* Ombres multi-niveaux (skinnables) — DEUX couches par niveau.
     Une ombre unique et floue lit comme un halo collé sous un rectangle. Un objet
     réel en projette deux : un contact net et serré juste sous lui (il touche le
     plan), et une ambiance large et très diluée (la lumière du reste de la pièce).
     C'est ce couple, pas l'opacité, qui fait qu'une surface paraît épaisse.
     Rayon négatif d'étalement sur la couche large : elle ne déborde pas sur les
     côtés, elle tombe — le poids se lit vers le bas, comme sous une lumière haute. */
  --crb-shadow-sm:     0 1px 2px  color-mix(in srgb, var(--crb-text) 5%,  transparent),
                       0 4px 10px -4px color-mix(in srgb, var(--crb-text) 10%, transparent);
  --crb-shadow-md:     0 1px 2px  color-mix(in srgb, var(--crb-text) 5%,  transparent),
                       0 14px 32px -12px color-mix(in srgb, var(--crb-text) 20%, transparent);
  --crb-shadow-lg:     0 2px 4px  color-mix(in srgb, var(--crb-text) 6%,  transparent),
                       0 28px 56px -20px color-mix(in srgb, var(--crb-text) 28%, transparent);
  --crb-shadow:        var(--crb-shadow-md);   /* alias historique = niveau medium */
  /* Surface des CTA (boutons primaires / FAB) — un skin peut y poser un dégradé */
  --crb-cta-bg:        var(--crb-primary);
  /* `0 0 #0000` et non `none` : ces tokens sont désormais COMPOSÉS avec l'arête de
     lumière (`box-shadow: var(--crb-edge-highlight), var(--crb-cta-shadow)`), et
     `A, none` est une liste invalide qui ferait tomber la déclaration entière.
     Une ombre nulle transparente rend le même vide, mais reste composable. */
  --crb-cta-shadow:    0 0 #0000;
  /* Sémantique swipe/matching (skinnable) — convention like=vert, pass=rouge, super=bleu */
  --crb-like:          var(--crb-success);
  --crb-pass:          var(--crb-danger);
  --crb-superlike:     #1d6ef5;
  --crb-touch-min:     44px;
  /* Tailles d'icônes (jeu vectoriel cohérent, skinnable) */
  --crb-icon-sm:       16px;
  --crb-icon-md:       20px;
  --crb-icon-lg:       24px;
  /* Échelle d'espacement 4px (skinnable : densité) */
  --crb-space-1:       4px;
  --crb-space-2:       8px;
  --crb-space-3:       12px;
  --crb-space-4:       16px;
  --crb-space-5:       24px;
  --crb-space-6:       32px;
  /* Graisses typographiques (skinnable) */
  --crb-fw-regular:    400;
  --crb-fw-medium:     500;
  --crb-fw-semibold:   600;
  --crb-fw-bold:       700;
  /* Échelle typographique (skinnable : densité/personnalité). Valeurs calées sur
     les tailles réellement utilisées dans le plugin → migration sans régression. */
  --crb-fs-3xs:        .7rem;
  --crb-fs-2xs:        .75rem;
  --crb-fs-xs:         .8rem;
  --crb-fs-sm:         .85rem;
  --crb-fs-base:       .9rem;
  --crb-fs-md:         .95rem;
  --crb-fs-lg:         1rem;
  --crb-fs-xl:         1.1rem;
  --crb-fs-2xl:        1.25rem;
  --crb-fs-3xl:        1.5rem;
  --crb-fs-4xl:        1.75rem;
  --crb-fs-5xl:        2rem;
  --crb-fs-6xl:        2.6rem;
  --crb-fs-7xl:        3.5rem;
  /* Interlignage (skinnable) */
  --crb-lh-tight:      1.2;
  --crb-lh-base:       1.5;
  --crb-lh-loose:      1.7;
  /* Personnalité typo des titres (skinnable) */
  --crb-heading-weight:   700;
  --crb-heading-tracking: 0;     /* letter-spacing des titres */
  /* Approche (letter-spacing) — jamais une valeur unique pour toute l'interface :
     elle est fonction de la TAILLE. Plus un caractère grandit, plus le blanc entre
     deux lettres grandit avec lui : à 2rem, une approche neutre se lit déjà
     délavée, d'où le serrage négatif. Inversement une légende à .75rem a besoin
     d'un peu d'air pour rester lisible. Une capitale isolée (eyebrow) n'a ni
     jambage ni hampe pour se distinguer : c'est l'approche qui fait le travail. */
  --crb-track-display: -.028em;  /* ≥ 2rem      : titres d'accueil, gros chiffres */
  --crb-track-title:   -.014em;  /* 1.1–1.75rem : titres de section, pseudos */
  --crb-track-body:    0;        /* corps de texte */
  --crb-track-caption: .005em;   /* ≤ .8rem     : méta, aide, horodatage */
  --crb-track-label:   .08em;    /* capitales   : eyebrows, badges */
  /* Mouvement (skinnable) */
  --crb-ease:          cubic-bezier(.4,0,.2,1);
  --crb-ease-out:      cubic-bezier(0,0,.2,1);
  --crb-dur-fast:      .12s;
  --crb-dur-base:      .18s;
  --crb-dur-slow:      .32s;
  --crb-transition:    var(--crb-dur-base) ease;
  /* Trois courbes de plus, nommées par USAGE — le nom dit quand s'en servir :
       emphasized : entrée d'un élément ou changement de panneau. Démarre vite,
                    arrive long et amorti : l'œil suit sans être bousculé.
       spring     : retour d'un élément RELÂCHÉ (dépassement léger). À ne poser que
                    sur un geste qui portait de l'élan — un dépassement sur un menu
                    qui vient d'apparaître se lit comme un défaut, pas comme une
                    matière.
       exit       : sortie. Accélère et ne s'attarde pas : ce qui part n'a plus
                    besoin d'être lu. */
  --crb-ease-emphasized: cubic-bezier(.2, .9, .25, 1);
  --crb-ease-spring:     cubic-bezier(.34, 1.38, .5, 1);
  --crb-ease-exit:       cubic-bezier(.4, 0, 1, 1);
  --crb-dur-slower:      .48s;
  /* Enfoncement — retour tactile posé au POINTER-DOWN, jamais au relâchement :
     attendre le clic fait tomber la sensation de direct. Deux amplitudes : une
     petite surface peut s'enfoncer franchement, une carte de 300px non (le même
     ratio y devient un saut). */
  --crb-press-scale:     .97;
  --crb-press-scale-lg:  .985;
  --crb-lift:            -2px;    /* élévation au survol d'une surface cliquable */
  /* Anneau de focus accessible. La primaire PLEINE, et non un mélange à 55 % de
     transparent : sur une surface claire, l'ancien anneau se lisait comme une
     teinte pâle plutôt que comme un contour, et il disparaissait carrément posé
     sur une photo. Un indicateur de focus n'a pas à être discret — c'est le seul
     repère d'un membre qui navigue au clavier. */
  --crb-focus-ring:    var(--crb-primary);
  /* ── MATIÈRE ──────────────────────────────────────────────────────────────
     Les couches de « chrome » (topbar, barre mobile, drawer, menus, bottom-sheets,
     lightbox) ne sont pas des bandeaux opaques qui confisquent une bande d'écran :
     ce sont des couches translucides sous lesquelles le contenu continue de
     défiler. C'est ce qui donne la profondeur — on voit qu'il y a quelque chose
     dessous, donc il y a un dessous.
     La COULEUR reste gouvernée par l'admin (dérivée de --crb-surface) : seule
     l'opacité et le flou sont des décisions de design. La saturation compense le
     délavage qu'introduit le flou. */
  --crb-glass-bg:        color-mix(in srgb, var(--crb-surface) 76%, transparent);
  /* La topbar a sa propre couleur de socle (`--crb-nav-bg`, réglable en admin) :
     son verre en dérive séparément. Token à part entière — un skin qui renonce au
     flou DOIT pouvoir le rendre opaque, faute de quoi il obtiendrait une barre
     transparente sans flou, c'est-à-dire du texte qui défile lisiblement derrière
     d'autre texte. */
  --crb-glass-nav:       color-mix(in srgb, var(--crb-nav-bg) 76%, transparent);
  --crb-glass-bg-strong: color-mix(in srgb, var(--crb-surface) 88%, transparent);
  --crb-glass-blur:      18px;
  --crb-glass-saturate:  175%;
  /* Tranche d'une surface levée.
     ATTENTION — la première version posait ici un reflet BLANC sur l'arête haute
     (`inset 0 1px 0 rgba(255,255,255,.5)`). C'est l'idiome des interfaces sombres :
     sur une surface blanche — c'est-à-dire sur la totalité de ce produit — du blanc
     à 50 % sur du blanc ne rend RIEN. Le volet « matière » ne contribuait donc
     strictement rien au rendu statique.
     Ce qui lit sur une surface claire, c'est l'inverse : une LÈVRE basse, très
     légèrement assombrie, comme le dessous d'une tranche qui prend l'ombre. Dérivée
     de `--crb-text`, donc elle suit la palette au lieu d'imposer un gris.
     Elle fonctionne aussi sur une surface sombre ou colorée — contrairement au
     reflet blanc, qui n'avait qu'un seul cas d'usage valide. */
  --crb-edge-highlight:  inset 0 -1px 0 color-mix(in srgb, var(--crb-text) 7%, transparent);
  /* Le reflet blanc garde UN emploi légitime : le CTA, dont la surface est colorée
     et opaque. Token séparé, composé en plus de l'arête sur `.crb-btn--primary`. */
  --crb-cta-sheen:       inset 0 1px 0 rgba(255,255,255,.28);
  /* Squelettes de chargement : la surface et sa bande de lumière, toutes deux
     dérivées de la palette. L'attente fait partie de l'interface — un squelette
     hors palette est la première chose qu'un membre voit d'un écran. */
  --crb-skeleton-bg:     color-mix(in srgb, var(--crb-text) 8%, var(--crb-surface));
  --crb-skeleton-sheen:  color-mix(in srgb, var(--crb-text) 3%, var(--crb-surface));
  /* Séparation interne, plus légère que --crb-border (qui délimite un composant). */
  --crb-hairline:        color-mix(in srgb, var(--crb-border) 55%, transparent);
  /* Voile d'une tâche MODALE : dérivé de la couleur de texte, pas du noir pur, pour
     que l'assombrissement garde la teinte de la palette au lieu de la neutraliser. */
  --crb-veil:            color-mix(in srgb, var(--crb-text) 52%, transparent);
  /* ── Tokens DÉRIVÉS (color-mix, zéro PHP) ────────────────────────────────
     Portabilité : il suffit qu'Impreza fournisse --crb-primary + --crb-surface,
     tout le reste (survols, teintes, surfaces alternées) se calcule ici. */
  --crb-primary-hover: color-mix(in srgb, var(--crb-primary) 85%, #000);            /* survol CTA / liens */
  --crb-primary-tint:  color-mix(in srgb, var(--crb-primary) 12%, var(--crb-surface)); /* fond d'accent doux */
  --crb-danger-tint:   color-mix(in srgb, var(--crb-danger)  10%, var(--crb-surface));
  --crb-premium-tint:  color-mix(in srgb, var(--crb-premium) 14%, var(--crb-surface));
  --crb-bg-hover:      color-mix(in srgb, var(--crb-text)     6%, var(--crb-surface)); /* survol de ligne / surface */
  --crb-surface-alt:   color-mix(in srgb, var(--crb-text)     3%, var(--crb-surface)); /* surface alternée */
  --crb-border-soft:   color-mix(in srgb, var(--crb-border)  60%, transparent);
  /* TEINTE de base du survol du CTA — c'est le seul point d'entrée surchargé par
     l'admin › Couleurs (`color_button_bg_hover`). Les skins ne l'écrasent pas : ils en
     DÉRIVENT leur dégradé de survol (cf. skins/*.css), si bien qu'une couleur choisie en
     admin garde la personnalité du skin au lieu de l'aplatir. Ne jamais surcharger
     `--crb-cta-bg-hover` directement depuis PHP : ce serait imposer un aplat. */
  --crb-cta-hover-base: var(--crb-primary-hover);
  --crb-cta-bg-hover:  var(--crb-cta-hover-base);  /* survol du CTA primaire (un skin peut y poser un dégradé) */
  /* ── Rôles secondaires pilotables depuis l'admin › Couleurs (mode manual) ──
     Défauts = valeurs actuelles → aucune régression tant que l'admin garde les
     couleurs par défaut ; seule une surcharge admin (FrontendHooks) les modifie.
     Ces variables corrigent le fait que color_button_*, color_accent,
     color_notification et color_nav_* n'étaient consommées nulle part. */
  --crb-cta-text:      #fff;                 /* texte des boutons CTA (color_button_text) */
  --crb-cta-text-hover: var(--crb-cta-text); /* texte des CTA au survol (color_button_text_hover ;
                                                vide en admin = « automatique » = inchangé) */
  --crb-accent:        var(--crb-success);   /* indicateurs positifs / « en ligne » (color_accent) */
  --crb-notification:  var(--crb-danger);    /* badges de compteur (color_notification) */
  --crb-nav-bg:        var(--crb-surface);   /* fond de la barre de navigation (color_nav_bg) */
  --crb-nav-text:      var(--crb-text);      /* libellés de la navigation (color_nav_text) */
  /* Hauteur du header (thème) fixe à compenser — à paramétrer dans l'admin plus tard.
     NB : le shell front 3 colonnes (.crb-shell) ne s'en sert plus (sa topbar interne
     occupe le haut) ; cette variable reste pour les vues hors-shell (messagerie
     standalone, toolbar Découvrir mobile). */
  --crb-header-height: 100px;
  /* Hauteur de la topbar FIXE du shell (recherche/filtres/compte). La page membre
     n'a PAS de header de thème : la topbar est épinglée au tout en haut (top:0) et
     occupe cette hauteur. Sert de padding-top au contenu (clearance) et d'offset
     sticky aux éléments internes (rail droit, onglets compte, photo de profil). */
  --crb-topbar-height: 64px;
  --crb-topbar-clearance: var(--crb-topbar-height);
  /* Hauteur de la barre mobile du shell (hamburger + titre, <1024px). Variable
     car les vues plein écran (messagerie mobile) doivent en déduire la hauteur
     utile du viewport : à ne jamais recopier en dur. */
  --crb-mobilebar-height: 56px;
  /* Largeur de la colonne gauche réservée du shell pleine largeur (.crb-shell).
     Affichée à partir de ≥1024px ; contenu à définir ultérieurement. */
  --crb-shell-aside-width: 280px;
  /* Largeur de la colonne droite contextuelle (.crb-shell__rail, Phase B).
     Affichée ≥1024px seulement quand le panneau actif fournit des widgets. */
  --crb-shell-rail-width: 320px;
  /* Typographie — héritée du thème par défaut (surchargée par skin/admin en Phase 2) */
  --crb-font:          inherit;
  /* Échelle de z-index centralisée — évite les conflits avec le header/megamenu Impreza */
  --crb-z-raised:      2;      /* badges posés sur une carte (super-like) */
  --crb-z-sticky:      10;     /* en-têtes sticky internes (chat, progress, CTA) */
  --crb-z-dropdown:    100;    /* tooltips, menus déroulants */
  --crb-z-nav:         200;    /* conteneur bottom-sheet */
  --crb-z-fixed:       1000;   /* barre de navigation fixe */
  --crb-z-sheet:       1001;   /* panneau bottom-sheet / tooltip en toolbar */
  --crb-z-toast:       9999;   /* toasts de feedback */
  --crb-z-modal:       99990;  /* modales (nudge) */
  --crb-z-lightbox:    100000; /* lightbox galerie (au-dessus de tout) */
}

/* ─── Reset ─────────────────────────────────────────────────────────────── */
.crb-plugin *, .crb-plugin *::before, .crb-plugin *::after {
  box-sizing: border-box;
}
/* Le thème enfant pose `header { z-index: 1000 !important }` (règle sans classe,
   écrite pour son ancien menu .meetMenu) : elle atteint TOUS nos <header> internes.
   Sur un élément `position: static` un z-index est normalement ignoré — mais pas
   sur un ITEM FLEX, où la spec flexbox le fait honorer. Or les deux en-têtes de la
   messagerie en sont : `.crb-inbox__header` dans `.crb-inbox` et `.crb-chat__header`
   dans `.crb-chat`, tous deux en flex-direction:column. Ils créaient donc un contexte
   d'empilement à 1000 dans le dashboard, au-dessus de la barre mobile (--crb-z-dropdown),
   et le menu compte de celle-ci passait dessous — en mobile uniquement, puisque ≥1024px
   la barre laisse place à la topbar. On rend la main à l'échelle --crb-z-* ; les deux
   en-têtes qui ont vraiment besoin d'un rang le redéclarent, en !important puisqu'il
   faut repasser devant celui du thème. */
.crb-plugin header { z-index: auto !important; }
.crb-plugin .crb-topbar      { z-index: var(--crb-z-fixed) !important; }
.crb-plugin .crb-chat__header { z-index: var(--crb-z-sticky) !important; }
.crb-plugin { color: var(--crb-text); line-height: 1.5; font-family: var(--crb-font); }
/* Certains contextes d'insertion (éditeur classique, page-builder) enveloppent la
   sortie d'un shortcode dans <code>/<pre>. Ces balises portent une police monospace
   (et souvent une taille réduite) via la feuille du navigateur/thème, qui se propage
   à TOUT le contenu (ex. galerie) et masque la police de corps (--crb-font, réglage
   font_family). On rétablit l'héritage de la police et de la taille sous .crb-plugin.
   Sélecteurs scindés (spécificité 0,2,0) pour dépasser une éventuelle règle de thème. */
.crb-plugin code,
.crb-plugin pre,
.crb-plugin kbd,
.crb-plugin samp,
.crb-plugin tt {
  font-family: inherit;
  font-size: inherit;
}
/* Neutralise l'héritage du thème (police/taille des champs) SANS l'emporter sur les
   composants crb-* : :where() a une spécificité nulle, donc .crb-form__input gagne. */
.crb-plugin :where(button, input, select, textarea, optgroup) {
  font-family: inherit;
  font-size: 100%;
  line-height: inherit;
  margin: 0;
  color: inherit;
}
/* Neutralise le « chrome » natif des boutons hérité du thème (fond/bordure/ombre que
   certains thèmes — dont Impreza — appliquent à <button>). Spécificité nulle : tout
   composant .crb-btn / .crb-*-btn réimpose son propre style. */
.crb-plugin :where(button) {
  -webkit-appearance: none;
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  border-radius: 0;
  box-shadow: none;
  text-align: inherit;
  text-transform: none;
}
/* Retire l'ombre interne des champs héritée du thème (Impreza : `box-shadow:
   var(--inputs-box-shadow)` sur `input:not([type=submit]), textarea, select`).
   Sélecteurs scindés (pas de :where) pour dépasser la spécificité de la règle du thème. */
.crb-plugin input:not([type=submit]),
.crb-plugin textarea,
.crb-plugin select {
  box-shadow: none;
}
/* Focus visible accessible et homogène — anneau dérivé de la primaire (skinnable). */
.crb-plugin :where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--crb-focus-ring);
  outline-offset: 2px;
}

/* Accessibilité : neutralise les animations non essentielles si l'utilisateur le demande. */
@media (prefers-reduced-motion: reduce) {
  .crb-plugin *, .crb-plugin *::before, .crb-plugin *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ─── Boutons ────────────────────────────────────────────────────────────── */
.crb-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: var(--crb-touch-min);
  padding: 0 18px;
  border-radius: var(--crb-radius);
  font-size: var(--crb-fs-md);
  font-weight: var(--crb-fw-semibold);
  cursor: pointer;
  text-decoration: none;
  border: 1px solid transparent;
  /* `background` (raccourci) couvre aussi `background-image`, donc les dégradés des skins
     s'animent. Deux garde-fous rendent ça sûr : (1) repos et survol sont toujours de même
     nature — un skin à dégradé dérive AUSSI son survol en dégradé de même angle et même
     nombre de bornes, donc interpolable ; (2) le socle opaque posé sur `.crb-btn--primary`
     empêche tout état transparent. Sans eux, une image non interpolable (dégradé → none)
     bascule au MILIEU de la transition et laisse voir la page au travers du bouton — le
     flash blanc constaté quand le survol était imposé en aplat. */
  transition: background var(--crb-transition),
              box-shadow var(--crb-dur-base) var(--crb-ease),
              transform var(--crb-dur-slow) var(--crb-ease-spring);
  white-space: nowrap;
  /* L'approche suit la taille du libellé, pas une valeur unique (cf. --crb-track-*). */
  letter-spacing: var(--crb-track-body);
}
/* L'enfoncement part au POINTER-DOWN et doit être là au même frame que le doigt :
   la transition d'entrée est donc court-circuitée (durée quasi nulle, courbe de
   sortie), tandis que le RELÂCHEMENT reprend la transition longue à ressort
   déclarée juste au-dessus. Deux vitesses pour un seul état : c'est ce décalage
   qui fait la différence entre « le bouton réagit » et « le bouton est animé ». */
.crb-btn:active {
  transform: scale(var(--crb-press-scale));
  transition: transform var(--crb-dur-fast) var(--crb-ease-exit);
}

/* Socle opaque sous le CTA : quand `--crb-cta-bg` est un dégradé (skins aurora/bold), le
   raccourci `background` le range dans `background-image` et remet `background-color` à
   `transparent`. Le bouton n'a alors AUCUNE couleur de fond propre, et tout survol qui
   retire l'image laisse voir la page au travers. On repose donc explicitement la primaire
   en couleur de fond : invisible sous un dégradé opaque, elle sert de point de départ à la
   transition vers la couleur de survol. */
/* Arête de lumière EN PLUS du halo du skin : le CTA est la surface la plus levée
   d'un écran, c'est elle qui doit accrocher la lumière en premier. */
.crb-btn--primary  { background: var(--crb-cta-bg);   background-color: var(--crb-primary); color: var(--crb-cta-text); box-shadow: var(--crb-cta-sheen), var(--crb-edge-highlight), var(--crb-cta-shadow); }
.crb-btn--primary:hover { background: var(--crb-cta-bg-hover); color: var(--crb-cta-text-hover); }
.crb-btn--premium  { background: var(--crb-premium);  color: #fff; }
.crb-btn--premium:hover { background: var(--crb-premium-dark); color: #fff; }
.crb-btn--outline:hover { background: var(--crb-primary-tint); }
.crb-btn--danger   { background: var(--crb-danger);   color: #fff; }
.crb-btn--outline  { border-color: var(--crb-border); color: var(--crb-primary); background: transparent; }
.crb-btn--ghost    { background: transparent; color: var(--crb-text-muted); }
.crb-btn--ghost:hover { background: var(--crb-bg-hover); color: var(--crb-text); }
/* Action secondaire (upload photo, Modifier, télécharger un ebook…) : surface
   neutre bordée, pour rester lisible à côté d'un CTA coloré. Sans cette règle,
   `.crb-btn--secondary` n'apportait ni fond ni bordure et les boutons
   ressemblaient à du texte brut. */
.crb-btn--secondary { background: var(--crb-surface); color: var(--crb-text); border-color: var(--crb-border); }
.crb-btn--secondary:hover { background: var(--crb-bg-hover); color: var(--crb-text); }

/* Impreza applique, depuis sa feuille générée (uploads/us-assets/<site>.css) :
     .no-touch a:hover { text-decoration: underline; color: var(--color-content-link-hover) }
   Spécificité (0,2,1) — elle bat le `text-decoration:none` de `.crb-btn` (0,1,0) ET la
   `color` des modificateurs (0,1,0). Conséquence : tout bouton rendu en <a> (« Envoyer un
   message » des cartes Découvrir et de la fiche profil) se soulignait au survol et son
   libellé virait au bleu-gris #447490 sur le dégradé rose — d'où l'effet « délavé ». Les
   mêmes CTA rendus en <button> (accueil, « Découvrir mes matchs ») n'étaient pas touchés,
   d'où la différence entre les deux pages. `.no-touch` n'existant que sur pointeur fin, le
   bug ne se voyait qu'au bureau. On repasse devant en (0,3,1), sans !important. */
.crb-plugin a.crb-btn,
.crb-plugin a.crb-btn:link,
.crb-plugin a.crb-btn:visited,
.crb-plugin a.crb-btn:hover,
.crb-plugin a.crb-btn:focus,
.crb-plugin a.crb-btn:active { text-decoration: none; }
.crb-plugin a.crb-btn--primary:hover   { color: var(--crb-cta-text-hover); }
.crb-plugin a.crb-btn--premium:hover   { color: #fff; }
.crb-plugin a.crb-btn--danger:hover    { color: #fff; }
.crb-plugin a.crb-btn--outline:hover   { color: var(--crb-primary); }
.crb-plugin a.crb-btn--secondary:hover { color: var(--crb-text); }
.crb-plugin a.crb-btn--ghost:hover     { color: var(--crb-text); }

.crb-btn--sm  { min-height: 36px; padding: 0 12px; font-size: var(--crb-fs-sm); }
.crb-btn--xs  { min-height: 30px; padding: 0 10px; font-size: var(--crb-fs-xs); }
.crb-btn--lg  { min-height: 52px; padding: 0 28px; font-size: var(--crb-fs-xl); }

/* Impreza (theme.css) cible `button[type=submit]:not(.w-btn)` avec une spécificité
   (0,2,1) — gradient violet, padding 0.8em/1.8em, color:#fff!important et un :before
   d'imitation de bordure — qui bat `.crb-btn` (0,1,0). Les boutons « submit » du
   plugin (réf. Enregistrer du formulaire profil) héritaient donc du skin du thème.
   On réaffirme le composant ici avec assez de spécificité (0,3,1) pour gagner, sans
   !important. Les `type="button"` (ex. `.crb-pf-save`) n'étaient pas touchés. */
.crb-plugin button[type="submit"].crb-btn {
  display: inline-flex;
  padding: 0 18px;
  border: 2px solid transparent;
  border-radius: var(--crb-radius);
  line-height: 1.2;
}
.crb-plugin button[type="submit"].crb-btn::before { content: none; }
.crb-plugin button[type="submit"].crb-btn--sm { padding: 0 12px; }
.crb-plugin button[type="submit"].crb-btn--lg { padding: 0 28px; }
/* Ce raccourci (0,3,1) réécrit `background-color` : il faut y reposer le socle opaque,
   sinon les boutons « submit » retrouvent le fond transparent et le flash au survol. */
.crb-plugin button[type="submit"].crb-btn--primary { background: var(--crb-cta-bg); background-color: var(--crb-primary); }
.crb-plugin button[type="submit"].crb-btn--primary:hover { background: var(--crb-cta-bg-hover); }

/* ─── Géolocalisation (onglet Profil) ────────────────────────────────────── */
.crb-geo__prompt {
  background: var(--crb-primary-tint);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius);
  padding: 10px 12px;
  margin-bottom: 10px;
}
.crb-geo__intro {
  margin: 0;
  font-size: var(--crb-fs-sm);
  line-height: 1.45;
  color: var(--crb-text);
}
.crb-geo__active {
  margin: 0 0 10px;
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-success);
}
.crb-geo__actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.crb-geo__status {
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
}
.crb-geo__help {
  margin-top: 10px;
  background: var(--crb-warning-tint, #fff7e6);
  border: 1px solid var(--crb-warning, #d98c00);
  border-radius: var(--crb-radius);
  padding: 10px 12px;
}
.crb-geo__help-title {
  margin: 0 0 4px;
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text);
}
.crb-geo__help-text {
  margin: 0 0 8px;
  font-size: var(--crb-fs-sm);
  line-height: 1.45;
  color: var(--crb-text);
}

/* ─── Badges ─────────────────────────────────────────────────────────────── */
.crb-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--crb-radius-pill);
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-bold);
  text-transform: uppercase;
  /* Capitales à très petit corps : c'est le cas où l'approche compte le plus. */
  letter-spacing: var(--crb-track-label);
}
.crb-badge .crb-icon { width: 1em; height: 1em; vertical-align: -0.12em; }
.crb-badge--premium { background: var(--crb-premium); color: #fff; }
.crb-badge--fake    { background: var(--crb-danger);  color: #fff; }

/* ─── Cards ─────────────────────────────────────────────────────────────── */
/* Aucun survol ici : `.crb-card` sert aussi de conteneur de LECTURE (réglages,
   texte d'aide), et une carte qui se soulève sans être cliquable ment sur ce
   qu'elle offre. L'élévation au survol est réservée aux surfaces réellement
   activables (cartes membre, galerie, lignes de conversation). */
.crb-card {
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  padding: 20px;
  box-shadow: var(--crb-edge-highlight), var(--crb-shadow);
}

/* ─── Nudge — Bannière ──────────────────────────────────────────────────── */
.crb-nudge--banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 16px;
  border-radius: var(--crb-radius);
  border-left: 4px solid currentColor;
  margin: 8px 0;
  font-size: var(--crb-fs-base);
  animation: crb-slide-in .2s ease;
}
.crb-nudge--banner.crb-nudge--blocked  { background: var(--crb-danger-tint);  color: var(--crb-danger); }
.crb-nudge--banner.crb-nudge--warning  { background: var(--crb-premium-tint); color: #b45309; }
.crb-nudge--banner.crb-nudge--info     { background: var(--crb-primary-tint); color: var(--crb-primary); }

.crb-nudge__body {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
}
.crb-nudge__text {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: baseline;
}
.crb-nudge__title  { font-weight: var(--crb-fw-bold); margin-right: 4px; }
.crb-nudge__message { color: inherit; opacity: .9; }

.crb-nudge__close {
  background: none;
  border: none;
  cursor: pointer;
  font-size: var(--crb-fs-2xl);
  opacity: .6;
  padding: 0 4px;
  line-height: 1;
  transition: opacity var(--crb-transition);
}
.crb-nudge__close:hover { opacity: 1; }

/* ─── Nudge — Modal ─────────────────────────────────────────────────────── */
.crb-nudge--modal {
  position: fixed;
  inset: 0;
  z-index: var(--crb-z-modal);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0 0 env(safe-area-inset-bottom);
}
@media (min-width: 600px) {
  .crb-nudge--modal { align-items: center; }
}
.crb-nudge__backdrop {
  position: absolute;
  inset: 0;
  background: var(--crb-veil);
  animation: crb-fade-in var(--crb-dur-base) var(--crb-ease-out);
}
.crb-nudge__dialog {
  position: relative;
  background: var(--crb-surface);
  border-radius: var(--crb-radius-lg) var(--crb-radius-lg) 0 0;
  padding: 32px 24px 28px;
  width: 100%;
  max-width: 480px;
  text-align: center;
  /* Une feuille modale monte du bas : elle porte l'élan de son entrée, donc un
     léger dépassement y est juste — la même courbe sur un menu déroulant, non. */
  animation: crb-slide-up var(--crb-dur-slow) var(--crb-ease-emphasized);
  box-shadow: var(--crb-edge-highlight), var(--crb-shadow-lg);
}
@media (min-width: 600px) {
  .crb-nudge__dialog { border-radius: var(--crb-radius-lg); }
}
.crb-nudge__icon-lg { font-size: var(--crb-fs-6xl); margin-bottom: 12px; color: var(--crb-premium); }
.crb-nudge__icon-lg svg { width: var(--crb-fs-6xl); height: var(--crb-fs-6xl); display: inline-block; }
.crb-nudge__dialog .crb-nudge__title   { display: block; font-size: var(--crb-fs-2xl); font-weight: var(--crb-fw-bold); margin-bottom: 8px; }
.crb-nudge__dialog .crb-nudge__message { color: var(--crb-text-muted); margin-bottom: 20px; line-height: 1.5; }
.crb-nudge__dialog .crb-nudge__close   { position: absolute; top: 12px; right: 14px; font-size: var(--crb-fs-3xl); }
.crb-nudge__actions { display: flex; flex-direction: column; gap: 8px; }
.crb-nudge__skip    { background: none; border: none; cursor: pointer; color: var(--crb-text-muted); font-size: var(--crb-fs-sm); padding: 6px; text-decoration: underline; }

/* ─── Nudge — Overlay ───────────────────────────────────────────────────── */
.crb-nudge--overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0,0,0,.55);
  backdrop-filter: blur(4px);
  border-radius: inherit;
  z-index: var(--crb-z-sticky);
}
.crb-nudge__overlay-inner {
  text-align: center;
  color: #fff;
  padding: 20px 16px;
}
.crb-nudge__overlay-inner .crb-nudge__title   { font-size: var(--crb-fs-lg); font-weight: var(--crb-fw-bold); margin-bottom: 6px; display: block; }
.crb-nudge__overlay-inner .crb-nudge__message { font-size: var(--crb-fs-sm); opacity: .85; margin-bottom: 14px; }
.crb-nudge__lock-icon { font-size: var(--crb-fs-4xl); display: block; margin-bottom: 8px; }

/* ─── Nudge — Tooltip ───────────────────────────────────────────────────── */
.crb-nudge--tooltip {
  position: relative;
  display: inline-block;
}
.crb-nudge__tooltip-content {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  background: #1a1a2e;
  color: #fff;
  border-radius: 6px;
  padding: 10px 12px;
  font-size: var(--crb-fs-xs);
  white-space: nowrap;
  min-width: 160px;
  text-align: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity .15s;
  z-index: var(--crb-z-dropdown);
  box-shadow: var(--crb-shadow);
}
/* Pont invisible comblant l'écart de 8px entre le badge et le tooltip,
   pour pouvoir atteindre le lien sans que le tooltip ne se ferme. */
.crb-nudge__tooltip-content::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: 10px;
}
.crb-nudge--tooltip:hover .crb-nudge__tooltip-content,
.crb-nudge__tooltip-trigger:focus + .crb-nudge__tooltip-content {
  opacity: 1;
  pointer-events: auto;
}
/* Dans la toolbar (sticky en haut), le badge est près du bord droit et le header
   du thème passe au-dessus : on ouvre le tooltip vers le bas, ancré à droite. */
.crb-discover-toolbar__actions .crb-nudge__tooltip-content {
  top: calc(100% + 8px);
  bottom: auto;
  left: auto;
  right: 0;
  transform: none;
  z-index: var(--crb-z-sheet);
}
/* Tooltip ouvert vers le bas : le pont va au-dessus du contenu, vers le badge. */
.crb-discover-toolbar__actions .crb-nudge__tooltip-content::before {
  top: auto;
  bottom: 100%;
}
.crb-nudge__tooltip-cta {
  display: block;
  margin-top: 6px;
  color: var(--crb-premium);
  font-weight: var(--crb-fw-bold);
  text-decoration: none;
}

/* ─── Statuts de transaction (tokenisés, dérivés des couleurs sémantiques) ─── */
.crb-status { display: inline-block; padding: 2px 8px; border-radius: var(--crb-radius-pill); font-size: var(--crb-fs-2xs); font-weight: var(--crb-fw-semibold); }
.crb-status--paid     { background: color-mix(in srgb, var(--crb-success) 15%, var(--crb-surface)); color: color-mix(in srgb, var(--crb-success) 60%, #000); }
.crb-status--pending  { background: var(--crb-premium-tint); color: var(--crb-premium-dark); }
.crb-status--failed   { background: var(--crb-danger-tint);  color: color-mix(in srgb, var(--crb-danger) 65%, #000); }
.crb-status--refunded { background: var(--crb-primary-tint); color: color-mix(in srgb, var(--crb-primary) 65%, #000); }

/* ─── Messages / Bulles ─────────────────────────────────────────────────── */
.crb-chat { display: flex; flex-direction: column; height: 100%; position: relative; }
.crb-chat__header {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--crb-border);
  background: var(--crb-surface);
  position: sticky; top: 0; z-index: var(--crb-z-sticky);
}
.crb-chat__messages {
  flex: 1; overflow-y: auto; padding: 16px;
  display: flex; flex-direction: column; gap: 6px;
}
.crb-bubble {
  max-width: 72%; padding: 10px 14px; border-radius: 18px;
  line-height: 1.4; font-size: var(--crb-fs-base); position: relative;
  word-break: break-word;
  margin-bottom: 16px; /* réserve la place pour l'horodatage placé sous la bulle */
}
.crb-bubble--theirs { background: var(--crb-bubble-theirs-bg, var(--crb-surface)); color: var(--crb-bubble-theirs-text, var(--crb-text)); border: 1px solid var(--crb-border); align-self: flex-start; border-bottom-left-radius: 4px; }
.crb-bubble--mine   { background: var(--crb-bubble-mine-bg, var(--crb-primary)); color: var(--crb-bubble-mine-text, #fff); border: 1px solid var(--crb-border); align-self: flex-end; border-bottom-right-radius: 4px; }
/* Émojis (Twemoji : le glyphe devient un <img class="emoji"> dimensionné à 1em par WP).
   Dans les bulles, la police de corps est petite → l'émoji paraît minuscule. On l'agrandit
   pour retrouver une taille lisible proche de celle du sélecteur.
   WordPress imprime un style inline `img.emoji { width/height: 1em !important }` dans le
   <head> : il faut donc surcharger avec !important, sinon la taille reste bloquée à 1em. */
.crb-bubble__text img.emoji {
  width: 1.4em !important; height: 1.4em !important; vertical-align: -0.25em !important; margin: 0 .05em !important;
}
/* Horodatage sorti de la bulle : positionné juste en dessous, côté de la bulle. */
.crb-bubble__meta {
  position: absolute; top: calc(100% + 3px);
  font-size: var(--crb-fs-3xs); opacity: 1; white-space: nowrap;
  color: var(--crb-text-muted); pointer-events: none;
}
.crb-bubble--mine .crb-bubble__meta   { right: 4px; text-align: right; }
.crb-bubble--theirs .crb-bubble__meta { left: 4px; text-align: left; }
/* Accusé de lecture : ✓ grisé (envoyé, non lu) → ✓✓ vert gras (lu). */
.crb-tick { margin-left: 3px; opacity: .65; font-weight: var(--crb-fw-regular); }
.crb-tick[data-read="1"] { color: var(--crb-success); opacity: 1; font-weight: var(--crb-fw-bold); }
.crb-tick svg { width: 16px; height: 12px; vertical-align: middle; }
.crb-tick__date { margin-left: 4px; font-weight: var(--crb-fw-regular); opacity: .85; }
.crb-separator { text-align: center; font-size: var(--crb-fs-2xs); color: var(--crb-text-muted); margin: 8px 0; }
.crb-date-sep { align-self: stretch; text-align: center; font-size: var(--crb-fs-2xs); color: var(--crb-text-muted); margin: 8px 0; }
.crb-online-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--crb-success); display: inline-block; }

/* ─── Carte « À propos » du correspondant → 3ᵉ colonne (rail droit) ─────────── */
/* Déplacée par app.js dans #crb-context-rail .crb-rail-widgets[data-panel="messages"]
   (visible ≥1024px via la grille .is-rail-active). Même langage visuel que les
   autres cartes de rail (.crb-rail-card). */
.crb-chat-about {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: var(--crb-space-4);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
}
.crb-chat-about[hidden] { display: none; }
.crb-chat-about__head {
  display: flex;
  align-items: center;
  gap: 12px;
}
.crb-chat-about__avatar {
  position: relative;
  width: 56px; height: 56px;
  border-radius: var(--crb-radius-pill);
  flex-shrink: 0;
}
.crb-chat-about__avatar img {
  width: 56px; height: 56px;
  border-radius: var(--crb-radius-pill);
  object-fit: cover;
  display: block;
}
.crb-chat-about__avatar--online::after {
  content: "";
  position: absolute; right: 2px; bottom: 2px;
  width: 12px; height: 12px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-success);
  border: 2px solid var(--crb-surface);
}
.crb-chat-about__id { flex: 1; min-width: 0; }
.crb-chat-about__title {
  margin: 0;
  font-weight: var(--crb-fw-bold);
  font-size: var(--crb-fs-lg);
  color: var(--crb-text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.crb-chat-about__sub {
  margin: 2px 0 0;
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
}
.crb-chat-about__more {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 8px 14px;
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-pill);
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-primary);
  text-decoration: none;
  transition: background .15s, border-color .15s;
}
.crb-chat-about__more:hover,
.crb-chat-about__more:focus-visible {
  background: var(--crb-primary-tint);
  border-color: var(--crb-primary);
}
.crb-chat-about__facts {
  list-style: none;
  margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.crb-chat-about__fact {
  display: flex; align-items: center; gap: 8px;
  font-size: var(--crb-fs-sm);
  color: var(--crb-text);
}
.crb-chat-about__fact-icon {
  width: var(--crb-icon-sm); height: var(--crb-icon-sm);
  flex-shrink: 0;
  color: var(--crb-text-muted);
}
.crb-chat-about__fact-label {
  color: var(--crb-text-muted);
  margin-right: 4px;
}
.crb-chat-about__bio {
  margin: 0;
  font-size: var(--crb-fs-sm);
  line-height: var(--crb-lh-base);
  color: var(--crb-text);
  white-space: pre-line;
  word-break: break-word;
}
.crb-chat-about__tags {
  list-style: none;
  margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 6px;
}
.crb-chat-about__tag {
  padding: 4px 10px;
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-pill);
  font-size: var(--crb-fs-xs);
  color: var(--crb-text);
  background: var(--crb-bg);
}

.crb-rail-widgets > section {
    margin-bottom: .75rem;
}

/* ─── Rail messagerie : KPIs de réactivité du correspondant ───────────────── */
/* Déplacés par app.js dans le rail droit (data-crb-rail-widget). Deux mini-cartes
   côte à côte (Temps moyen de réponse / Taux de réponse). */
.crb-rail-kpis {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.crb-rail-kpis[hidden] { display: none; }
.crb-rail-kpi {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: var(--crb-space-3);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
}
.crb-rail-kpi__label {
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
  line-height: var(--crb-lh-base);
}
.crb-rail-kpi__value {
  font-size: var(--crb-fs-xl);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text);
}
.crb-rail-kpi__value--empty {
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-medium);
  font-style: italic;
  color: var(--crb-text-muted);
}
.crb-rail-kpi__trend {
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-success);
}

/* ─── Rail messagerie : bloc « Sécurité & confiance » ─────────────────────── */
.crb-rail-safety {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: var(--crb-space-4);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
}
.crb-rail-safety[hidden] { display: none; }
.crb-rail-safety__head {
  display: flex;
  align-items: center;
  gap: 8px;
}
.crb-rail-safety__icon {
  width: var(--crb-icon-sm); height: var(--crb-icon-sm);
  flex-shrink: 0;
  color: var(--crb-primary);
}
.crb-rail-safety__title {
  font-weight: var(--crb-fw-bold);
  font-size: var(--crb-fs-base);
  color: var(--crb-text);
}
.crb-rail-safety__text {
  margin: 0;
  font-size: var(--crb-fs-sm);
  line-height: var(--crb-lh-base);
  color: var(--crb-text-muted);
}
.crb-rail-safety__actions {
  display: flex;
  gap: 10px;
}
.crb-rail-safety__action {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 10px;
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-pill);
  background: var(--crb-surface);
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-medium);
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.crb-rail-safety__action svg {
  width: var(--crb-icon-sm); height: var(--crb-icon-sm);
  flex-shrink: 0;
}
.crb-rail-safety__action--report { color: var(--crb-primary); }
.crb-rail-safety__action--report:hover,
.crb-rail-safety__action--report:focus-visible {
  background: var(--crb-primary-tint);
  border-color: var(--crb-primary);
}
.crb-rail-safety__action--block { color: var(--crb-danger); }
.crb-rail-safety__action--block:hover,
.crb-rail-safety__action--block:focus-visible {
  background: var(--crb-danger-tint);
  border-color: var(--crb-danger);
}

/* États « fait » : l'action est figée en rappel visuel (non cliquable). */
.crb-rail-safety__action--reported,
.crb-rail-safety__action--blocked {
  cursor: default;
  pointer-events: none;
}
.crb-rail-safety__action--reported {
  color: var(--crb-primary);
  background: var(--crb-primary-tint);
  border-color: var(--crb-primary);
}
.crb-rail-safety__action--blocked {
  color: var(--crb-danger);
  background: var(--crb-danger-tint);
  border-color: var(--crb-danger);
}

/* Retrait de son propre signalement : lien discret sous les actions du rail. */
.crb-rail-safety__undo {
  display: block;
  margin-top: 8px;
  width: 100%;
  padding: 4px 0;
  border: 0;
  background: none;
  color: var(--crb-text-muted);
  font-size: var(--crb-fs-sm);
  text-align: center;
  text-decoration: underline;
  cursor: pointer;
  transition: color .15s;
}
.crb-rail-safety__undo:hover,
.crb-rail-safety__undo:focus-visible {
  color: var(--crb-text);
}

/* ─── Rail fiche profil : « Affichage des fiches » (gabarit du lecteur) ─────
   Même réglage que l'onglet « Affichage » du compte, posé là où on le juge :
   sur une fiche ouverte. Reprend la carte du bloc Sécurité (tête, texte) pour
   que le rail garde une seule grammaire ; seule la grille d'options change —
   trois wireframes de front dans 320 px, donc sans les descriptions, reportées
   en infobulle. */
.crb-rail-tpl {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: var(--crb-space-4);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
}
.crb-rail-tpl[hidden] { display: none; }
.crb-rail-tpl__opts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}
.crb-rail-tpl__opt {
  position: relative;                  /* ancre le radio masqué */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 6px;
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius);
  background: var(--crb-surface);
  cursor: pointer;
  transition: border-color var(--crb-transition), background var(--crb-transition);
}
.crb-rail-tpl__opt:hover { border-color: var(--crb-primary); }
.crb-rail-tpl__opt.is-active {
  border-color: var(--crb-primary);
  box-shadow: inset 0 0 0 1px var(--crb-primary);
}
/* Le radio reste dans le DOM (navigation clavier, état coché) ; la vignette
   entière est la cible du clic. */
.crb-rail-tpl__radio { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; }
.crb-rail-tpl__opt:has(.crb-rail-tpl__radio:focus-visible) {
  outline: 2px solid var(--crb-primary);
  outline-offset: 2px;
}
.crb-rail-tpl__name {
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-text);
  text-align: center;
  line-height: 1.2;
}
.crb-rail-tpl__feedback {
  margin: 0;
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
}
.crb-rail-tpl__feedback:empty { display: none; }
/* Pendant l'enregistrement : plus de clic, mais l'état reste lisible. */
.crb-rail-tpl.is-busy .crb-rail-tpl__opts { pointer-events: none; opacity: .6; }

/* ─── Fiche profil : en-tête « Retour » + bascule de gabarit (mobile) ───────
   Le sélecteur de gabarit du rail droit (.crb-rail-tpl) n'existe pas sous
   1024px, où la 3ᵉ colonne est masquée : le membre entré sur une fiche n'avait
   alors plus aucun moyen de changer de mise en page. Cette barre d'icônes prend
   le relais À CET ENDROIT-LÀ seulement — même valeur, même endpoint, même
   gestionnaire (cf. dashboard.php) ; c'est une question de place à l'écran, pas
   un réglage mobile séparé. D'où la symétrie stricte des deux règles d'affichage :
   la barre disparaît exactement là où la carte du rail apparaît. */
.crb-profile-topbar {
  position: relative;                  /* ancre le panneau d'options « ⋯ » (mobile) */
  display: flex;
  align-items: center;
  gap: var(--crb-space-3);
  /* La fiche démarre par une photo pleine largeur (gabarits Immersif et Bandeau) :
     sans cet écart, « Retour », les gabarits et le « ⋯ » se posaient directement
     sur le bord de l'image, comme collés dessus. L'écart vaut aussi pour le message
     d'échec de .crb-tplbar__feedback, posé hors flux sous la barre. */
  margin-bottom: var(--crb-space-3);
}
.crb-tplbar {
  position: relative;                  /* ancre le message d'échec */
  margin-left: auto;                   /* poussée à droite, face au bouton Retour */
}
@media (min-width: 1024px) { .crb-tplbar { display: none; } }
/* Même grammaire que le sélecteur d'affichage de « Découvrir »
   (.crb-discover-layouts) : pilule d'icônes, l'active en primaire pleine. */
.crb-tplbar__opts {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-pill);
  background: var(--crb-surface-alt);
}
.crb-tplbar__opt {
  position: relative;                  /* ancre le radio masqué */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: var(--crb-radius-pill);
  color: var(--crb-text-muted);
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.crb-tplbar__opt:hover { color: var(--crb-text); }
.crb-tplbar__opt.is-active { background: var(--crb-primary); color: #fff; }
/* Le radio reste dans le DOM (navigation clavier, état coché) ; l'icône entière
   est la cible du clic. */
.crb-tplbar__radio { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; }
.crb-tplbar__opt:has(.crb-tplbar__radio:focus-visible) {
  outline: 2px solid var(--crb-primary);
  outline-offset: 2px;
}
/* Échec d'enregistrement : posé sous la barre, hors flux (la ligne « Retour »
   ne doit pas se déformer). La sélection précédente est déjà restaurée par app.js. */
.crb-tplbar__feedback {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  margin: 0;
  white-space: nowrap;
  font-size: var(--crb-fs-xs);
  color: var(--crb-danger);
}
.crb-tplbar__feedback:empty { display: none; }
/* Pendant l'enregistrement : plus de clic, mais l'état reste lisible. */
.crb-tplbar.is-busy .crb-tplbar__opts { pointer-events: none; opacity: .6; }

/* ─── Fiche profil : options « ⋯ » + panneau Sécurité (mobile) ──────────────
   Pendant exact de .crb-chat__more / .crb-chat__sheet pour la fiche membre :
   au-dessus de 1024px le bloc « Sécurité & confiance » retourne dans le rail
   droit (cf. app.js, syncProfileSafetySheet), bouton et panneau n'ont donc plus
   lieu d'être. Le panneau s'ancre sur .crb-profile-topbar (position: relative). */
.crb-profile-more {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px; height: 36px;
  flex-shrink: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--crb-text);
  border-radius: var(--crb-radius-pill);
  cursor: pointer;
  transition: background var(--crb-transition);
}
/* `display: inline-flex` l'emporterait sur l'attribut `hidden` posé par app.js
   (sa propre fiche, ou desktop) : le rendre explicite. */
.crb-profile-more[hidden] { display: none; }
.crb-profile-more:hover,
.crb-profile-more[aria-expanded="true"] { background: var(--crb-bg-hover); }
.crb-profile-more svg { width: 20px; height: 20px; }
.crb-profile-sheet {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  width: min(300px, calc(100vw - 2 * var(--crb-space-4)));
  border-radius: var(--crb-radius-lg);
  /* Ombre portée du popover : la carte interne fournit fond, bordure et rayon. */
  box-shadow: var(--crb-shadow-lg);
  z-index: var(--crb-z-dropdown);
}
.crb-profile-sheet[hidden] { display: none; }
.crb-profile-sheet .crb-rail-safety { box-shadow: none; }
@media (min-width: 1024px) {
  .crb-profile-more,
  .crb-profile-sheet { display: none; }
}

/* ─── Modale de signalement (injectée par app.js) ─────────────────────────── */
.crb-report-modal {
  position: fixed;
  inset: 0;
  z-index: 100000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(0, 0, 0, .45);
}
.crb-report-modal__card {
  width: 100%;
  max-width: 420px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: var(--crb-space-4);
  background: var(--crb-surface);
  border-radius: var(--crb-radius-lg);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .25);
}
.crb-report-modal__title {
  margin: 0 0 4px;
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text);
}
.crb-report-modal__label {
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-text-muted);
  margin-top: 4px;
}
.crb-report-modal__select,
.crb-report-modal__textarea {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-md, 8px);
  font-size: var(--crb-fs-sm);
  color: var(--crb-text);
  background: var(--crb-bg);
}
.crb-report-modal__textarea { resize: vertical; min-height: 64px; }
.crb-report-modal__actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 8px;
}

/* ─── Messagerie : layout pleine hauteur sous le header fixe ──────────────── */
/* Le header thème est en position:fixed et recouvre le contenu : on décale la
   messagerie sous lui et on borne sa hauteur au viewport restant, comme .crb-dashboard. */
.crb-messages-layout {
  display: flex;
  height: calc(100dvh - var(--crb-header-height));
  background: var(--crb-bg);
  overflow: hidden;
}
.crb-inbox {
  display: flex;
  flex-direction: column;
  width: 100%;
  border-right: 1px solid var(--crb-border);
  background: var(--crb-surface);
  overflow-y: auto;
}
.crb-chat-panel {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.crb-chat-panel__empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  text-align: center;
  color: var(--crb-text-muted);
}

/* Mobile (par défaut) : une seule colonne visible à la fois */
.crb-messages-layout--chat-open .crb-inbox { display: none; }
.crb-messages-layout:not(.crb-messages-layout--chat-open) .crb-chat-panel { display: none; }

@media (min-width: 600px) {
  .crb-inbox { width: 430px; flex-shrink: 0; }
  /* Desktop : les deux colonnes coexistent toujours */
  .crb-messages-layout--chat-open .crb-inbox,
  .crb-messages-layout:not(.crb-messages-layout--chat-open) .crb-chat-panel { display: flex; }
  /* La liste reste visible à gauche → le bouton retour est inutile en desktop */
  .crb-chat__back { display: none; }
}

/* ─── Messagerie DESKTOP dans le shell : hauteur utile RÉELLE ───────────────
   Dans le shell 3 colonnes il n'y a pas de header de thème : la hauteur à
   déduire du viewport n'est donc pas `--crb-header-height` (règle de base
   ci-dessus, prévue pour les vues hors-shell) mais la topbar FIXE, dont
   `.crb-shell__grid` réserve la place en padding-top, plus la gouttière du
   panneau. Avec l'ancien calcul le layout dépassait le bas du viewport et la
   barre de saisie — collée en bas du LAYOUT, pas du viewport — passait sous le
   pli : à moitié coupée sur PC (le mobile n'était pas concerné, il est borné à
   `--crb-vvh`). Le padding BAS du panneau est annulé : le layout descend pile
   jusqu'au bord inférieur, comme une app de messagerie. */
@media (min-width: 1024px) {
  .crb-shell #crb-panel-messages > .crb-panel__inner { padding-bottom: 0; }
  .crb-shell .crb-messages-layout {
    height: calc(100dvh - var(--crb-topbar-clearance) - var(--crb-space-4));
  }
}

/* ─── Messagerie MOBILE : vue « app » plein écran, un seul ascenseur ────────
   Dans le shell, la messagerie était posée dans le flux d'une page qui défile :
   on cumulait l'ascenseur du document, celui du fil de conversation, et les
   gouttières du panneau (chat en retrait des bords). Sous le seuil desktop on
   verrouille donc le document (classes posées sur <html> ET <body> par
   activateTab — le <html> est indispensable, l'overflow du seul <body> ne
   suffit pas à figer le scroll du document), on annule les gouttières pour un
   rendu edge-to-edge, et on borne le layout au viewport moins la barre mobile
   du shell (seul élément conservé au-dessus). Il ne reste alors qu'un scroll :
   celui de .crb-chat__messages — en-tête du chat et zone de saisie, aux deux
   bouts du flex, restent en permanence à l'écran. */
@media (max-width: 1023.98px) {
  html.crb-tab-messages,
  body.crb-tab-messages {
    height: 100%;
    overflow: hidden;
    overscroll-behavior: none;
  }
  /* --crb-vvh = hauteur RÉELLEMENT visible, publiée par messaging.js depuis
     visualViewport : à l'ouverture du clavier iOS ne réduit pas 100dvh, seul le
     viewport visuel rétrécit. Repli 100dvh si l'API manque. */
  /* Plaquée sur la zone RÉELLEMENT visible, et non posée dans le flux du document.
     En restant dans le flux, la messagerie subissait tout ce qui la précède ou la suit
     dans la page (gouttières du thème, bandeau de consentement Google injecté par le
     script AdSense du thème…) : à l'ouverture du clavier iOS, qui fait glisser la
     fenêtre visible vers le bas sans redimensionner la page, le fil sortait par le haut
     et il ne restait que la barre de saisie, suivie du reste du document.
     `position: fixed` + `top: --crb-vv-top` (décalage du viewport visuel, publié par
     messaging.js) la recalent exactement sur la fenêtre visible, clavier ouvert comme
     fermé. Effet de bord voulu : la page ne contient plus rien de défilable, donc iOS
     ne peut plus la faire glisser sous nos pieds. Pas de z-index : on se contente de
     l'ordre de peinture, sans entrer dans une course aux couches avec les scripts tiers.
     NB : un élément fixe ne devient PAS bloc conteneur pour ses descendants fixes
     (contrairement à `transform`) — sélecteur d'émojis, lightbox et modales restent
     ancrés au viewport. */
  body.crb-tab-messages .crb-dashboard {
    position: fixed;
    top: var(--crb-vv-top, 0px);
    left: 0;
    right: 0;
    height: var(--crb-vvh, 100dvh);
    min-height: 0;
    overflow: hidden;
  }
  /* Pleine largeur : le chat touche les bords de l'écran (padding du contenu du
     dashboard + padding du panneau annulés, y compris en haut/bas). */
  body.crb-tab-messages .crb-dashboard__content { padding: 0; }
  body.crb-tab-messages #crb-panel-messages > .crb-panel__inner { padding: 0; }
  /* Hauteur utile : la barre mobile est le seul bandeau au-dessus (la topbar du
     shell et le header du thème n'existent pas sur cette vue). */
  body.crb-tab-messages .crb-messages-layout {
    height: calc(var(--crb-vvh, 100dvh) - var(--crb-mobilebar-height));
  }
  /* Clavier virtuel ouvert (classe posée par messaging.js depuis visualViewport) :
     la barre mobile se replie. Elle n'est de toute façon plus atteignable derrière
     le clavier, et ses 56px reviennent au fil de conversation — le gain visé.
     Remettre la variable à 0 suffit et tient en une déclaration : la barre s'aplatit
     (sa hauteur EST la variable) et .crb-messages-layout récupère les pixels dans le
     même calc. Repli instantané, sans transition : la hauteur du layout est celle du
     conteneur de défilement, l'animer ferait sauter le fil pendant que le clavier
     monte. Aucun effet hors messagerie mobile (sélecteur scopé + media query). */
  body.crb-tab-messages.crb-keyboard-open { --crb-mobilebar-height: 0px; }
  body.crb-tab-messages.crb-keyboard-open .crb-shell__mobilebar {
    overflow: hidden;          /* hamburger + titre ne débordent pas d'une barre à 0 */
    border-bottom-width: 0;    /* sinon la bordure laisse un trait résiduel */
    opacity: 0;
    pointer-events: none;
  }
  /* Le scroll interne ne se propage pas au document (bounce iOS, pull-to-refresh). */
  .crb-chat__messages,
  .crb-inbox { overscroll-behavior: contain; }
}

/* Note : la bottom-nav a été retirée (refonte 3 colonnes). La navigation est
   désormais portée par le seul rail gauche (.crb-rail-nav), persistant ≥1024px
   et ouvert en drawer hamburger <1024px (cf. .crb-shell__mobilebar). */

/* ─── Toolbar Découvrir (toggle mode + filtres) ────────────────────────── */
.crb-discover-toolbar {
  display: flex;
  flex-direction: column;   /* titre / sous-titre / critères empilés */
  gap: 8px;
  padding: 12px;
  background: var(--crb-surface);
  border-bottom: 1px solid var(--crb-border);
  position: sticky;
  /* La page défile désormais (plus de cadre interne) : on colle la toolbar SOUS le
     header fixe du thème, pas en haut du viewport (où elle passerait dessous). */
  top: var(--crb-header-height);
  z-index: var(--crb-z-sticky);
}
.crb-discover-toolbar__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;          /* < ~360px : les actions passent sous le titre au lieu d'être rognées */
  gap: 8px;
}
.crb-discover-toolbar__title {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: clamp(1.25rem, 4vw, 1.6rem);
  font-weight: var(--crb-fw-bold);
  line-height: 1.15;
  color: var(--crb-text);
}
.crb-discover-toolbar__sparkle {
  width: 18px;
  height: 18px;
  color: var(--crb-primary);
  flex-shrink: 0;
}
.crb-discover-toolbar__subtitle {
  margin: 0;
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
}
.crb-discover-toolbar__actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

/* ─── Gabarit de la liste : raccourci de la barre Découvrir ─────────────────
   Trois boutons = les trois templates de `template_member_list`. Le sélecteur
   n'est pas rendu sous 1024px (display:none) — la barre n'a pas la place — mais
   la PRÉFÉRENCE, elle, s'applique à toutes les largeurs : c'est un réglage de
   compte, qu'on retrouve dans l'onglet « Affichage » (carte « Liste des membres »).
   Ne pas remettre de garde de largeur côté rendu : un réglage sans effet sur son
   téléphone est un réglage cassé. */
.crb-discover-layouts { display: none; }
@media (min-width: 1024px) {
  .crb-discover-layouts {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    /* Collé au titre : les actions (nudge) restent poussées à droite. */
    margin-right: auto;
    padding: 2px;
    border: 1px solid var(--crb-border);
    border-radius: var(--crb-radius-pill);
    background: var(--crb-surface-alt);
  }
}
.crb-discover-layout {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: var(--crb-radius-pill);
  background: transparent;
  color: var(--crb-text-muted);
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.crb-discover-layout:hover { color: var(--crb-text); }
.crb-discover-layout[aria-pressed="true"] {
  background: var(--crb-primary);
  color: #fff;
}

/* ─── Critères « ma recherche » (badges) ────────────────────────────────────
   Une seule ligne en scroll horizontal (les chips ne wrappent pas) ; le bouton
   « Ajouter » est épinglé HORS du scroll pour rester toujours atteignable. Le
   débordement au-delà de N critères est replié côté serveur en un chip « +N ». */
.crb-discover-criteria {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.crb-discover-criteria__scroll {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  padding-bottom: 2px;
  scrollbar-width: none;            /* Firefox */
  -ms-overflow-style: none;         /* IE/Edge legacy */
  /* Dégradé de fin : ne « mord » que lorsque le contenu atteint le bord droit
     (donc uniquement en cas de débordement), signalant qu'il y a plus à droite. */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
          mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
}
.crb-discover-criteria__scroll::-webkit-scrollbar { display: none; } /* Chrome/Safari */

.crb-discover-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex-shrink: 0;
  white-space: nowrap;
  padding: 6px 12px;
  border-radius: var(--crb-radius-pill);
  border: 1px solid var(--crb-border);
  background: var(--crb-bg);
  color: var(--crb-text);
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-medium);
  text-decoration: none;
  transition: border-color .15s, color .15s, background .15s;
}
.crb-discover-chip:hover { border-color: var(--crb-primary); color: var(--crb-primary); }
.crb-discover-chip__icon { width: 16px; height: 16px; }
.crb-discover-chip--more { font-weight: var(--crb-fw-semibold); color: var(--crb-text-muted); }
.crb-discover-chip--empty {
  border-style: dashed;
  color: var(--crb-text-muted);
  cursor: default;
}
.crb-discover-chip--empty:hover { border-color: var(--crb-border); color: var(--crb-text-muted); }
.crb-discover-chip--add {
  border-style: dashed;
  border-color: var(--crb-primary);
  color: var(--crb-primary);
  background: transparent;
}
.crb-discover-chip--add:hover { background: var(--crb-primary-tint); }

/* ─── Badges de filtres éditables (remplacent l'ancienne modale) ─────────────
   Rangée de chips ; chaque chip ouvre un popover d'édition (sauf les cases à
   cocher, qui basculent directement). Scroll horizontal sur petit écran. */
.crb-discover-filters {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  min-width: 0;
}
@media (max-width: 600px) {
  .crb-discover-filters {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  .crb-discover-filters::-webkit-scrollbar { display: none; }
}
.crb-discover-filter { position: relative; flex-shrink: 0; }
.crb-discover-filter .crb-discover-chip { cursor: pointer; }
.crb-discover-chip__value { max-width: 160px; overflow: hidden; text-overflow: ellipsis; }
.crb-discover-chip__caret { flex-shrink: 0; opacity: .55; transition: transform .15s; }
.crb-discover-filter--open .crb-discover-chip__caret { transform: rotate(180deg); }
.crb-discover-filter--open .crb-discover-chip,
.crb-discover-chip--toggle[aria-pressed="true"] {
  border-color: var(--crb-primary);
  color: var(--crb-primary);
  background: var(--crb-primary-tint);
}
.crb-discover-chip--locked {
  border-style: dashed;
  color: var(--crb-text-muted);
}
.crb-discover-chip--locked .crb-discover-chip__icon { width: 14px; height: 14px; }
.crb-discover-chip--toggle { cursor: pointer; }
.crb-discover-chip__dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--crb-border);
  transition: background .15s;
}
.crb-discover-chip--toggle[aria-pressed="true"] .crb-discover-chip__dot { background: var(--crb-success, #16a34a); }

/* Popover d'édition d'un filtre */
.crb-discover-pop {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: var(--crb-z-dropdown, 60);
  min-width: 200px;
  max-width: 280px;
  padding: 12px;
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius);
  box-shadow: var(--crb-shadow-lg, 0 8px 28px rgba(0,0,0,.16));
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.crb-discover-pop[hidden] { display: none; }
.crb-discover-pop__label {
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text-muted);
}
/* État vide d'un niveau de la cascade Pays → Région → Département : le <select>
   est masqué et ce message prend sa place (« Choisis d'abord une région »,
   « Aucun département pour cette région »). */
.crb-discover-pop__hint {
  margin: 0;
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
  font-style: italic;
}
.crb-discover-pop__hint[hidden] { display: none; }
/* `.crb-plugin .crb-form__select { display: block }` l'emporterait sur la règle
   [hidden] du navigateur : sans ce rappel plus spécifique, un niveau de la cascade
   masqué par JS resterait affiché, vide, à côté de son message d'état. */
.crb-discover-pop [data-geo-role][hidden] { display: none; }
.crb-discover-pop .crb-astro-options {
  display: flex; flex-direction: column; gap: 4px;
  max-height: 220px; overflow-y: auto;
}
/* MOBILE : la rangée de badges défile horizontalement (overflow-x:auto), ce qui
   force aussi overflow-y à « auto » → un popover en position:absolute placé sous
   la rangée était rogné par ce scroller et restait invisible. Aucun critère
   n'était donc modifiable et la grille conservait les valeurs par défaut.
   position:fixed échappe au rognage d'un ancêtre overflow ; le popover reste
   néanmoins ancré SOUS la rangée de badges comme en desktop (et non collé en bas
   d'écran) : `top`/`left`/`width` sont calculés en JS depuis le rect de la rangée
   (positionDiscoverPop dans app.js), qui les recalcule au scroll et au resize. */
@media (max-width: 600px) {
  .crb-discover-pop {
    position: fixed;
    top: 0;                        /* remplacé en ligne par le JS */
    left: 12px;
    right: auto;
    bottom: auto;
    width: calc(100vw - 24px);     /* idem : ajusté à la largeur de la rangée */
    min-width: 0;
    max-width: none;
    padding: 16px;
    overflow-y: auto;
    overscroll-behavior: contain;
    z-index: var(--crb-z-modal);
  }
  .crb-discover-pop .crb-astro-options { max-height: 40vh; }
}

.crb-discover-toggle {
  display: flex;
  background: var(--crb-bg);
  border-radius: 20px;
  padding: 3px;
  gap: 2px;
}
.crb-toggle-btn {
  border: none;
  background: transparent;
  border-radius: 18px;
  padding: 5px 14px;
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-text-muted);
  cursor: pointer;
  transition: background var(--crb-transition), color var(--crb-transition);
}
.crb-toggle-btn--active {
  background: var(--crb-surface);
  color: var(--crb-primary);
  box-shadow: 0 1px 3px rgba(0,0,0,.12);
}

/* ─── NAV-B : Liste visiteurs ────────────────────────────────────────────── */
.crb-visitor-item { border-bottom: 1px solid var(--crb-border); }
.crb-visitor-item:last-child { border-bottom: none; }
.crb-visitor-item__link {
  display: flex;
  align-items: center;
  gap: var(--crb-space-3);
  padding: var(--crb-space-3) var(--crb-space-4);
  text-decoration: none;
  color: inherit;
  transition: background var(--crb-transition);
}
.crb-visitor-item__link:hover { background: var(--crb-bg-hover); }
.crb-visitor-item__avatar {
  width: 48px; height: 48px;
  border-radius: var(--crb-radius-pill);
  object-fit: cover;
  flex-shrink: 0;
}
.crb-visitor-item__avatar--placeholder {
  width: 48px; height: 48px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--crb-fs-xl);
  font-weight: var(--crb-fw-bold);
  flex-shrink: 0;
}
.crb-visitor-item__info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.crb-visitor-item__name { font-weight: var(--crb-fw-semibold); font-size: var(--crb-fs-base); }
.crb-visitor-item__age, .crb-visitor-item__ville {
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
}
.crb-visitor-item__time {
  font-size: var(--crb-fs-2xs);
  color: var(--crb-text-muted);
  white-space: nowrap;
}
.crb-visitors-upsell {
  padding: var(--crb-space-6) var(--crb-space-4);
  text-align: center;
}
.crb-visitors-upsell__count { font-size: var(--crb-fs-xl); margin-bottom: var(--crb-space-2); }
.crb-visitors-upsell__text  { margin-bottom: var(--crb-space-3); }

/* ─── Skeleton screens ───────────────────────────────────────────────────── */
/* Le balayage part TRÈS à gauche et finit très à droite d'une piste large : la
   bande de lumière traverse une fois, puis marque un temps mort avant de revenir.
   Un shimmer sans temps mort clignote ; avec, il respire. */
@keyframes crb-shimmer {
  0%   { background-position: -420px 0; }
  100% { background-position:  420px 0; }
}
/* Gris fixes remplacés par des teintes DÉRIVÉES de la palette : sur une surface
   sombre réglée en admin, deux gris clairs codés en dur transformaient chaque
   chargement en flash blanc. La bande de lumière est la surface elle-même. */
.crb-skeleton {
  background: linear-gradient(90deg,
                var(--crb-skeleton-bg) 25%,
                var(--crb-skeleton-sheen) 50%,
                var(--crb-skeleton-bg) 75%);
  background-size: 840px 100%;
  animation: crb-shimmer 1.6s infinite var(--crb-ease);
  border-radius: 4px;
}
.crb-skeleton--text  { height: 16px; margin-bottom: 8px; }
.crb-skeleton--title { height: 22px; width: 60%; margin-bottom: 12px; }
.crb-skeleton--avatar { width: 48px; height: 48px; border-radius: 50%; }
.crb-skeleton--card  { height: 120px; border-radius: var(--crb-radius); }

/* ─── Animations ─────────────────────────────────────────────────────────── */
@keyframes crb-slide-in  { from { transform: translateY(-8px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes crb-slide-up  { from { transform: translateY(100%); } to { transform: none; } }
@keyframes crb-fade-in   { from { opacity: 0; } to { opacity: 1; } }

/* ─── Transition d'entrée des panels ─────────────────────────────────────── */
/* Un panneau ne « paraît » pas : il arrive. Le très léger recul d'échelle (.985)
   le fait venir DE derrière le plan de l'écran plutôt que de simplement s'allumer,
   et la courbe emphasized le pose au lieu de le laisser tomber. La durée reste
   courte : c'est une navigation, pas une scène. */
.crb-panel--active {
  animation: crb-panel-in var(--crb-dur-slow) var(--crb-ease-emphasized) both;
}
@keyframes crb-panel-in {
  from { opacity: 0; transform: translateY(8px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

/* ─── Phase 6 : Pulse badge (nouveaux messages / visiteurs) ─────────────── */
@keyframes crb-badge-pulse {
  0%, 100% { transform: scale(1); }
  50%       { transform: scale(1.45); }
}
.crb-badge--pulse {
  animation: crb-badge-pulse .5s ease 2;
}

/* ─── Fiche Profil Membre (Sprint 3 / Vue 4) ─────────────────────────────── */
.crb-profile {
  max-width: 640px;
  /* Rendue dans le shell front (.crb-shell__main, sous la topbar interne) : plus de
     décalage sous le header du thème — la topbar occupe désormais le haut. */
  margin: 0 auto;
  background: var(--crb-surface);
  border-radius: var(--crb-radius-lg);
  overflow: hidden;
  box-shadow: var(--crb-shadow);
  padding-bottom: 80px; /* espace pour le CTA sticky */
}

/* Header photo.
   `max-height` borne la hauteur sur mobile : en 4/5 pur, la photo mesure 1,25× la
   largeur de la carte et occupe à elle seule tout le premier écran — le titre et
   l'annonce passaient sous la ligne de flottaison. Le cadrage portrait est
   conservé (object-fit: cover recadre), la fiche commence à être lisible d'emblée. */
.crb-profile__header {
  position: relative;
  width: 100%;
  aspect-ratio: 4/5;
  max-height: 58vh;
  overflow: hidden;
  background: var(--crb-surface-alt);
}
@media (min-width: 600px) {
  .crb-profile__header { aspect-ratio: 16/9; max-height: none; }
}
.crb-profile__photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.crb-profile__photo-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--crb-surface-alt);
}
.crb-profile__photo-placeholder--empty svg {
  width: 72px;
  height: 72px;
  fill: var(--crb-text-muted);
  opacity: .5;
}
.crb-profile__photo-pending-label {
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
  padding: 8px;
  text-align: center;
}
.crb-profile__blur-nudge {
  position: absolute;
  bottom: 0;
  left: 0; right: 0;
  padding: 16px;
  text-align: center;
  background: linear-gradient(transparent, rgba(0,0,0,.7));
  color: #fff;
}
.crb-profile__blur-nudge p { margin: 0 0 8px; font-size: var(--crb-fs-md); font-weight: var(--crb-fw-semibold); }

/* Overlay identité sur la photo.
   Un dégradé fixe suffit sur une photo sombre mais pas sur une photo claire (peau,
   chemisier beige, ciel, mur blanc) : le texte blanc s'y noyait. On empile donc
   deux défenses indépendantes de la luminosité de l'image :
     1. le dégradé noir, plus haut et plus opaque en pied ;
     2. un assombrissement de la photo elle-même (backdrop-filter), estompé par un
        masque pour ne pas laisser de bord franc — sans effet si le navigateur ne
        le gère pas, d'où la superposition des deux plutôt qu'un remplacement.
   Le voile est porté par un ::before : le masque ne doit jamais atteindre le
   texte, qui repasse au-dessus via z-index.

   `--crb-scrim` module la force de l'ensemble. Sa valeur par défaut (1) donne le
   voile fixe décrit ci-dessus. Quand le réglage « Adapter le voile à la luminosité
   réelle » est actif, le serveur pose une valeur mesurée par photo (0,55 sur une
   photo très sombre → 1,45 sur une photo très claire, cf. PhotoLuminance).
   L'alpha d'un rgba() étant borné à 1 par le navigateur, la multiplication ne peut
   pas déborder : pas de clamp() à écrire ici. */
.crb-profile__header-overlay,
.crb-member-card__overlay,
.crb-swipe-card__info { --crb-scrim: 1; }

.crb-profile__header-overlay {
  position: absolute;
  bottom: 0; left: 0; right: 0;
  padding: 64px 20px 20px;
}
.crb-profile__header-overlay::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to top,
               rgba(0,0,0,calc(.90 * var(--crb-scrim))) 0%,
               rgba(0,0,0,calc(.76 * var(--crb-scrim))) 25%,
               rgba(0,0,0,calc(.48 * var(--crb-scrim))) 55%,
               rgba(0,0,0,calc(.18 * var(--crb-scrim))) 80%,
               rgba(0,0,0,0)  100%);
}
@supports ((backdrop-filter: brightness(1)) or (-webkit-backdrop-filter: brightness(1))) {
  .crb-profile__header-overlay::before {
    /* Assombrissement INVERSEMENT proportionnel à la force du voile : une photo
       claire (scrim 1,45) descend à ~.43, une photo sombre (scrim 0,55) remonte à
       ~1,13 et n'est donc quasiment pas touchée. */
    -webkit-backdrop-filter: brightness(calc(.62 / var(--crb-scrim))) saturate(.85);
    backdrop-filter: brightness(calc(.62 / var(--crb-scrim))) saturate(.85);
    -webkit-mask-image: linear-gradient(to top, #000 40%, rgba(0,0,0,0) 100%);
    mask-image: linear-gradient(to top, #000 40%, rgba(0,0,0,0) 100%);
  }
}
.crb-profile__identity {
  position: relative;
  z-index: 1;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0,0,0,.65), 0 2px 14px rgba(0,0,0,.45);
}
/* `color: inherit` obligatoire : Impreza pose `h1,h2,…{color: var(--color-content-heading)}`,
   une règle DIRECTE sur h1 qui bat le `color:#fff` seulement HÉRITÉ de `.crb-profile__identity`.
   Le pseudo sortait donc en gris foncé du thème sur toutes les photos, claires comme
   sombres — aucun voile ne pouvait le rattraper. Idem pour le <p> du méta, par sécurité. */
.crb-profile__identity h1,
.crb-profile__identity p { color: inherit; }
.crb-profile__name {
  margin: 0 0 4px;
  padding-top: 0;                      /* le thème ajoute 1,5rem sur tous les titres */
  font-size: var(--crb-fs-3xl);
  font-weight: var(--crb-fw-bold);
  line-height: var(--crb-lh-tight);
  display: flex;
  align-items: center;
  gap: 8px;
  overflow-wrap: anywhere;
}
.crb-profile__meta { margin: 0; font-size: var(--crb-fs-lg); opacity: .95; }
/* Blocs d'en-tête déplaçables (Personnalisation → Templates) : n'importe lequel
   peut se retrouver sur la ligne du pseudo ou sur la ligne d'infos. Ils
   héritent donc de la typographie de leur ligne ; seul le titre, plus long,
   reste secondaire quand il monte dans l'en-tête. */
.crb-profile__name .crb-profile__titre-inline {
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-fw-medium);
  opacity: .95;
}
.crb-profile__meta .crb-profile__flag { margin-right: 2px; }

/* Dernière connexion (« Vu il y a 15 min ») — bloc déplaçable comme les autres :
   il hérite de la typographie de sa ligne, en un ton plus discret. Insécable :
   « il y a 15 min » coupé en fin de ligne se lit deux fois. Posé sur la ligne du
   pseudo, il redescend à la taille du texte courant — c'est une information de
   contexte, jamais un titre. */
.crb-profile__lastseen { opacity: .85; white-space: nowrap; }
.crb-profile__name .crb-profile__lastseen {
  font-size: var(--crb-fs-base);
  font-weight: var(--crb-fw-regular);
}

/* ─── Goûts mis en avant : la ligne de badges de la carte, reprise sur la fiche ─
   Même pastille que les cartes de Découvrir et de swipe (.crb-card-badge,
   partagée), même source (les 4 goûts cochés dans « Mettre en avant sur ma
   fiche ») : le membre choisit une fois, et l'on retrouve exactement la même
   ligne quand on ouvre son profil. Elle se pose AU-DESSUS du pseudo — jamais sur
   sa ligne : quatre pastilles y écraseraient l'identité. */
.crb-profile__badges {
  list-style: none;
  margin: 0 0 var(--crb-space-2);
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
/* Sur la photo (« Immersif ») : noir sur blanc, sans l'ombre de texte héritée du
   bandeau — elle salirait la pastille (même arbitrage que sur les cartes). */
.crb-profile__identity .crb-card-badge { text-shadow: none; }
/* Identité posée sur la SURFACE (« Bandeau », « Fiche ») et variante « corps » :
   une pastille blanche sur fond blanc disparaîtrait — on la reprend en couleurs
   de thème, cernée d'une bordure, comme les faits saillants juste en dessous. */
.crb-profile__ident .crb-card-badge,
.crb-profile__badges-row .crb-card-badge {
  background: var(--crb-surface-alt);
  color: var(--crb-text);
  border: 1px solid var(--crb-border);
  box-shadow: none;
}
.crb-profile__badges-row .crb-profile__badges { margin-bottom: var(--crb-space-4); }

/* ─── Bloc identité HORS surimpression (gabarits « Bandeau » et « Fiche ») ───
   Les trois gabarits de fiche ne diffèrent pas que par les blocs affichés : le
   gabarit décide aussi de la place de l'identité. En « Immersif » elle est
   posée sur la photo (texte blanc + voile) ; ici elle est posée sur la SURFACE
   de la fiche, donc en couleurs de thème, sans ombre portée ni voile — sinon
   du blanc sur fond clair deviendrait illisible. */
.crb-profile__ident {
  display: flex;
  align-items: center;
  gap: var(--crb-space-4);
  padding: 0 20px;
}
.crb-profile__ident .crb-profile__identity {
  color: var(--crb-text);
  text-shadow: none;
  min-width: 0;                        /* laisse le pseudo long se couper */
}
.crb-profile__ident .crb-profile__name { font-size: var(--crb-fs-2xl); }
.crb-profile__ident .crb-profile__meta {
  color: var(--crb-text-muted);
  font-size: var(--crb-fs-md);
  opacity: 1;
}
/* Le badge « en ligne » et le drapeau restent lisibles sur fond clair. */
.crb-profile__ident .crb-profile__titre-inline { color: var(--crb-text-muted); }

/* Vignette d'identité : médaillon rond (Bandeau) ou carré arrondi (Fiche).
   `flex: 0 0 auto` + dimensions fixes : sans cela, une photo panoramique
   étirerait la ligne d'en-tête et écraserait le pseudo. */
.crb-profile__avatar {
  flex: 0 0 auto;
  width: 96px;
  height: 96px;
  border-radius: var(--crb-radius-pill);
  object-fit: cover;
  background: var(--crb-surface-alt);
  border: 3px solid var(--crb-surface);
  box-shadow: var(--crb-shadow-md);
}
.crb-profile__avatar--square {
  width: 84px;
  height: 84px;
  border: 0;
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow);
}
.crb-profile__avatar--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--crb-text-muted);
}
.crb-profile__avatar--empty svg { width: 45%; height: 45%; }


/* Indicateur en ligne */
.crb-online-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-success);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--crb-success) 30%, transparent);
  flex-shrink: 0;
}

/* Corps du profil */
.crb-profile__body { padding: 20px; }

.crb-profile__titre {
  font-size: var(--crb-fs-xl);
  font-weight: var(--crb-fw-bold);
  margin: 0 0 12px;
  color: var(--crb-text);
}
/* Blocs de lecture (annonce, « je cherche ») : ce sont les seuls vrais paragraphes
   de la fiche → taille de confort (1rem) et interlignage large, pas l'échelle
   compacte des libellés d'interface. `anywhere` : les textes legacy contiennent
   des chaînes sans espace (URL, suites de caractères) qui débordaient la carte. */
.crb-profile__annonce,
.crb-profile__action {
  margin-bottom: 20px;
  color: var(--crb-text);
  line-height: var(--crb-lh-loose);
  font-size: var(--crb-fs-lg);
  overflow-wrap: anywhere;
}
.crb-profile__action-label {
  font-weight: var(--crb-fw-semibold);
  font-size: var(--crb-fs-xs);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--crb-text-muted);
  margin-bottom: 4px;
}
/* Titre de section (Photos, Qui m'a visité…). Il était plus petit et plus pâle
   que le texte qu'il introduit : aucune hiérarchie à l'œil. */
.crb-profile__section-title {
  font-size: var(--crb-fs-base);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--crb-text);
  font-weight: var(--crb-fw-bold);
  margin: 0 0 10px;
}

/* Hobbies chips */
.crb-profile__hobbies { margin-bottom: 20px; }
.crb-hobby-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.crb-chip {
  display: inline-block;
  padding: 5px 12px;
  border-radius: 50px;
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-semibold);
}
.crb-chip--sport     { background: #dcfce7; color: #166534; }
.crb-chip--culture   { background: #ede9fe; color: #4c1d95; }
.crb-chip--lifestyle { background: #fef3c7; color: #92400e; }
.crb-chip--values    { background: #fee2e2; color: #991b1b; }
.crb-chip--default,
.crb-chip            { background: #f1f5f9; color: #334155; }

/* Éditeur de champs de profil typés (onglet « Profil détaillé ») */
/* Catégorie principale (« mes goûts », « ma personnalité »…) :
   bloc nettement détaché, avec un en-tête fort et un séparateur entre catégories. */
.crb-pf-section { margin: 0 0 28px; }
.crb-pf-section + .crb-pf-section {
  margin-top: 28px;
  padding-top: 28px;
  border-top: 2px solid var(--crb-border, #dde0e3);
}
.crb-pf-category {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 16px;
  font-size: var(--crb-fs-xl);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text, inherit);
}
.crb-pf-category::before {
  content: "";
  flex: 0 0 auto;
  width: 4px;
  height: 1.1em;
  border-radius: var(--crb-radius-pill, 999px);
  background: var(--crb-primary, #2271b1);
}
.crb-pf-field { margin-bottom: 12px; }
.crb-pf-label { display: block; font-size: var(--crb-fs-sm); font-weight: var(--crb-fw-semibold); margin-bottom: 4px; }
.crb-pf-input {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--crb-border, #d1d5db);
  border-radius: var(--crb-radius, 8px);
  font-size: var(--crb-fs-base);
  box-sizing: border-box;
}
.crb-pf-checks { display: flex; flex-wrap: wrap; gap: 6px 14px; }
.crb-pf-check { display: inline-flex; align-items: center; gap: 4px; font-size: var(--crb-fs-sm); }
/* Barre d'action de l'éditeur de profil : bouton + témoin d'enregistrement sur une
   même ligne, centrés verticalement. Sans ce conteneur, le <span> du témoin se
   calait sur la ligne de base du bouton et venait chevaucher son coin bas droit. */
.crb-pf-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 16px;
}
.crb-pf-save { margin-top: 0; }

/* Sous-onglets par catégorie (« mes goûts », « ma personnalité »…) :
   segmentent l'onglet « Profil détaillé » pour éviter une page interminable. */
.crb-pf-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 4px;
  margin: 0 0 22px;
  border-bottom: 1px solid var(--crb-border, #dde0e3);
}
.crb-pf-tab {
  padding: 8px 14px;
  border: none;
  background: none;
  cursor: pointer;
  font-size: var(--crb-fs-base);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-text-muted);
  border-bottom: 3px solid transparent;
  white-space: nowrap;
  min-height: var(--crb-touch-min);
  transition: color var(--crb-transition), border-color var(--crb-transition);
}
.crb-pf-tab:hover { color: var(--crb-text); }
.crb-pf-tab--active {
  color: var(--crb-primary);
  border-bottom-color: var(--crb-primary);
}
/* En mode onglets, une seule section est visible à la fois : on supprime le
   séparateur inter-catégories (réservé au mode liste à catégorie unique). */
.crb-pf-sections .crb-pf-section { margin-bottom: 0; }
.crb-pf-sections .crb-pf-section + .crb-pf-section {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}
/* Témoin d'enregistrement : pastille verte en succès, rouge en erreur. Vide, il ne
   réserve aucune place (sinon le `gap` de la barre d'action laisserait un trou). */
.crb-pf-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  border-radius: var(--crb-radius-pill, 999px);
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text-muted, #6b7280);
}
.crb-pf-status:empty { display: none; }
.crb-pf-status--ok {
  background: color-mix(in srgb, var(--crb-success) 15%, var(--crb-surface));
  color: color-mix(in srgb, var(--crb-success) 65%, #000);
}
.crb-pf-status--ok::before { content: "\2713"; font-weight: var(--crb-fw-bold); }
.crb-pf-status--ko {
  background: color-mix(in srgb, var(--crb-danger) 12%, var(--crb-surface));
  color: color-mix(in srgb, var(--crb-danger) 75%, #000);
}
.crb-pf-status--ko::before { content: "\26A0"; }

/* Champs multi-sélection : accordéon repliable + pastilles toggle */
.crb-pf-acc {
  border: 1px solid var(--crb-border, #dde0e3);
  border-radius: var(--crb-radius, 8px);
  margin-bottom: 10px;
  overflow: hidden;
}
.crb-pf-acc__head {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 12px 14px;
  background: transparent;
  border: 0;
  cursor: pointer;
  text-align: left;
  font: inherit;
}
.crb-pf-acc__head:hover { background: var(--crb-primary-tint); }
.crb-pf-acc__head:focus-visible {
  outline: 2px solid var(--crb-focus-ring);
  outline-offset: -2px;
}
.crb-pf-acc__title {
  flex: 1 1 auto;
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text, inherit);
}
.crb-pf-acc__count {
  flex: 0 0 auto;
  min-width: 20px;
  padding: 1px 8px;
  border-radius: var(--crb-radius-pill, 999px);
  /* Nombre de choix EFFECTUÉS dans l'accordéon → success (distinct du primary
     réservé aux manquants et aux sélections actives des chips). */
  background: var(--crb-success, #0a0);
  color: #fff;
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-semibold);
  text-align: center;
}
.crb-pf-acc__count[hidden] { display: none; }
.crb-pf-acc__chevron {
  flex: 0 0 auto;
  width: 10px;
  height: 10px;
  border-right: 2px solid var(--crb-text-muted, #6b7280);
  border-bottom: 2px solid var(--crb-text-muted, #6b7280);
  transform: rotate(45deg);
  transition: transform .18s ease;
  margin-top: -3px;
}
.crb-pf-acc--open .crb-pf-acc__chevron { transform: rotate(225deg); margin-top: 3px; }
.crb-pf-acc__body { display: none; padding: 4px 14px 14px; }
.crb-pf-acc--open .crb-pf-acc__body { display: block; }

.crb-pf-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.crb-pf-chip { display: inline-flex; cursor: pointer; }
.crb-pf-chip__input {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}
.crb-pf-chip__label {
  display: inline-block;
  padding: 6px 14px;
  border: 1px solid var(--crb-border, #dde0e3);
  border-radius: var(--crb-radius-pill, 999px);
  background: var(--crb-surface, #fff);
  color: var(--crb-text, inherit);
  font-size: var(--crb-fs-sm);
  line-height: 1.2;
  transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.crb-pf-chip:hover .crb-pf-chip__label { border-color: var(--crb-primary, #2271b1); }
.crb-pf-chip__input:checked + .crb-pf-chip__label {
  background: var(--crb-primary, #2271b1);
  border-color: var(--crb-primary, #2271b1);
  color: #fff;
}
.crb-pf-chip__input:focus-visible + .crb-pf-chip__label {
  outline: 2px solid var(--crb-focus-ring);
  outline-offset: 2px;
}

/* ── Mise en avant : badges de la fiche Découvrir + aperçu temps réel ─────────
   Rendu en fin de l'onglet « mes goûts », au-dessus du bouton « Enregistrer ». */
.crb-pf-highlights {
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--crb-border, #dde0e3);
}
.crb-pf-highlights__title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 4px;
  font-size: var(--crb-fs-base);
  font-weight: var(--crb-fw-semibold);
}
.crb-pf-highlights__count {
  padding: 1px 8px;
  border-radius: var(--crb-radius-pill, 999px);
  background: var(--crb-primary, #2271b1);
  color: #fff;
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-semibold);
}
.crb-pf-highlights__hint {
  margin: 0 0 12px;
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
}
.crb-pf-highlights__pool {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 18px;
}
.crb-pf-highlights__empty {
  margin: 0;
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
}
.crb-pf-hlchip {
  padding: 6px 14px;
  border: 1px solid var(--crb-border, #dde0e3);
  border-radius: var(--crb-radius-pill, 999px);
  background: var(--crb-surface, #fff);
  color: var(--crb-text, inherit);
  font-size: var(--crb-fs-sm);
  line-height: 1.2;
  min-height: var(--crb-touch-min);
  cursor: pointer;
  transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.crb-pf-hlchip:hover:not(:disabled) { border-color: var(--crb-primary, #2271b1); }
.crb-pf-hlchip:focus-visible {
  outline: 2px solid var(--crb-focus-ring);
  outline-offset: 2px;
}
/* Sélectionné = apparaîtra en badge noir/blanc sur la fiche (rappel visuel). */
.crb-pf-hlchip--on {
  background: #111;
  border-color: #111;
  color: #fff;
}
.crb-pf-hlchip:disabled { opacity: .45; cursor: not-allowed; }

.crb-pf-highlights__previewwrap {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.crb-pf-highlights__preview-label {
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-text-muted);
}
/* Carte d'aperçu : même markup que la carte Découvrir mais statique et bornée.
   La carte réelle est en position:absolute/inset:0 + transform, et ces règles de
   base sont déclarées PLUS BAS dans la feuille → on scope l'aperçu sous son wrapper
   pour gagner en spécificité (sinon l'ordre source l'emporte et la carte « flotte »). */
.crb-pf-highlights__preview .crb-swipe-card--preview {
  position: relative;
  inset: auto;
  width: 400px;
  max-width: 100%;
  aspect-ratio: 3 / 2;
  transform: none;
  cursor: default;
  box-shadow: var(--crb-shadow-md, 0 6px 20px rgba(0, 0, 0, .12));
}
.crb-pf-highlights__preview .crb-swipe-card--preview:hover { transform: none; }

/* Monté dans sa propre carte de « Mon profil » (#crb-highlights-card) : le titre,
   l'explication et le compteur sont rendus par le template, et le filet de
   séparation n'a plus lieu d'être — la carte fait déjà la coupure. */
.crb-pf-highlights--card {
  margin-top: var(--crb-space-3);
  padding-top: 0;
  border-top: none;
}
.crb-card h3 > .crb-pf-highlights__count {
  margin-left: 8px;
  vertical-align: middle;
}
/* Le pool est une rangée de puces ; son état vide empile un texte et un bouton. */
.crb-pf-highlights__pool--empty {
  flex-direction: column;
  align-items: flex-start;
}

/* Filtres de swipe : âge + distance (panneau ouvert depuis « Élargir mes critères ») */
.crb-swipe-prefs {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
  padding: 18px;
  margin: 0 0 16px;
  border: 1px solid var(--crb-border, #dde0e3);
  border-radius: var(--crb-radius-lg, 12px);
  background: var(--crb-surface, #fff);
}
@media (min-width: 640px) {
  .crb-swipe-prefs { grid-template-columns: auto 1fr; gap: 28px; align-items: start; }
}
.crb-swipe-prefs__group { min-width: 0; }
.crb-swipe-prefs__label {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 10px;
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-semibold);
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--crb-text-muted, #6b7280);
}
.crb-swipe-prefs__out {
  font-weight: var(--crb-fw-bold);
  text-transform: none;
  letter-spacing: 0;
  color: var(--crb-primary, #2271b1);
}

/* Âge : deux champs encadrés */
.crb-swipe-prefs__ages { display: flex; align-items: center; gap: 12px; }
.crb-swipe-prefs__age {
  width: 84px;
  padding: 12px 14px;
  border: 1px solid var(--crb-border, #dde0e3);
  border-radius: var(--crb-radius, 8px);
  font-size: var(--crb-fs-md);
  text-align: center;
  box-sizing: border-box;
  -moz-appearance: textfield;
}
.crb-swipe-prefs__age::-webkit-outer-spin-button,
.crb-swipe-prefs__age::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.crb-swipe-prefs__age:focus-visible {
  outline: 2px solid var(--crb-focus-ring);
  outline-offset: 1px;
  border-color: var(--crb-primary, #2271b1);
}
.crb-swipe-prefs__sep { color: var(--crb-text-muted, #6b7280); }

/* Distance : curseur */
.crb-swipe-prefs__slider {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 4px;
  border-radius: var(--crb-radius-pill, 999px);
  background: var(--crb-border, #dde0e3);
  outline: none;
  margin: 6px 0;
}
.crb-swipe-prefs__slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--crb-primary, #2271b1);
  border: 2px solid var(--crb-surface, #fff);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .25);
  cursor: pointer;
}
.crb-swipe-prefs__slider::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--crb-primary, #2271b1);
  border: 2px solid var(--crb-surface, #fff);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .25);
  cursor: pointer;
}
.crb-swipe-prefs__slider:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 4px var(--crb-focus-ring); }
.crb-swipe-prefs__slider:focus-visible::-moz-range-thumb     { box-shadow: 0 0 0 4px var(--crb-focus-ring); }
.crb-swipe-prefs__scale {
  display: flex;
  justify-content: space-between;
  font-size: var(--crb-fs-2xs);
  color: var(--crb-text-muted, #6b7280);
}

/* ─── Affichage des champs de profil sur la fiche publique ──────────────────
   Bande de faits saillants : l'essentiel (statut, enfants, métier…) lisible en
   tête de fiche, sans avoir à dérouler les catégories. */
.crb-profile__facts {
  list-style: none;
  margin: 0 0 var(--crb-space-4);
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--crb-space-2);
}
.crb-profile__fact {
  min-width: 0;
  padding: 6px 12px;
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius);
  background: var(--crb-surface-alt);
  line-height: var(--crb-lh-tight);
}
.crb-profile__fact-label {
  display: block;
  font-size: var(--crb-fs-3xs);
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--crb-text-muted);
}
.crb-profile__fact-value {
  display: block;
  margin-top: 2px;
  font-size: var(--crb-fs-base);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text);
  overflow-wrap: anywhere;
}

.crb-profile__attributes { margin-bottom: 20px; }

/* Catégorie repliable — <details> natif (pas de JS, accessible au clavier). */
.crb-profile__cat {
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius);
  background: var(--crb-surface);
  overflow: hidden;
}
.crb-profile__cat + .crb-profile__cat { margin-top: var(--crb-space-3); }
.crb-profile__cat-head {
  list-style: none;                       /* masque le triangle natif (Firefox) */
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: var(--crb-space-2);
  min-height: var(--crb-touch-min);       /* cible tactile confortable */
  padding: var(--crb-space-2) var(--crb-space-4);
  background: var(--crb-surface-alt);
}
.crb-profile__cat-head::-webkit-details-marker { display: none; }
.crb-profile__cat-head:hover { background: var(--crb-bg-hover); }
.crb-profile__cat-head:focus-visible {
  outline: 2px solid var(--crb-focus-ring);
  outline-offset: -2px;
}
/* Les catégories sont saisies en minuscules en base (« ma personnalité ») ; on
   capitalise la seule initiale — `capitalize` majusculerait chaque mot. */
.crb-profile__cat-title {
  min-width: 0;
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text);
  overflow-wrap: anywhere;
}
.crb-profile__cat-title::first-letter { text-transform: uppercase; }
.crb-profile__cat-count {
  flex: none;
  padding: 1px 8px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text-muted);
}
.crb-profile__cat-chevron {
  flex: none;
  margin-left: auto;
  width: var(--crb-icon-md);
  height: var(--crb-icon-md);
  color: var(--crb-text-muted);
  transition: transform var(--crb-dur-base) var(--crb-ease);
}
.crb-profile__cat[open] .crb-profile__cat-chevron { transform: rotate(180deg); }
.crb-profile__cat-body { padding: var(--crb-space-3) var(--crb-space-4); }

/* Liste libellé/valeur.
   MOBILE-FIRST — EMPILÉE. L'ancienne grille `max-content 1fr` dimensionnait la
   colonne de gauche sur le libellé le plus long de la catégorie (« Mon principal
   trait de caractère », 32 caractères) : sur un écran de 375px il ne restait
   ~50px pour la valeur, et comme la piste `1fr` ne descend pas sous son
   `min-content`, la grille débordait la carte — que `.crb-profile{overflow:hidden}`
   rognait net. La valeur était donc littéralement coupée. */
.crb-profile__attr-list { margin: 0; }
.crb-profile__attr-list dt {
  margin: 0 0 2px;
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-semibold);
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--crb-text-muted, #6b7280);
  overflow-wrap: anywhere;
}
.crb-profile__attr-list dd {
  margin: 0;
  padding-bottom: var(--crb-space-3);
  border-bottom: 1px solid var(--crb-border-soft);
  font-size: var(--crb-fs-lg);
  line-height: var(--crb-lh-base);
  color: var(--crb-text);
  overflow-wrap: anywhere;
}
.crb-profile__attr-list dd + dt { margin-top: var(--crb-space-3); }
.crb-profile__attr-list dd:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

/* ≥600px : deux colonnes, mais avec des pistes BORNÉES (jamais `max-content`) —
   le libellé ne peut plus manger la largeur de la valeur ni faire déborder. */
@media (min-width: 600px) {
  .crb-profile__attr-list {
    display: grid;
    grid-template-columns: minmax(110px, 34%) minmax(0, 1fr);
    /* Pas de `column-gap` : le filet de séparation est porté par chaque cellule,
       une gouttière le couperait en deux tronçons. L'écart vient du padding
       intérieur du <dt>, ce qui laisse le trait courir d'un bord à l'autre. */
    column-gap: 0;
  }
  .crb-profile__attr-list dt,
  .crb-profile__attr-list dd {
    min-width: 0;
    margin: 0;
    padding: var(--crb-space-3) 0;
    border-bottom: 1px solid var(--crb-border-soft);
    /* Même interlignage des deux côtés → les premières lignes s'alignent. */
    line-height: var(--crb-lh-base);
  }
  .crb-profile__attr-list dt {
    grid-column: 1;
    padding-right: var(--crb-space-4);
    font-size: var(--crb-fs-base);
    text-transform: none;
    letter-spacing: 0;
  }
  .crb-profile__attr-list dd { grid-column: 2; }
  /* L'espacement inter-lignes de la version empilée (`dd + dt`) est plus
     spécifique que le `margin: 0` ci-dessus : sans ce rappel il subsiste ici et
     décale le libellé vers le bas de sa cellule. */
  .crb-profile__attr-list dd + dt { margin-top: 0; }
  .crb-profile__attr-list dt:last-of-type,
  .crb-profile__attr-list dd:last-of-type { border-bottom: 0; }
}

/* Activité forum (bbPress) — « ses sujets créés » / « ses sujets répondus ».
   MOBILE-FIRST : les deux listes s'empilent ; à partir de 600px elles passent
   côte à côte, comme sur l'ancienne fiche css-custom-pro. */
.crb-profile__forum { margin-bottom: 20px; }
.crb-profile__forum-cols {
  display: grid;
  gap: var(--crb-space-3);
}
@media (min-width: 600px) {
  .crb-profile__forum-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.crb-forum-list {
  min-width: 0;
  padding: var(--crb-space-3) var(--crb-space-4);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius);
  background: var(--crb-surface);
}
.crb-forum-list__title {
  margin: 0 0 var(--crb-space-2);
  font-size: var(--crb-fs-base);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text);
}
.crb-forum-list__items {
  margin: 0;
  padding: 0;
  list-style: none;
}
/* Le tiret de l'ancienne fiche, mais posé en `::before` : il reste hors du flux
   du texte, donc un titre qui passe à la ligne s'aligne sous lui et non dessous. */
.crb-forum-list__item {
  position: relative;
  padding-left: 12px;
  line-height: var(--crb-lh-base);
  overflow-wrap: anywhere;
}
.crb-forum-list__item + .crb-forum-list__item { margin-top: var(--crb-space-2); }
.crb-forum-list__item::before {
  content: '–';
  position: absolute;
  left: 0;
  color: var(--crb-text-muted);
}
.crb-forum-list__item a {
  color: var(--crb-primary);
  text-decoration: none;
}
.crb-forum-list__item a:hover { text-decoration: underline; }
.crb-forum-list__more { margin-top: var(--crb-space-3); }

/* Section visiteurs */
.crb-profile__visitors { margin-bottom: 20px; }
.crb-visitors-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
  gap: 8px;
}
.crb-visitor-card { display: block; border-radius: var(--crb-radius); overflow: hidden; }
.crb-visitor-card__img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  display: block;
}
.crb-visitor-card__img--empty {
  background: var(--crb-surface-alt);
  aspect-ratio: 1;
}

/* CTA sticky en bas */
.crb-profile__cta-sticky {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: var(--crb-z-dropdown);
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
  background: var(--crb-surface);
  border-top: 1px solid var(--crb-border);
  box-shadow: 0 -4px 16px rgba(0,0,0,.08);
  display: flex;
  gap: 10px;
}
.crb-profile__cta-btn { flex: 1; justify-content: center; }
.crb-profile__cta-sticky--owner { justify-content: center; }

/* Notice générique */
.crb-notice {
  padding: 12px 16px;
  background: #f8f9fa;
  border-radius: var(--crb-radius);
  color: var(--crb-text-muted);
  text-align: center;
  font-size: var(--crb-fs-base);
}
/* [crb_search] déprécié : invitation vers la recherche du tableau de bord. */
.crb-search-deprecated .crb-btn { margin-top: var(--crb-space-3); }

input#crb-topbar-search-input,
input#crb-discover-search-input {
  padding: 0 var(--inputs-padding, .6em) 0 40px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SHELL PLEINE LARGEUR + COLONNE GAUCHE RÉSERVÉE (.crb-shell)
   Une fois connecté, le membre bascule sur UNE page unique (le [crb_dashboard])
   qui contient tout le plugin. Ce shell lui donne :
   - une largeur edge-to-edge (il s'évade du conteneur borné du thème) ;
   - une colonne gauche réservée, visible sur desktop (placeholder), dont le
     contenu sera défini plus tard ;
   - un comportement MOBILE-FIRST : base = une seule colonne (l'aside est masqué) ;
     la 2ᵉ colonne n'apparaît qu'à ≥1024px (même seuil que la mise en page 2-col
     existante du profil / compte, cf. Phase 5).
   ═══════════════════════════════════════════════════════════════════════════ */

/* Full-bleed : on tire les bords jusqu'au viewport sans `width:100vw` (qui
   déborderait de la largeur de la scrollbar). Des marges négatives symétriques
   suffisent : l'élément en largeur auto remplit alors toute la fenêtre. */
.crb-shell {
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}

/* Gouttières VERTICALES du conteneur du thème — annulées sur les pages du shell.
   Le full-bleed ci-dessus ne règle que l'axe horizontal : verticalement, la page
   membre est un [vc_row] Impreza, donc une `<section class="l-section height_medium">`
   qui applique 4rem de padding (2.5rem ≤1024px, 1.5rem ≤600px) + la marge basse des
   éléments WPBakery. Deux conséquences sur mobile :
     • une bande vide au-dessus de la barre mobile (« Espace membre ») ;
     • en messagerie, où le document est verrouillé et .crb-dashboard borné au viewport
       visible (--crb-vvh), le shell partait ~24px trop bas et débordait d'autant : la
       zone de saisie se retrouvait sous la barre d'outils de Safari iOS.
   Portée : `.l-main` uniquement (le contenu de la page) → le pied de page du thème
   (.l-footer, hors de <main>) garde ses gouttières. Classe posée par
   FrontendHooks::addSkinBodyClass (cf. pageEmbedsShell). */
body.crb-shell-page .l-main .l-section {
  padding-top: 0;
  padding-bottom: 0;
}
body.crb-shell-page .l-main .wpb_content_element,
body.crb-shell-page .l-main .wpb_text_column {
  margin-bottom: 0;
}

/* Mobile-first : flux mono-colonne, aucune grille. */
.crb-shell__grid { display: block; }

/* Bandeau image / logo (réglage shell_left_image) — première position de la colonne
   gauche, AU-DESSUS du menu. C'est la HAUTEUR (celle de la topbar) qui dimensionne
   l'image ; la largeur suit le ratio (jamais rognée). Affleure le haut du rail
   (marge négative qui annule le padding-top de l'aside) → aligné sur la topbar ;
   le retrait horizontal du rail est conservé (logo aligné sur la nav). */
.crb-shell__topimg {
  height: calc(0.75 * var(--crb-topbar-height));
  margin-top: calc(-1 * var(--crb-space-2));
  margin-bottom: var(--crb-space-4);
  display: flex;
  align-items: center;
}
.crb-shell__topimg-img {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* Colonnes latérales réservées — masquées tant qu'on est sous le seuil desktop. */
.crb-shell__aside { display: none; }
.crb-shell__rail  { display: none; }

/* La colonne principale ne touche pas les bords du viewport en full-bleed. */
.crb-shell__main { min-width: 0; }

@media (min-width: 1024px) {
  /* ── App frame plein écran (la page membre n'a PAS de header de thème) ──
     Trois zones fixes, comme les maquettes :
       • RAIL GAUCHE   : fixe, plein écran à gauche (bord à bord en hauteur).
       • TOPBAR        : fixe, en haut, du bord droit du rail jusqu'au bord droit
                         (au-dessus du contenu ET de la colonne droite).
       • ZONE CONTENU  : la grille elle-même, décalée à droite du rail (margin-left)
                         et sous la topbar (padding-top). Contient le contenu central
                         (+ la colonne droite quand le panneau fournit des widgets).
     Rail et topbar sont en position:fixed → hors-flux : c'est la GRILLE qui réserve
     leur place. .crb-shell est full-bleed (bord gauche = bord viewport) donc
     margin-left:aside-width aligne pile la grille sur le bord droit du rail. */
  .crb-shell__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    margin-left: var(--crb-shell-aside-width);
    /* Clearance de la topbar FIXE : sans elle, les 64 premiers pixels de CHAQUE
       panneau (titre d'accueil, en-tête de conversation…) passaient sous la barre,
       définitivement masqués — le contenu ne pouvait pas remonter au-dessus.
       Seul le retrait vertical est posé ici : le retrait horizontal du contenu est
       déjà assuré par `.crb-panel__inner`, l'ajouter ici le doublerait. */
    padding-top: var(--crb-topbar-clearance);
    align-items: start;
  }

  /* Shell dashboard à 3 colonnes (Phase B) : la colonne droite n'est ajoutée QUE
     quand le panneau actif fournit des widgets (.is-rail-active, posé par
     activateTab). Sinon une seule colonne (contenu central pleine largeur). */
  .crb-shell__grid--3col.is-rail-active {
    grid-template-columns: minmax(0, 1fr) var(--crb-shell-rail-width);
    column-gap: var(--crb-space-4);
  }
  .crb-shell__grid--3col.is-rail-active .crb-shell__rail { display: block; }

  /* RAIL GAUCHE : panneau plat fixe, pleine hauteur, scroll interne. */
  .crb-shell__aside {
    display: block;
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--crb-shell-aside-width);
    z-index: var(--crb-z-fixed);
    overflow-y: auto;
    padding: var(--crb-space-4);
    background: var(--crb-surface);
    border-right: 1px solid var(--crb-border);
  }
  /* COLONNE DROITE : collante sous la topbar pendant le scroll du contenu. */
  .crb-shell__rail {
    position: sticky;
    top: var(--crb-topbar-clearance);
    align-self: start;
    padding: var(--crb-space-4);
  }

  /* PIED DE PAGE (bloc réutilisable Impreza) : court sous le contenu central ET la
     colonne droite (toute la largeur de la grille), jamais sous le rail gauche fixe. */
  .crb-shell__footer {
    grid-column: 1 / -1;
  }
}

/* Pied de page — base (mobile-first) : pleine largeur de la colonne unique, séparé
   du contenu par un filet discret. Le bloc Impreza gère sa propre mise en page interne. */
.crb-shell__footer {
  margin-top: var(--crb-space-6);
  padding-top: var(--crb-space-5);
  border-top: 1px solid var(--crb-border);
}

/* Pied de page du THÈME masqué dans l'espace membre : le shell rend déjà le sien
   (.crb-shell__footer, bloc réutilisable du réglage shell_footer_block) et les deux
   s'empilaient — deux pieds de page superposés sur /mon-compte/, le dashboard, etc.
   La classe est posée sur <body> par FrontendHooks::addSkinBodyClass() SAUF pour les
   vues cochées dans Personnalisation › Templates (réglage shell_theme_footer_views),
   où l'on veut délibérément garder le pied du thème. Sélecteurs Impreza : #page-footer
   (id du conteneur) et .l-footer (classe de section), tous deux hors du shell. */
body.crb-hide-theme-footer #page-footer,
body.crb-hide-theme-footer .l-footer {
  display: none;
}

/* Panneaux Messages et Swipe en MOBILE : pas de pied de page (double ascenseur).
   Les deux vues sont bornées à la hauteur utile (.crb-messages-layout d'un côté,
   .crb-swipe-app de l'autre) et n'ont rien à faire défiler au niveau de la PAGE.
   Un pied de page dessous la rendait scrollable quand même : en messagerie c'était
   un 2ᵉ ascenseur superposé à celui de la conversation ; en swipe, le geste de
   glissement vertical faisait dériver la page et sortait la rangée like/pass de
   l'écran. La classe est posée sur <body> par activateTab() (app.js) :
   indispensable pour atteindre aussi le pied du THÈME (#page-footer), qui vit hors
   du shell. Mobile-first : masqué par défaut, rétabli au seuil desktop où le shell
   a sa propre mise en page (rail + topbar fixes) et où le problème ne se pose pas. */
body.crb-tab-messages .crb-shell__footer,
body.crb-tab-messages #page-footer,
body.crb-tab-messages .l-footer,
body.crb-tab-swipe .crb-shell__footer,
body.crb-tab-swipe #page-footer,
body.crb-tab-swipe .l-footer {
  display: none;
}

/* Rétablissement desktop. `:not(.crb-hide-theme-footer)` sur les sélecteurs du pied
   du THÈME : sans lui, ces règles (même spécificité, mais postérieures dans le
   fichier) l'emporteraient sur le masquage global ci-dessus et feraient réapparaître
   le pied du thème en desktop sur les onglets Messages/Swipe. Le pied du SHELL, lui,
   se rétablit sans condition : c'est le seul qu'on veut voir. */
@media (min-width: 1024px) {
  body.crb-tab-messages .crb-shell__footer,
  body.crb-tab-swipe .crb-shell__footer,
  body.crb-tab-messages:not(.crb-hide-theme-footer) #page-footer,
  body.crb-tab-messages:not(.crb-hide-theme-footer) .l-footer,
  body.crb-tab-swipe:not(.crb-hide-theme-footer) #page-footer,
  body.crb-tab-swipe:not(.crb-hide-theme-footer) .l-footer {
    display: block;
  }
}

/* Placeholder discret du slot réservé (à remplacer par le futur contenu). */
.crb-shell__aside-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 200px;
  border: 1px dashed var(--crb-border);
  border-radius: var(--crb-radius-lg);
  background: var(--crb-surface-alt);
}
.crb-shell__aside-label {
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-text-muted);
  text-transform: uppercase;
  letter-spacing: .04em;
}

/* Menu WP rendu verticalement dans la colonne gauche (réglage shell_left_menu).
   Le ShellMenuWalker rend chaque <a> au format .crb-rail-nav__item : ici on ne
   gère que la mise en liste (flex column) pour reproduire la nav interne. */
.crb-shell__nav .crb-shell__menu,
.crb-shell__nav .crb-shell__menu ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.crb-shell__nav .crb-shell__menu,
.crb-shell__nav .crb-shell__menu .sub-menu {
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-1);
}
.crb-shell__nav .crb-shell__menu li {
  margin: 0;
}
/* Sous-menus (depth 2) : pas d'icône → on retombe sur l'indentation du libellé. */
.crb-shell__nav .crb-shell__menu .sub-menu {
  margin-top: var(--crb-space-1);
}
.crb-rail-nav__item--sub {
  padding-left: var(--crb-space-5);
  font-weight: var(--crb-fw-regular);
}

/* ─── Rail gauche : navigation interne du plugin (Phase A) ─────────────────
   Les panneaux à onglets (Découvrir / Messages / Visiteurs) portés en rail
   vertical. Même moteur que la bottom-nav (data-tab → activateTab) : deux
   présentations, une logique (garde-fou #10). Rendu dans .crb-shell__aside,
   donc déjà masqué <1024px et collant sous le header ≥1024px. */
.crb-rail-nav {
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-1);
}
.crb-rail-nav__item {
  display: flex;
  align-items: center;
  gap: var(--crb-space-3);
  width: 100%;
  padding: var(--crb-space-2) var(--crb-space-3);
  background: none;
  border: none;
  border-radius: var(--crb-radius);
  cursor: pointer;
  color: var(--crb-nav-text);
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-medium);
  line-height: 1.2;
  text-align: left;
  text-decoration: none;
  position: relative;
  /* `transform` figure ici et pas seulement dans `:active` : une transition
     déclarée dans le seul état enfoncé ne joue qu'à l'aller, et l'élément
     REVIENT d'un coup à sa taille pleine. Le retour est justement le moment où
     le ressort se voit. */
  transition: background var(--crb-transition),
              color var(--crb-transition),
              transform var(--crb-dur-slow) var(--crb-ease-spring);
}
.crb-rail-nav__item:hover,
.crb-rail-nav__item:focus-visible {
  background: var(--crb-surface-alt);
  color: var(--crb-primary);
}
.crb-rail-nav__item--active {
  /* Fond corail clair issu de la palette (jamais hardcodé). */
  background: color-mix(in srgb, var(--crb-primary) 12%, var(--crb-surface));
  color: var(--crb-primary);
  font-weight: var(--crb-fw-semibold);
}
/* Repère vertical sur le bord d'attaque de l'élément actif. La teinte de fond seule
   demande de COMPARER les items entre eux pour savoir où l'on est ; un repère se
   voit sans comparaison — et c'est la question à laquelle une navigation doit
   répondre en premier. Il grandit depuis le centre plutôt que d'apparaître. */
.crb-rail-nav__item::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  width: 3px;
  height: 60%;
  border-radius: 0 var(--crb-radius-pill) var(--crb-radius-pill) 0;
  background: var(--crb-primary);
  transform: translateY(-50%) scaleY(0);
  transform-origin: center;
  transition: transform var(--crb-dur-slow) var(--crb-ease-emphasized);
}
.crb-rail-nav__item--active::before { transform: translateY(-50%) scaleY(1); }
/* Retour au doigt sur toute la ligne, comme partout ailleurs. */
.crb-rail-nav__item:active {
  transform: scale(var(--crb-press-scale-lg));
  transition: transform var(--crb-dur-fast) var(--crb-ease-exit);
}
.crb-rail-nav__icon {
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
}
.crb-rail-nav__label { flex: 1 1 auto; }
.crb-rail-nav__badge {
  flex: 0 0 auto;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 50px;
  background: var(--crb-notification);
  color: #fff;
  font-size: var(--crb-fs-3xs);
  font-weight: var(--crb-fw-bold);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Menu WP (pages publiques) prolongeant la nav interne : AUCUN séparateur ni
   titre — il se fond dans la nav interne pour ne former qu'un seul menu. Le
   gap reproduit l'espacement entre deux .crb-rail-nav__item. */
.crb-shell__nav--merged {
  margin-top: var(--crb-space-1);
}

/* ─── Cartes du rail gauche (Phase D) : complétion + upsell Premium ────────── */
.crb-rail-cards {
  margin-top: var(--crb-space-4);
  padding-top: var(--crb-space-4);
  border-top: 1px solid var(--crb-border);
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-3);
}
.crb-rail-card {
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-2);
  padding: var(--crb-space-4);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
}
.crb-rail-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--crb-space-2);
}
.crb-rail-card__title {
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text);
}
.crb-rail-card__pct {
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-primary);
}
.crb-rail-card__cta { width: 100%; justify-content: center; }

/* Jauge de complétion */
.crb-rail-gauge {
  height: 8px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-surface-alt);
  overflow: hidden;
}
.crb-rail-gauge__fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--crb-primary);
  transition: width var(--crb-transition);
}

/* Carte Premium — accent corail/dégradé léger */
.crb-rail-card--premium {
  align-items: flex-start;
  background: color-mix(in srgb, var(--crb-primary) 8%, var(--crb-surface));
  border-color: color-mix(in srgb, var(--crb-primary) 24%, var(--crb-border));
}
.crb-rail-card__premium-icon {
  display: inline-flex;
  color: var(--crb-primary);
}
.crb-rail-card__premium-icon svg { width: 24px; height: 24px; }
.crb-rail-card__text {
  margin: 0;
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
  line-height: 1.4;
}

/* ─── Panneau « Compléter mon profil » : checklist des infos manquantes ─────── */
.crb-completion { max-width: 720px; margin: 0 auto; }
.crb-completion__head { margin-bottom: var(--crb-space-4); }
.crb-completion__title {
  margin: 0 0 var(--crb-space-3);
  font-size: var(--crb-fs-xl);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text);
}
.crb-completion__gauge-row { display: flex; align-items: center; gap: var(--crb-space-3); }
.crb-completion__gauge { flex: 1 1 auto; height: 12px; }
.crb-completion__pct {
  flex: 0 0 auto;
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-primary);
  font-variant-numeric: tabular-nums;
}
.crb-completion__intro {
  margin: 0 0 var(--crb-space-4);
  color: var(--crb-text-muted);
  font-size: var(--crb-fs-sm);
  line-height: 1.5;
}
/* Barre de sous-onglets (une section par onglet) — sur le modèle des onglets
   compte (.crb-account-tabs), défilable horizontalement en mobile. */
.crb-completion__tabs {
  display: flex;
  gap: 0;
  margin-bottom: var(--crb-space-4);
  border-bottom: 1px solid var(--crb-border);
  overflow-x: auto;
  scrollbar-width: none;
}
.crb-completion__tabs::-webkit-scrollbar { display: none; }
.crb-completion__tab {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  border: none;
  background: none;
  cursor: pointer;
  font-size: var(--crb-fs-base);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-text-muted);
  border-bottom: 3px solid transparent;
  white-space: nowrap;
  min-height: var(--crb-touch-min);
}
.crb-completion__tab:hover { color: var(--crb-text); }
.crb-completion__tab--active {
  color: var(--crb-primary);
  border-bottom-color: var(--crb-primary);
}
/* Pastille du nombre d'items restants / coche si section complète */
.crb-completion__tab-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary);
  color: #fff;
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-bold);
  line-height: 1;
}
.crb-completion__tab-done {
  display: inline-flex;
  color: color-mix(in srgb, var(--crb-success) 65%, #000);
}
.crb-completion__tab-done svg { width: 16px; height: 16px; }
.crb-completion__pane[hidden] { display: none; }

/* ─── Onglet « Profil (new) » : sous-onglets maîtres (un par section) ─────────
   Réutilise l'ossature des sous-onglets de #completion. Convention couleur :
   badge des MANQUANTS = var(--crb-primary) ; badge des choix FAITS (section
   complète) = var(--crb-success) — voir aussi .crb-pf-acc__count. */
.crb-pf-master-tabs {
  display: flex;
  gap: 0;
  margin: var(--crb-space-4) 0;
  border-bottom: 1px solid var(--crb-border);
  overflow-x: auto;
  scrollbar-width: none;
}
.crb-pf-master-tabs::-webkit-scrollbar { display: none; }
.crb-pf-master-tab {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  border: none;
  background: none;
  cursor: pointer;
  font-size: var(--crb-fs-base);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-text-muted);
  border-bottom: 3px solid transparent;
  white-space: nowrap;
  min-height: var(--crb-touch-min);
}
.crb-pf-master-tab:hover { color: var(--crb-text); }
.crb-pf-master-tab--active {
  color: var(--crb-primary);
  border-bottom-color: var(--crb-primary);
}
/* Pastille des champs restants (manquants) → primary */
.crb-pf-master-tab__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary);
  color: #fff;
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-bold);
  line-height: 1;
}
/* Pastille « section complète » (choix effectués) → success (couleur distincte) */
.crb-pf-master-tab__done {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 4px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-success);
  color: #fff;
}
.crb-pf-master-tab__done svg { width: 14px; height: 14px; }
.crb-pf-master-pane[hidden] { display: none; }

/* Encart des anciens onglets devenus pointeurs (transition avant suppression). */
.crb-moved-notice { text-align: center; }
.crb-moved-notice p { margin: 0 0 var(--crb-space-3); }
.crb-completion__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--crb-space-2); }
.crb-completion__item {
  display: flex;
  align-items: center;
  gap: var(--crb-space-3);
  padding: var(--crb-space-3);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius);
}
.crb-completion__item-label { flex: 1 1 auto; font-size: var(--crb-fs-sm); color: var(--crb-text); }
.crb-completion__check {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: var(--crb-radius-pill);
}
.crb-completion__check svg { width: 15px; height: 15px; }
/* Item déjà rempli — atténué, rassurance */
.crb-completion__item--done { border-style: dashed; background: var(--crb-surface-alt); }
.crb-completion__item--done .crb-completion__item-label { color: var(--crb-text-muted); }
.crb-completion__item--done .crb-completion__check {
  background: color-mix(in srgb, var(--crb-success) 15%, var(--crb-surface));
  color: color-mix(in srgb, var(--crb-success) 60%, #000);
}
/* Item manquant — mis en avant + CTA vers la saisie du champ */
.crb-completion__item--todo { border-color: color-mix(in srgb, var(--crb-primary) 30%, var(--crb-border)); }
.crb-completion__check--empty {
  border: 2px solid color-mix(in srgb, var(--crb-primary) 45%, var(--crb-border));
  background: transparent;
}
.crb-completion__cta { flex: 0 0 auto; white-space: nowrap; }
/* État 100 % — carte placeholder (bénéfices à venir) */
.crb-completion__complete-card {
  text-align: center;
  padding: var(--crb-space-6) var(--crb-space-4);
  background: var(--crb-primary-tint);
  border: 1px solid color-mix(in srgb, var(--crb-primary) 24%, var(--crb-border));
  border-radius: var(--crb-radius-lg);
}
.crb-completion__complete-emoji { font-size: 40px; line-height: 1; }
.crb-completion__complete-title {
  margin: var(--crb-space-3) 0 var(--crb-space-2);
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text);
}
.crb-completion__complete-text { margin: 0; color: var(--crb-text-muted); font-size: var(--crb-fs-sm); line-height: 1.5; }
/* Sous 480px : le CTA passe sous le libellé pour ne pas comprimer la ligne */
@media (max-width: 480px) {
  .crb-completion__item--todo { flex-wrap: wrap; }
  .crb-completion__cta { width: 100%; }
}

/* ─── Panneau Paramètres (Phase E) : grille de raccourcis compte ───────────── */
.crb-settings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--crb-space-3);
}
.crb-settings-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--crb-space-2);
  padding: var(--crb-space-4);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
  color: var(--crb-text);
  text-decoration: none;
  transition: border-color var(--crb-transition), transform var(--crb-transition), box-shadow var(--crb-transition);
}
.crb-settings-card:hover {
  border-color: var(--crb-primary);
  transform: translateY(-2px);
  box-shadow: var(--crb-shadow);
}
.crb-settings-card__icon {
  display: inline-flex;
  color: var(--crb-primary);
}
.crb-settings-card__icon svg { width: 24px; height: 24px; }
.crb-settings-card__label {
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-semibold);
}
.crb-settings-card--logout { color: var(--crb-danger); }
.crb-settings-card--logout .crb-settings-card__icon { color: var(--crb-danger); }
.crb-settings-card--logout:hover { border-color: var(--crb-danger); }

/* ═══════════════════════════════════════════════════════════════════════════
   TOPBAR DU SHELL (Phase C) — recherche · filtres · statut · notifs · compte
   FIXE en haut du viewport (plus de décalage sous le header du thème). Hors-flux :
   elle court de la colonne centrale (à droite du rail gauche) jusqu'au bord droit,
   au-dessus du contenu central ET de la colonne droite, qui réservent sa hauteur
   via --crb-topbar-clearance. Desktop ≥1024px only : sur mobile, la discover-toolbar
   + la bottom-nav restent la navigation.
   .crb-shell étant full-bleed (bord gauche = bord viewport), le contenu central
   commence à `aside-width + column-gap` du bord gauche → c'est l'inset gauche fixe.
   ═══════════════════════════════════════════════════════════════════════════ */
.crb-topbar { display: none; }

@media (min-width: 1024px) {
  .crb-topbar {
    display: flex;
    align-items: center;
    gap: var(--crb-space-4);
    position: fixed;
    top: 0;
    left: var(--crb-shell-aside-width);
    right: 0;
    height: var(--crb-topbar-height);
    z-index: var(--crb-z-fixed);
    padding: 0 var(--crb-space-5);
    /* Couche de VERRE, pas bandeau opaque : le contenu passe visiblement dessous,
       et c'est ce qui crée la profondeur — on voit qu'il y a un dessous, donc il y
       a un dessous. `--crb-nav-bg` (réglable en admin) reste le socle de repli et
       la couleur de référence du mélange ; seule l'opacité est un choix de design.
       La saturation compense le délavage que produit tout flou.
       `background-color` est reposé APRÈS le raccourci : sans repli opaque, un
       navigateur sans backdrop-filter laisserait lire le contenu au travers. */
    background: var(--crb-nav-bg);
    border-bottom: 1px solid var(--crb-hairline);
  }
  @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .crb-topbar {
      background: var(--crb-glass-nav);
      -webkit-backdrop-filter: blur(var(--crb-glass-blur)) saturate(var(--crb-glass-saturate));
      backdrop-filter: blur(var(--crb-glass-blur)) saturate(var(--crb-glass-saturate));
    }
  }

  /* Le bouton Filtres global est dans la topbar : éviter le doublon dans la
     toolbar Découvrir sur desktop (le toggle Swipe/Liste, lui, y reste). */
  #crb-filters-trigger { display: none; }

  /* La toolbar Découvrir défile dans le contenu central, sous la topbar fixe :
     son sticky se cale sous la topbar (et non plus sous le header du thème). */
  .crb-discover-toolbar { top: var(--crb-topbar-clearance); }
}

/* Champ de recherche (souple) */
.crb-topbar__search {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  margin: 0;
}
.crb-topbar__search-icon {
  position: absolute;
  left: var(--crb-space-3);
  display: inline-flex;
  color: var(--crb-text-muted);
  pointer-events: none;
}
.crb-topbar__search-icon svg { width: 18px; height: 18px; }

/* ─── Recherche par pseudo dans la toolbar Découvrir (<1024px) ──────────────
   Le champ de recherche du shell vit dans la topbar… qui n'existe pas sous
   1024px : la recherche par pseudo était donc simplement introuvable en mobile.
   Ce champ prend le relais À CET ENDROIT-LÀ, et disparaît exactement là où la
   topbar apparaît — les deux ne coexistent jamais.
   Ce n'est pas une seconde recherche : les deux champs portent
   [data-crb-search-input], app.js les tient à la même valeur et les badges de
   filtres lisent le terme sans savoir lequel l'a saisi (cf. searchTerm()). */
.crb-discover-search {
  position: relative;
  display: flex;
  align-items: center;
  margin: 0;
}
@media (min-width: 1024px) { .crb-discover-search { display: none; } }
.crb-discover-search__icon {
  position: absolute;
  left: var(--crb-space-3);
  display: inline-flex;
  color: var(--crb-text-muted);
  pointer-events: none;
}
.crb-discover-search__icon svg { width: 18px; height: 18px; }
.crb-plugin .crb-topbar__search-input,
.crb-plugin .crb-discover-search__input {
  width: 100%;
  padding: var(--crb-space-2) var(--crb-space-3);
  padding-left: calc(var(--crb-space-3) * 2 + 18px);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-pill);
  background: var(--crb-surface);
  font-size: var(--crb-fs-sm);
  color: var(--crb-text);
}
.crb-plugin .crb-topbar__search-input:focus,
.crb-plugin .crb-discover-search__input:focus {
  outline: none;
  border-color: var(--crb-primary);
  background: var(--crb-surface);
}

.crb-topbar__actions {
  display: flex;
  align-items: center;
  gap: var(--crb-space-3);
  flex: 0 0 auto;
}

/* Statut « En ligne » / « Hors ligne »
   La pastille est VERTE (--crb-success), comme tous les autres témoins de présence
   du front (.crb-online-dot, .crb-gallery-card--online, .crb-chat__online-dot). Elle
   suivait auparavant --crb-accent, que l'admin peint en corail dans la palette par
   défaut : le témoin « en ligne » s'affichait alors orange. */
.crb-topbar__status {
  display: inline-flex;
  align-items: center;
  gap: var(--crb-space-2);
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
  white-space: nowrap;
}
.crb-topbar__status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--crb-success);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--crb-success) 20%, transparent);
}

/* Mode « Hors ligne » choisi par le membre (formule can_appear_offline) : pastille
   éteinte, creuse, pour se distinguer d'un simple témoin gris de texte. */
.crb-topbar__status--offline .crb-topbar__status-dot {
  background: transparent;
  border: 2px solid var(--crb-text-muted);
  box-shadow: none;
}

/* Bascule cliquable — rendue en <button>, à neutraliser des styles de bouton du thème. */
.crb-plugin .crb-topbar__status--toggle,
.crb-plugin .crb-topbar__status--upsell {
  padding: var(--crb-space-1) var(--crb-space-2);
  margin: 0;
  border: 0;
  border-radius: var(--crb-radius-pill);
  background: transparent;
  color: var(--crb-text-muted);
  font: inherit;
  font-size: var(--crb-fs-sm);
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
}
.crb-plugin .crb-topbar__status--toggle:hover,
.crb-plugin .crb-topbar__status--upsell:hover {
  background: var(--crb-bg-hover);
  color: var(--crb-text);
}
.crb-plugin .crb-topbar__status--toggle:focus-visible,
.crb-plugin .crb-topbar__status--upsell:focus-visible {
  outline: 2px solid var(--crb-primary);
  outline-offset: 2px;
}
/* Bascule en cours (appel REST) : on gèle l'interaction sans faire sauter la mise en page. */
.crb-plugin .crb-topbar__status--toggle[aria-busy="true"] {
  opacity: .6;
  pointer-events: none;
}

/* Boutons icône (notifications) — badges mutualisés avec la bottom-nav */
.crb-topbar__icon-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: none;
  border-radius: var(--crb-radius);
  background: none;
  color: var(--crb-text-muted);
  cursor: pointer;
  transition: background var(--crb-transition), color var(--crb-transition);
}
.crb-topbar__icon-btn:hover { background: var(--crb-bg-hover); color: var(--crb-primary); }
.crb-topbar__icon-btn svg { width: 22px; height: 22px; }
.crb-topbar__badge {
  position: absolute;
  top: 2px;
  right: 2px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 50px;
  background: var(--crb-notification);
  color: #fff;
  font-size: var(--crb-fs-3xs);
  font-weight: var(--crb-fw-bold);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Menu compte (avatar) — <details> natif, fermé au clic extérieur via app.js */
.crb-topbar__avatar { position: relative; }
.crb-topbar__avatar-summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: var(--crb-space-2);
  padding: var(--crb-space-1) var(--crb-space-2) var(--crb-space-1) var(--crb-space-1);
  border-radius: 999px;
}
.crb-topbar__avatar-summary:hover { background: var(--crb-surface-alt); }
.crb-topbar__avatar-summary::-webkit-details-marker { display: none; }
.crb-topbar__avatar-pseudo {
  font-weight: var(--crb-fw-semibold);
  font-size: var(--crb-fs-sm);
  color: var(--crb-text);
  white-space: nowrap;
}
.crb-topbar__avatar-chevron {
  color: var(--crb-text-muted);
  transition: transform .2s ease;
  flex: none;
}
.crb-topbar__avatar[open] .crb-topbar__avatar-chevron { transform: rotate(180deg); }
.crb-topbar__avatar-img {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  object-fit: cover;
  display: block;
  box-shadow: 0 0 0 2px var(--crb-border);
}
.crb-topbar__avatar[open] .crb-topbar__avatar-img { box-shadow: 0 0 0 2px var(--crb-primary); }
/* Le menu naît de l'avatar : `transform-origin` au coin haut-DROIT, c'est-à-dire
   sous le déclencheur. Un menu qui grandit depuis son propre centre rompt le lien
   entre le bouton et ce qu'il ouvre — et ce lien est tout ce qui rend une commande
   prévisible. */
.crb-topbar__avatar-menu {
  position: absolute;
  top: calc(100% + var(--crb-space-2));
  right: 0;
  min-width: 200px;
  display: flex;
  flex-direction: column;
  padding: var(--crb-space-2);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-edge-highlight), var(--crb-shadow-lg);
  z-index: var(--crb-z-dropdown);
  transform-origin: top right;
  animation: crb-menu-in var(--crb-dur-base) var(--crb-ease-emphasized) both;
}
@keyframes crb-menu-in {
  from { opacity: 0; transform: translateY(-6px) scale(.96); }
  to   { opacity: 1; transform: none; }
}
/* Pas de verre dépoli ici, contrairement à la topbar et au rail : ce menu se pose
   au-dessus de cartes claires et de photos de membres, et la moindre translucidité
   y faisait remonter le contenu de la page entre les libellés. Un menu se lit d'un
   coup d'œil ou ne sert à rien — fond plein, `--crb-surface`, sans exception. */
.crb-topbar__avatar-link {
  padding: var(--crb-space-2) var(--crb-space-3);
  border-radius: var(--crb-radius-sm);
  color: var(--crb-text);
  text-decoration: none;
  font-size: var(--crb-fs-sm);
}
.crb-topbar__avatar-link:hover { background: var(--crb-surface-alt); color: var(--crb-primary); }
.crb-topbar__avatar-link--logout { color: var(--crb-danger); }
/* En-tête du menu : pseudo du membre (menus qui n'affichent pas le pseudo à côté
   de l'avatar — topbar des vues standalone, barre mobile). */
.crb-topbar__avatar-name {
  padding: var(--crb-space-2) var(--crb-space-3);
  font-weight: var(--crb-fw-semibold);
  font-size: var(--crb-fs-sm);
  color: var(--crb-text);
  border-bottom: 1px solid var(--crb-border);
  margin-bottom: var(--crb-space-1);
}

/* ─── Dashboard SPA ─────────────────────────────────────────────────────── */
.crb-dashboard {
  display: flex;
  flex-direction: column;
  /* PAS de margin-top ici : on garde le flux naturel (la page a son propre ascenseur,
     pas de cadre interne → plus de double scrollbar). Le shell ne réserve plus la
     hauteur du header du thème : sa topbar interne (sticky top:0) occupe le haut. */
  min-height: 100dvh;
  background: var(--crb-bg);
}
.crb-dashboard__content {
  flex: 1;
  padding: 0 var(--crb-space-4);
}
/* Sous 1024px, cette gouttière se CUMULAIT avec celle de `.crb-panel__inner`
   (16 + 16 = 32px de chaque côté) : sur un écran de 390px, un sixième de la
   largeur partait en marges, et les cartes membres s'en trouvaient d'autant
   rétrécies. Une seule gouttière suffit — celle du panneau, qui vaut aussi pour
   les vues standalone (elles n'ont jamais eu ce doublon) et qui aligne le
   contenu sur le hamburger de la barre mobile (même retrait de 16px).
   Desktop inchangé : là, les 32px sont confortables et la topbar s'y accorde. */
@media (max-width: 1023px) {
  .crb-dashboard__content { padding-left: 0; padding-right: 0; }
}
/* ─── Barre mobile + rail en drawer (<1024px) ──────────────────────────────
   La bottom-nav a disparu : sous 1024px le rail gauche (.crb-shell__aside) est
   un panneau hors-écran ouvert par le hamburger de la barre mobile. ≥1024px le
   rail redevient persistant (cf. @media plus haut) et cette barre disparaît.
   Composant du SHELL (et non du seul dashboard) : les vues standalone (compte,
   fiche profil, swipe) la rendent aussi via ShellLayout::wrap(), sans quoi elles
   n'offraient sur mobile ni navigation ni accès au compte. */
.crb-shell__mobilebar {
  display: flex;
  align-items: center;
  gap: var(--crb-space-3);
  position: sticky;
  top: 0;
  z-index: var(--crb-z-dropdown);
  height: var(--crb-mobilebar-height);
  padding: 0 var(--crb-space-4);
  background: var(--crb-surface);
  border-bottom: 1px solid var(--crb-hairline);
}
/* Même matière que la topbar desktop : la barre est collante, donc du contenu
   passe SOUS elle en permanence — c'est exactement le cas où une couche opaque
   confisque une bande d'écran alors qu'une couche translucide la restitue. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .crb-shell__mobilebar {
    background: var(--crb-glass-bg-strong);
    -webkit-backdrop-filter: blur(var(--crb-glass-blur)) saturate(var(--crb-glass-saturate));
    backdrop-filter: blur(var(--crb-glass-blur)) saturate(var(--crb-glass-saturate));
  }
}
.crb-shell__menu-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--crb-text);
  border-radius: var(--crb-radius);
  transition: background var(--crb-transition), color var(--crb-transition);
}
.crb-shell__menu-toggle:hover { background: var(--crb-surface-alt); color: var(--crb-primary); }
.crb-shell__menu-toggle svg { width: 24px; height: 24px; }
.crb-shell__mobilebar-title {
  font-size: var(--crb-fs-base);
  font-weight: var(--crb-fw-semibold);
  /* Titre tronqué plutôt que de pousser l'avatar hors de l'écran. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Avatar + menu compte de la barre mobile : collé à droite, le menu s'ouvre en
   dessous (le <details> porte déjà position:relative via .crb-topbar__avatar). */
.crb-shell__mobilebar-avatar {
  margin-left: auto;
  flex: none;
}
.crb-shell__mobilebar-avatar .crb-topbar__avatar-summary { padding: 2px; }
.crb-shell__mobilebar-avatar .crb-topbar__avatar-menu {
  /* Le menu déborderait sous la barre collante sans être au-dessus du contenu. */
  z-index: var(--crb-z-sheet);
  /* Borne de repli seulement : la vraie hauteur disponible est mesurée à
     l'ouverture par app.js (fitMenu). Ce calc() suppose la barre en haut de
     l'écran, ce qui est faux dès qu'un header de thème la précède — il coupait
     alors les dernières entrées du menu. */
  max-height: calc(100dvh - var(--crb-mobilebar-height) - var(--crb-space-4));
  overflow-y: auto;
  /* Arrivé en bout de liste, le geste ne doit pas se propager à la page
     derrière : le menu se refermerait sous le doigt. */
  overscroll-behavior: contain;
  /* Écran vraiment bas (paysage, clavier ouvert) : la liste défile. Sur mobile
     la barre de défilement est invisible — cette fine barre est le seul indice
     qu'il reste des entrées en dessous. */
  scrollbar-width: thin;
}

/* Rail en drawer (mobile) — vaut pour TOUTES les vues du shell : le dashboard
   comme les vues standalone (compte, fiche profil, swipe), qui portent désormais
   la même barre mobile, donc le même hamburger. */
.crb-shell .crb-shell__aside {
  display: block;
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: min(320px, 85vw);
  z-index: var(--crb-z-sheet);
  overflow-y: auto;
  padding: var(--crb-space-4);
  background: var(--crb-surface);
  border-right: 1px solid var(--crb-border);
  transform: translateX(-100%);
  visibility: hidden;
  /* Un tiroir tenu par le doigt mérite plus que 180 ms linéaires : la courbe
     emphasized démarre vif et arrive amorti, ce qui donne la masse du panneau. */
  transition: transform var(--crb-dur-slow) var(--crb-ease-emphasized),
              visibility var(--crb-dur-slow) var(--crb-ease-emphasized);
}
.crb-shell .crb-shell__aside.is-open {
  transform: translateX(0);
  visibility: visible;
  box-shadow: var(--crb-shadow-lg);
}
/* Panneau translucide : le contenu de la page reste perceptible derrière lui, ce
   qui rappelle en permanence qu'on est en surimpression et non sur un autre écran. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  @media (max-width: 1023px) {
    .crb-shell .crb-shell__aside {
      background: var(--crb-glass-bg-strong);
      border-right-color: var(--crb-hairline);
      -webkit-backdrop-filter: blur(var(--crb-glass-blur)) saturate(var(--crb-glass-saturate));
      backdrop-filter: blur(var(--crb-glass-blur)) saturate(var(--crb-glass-saturate));
    }
  }
}

/* Voile cliquable derrière le drawer ouvert. */
.crb-shell__aside-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--crb-z-fixed);
  /* Voile dérivé de la couleur de TEXTE et non du noir pur : l'assombrissement
     garde la teinte de la palette au lieu de la neutraliser en gris. */
  background: var(--crb-veil);
  border: 0;
  animation: crb-fade-in var(--crb-dur-base) var(--crb-ease-out);
}
.crb-shell__aside-backdrop[hidden] { display: none; }

@media (min-width: 1024px) {
  /* Rail persistant : on neutralise l'état drawer ; la barre mobile et le voile
     disparaissent. (Le reste du positionnement fixe vient du bloc shell plus haut.) */
  .crb-shell__mobilebar { display: none; }
  .crb-shell__aside-backdrop { display: none !important; }
  .crb-shell .crb-shell__aside {
    transform: none;
    visibility: visible;
    z-index: var(--crb-z-fixed);
    width: var(--crb-shell-aside-width);
    box-shadow: none;
  }
}

/* ─── Panneaux (sections) ────────────────────────────────────────────────── */
.crb-panel { display: none; }
.crb-panel--active { display: block; }
.crb-panel__inner {
  padding: 16px;
  margin: 0 auto;
}

/* ─── Accueil : zone « résumé du jour » ─────────────────────────────────────
   Carte d'en-tête du panneau Accueil : identité + CTA, deux KPI, le bloc
   « Vos accès du jour » (quotas de la formule) et le conseil du jour.
   Fond en dégradé doux dérivé de la primaire (manuel = corail).
   Mobile-first : bandeau pleine largeur, avatar + salutation sur une rangée,
   CTA pleine largeur dessous, KPI côte à côte ; ≥640px la carte reprend ses
   marges, ≥900px les KPI passent à côté de l'identité. */
.crb-home-hero {
  background:
    linear-gradient(135deg,
      color-mix(in srgb, var(--crb-primary) 10%, var(--crb-surface)),
      color-mix(in srgb, var(--crb-superlike) 8%, var(--crb-surface)));
  /* Mobile : bandeau edge-to-edge. La salutation ouvre l'écran — encadrée à
     16px de chaque bord, elle lisait comme un widget de plus au lieu de l'en-tête
     de la page. Elle déborde la gouttière de `.crb-panel__inner` puis la restitue
     en padding (même technique que la piste du spotlight) : les deux valeurs
     doivent bouger ensemble. Seul le filet du bas subsiste, pour la détacher de
     ce qui suit. */
  --crb-hero-gutter: 16px;   /* = padding de .crb-panel__inner ; à bouger ensemble */
  margin: 0 calc(var(--crb-hero-gutter) * -1) var(--crb-space-4);
  border: 0;
  border-bottom: 1px solid var(--crb-border-soft);
  border-radius: 0;
  padding: var(--crb-space-4) var(--crb-hero-gutter);
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-4);
}
@media (min-width: 640px) {
  /* Au-delà du téléphone, la carte reprend sa forme : marges, filet complet,
     coins arrondis et respiration intérieure. */
  .crb-home-hero {
    margin: 0 0 var(--crb-space-5);
    border: 1px solid var(--crb-border-soft);
    border-radius: var(--crb-radius-lg);
    padding: var(--crb-space-5);
    gap: var(--crb-space-5);
  }
}

/* Rangée haute : identité (avatar + salutation + CTA) | KPI. */
.crb-home-hero__top {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--crb-space-4);
  align-items: start;
}
@media (min-width: 640px) { .crb-home-hero__top { gap: var(--crb-space-5); } }
@media (min-width: 900px) {
  .crb-home-hero__top { grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); }
}

/* Mobile : grille à deux colonnes plutôt qu'une rangée flex — l'avatar tient la
   colonne de gauche en face de la salutation et du sous-titre, et le CTA passe
   SOUS l'avatar, sur toute la largeur (un bouton d'appel indenté de 88px dans une
   carte de 358px n'a plus l'air d'un appel). `display: contents` sur `__head` fait
   remonter ses trois enfants dans cette grille sans toucher au gabarit ; le <div>
   n'ayant aucune sémantique, rien n'est perdu pour les technologies d'assistance. */
.crb-home-hero__intro {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--crb-space-4);
  row-gap: var(--crb-space-2);
  align-items: center;
  min-width: 0;
}
@media (min-width: 640px) {
  .crb-home-hero__intro {
    display: flex;
    align-items: flex-start;
    gap: var(--crb-space-4);
  }
}
.crb-home-hero__avatar {
  position: relative;
  flex: 0 0 auto;
  /* Colonne de gauche de la grille mobile, en face du couple salutation +
     sous-titre (le CTA, lui, passe dessous sur toute la largeur). */
  grid-column: 1;
  grid-row: 1 / span 2;
  align-self: start;
  width: 72px; height: 72px;
  border-radius: var(--crb-radius-pill);
  overflow: hidden;
  background: var(--crb-surface-alt);
  box-shadow: 0 0 0 4px var(--crb-surface), var(--crb-shadow-sm);
}
@media (min-width: 640px) { .crb-home-hero__avatar { width: 104px; height: 104px; } }
.crb-home-hero__avatar img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
/* Pastille de présence — posée sur l'enveloppe (overflow:hidden sur l'image
   uniquement), sinon le rond serait rogné par le masque circulaire. */
.crb-home-hero__avatar.is-online::after {
  content: "";
  position: absolute;
  right: 4px; bottom: 4px;
  width: 14px; height: 14px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-success);
  box-shadow: 0 0 0 3px var(--crb-surface);
}
@media (min-width: 640px) {
  .crb-home-hero__avatar.is-online::after { right: 6px; bottom: 6px; width: 18px; height: 18px; }
}

/* Mobile : le conteneur s'efface, ses enfants deviennent les cases de la grille
   `__intro` ci-dessus. ≥640px il redevient la colonne de texte à droite de
   l'avatar (salutation, sous-titre, boutons empilés). */
.crb-home-hero__head { display: contents; }
@media (min-width: 640px) {
  .crb-home-hero__head { display: flex; flex-direction: column; gap: var(--crb-space-2); min-width: 0; }
}
.crb-home-hero__greeting {
  margin: 0;
  grid-column: 2;
  grid-row: 1;
  /* 24px sur téléphone : à 28px, « Bonjour <pseudo> » poussait déjà la main qui
     salue sur une deuxième ligne pour un pseudo de huit caractères. */
  font-size: var(--crb-fs-3xl);
  font-weight: var(--crb-heading-weight);
  line-height: var(--crb-lh-tight);
  /* Impreza impose sa propre couleur aux h1-h6 : la redéclarer explicitement. */
  color: var(--crb-text);
  /* Texte courant, et non `inline-flex` + `flex-wrap` : en flex, le pseudo forme
     un item à lui seul, donc dès qu'il occupait toute la largeur la main qui salue
     partait seule à la ligne suivante. En flux inline elle reste collée au dernier
     mot, quelle que soit la longueur du pseudo. */
  display: block;
}
@media (min-width: 640px) { .crb-home-hero__greeting { font-size: var(--crb-fs-5xl); } }
.crb-home-hero__wave { font-size: .9em; margin-left: .25em; }
.crb-home-hero__subtitle {
  margin: 0;
  grid-column: 2;
  grid-row: 2;
  color: var(--crb-text-muted);
  font-size: var(--crb-fs-md);
  line-height: var(--crb-lh-base);
}

.crb-home-hero__actions {
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-2);
  margin-top: var(--crb-space-2);
  /* Mobile : sous l'avatar ET sous le texte, d'un bord à l'autre du bandeau. */
  grid-column: 1 / -1;
  grid-row: 3;
}
@media (min-width: 520px) { .crb-home-hero__actions { flex-direction: row; flex-wrap: wrap; } }
.crb-home-hero__cta { justify-content: center; }
/* Sous 520px, « Voir mes messages » double exactement le lien de la carte KPI
   « messages non lus » posée juste dessous (et la bottom-nav) : deux boutons
   pleine largeur pour une seule action utile. On ne garde que le CTA primaire ;
   il réapparaît dès que les deux boutons tiennent côte à côte. */
@media (max-width: 519.98px) {
  .crb-home-hero__cta.crb-btn--outline { display: none; }
}
.crb-home-hero__cta svg { width: var(--crb-icon-md); height: var(--crb-icon-md); }
.crb-home-hero__cta.crb-btn--outline { background: var(--crb-surface); }

/* ── Les deux KPI (profils compatibles / messages non lus) ──
   Côte à côte dès qu'ils tiennent : empilées, ces deux cartes coûtaient à elles
   seules la moitié du premier écran d'un téléphone et repoussaient les quotas
   hors champ. `auto-fit` les remet l'une sous l'autre sous ~330px de large. */
.crb-home-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: var(--crb-space-3);
}

.crb-home-kpi {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--crb-space-1);
  text-align: left;
  padding: var(--crb-space-3);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border-soft);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
  cursor: pointer;
  transition: transform var(--crb-dur-fast) var(--crb-ease), box-shadow var(--crb-dur-fast) var(--crb-ease);
}
@media (min-width: 640px) {
  .crb-home-kpi { gap: var(--crb-space-2); padding: var(--crb-space-4); }
}
.crb-home-kpi:hover { transform: translateY(-1px); box-shadow: var(--crb-shadow-md); }
.crb-home-kpi:focus-visible { outline: 2px solid var(--crb-focus-ring); outline-offset: 2px; }
.crb-home-kpi__icon {
  flex: 0 0 auto;
  width: 36px; height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--crb-radius-pill);
  margin-bottom: var(--crb-space-1);
}
@media (min-width: 640px) {
  .crb-home-kpi__icon { width: 44px; height: 44px; margin-bottom: var(--crb-space-2); }
}
.crb-home-kpi__icon svg { width: var(--crb-icon-md); height: var(--crb-icon-md); }
.crb-home-kpi--match   .crb-home-kpi__icon { background: var(--crb-primary-tint); color: var(--crb-primary); }
.crb-home-kpi--message .crb-home-kpi__icon { background: color-mix(in srgb, var(--crb-superlike) 14%, var(--crb-surface)); color: var(--crb-superlike); }
.crb-home-kpi__value {
  font-size: var(--crb-fs-4xl);
  font-weight: var(--crb-fw-bold);
  line-height: var(--crb-lh-tight);
  color: var(--crb-text);
}
.crb-home-kpi__title { font-size: var(--crb-fs-base); font-weight: var(--crb-fw-semibold); color: var(--crb-text); }
.crb-home-kpi__desc  { font-size: var(--crb-fs-2xs); color: var(--crb-text-muted); }
.crb-home-kpi__link {
  margin-top: auto;
  padding-top: var(--crb-space-2);
  display: inline-flex;
  align-items: center;
  gap: var(--crb-space-1);
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-semibold);
}
/* Deux cartes par rangée sur téléphone : la typographie du desktop n'est reprise
   qu'une fois la place revenue. */
@media (min-width: 640px) {
  .crb-home-kpi__value { font-size: var(--crb-fs-5xl); }
  .crb-home-kpi__title { font-size: var(--crb-fs-lg); }
  .crb-home-kpi__desc  { font-size: var(--crb-fs-sm); }
  .crb-home-kpi__link  { gap: var(--crb-space-2); font-size: var(--crb-fs-sm); }
}
.crb-home-kpi--match   .crb-home-kpi__link { color: var(--crb-primary); }
.crb-home-kpi--message .crb-home-kpi__link { color: var(--crb-superlike); }
.crb-home-kpi__arrow { transition: transform var(--crb-dur-fast) var(--crb-ease); }
.crb-home-kpi:hover .crb-home-kpi__arrow { transform: translateX(3px); }

/* ── « Votre plan … — Vos accès du jour » ──────────────────────────────────
   Carte blanche : à gauche l'en-tête + les trois quotas, à droite le panneau
   d'upsell (absent du DOM pour un membre déjà au maximum). Mobile : un quota
   par ligne ; tablette : 2 + 1 ; desktop : 3 sur une ligne, upsell à droite. */
.crb-allowances {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--crb-space-4);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border-soft);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
  padding: var(--crb-space-4);
}
/* La respiration de 24px n'arrive qu'avec la largeur : sur téléphone, la carte
   est déjà encadrée par les 16px du bandeau d'accueil. */
@media (min-width: 640px) { .crb-allowances { padding: var(--crb-space-5); } }
@media (min-width: 1100px) {
  /* La 2ᵉ colonne n'existe que s'il y a un upsell à montrer : sinon les quotas
     prennent toute la largeur plutôt que de laisser un vide à droite. */
  .crb-allowances--with-upsell {
    grid-template-columns: minmax(0, 1fr) minmax(240px, 300px);
    gap: var(--crb-space-5);
  }
}
.crb-allowances__main { display: flex; flex-direction: column; gap: var(--crb-space-4); min-width: 0; }

.crb-allowances__head { display: flex; align-items: flex-start; gap: var(--crb-space-3); }
.crb-allowances__head-icon {
  flex: 0 0 auto;
  width: 40px; height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary-tint);
  color: var(--crb-primary);
}
.crb-allowances__head-icon svg { width: var(--crb-icon-md); height: var(--crb-icon-md); }
.crb-allowances__head-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.crb-allowances__title {
  margin: 0;
  font-size: var(--crb-fs-xl);
  font-weight: var(--crb-fw-bold);
  line-height: var(--crb-lh-tight);
  color: var(--crb-text);
}
.crb-allowances__hint { margin: 0; font-size: var(--crb-fs-sm); color: var(--crb-text-muted); }

.crb-allowances__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--crb-space-3);
}
@media (min-width: 640px)  { .crb-allowances__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .crb-allowances__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.crb-allowance {
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-3);
  padding: var(--crb-space-4);
  border: 1px solid var(--crb-border-soft);
  border-radius: var(--crb-radius);
  background: var(--crb-surface);
}
.crb-allowance__top { display: flex; align-items: center; gap: var(--crb-space-3); }
.crb-allowance__icon {
  flex: 0 0 auto;
  width: 40px; height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--crb-radius-pill);
}
.crb-allowance__icon svg { width: var(--crb-icon-md); height: var(--crb-icon-md); }
.crb-allowance__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.crb-allowance__value {
  margin: 0;
  font-size: var(--crb-fs-2xl);
  font-weight: var(--crb-fw-bold);
  line-height: var(--crb-lh-tight);
  color: var(--crb-text);
}
.crb-allowance__label { margin: 0; font-size: var(--crb-fs-sm); color: var(--crb-text); }
.crb-allowance__foot  { margin: 0; font-size: var(--crb-fs-2xs); color: var(--crb-text-muted); }

/* La barre décrit ce qui RESTE ; sa largeur vient du serveur (percent), jamais
   d'une lecture du texte affiché. La transition rend visible la consommation.
   `margin-top:auto` aligne les trois barres sur la même ligne même quand un
   libellé passe sur deux lignes (« nouvelles conversations possibles »). */
.crb-allowance__track {
  margin-top: auto;
  height: 6px;
  border-radius: var(--crb-radius-pill);
  background: color-mix(in srgb, var(--crb-text) 8%, var(--crb-surface));
  overflow: hidden;
}
.crb-allowance__bar {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: currentColor;
  transition: width 300ms var(--crb-ease);
}
@media (prefers-reduced-motion: reduce) { .crb-allowance__bar { transition: none; } }

/* Teintes par quota — la couleur est portée par la carte, la barre hérite via
   currentColor : une seule déclaration par tonalité. */
.crb-allowance--like         { color: var(--crb-primary); }
.crb-allowance--message      { color: var(--crb-superlike); }
.crb-allowance--conversation { color: var(--crb-success); }
.crb-allowance--like         .crb-allowance__icon { background: var(--crb-primary-tint); color: var(--crb-primary); }
.crb-allowance--message      .crb-allowance__icon { background: color-mix(in srgb, var(--crb-superlike) 14%, var(--crb-surface)); color: var(--crb-superlike); }
.crb-allowance--conversation .crb-allowance__icon { background: color-mix(in srgb, var(--crb-success) 14%, var(--crb-surface)); color: var(--crb-success); }

/* « Illimité » : barre pleine, rayée, pour ne pas la confondre avec un quota
   qui se viderait. Aucune fausse limite n'est jamais affichée. */
.crb-allowance[data-state="unlimited"] .crb-allowance__bar {
  background-image: repeating-linear-gradient(
    135deg,
    color-mix(in srgb, var(--crb-surface) 45%, transparent) 0 6px,
    transparent 6px 12px);
}
/* « Indisponible » : la fonctionnalité est fermée par la formule — piste vide
   et valeur en gris, plutôt qu'un 0 qui laisserait croire à un quota épuisé. */
.crb-allowance[data-state="unavailable"] { color: var(--crb-text-muted); }
.crb-allowance[data-state="unavailable"] .crb-allowance__value { font-size: var(--crb-fs-lg); color: var(--crb-text-muted); }
.crb-allowance[data-state="unavailable"] .crb-allowance__icon  { background: var(--crb-surface-alt); color: var(--crb-text-muted); }

/* ── Panneau d'upsell (jamais rendu pour un membre déjà au plan maximum) ── */
.crb-allowances__upsell {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--crb-space-2);
  padding-top: var(--crb-space-4);
  border-top: 1px solid var(--crb-border-soft);
}
@media (min-width: 1100px) {
  .crb-allowances__upsell {
    padding-top: 0;
    padding-left: var(--crb-space-5);
    border-top: 0;
    border-left: 1px solid var(--crb-border-soft);
    justify-content: center;
  }
}
.crb-allowances__upsell-icon {
  width: 44px; height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary-tint);
  color: var(--crb-primary);
  margin-bottom: var(--crb-space-1);
}
.crb-allowances__upsell-icon svg { width: var(--crb-icon-md); height: var(--crb-icon-md); }
.crb-allowances__upsell-title {
  margin: 0;
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-fw-bold);
  line-height: var(--crb-lh-tight);
  color: var(--crb-text);
}
.crb-allowances__upsell-text { margin: 0; font-size: var(--crb-fs-sm); color: var(--crb-text-muted); }
.crb-allowances__upsell-cta {
  margin-top: var(--crb-space-2);
  width: 100%;
  justify-content: center;
  gap: var(--crb-space-2);
}
.crb-allowances__arrow { transition: transform var(--crb-dur-fast) var(--crb-ease); }
.crb-allowances__upsell-cta:hover .crb-allowances__arrow { transform: translateX(3px); }

/* ── Conseil du jour ── */
.crb-home-tip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--crb-space-2) var(--crb-space-3);
  padding: var(--crb-space-3) var(--crb-space-4);
  border-radius: var(--crb-radius-lg);
  background: color-mix(in srgb, var(--crb-surface) 70%, transparent);
  border: 1px solid var(--crb-border-soft);
}
.crb-home-tip__icon {
  flex: 0 0 auto;
  width: 36px; height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary-tint);
  color: var(--crb-primary);
}
.crb-home-tip__icon svg { width: var(--crb-icon-sm); height: var(--crb-icon-sm); }
.crb-home-tip__label { font-weight: var(--crb-fw-bold); color: var(--crb-text); font-size: var(--crb-fs-md); }
.crb-home-tip__text  { flex: 1 1 240px; color: var(--crb-text-muted); font-size: var(--crb-fs-sm); }
.crb-home-tip__cta {
  display: inline-flex;
  align-items: center;
  gap: var(--crb-space-2);
  color: var(--crb-primary);
  font-weight: var(--crb-fw-semibold);
  font-size: var(--crb-fs-sm);
  text-decoration: none;
}
.crb-home-tip__cta:hover { text-decoration: underline; }

/* ─── « Mes matchs » — extrait de l'Accueil ET panneau dédié ────────────────
   Un seul jeu de règles pour les deux emplacements du partial matches-block.php :
   `--home` (extrait) et `--panel` (liste complète) ne diffèrent que par ce que le
   JS remplit et par la pagination. Mobile-first : tout empile, la carte vedette
   passe à côté de la liste ≥1024px.

   Aucune couleur en dur : les médaillons et pictogrammes reprennent la palette du
   site (--crb-primary, --crb-superlike, --crb-premium), donc suivent le skin. */
.crb-matches {
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-4);
  margin-bottom: var(--crb-space-5);
}

/* Toute règle d'auteur qui pose un `display` bat le `[hidden] { display:none }` de
   la feuille du NAVIGATEUR (origine UA, la plus faible) : sans ce rappel, les blocs
   ci-dessous resteraient visibles alors que le JS les a marqués masqués. Ils sont
   groupés ici parce que ce sont exactement ceux que matchesShow() commute. */
.crb-matches__loading[hidden],
.crb-matches__layout[hidden],
.crb-matches__empty[hidden],
.crb-matches__error[hidden],
.crb-matches__more[hidden],
.crb-matches__list[hidden],
.crb-matches__all[hidden] { display: none; }

.crb-matches__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--crb-space-3);
}
.crb-matches__heading { display: flex; flex-direction: column; gap: var(--crb-space-1); min-width: 0; }
.crb-matches__title {
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--crb-space-3);
  font-size: var(--crb-fs-2xl);
  font-weight: var(--crb-fw-bold);
  line-height: var(--crb-lh-tight);
  letter-spacing: .04em;
  text-transform: uppercase;
  /* Impreza impose sa couleur aux h1-h6 : la reposer explicitement. */
  color: var(--crb-text);
}
.crb-matches__title-icon {
  flex: 0 0 auto;
  width: 40px; height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--crb-radius-lg);
  background: var(--crb-primary-tint);
  color: var(--crb-primary);
}
.crb-matches__title-icon svg { width: var(--crb-icon-md); height: var(--crb-icon-md); }
.crb-matches__subtitle { margin: 0; font-size: var(--crb-fs-sm); color: var(--crb-text-muted); }

.crb-matches__all {
  display: inline-flex;
  align-items: center;
  gap: var(--crb-space-2);
  padding: var(--crb-space-2) var(--crb-space-4);
  min-height: 40px;
  border: 1px solid color-mix(in srgb, var(--crb-primary) 40%, transparent);
  border-radius: var(--crb-radius-pill);
  background: var(--crb-surface);
  color: var(--crb-primary);
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-semibold);
  cursor: pointer;
  transition: background var(--crb-dur-fast) var(--crb-ease), border-color var(--crb-dur-fast) var(--crb-ease);
}
.crb-matches__all:hover { background: var(--crb-primary-tint); border-color: var(--crb-primary); }
.crb-matches__all:focus-visible { outline: 2px solid var(--crb-focus-ring); outline-offset: 2px; }
.crb-matches__all-arrow { transition: transform var(--crb-dur-fast) var(--crb-ease); }
.crb-matches__all:hover .crb-matches__all-arrow { transform: translateX(3px); }

/* ── Disposition : vedette | liste ── */
.crb-matches__layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--crb-space-4);
  align-items: start;
}
@media (min-width: 1024px) {
  .crb-matches__layout { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
}
.crb-matches__list { display: flex; flex-direction: column; gap: var(--crb-space-3); min-width: 0; }

/* ── Carte vedette (match le plus récent) ── */
.crb-match-hero {
  display: flex;
  flex-direction: column;
  background: var(--crb-surface);
  border: 1px solid var(--crb-border-soft);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
  overflow: hidden;
}
.crb-match-hero__media {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--crb-surface-alt);
}
/* Photo SORTIE du flux : dans le flux, une image plus haute que le ratio ferait
   grandir la boîte et `aspect-ratio` ne serait plus qu'une taille préférée. */
.crb-match-hero__photo {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.crb-match-hero__photo--empty {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--crb-fs-6xl);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text-muted);
}
.crb-match-hero__online {
  position: absolute;
  top: var(--crb-space-3);
  right: var(--crb-space-3);
  display: inline-flex;
  align-items: center;
  gap: var(--crb-space-2);
  padding: 6px var(--crb-space-3);
  border-radius: var(--crb-radius-pill);
  background: var(--crb-glass-bg-strong);
  backdrop-filter: blur(6px);
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text);
}
.crb-match__dot {
  width: 9px; height: 9px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-success);
  flex: 0 0 auto;
}
.crb-match-hero__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--crb-space-3);
  padding: var(--crb-space-4);
}
.crb-match-hero__name {
  margin: 0;
  font-size: var(--crb-fs-3xl);
  font-weight: var(--crb-fw-bold);
  line-height: var(--crb-lh-tight);
  color: var(--crb-text);
}
.crb-match-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--crb-space-2);
  width: 100%;
}
.crb-match-hero__actions .crb-btn { flex: 1 1 180px; justify-content: center; }
.crb-match-hero__actions svg { width: var(--crb-icon-md); height: var(--crb-icon-md); }

/* ── Rangée de match ── */
.crb-match-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--crb-space-3);
  padding: var(--crb-space-3);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border-soft);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
  transition: transform var(--crb-dur-fast) var(--crb-ease), box-shadow var(--crb-dur-fast) var(--crb-ease);
}
.crb-match-row:hover { transform: translateY(-1px); box-shadow: var(--crb-shadow-md); }
@media (min-width: 560px) {
  .crb-match-row { grid-template-columns: auto minmax(0, 1fr) auto; }
}
.crb-match-row__avatar {
  position: relative;
  display: block;
  width: 72px; height: 72px;
  border-radius: var(--crb-radius-pill);
  overflow: hidden;
  flex: 0 0 auto;
  background: var(--crb-surface-alt);
}
.crb-match-row__photo { width: 100%; height: 100%; object-fit: cover; display: block; }
.crb-match-row__photo--empty {
  width: 100%; height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--crb-fs-2xl);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text-muted);
}
/* Pastille de présence : posée sur l'enveloppe, hors du masque circulaire de la
   photo — sinon elle serait rognée. */
.crb-match-row__avatar.is-online::after {
  content: "";
  position: absolute;
  right: 2px; bottom: 2px;
  width: 14px; height: 14px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-success);
  box-shadow: 0 0 0 3px var(--crb-surface);
}
.crb-match-row__body { display: flex; flex-direction: column; gap: var(--crb-space-2); min-width: 0; }
.crb-match-row__name {
  font-size: var(--crb-fs-xl);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text);
  text-decoration: none;
}
.crb-match-row__name:hover { color: var(--crb-primary); }
.crb-match-row__aside {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--crb-space-3);
}
@media (min-width: 560px) {
  .crb-match-row__aside {
    grid-column: auto;
    justify-content: flex-end;
    padding-left: var(--crb-space-3);
    border-left: 1px solid var(--crb-border-soft);
  }
}
.crb-match-row__msg {
  flex: 0 0 auto;
  width: 44px; height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--crb-border-soft);
  border-radius: var(--crb-radius);
  color: var(--crb-primary);
  background: var(--crb-surface);
  transition: background var(--crb-dur-fast) var(--crb-ease), border-color var(--crb-dur-fast) var(--crb-ease);
}
.crb-match-row__msg:hover { background: var(--crb-primary-tint); border-color: var(--crb-primary); }
.crb-match-row__msg svg { width: var(--crb-icon-md); height: var(--crb-icon-md); }

/* ── Métadonnées communes à la vedette et aux rangées ── */
.crb-match__place,
.crb-match__date {
  display: inline-flex;
  align-items: center;
  gap: var(--crb-space-2);
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
  min-width: 0;
}
.crb-match__place { color: var(--crb-primary); }
.crb-match__place svg,
.crb-match__date svg { width: var(--crb-icon-sm); height: var(--crb-icon-sm); flex: 0 0 auto; }
.crb-match__badges { display: flex; flex-wrap: wrap; gap: var(--crb-space-2); }
.crb-match__badge {
  display: inline-flex;
  align-items: center;
  padding: 4px var(--crb-space-3);
  border: 1px solid color-mix(in srgb, var(--crb-primary) 25%, transparent);
  border-radius: var(--crb-radius-pill);
  background: color-mix(in srgb, var(--crb-primary) 6%, var(--crb-surface));
  font-size: var(--crb-fs-2xs);
  color: var(--crb-text);
}

/* ── Pagination + squelettes ── */
.crb-matches__more { display: flex; justify-content: center; }
.crb-matches__more .crb-btn { min-width: 240px; justify-content: center; }
.crb-matches__loading {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--crb-space-4);
}
@media (min-width: 1024px) {
  .crb-matches__loading { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
}
.crb-matches__skeleton-hero { aspect-ratio: 4 / 3; border-radius: var(--crb-radius-lg); }
.crb-matches__skeleton-list { display: flex; flex-direction: column; gap: var(--crb-space-3); }
.crb-matches__skeleton-row { height: 96px; border-radius: var(--crb-radius-lg); }

/* ─── « Mes matchs » — état vide (pédagogie) ────────────────────────────── */
.crb-matches__empty {
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-5);
  padding: var(--crb-space-5) var(--crb-space-4);
}
.crb-matches-empty__lead { text-align: center; }
.crb-matches-empty__title {
  margin: 0 0 var(--crb-space-2);
  font-size: var(--crb-fs-4xl);
  font-weight: var(--crb-fw-bold);
  line-height: var(--crb-lh-tight);
  color: var(--crb-text);
}
.crb-matches-empty__spark { font-size: .8em; }
.crb-matches-empty__text {
  margin: 0;
  color: var(--crb-text-muted);
  font-size: var(--crb-fs-md);
  line-height: var(--crb-lh-base);
}
.crb-matches-empty__how {
  margin: 0;
  text-align: center;
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text);
}

/* Les 4 étapes. Mobile : une colonne. ≥720px : deux. ≥1024px : quatre, avec la
   flèche de liaison dessinée entre les médaillons. */
.crb-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--crb-space-5) var(--crb-space-4);
  counter-reset: crb-step;
}
@media (min-width: 720px)  { .crb-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .crb-steps { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.crb-step {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--crb-space-2);
}
.crb-step__medallion {
  position: relative;
  width: 96px; height: 96px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--crb-radius-pill);
  background: color-mix(in srgb, var(--crb-primary) 8%, var(--crb-surface));
  margin-bottom: var(--crb-space-2);
}
.crb-step__icon {
  display: inline-flex;
  width: 56px; height: 56px;
  align-items: center;
  justify-content: center;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary-tint);
  color: var(--crb-primary);
}
.crb-step__icon svg { width: 28px; height: 28px; }
.crb-step--accent .crb-step__medallion { background: color-mix(in srgb, var(--crb-superlike) 8%, var(--crb-surface)); }
.crb-step--accent .crb-step__icon {
  background: color-mix(in srgb, var(--crb-superlike) 14%, var(--crb-surface));
  color: var(--crb-superlike);
}
/* Numéro : pastille pleine en haut à gauche du médaillon. */
.crb-step__num {
  position: absolute;
  top: -2px; left: -2px;
  width: 28px; height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary);
  color: var(--crb-cta-text);
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-bold);
  box-shadow: 0 0 0 3px var(--crb-surface);
}
.crb-step__title { font-size: var(--crb-fs-lg); font-weight: var(--crb-fw-bold); color: var(--crb-text); }
.crb-step__text  { font-size: var(--crb-fs-sm); color: var(--crb-text-muted); line-height: var(--crb-lh-base); }

/* Flèche de liaison — décorative, donc en pseudo-élément : rien à lire, rien à
   masquer pour les lecteurs d'écran. Uniquement quand les 4 étapes sont en ligne. */
@media (min-width: 1024px) {
  .crb-step:not(:last-child)::after {
    content: "→";
    position: absolute;
    top: 40px;
    right: -12px;
    font-size: var(--crb-fs-2xl);
    line-height: 1;
    color: color-mix(in srgb, var(--crb-primary) 55%, transparent);
  }
}

.crb-matches-empty__thread {
  display: none;
  position: relative;
  height: 1px;
  margin: 0 auto;
  width: min(880px, 90%);
  border-top: 2px dashed color-mix(in srgb, var(--crb-primary) 35%, transparent);
}
@media (min-width: 1024px) { .crb-matches-empty__thread { display: block; } }
.crb-matches-empty__thread-heart {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--crb-space-2);
  border-radius: var(--crb-radius-pill);
  background: var(--crb-surface);
  color: var(--crb-primary);
}
.crb-matches-empty__thread-heart svg { width: var(--crb-icon-md); height: var(--crb-icon-md); }

.crb-matches-empty__cta { display: flex; justify-content: center; }
.crb-matches-empty__cta .crb-btn svg { width: var(--crb-icon-md); height: var(--crb-icon-md); }

/* ── Conseils ── */
.crb-tips {
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-4);
  padding: var(--crb-space-4);
  border-radius: var(--crb-radius-lg);
  background: color-mix(in srgb, var(--crb-primary) 5%, var(--crb-surface));
  border: 1px solid color-mix(in srgb, var(--crb-primary) 18%, transparent);
}
.crb-tips__head { display: flex; align-items: flex-start; gap: var(--crb-space-3); }
.crb-tips__head-icon {
  flex: 0 0 auto;
  width: 44px; height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary-tint);
  color: var(--crb-primary);
}
.crb-tips__head-icon svg { width: var(--crb-icon-md); height: var(--crb-icon-md); }
.crb-tips__head-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.crb-tips__title {
  margin: 0;
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text);
}
.crb-tips__subtitle { margin: 0; font-size: var(--crb-fs-sm); color: var(--crb-text-muted); }

.crb-tips__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--crb-space-3);
}
@media (min-width: 640px)  { .crb-tips__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .crb-tips__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.crb-tip { display: flex; align-items: flex-start; gap: var(--crb-space-3); min-width: 0; }
@media (min-width: 1100px) {
  /* Séparateurs verticaux entre conseils, seulement quand ils sont sur une ligne. */
  .crb-tip + .crb-tip { padding-left: var(--crb-space-3); border-left: 1px solid color-mix(in srgb, var(--crb-primary) 18%, transparent); }
}
.crb-tip__icon {
  flex: 0 0 auto;
  width: 44px; height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--crb-radius-pill);
  border: 1px solid color-mix(in srgb, var(--crb-primary) 25%, transparent);
  color: var(--crb-primary);
}
.crb-tip__icon svg { width: var(--crb-icon-md); height: var(--crb-icon-md); }
.crb-tip--premium .crb-tip__icon {
  border-color: color-mix(in srgb, var(--crb-premium) 45%, transparent);
  color: var(--crb-premium);
}
.crb-tip__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.crb-tip__title { font-size: var(--crb-fs-md); font-weight: var(--crb-fw-bold); color: var(--crb-text); }
.crb-tip__text  { font-size: var(--crb-fs-sm); color: var(--crb-text-muted); line-height: var(--crb-lh-base); }

/* ─── Membres grille (UX-03 search, feed) ──────────────────────────────── */
.crb-members-grid {
  display: grid;
  grid-template-columns: repeat(1, 1fr);
  gap: 12px;
}
@media (min-width: 600px) { .crb-members-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px) { .crb-members-grid { grid-template-columns: repeat(3, 1fr); } }

.crb-member-card {
  background: var(--crb-surface);
  border-radius: var(--crb-radius-lg);
  overflow: hidden;
  box-shadow: var(--crb-edge-highlight), var(--crb-shadow);
  min-height: 180px;
  /* Seules `transform` et `box-shadow` sont animées : ce sont les deux propriétés
     que le compositeur traite sans repeindre. Une grille peut afficher trente de
     ces cartes — tout ce qui déclencherait un layout y serait payé trente fois. */
  transition: transform var(--crb-dur-slow) var(--crb-ease-spring),
              box-shadow var(--crb-dur-base) var(--crb-ease);
}
/* La carte est cliquable dans son entier (la photo porte le lien) : elle a donc le
   droit — et le devoir — de réagir. Élévation au survol, enfoncement au doigt. */
.crb-member-card:hover {
  transform: translateY(var(--crb-lift));
  box-shadow: var(--crb-edge-highlight), var(--crb-shadow-lg);
}
.crb-member-card:active {
  transform: scale(var(--crb-press-scale-lg));
  transition: transform var(--crb-dur-fast) var(--crb-ease-exit);
}
/* `:active` remonte aux ancêtres : presser « Envoyer un message » enfonçait la
   carte ENTIÈRE, ce qui désigne la mauvaise cible — le membre a visé un bouton,
   c'est le bouton qui doit répondre (il a déjà son propre enfoncement).
   `:has()` porte la spécificité de son argument le plus fort (0,3,0 ici), donc
   cette règle l'emporte sans !important. Sur un moteur sans `:has()`, la carte
   s'enfonce avec le bouton : imperfection, pas panne. */
.crb-member-card:has(.crb-member-card__action:active),
.crb-member-card:has(.crb-btn:active) { transform: none; }
/* La photo grandit LÉGÈREMENT dans son cadre au survol. Le cadre ne bouge pas : la
   grille reste immobile, seul le contenu de la fenêtre se rapproche. C'est le
   mouvement le moins coûteux qui donne le plus l'impression que l'image est vivante.
   Durée longue et amortie : un zoom rapide se lit comme un défaut de rendu. */
.crb-member-card__photo,
.crb-member-card__no-photo {
  transition: transform var(--crb-dur-slower) var(--crb-ease-emphasized);
}
.crb-member-card:hover .crb-member-card__photo { transform: scale(1.045); }
/* La photo est TOUJOURS le lien vers la fiche, quel que soit le gabarit : c'est
   aussi le conteneur de positionnement des zones `coin` et `overlay`. */
.crb-member-card__media {
  position: relative;
  display: block;
  text-decoration: none;
  color: var(--crb-text);
}
.crb-member-card__photo,
.crb-member-card__no-photo {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  background: var(--crb-border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--crb-fs-5xl);
  color: var(--crb-text-muted);
}
.crb-member-card__info {
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.crb-member-card__name { font-weight: var(--crb-fw-semibold); font-size: var(--crb-fs-base); }
.crb-member-card__age  { font-size: var(--crb-fs-xs); color: var(--crb-text-muted); }

/* ─── Zones de contenu (Personnalisation → Templates) ────────────────────────
   La composition de la carte est réglée en admin : chaque information est
   placée dans une zone (coin / bandeau photo / lignes / accroche / corps /
   boutons). Ces règles stylent les zones, pas un gabarit particulier — un même
   champ doit rester lisible où qu'on le déplace. */
.crb-member-card__line {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: baseline;
  min-width: 0;
}
.crb-member-card__country,
.crb-member-card__title { font-size: var(--crb-fs-xs); color: var(--crb-text-muted); }
.crb-member-card__text {
  margin: 2px 0 0;
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.crb-member-card__text-label { color: var(--crb-text); font-weight: var(--crb-fw-semibold); }
/* Zone `coin` : deux ancres fixes (gauche / droite) pour que deux badges ne se
   superposent jamais. Les badges qui portaient leur propre position absolue
   (astro, score) la rendent au conteneur. */
.crb-member-card__coin {
  position: absolute;
  top: 8px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  z-index: var(--crb-z-raised);
}
.crb-member-card__coin--tl { left: 8px; }
.crb-member-card__coin--tr { right: 8px; }
.crb-member-card__coin .crb-astro-badge,
.crb-member-card__coin .crb-member-card__compat {
  position: static;
  top: auto;
  left: auto;
  right: auto;
}
.crb-member-card__online { box-shadow: 0 0 0 2px rgba(255, 255, 255, .85); }

/* ─── Layout : grille « riche » (Découvrir uniquement) ──────────────────────
   Carte ~300px : photo portrait plein cadre + overlay, zone d'accroche, 2
   boutons. Réservée à #crb-search-grid pour laisser « Mes matchs » inchangé. */
#crb-search-grid.crb-members-grid--grid,
.crb-search-results.crb-members-grid--grid {
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.crb-member-card--rich {
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.crb-member-card--rich .crb-member-card__photo,
.crb-member-card--rich .crb-member-card__no-photo {
  aspect-ratio: 3 / 2;
}
/* Badge score de compatibilité — coin haut-droit de la photo. */
.crb-member-card__compat {
  position: absolute;
  top: 8px;
  right: 8px;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .92);
  color: var(--crb-primary);
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-bold);
  line-height: 1;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .18);
}
.crb-member-card__compat::before {
  content: "\2665"; /* ♥ */
  font-size: .9em;
}
.crb-member-card__overlay {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 2px 8px;
  align-items: baseline;
  /* Voile de lisibilité : même logique que l'en-tête de la fiche profil, mais sans
     backdrop-filter — une grille en compte plusieurs dizaines et autant de couches
     filtrées font ramer le défilement. Dégradé plus haut et plus opaque + ombre
     portée sur tout le texte : c'est ce qui sauve les photos claires. */
  padding: 44px 12px 10px;
  background: linear-gradient(to top,
               rgba(0, 0, 0, calc(.85 * var(--crb-scrim))) 0%,
               rgba(0, 0, 0, calc(.66 * var(--crb-scrim))) 28%,
               rgba(0, 0, 0, calc(.34 * var(--crb-scrim))) 62%,
               rgba(0, 0, 0, 0)   100%);
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .6), 0 2px 10px rgba(0, 0, 0, .4);
}
.crb-member-card__overlay .crb-member-card__name {
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-fw-bold);
  color: #fff;
}
/* Les badges sont noir sur blanc : l'ombre héritée du voile les salirait. */
.crb-member-card__overlay .crb-card-badge { text-shadow: none; }
/* Sur le dégradé, tout le texte passe en blanc — y compris les champs qui sont
   colorés/atténués ailleurs (âge, pays, titre, textes libres). */
.crb-member-card__overlay .crb-member-card__age,
.crb-member-card__overlay .crb-member-card__country,
.crb-member-card__overlay .crb-member-card__title,
.crb-member-card__overlay .crb-member-card__text { color: #fff; opacity: .9; }
/* Blocs qui prennent toute la largeur de l'overlay plutôt que de s'aligner sur
   la ligne du pseudo. */
.crb-member-card__overlay .crb-member-card__badges,
.crb-member-card__overlay .crb-member-card__text { flex-basis: 100%; }
.crb-member-card__loc {
  font-size: var(--crb-fs-xs);
  opacity: .9;
}
/* Badges « mis en avant » (goûts) sous la ville dans l'overlay : noir sur blanc
   (cf. .crb-card-badge, partagé avec la carte de swipe). */
.crb-member-card__badges {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 6px;
}
.crb-member-card__hook {
  padding: 10px 12px;
  min-height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-size: var(--crb-fs-sm);
  line-height: 1.3;
  color: var(--crb-text);
}
.crb-member-card__hook--msg { font-style: italic; color: var(--crb-text-muted); }
.crb-member-card__hook--empty { color: var(--crb-text-muted); }
.crb-member-card__hook-text {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* L'accroche peut aussi recevoir le titre : il garde alors le style du bandeau,
   sans la couleur atténuée qu'il porte dans les lignes. */
.crb-member-card__hook .crb-member-card__title {
  font-size: var(--crb-fs-sm);
  color: inherit;
}
.crb-member-card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 0 12px 12px;
  margin-top: auto;
}
/* Côte à côte si la carte est assez large (base 130px), empilés sinon — évite
   que « Envoyer un message » ne déborde sur les cartes proches de 280px. */
.crb-member-card__actions .crb-member-card__action {
  flex: 1 1 130px;
  min-width: 0;
  padding: 0 10px;
  font-size: var(--crb-fs-xs);
  text-decoration: none;
}

/* ─── Layout : liste ─────────────────────────────────────────────────────────
   Une rangée, pas une carte. Elle occupe toute la largeur du feed : c'est sa
   seule ressource abondante, et c'est en la répartissant qu'on évite d'empiler
   quoi que ce soit sur une vignette de 64 px.

       ┌──────┬─────────────────────────┬────────────────────┬───────┬─────────┐
       │ 76px │ Pseudo · 37 ans · ♓ · … │ « Dernier message »│ ♥ 47% │ boutons │
       │      │ [Internet] [Gospel]     │                    │       │         │
       └──────┴─────────────────────────┴────────────────────┴───────┴─────────┘

   Des colonnes explicites plutôt qu'une carte empilée : chaque bloc a sa piste,
   aucun ne se pose sur un autre. Trois paliers, du plus étroit au plus large —
   ce sont les blocs à largeur incompressible qui sortent en premier :

     < 640 px   les boutons passent sur un second rang pleine largeur ;
     ≥ 640 px   photo | textes | score | boutons sur une seule rangée ;
     ≥ 1100 px  l'accroche quitte le bloc de texte pour sa propre colonne — la
                largeur est là, autant l'occuper plutôt que laisser le milieu
                vide et faire voyager le regard du pseudo jusqu'aux boutons.

   Le JS rend cette structure (assets/js/app.js › buildRowCardHtml) en ramenant
   les zones de surimpression dans la colonne de texte. */
.crb-members-grid--list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.crb-member-card--list {
  min-height: unset;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "media   body    score"
    "media   hook    score"
    "actions actions actions";
  align-items: center;
  column-gap: 14px;
  row-gap: 0;
  padding: 10px 14px;
}
@media (min-width: 640px) {
  .crb-member-card--list {
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    grid-template-areas:
      "media body score actions"
      "media hook score actions";
  }
}
@media (min-width: 1100px) {
  .crb-member-card--list {
    grid-template-columns: auto minmax(0, 1fr) minmax(0, 1.1fr) auto auto;
    grid-template-areas: "media body hook score actions";
  }
}
/* La photo reste calée en haut. Centrée, elle flottait au milieu du vide dès
   qu'une annonce un peu longue étirait la rangée : le portrait ne se lit plus
   comme celui de la personne dont on vient de lire le pseudo juste au-dessus.
   Sur une rangée courte, c'est la photo qui est l'élément le plus haut — `start`
   n'y change alors rien. */
.crb-member-card--list .crb-member-card__media {
  grid-area: media;
  align-self: start;
}
.crb-member-card--list .crb-member-card__photo,
.crb-member-card--list .crb-member-card__no-photo {
  width: 64px;
  height: 64px;
  aspect-ratio: unset;
  border-radius: var(--crb-radius);
  font-size: var(--crb-fs-2xl);
}
@media (min-width: 640px) {
  .crb-member-card--list .crb-member-card__photo,
  .crb-member-card--list .crb-member-card__no-photo { width: 76px; height: 76px; }
}
/* Colonne de texte : tout ce qui se lit, dans l'ordre où on le lit. `min-width:0`
   est ce qui autorise les enfants à se tronquer plutôt qu'à pousser la rangée. */
.crb-member-card--list .crb-member-card__body {
  grid-area: body;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 2px 0;
}
.crb-member-card--list .crb-member-card__name { font-size: var(--crb-fs-lg); }
/* Identité et pastilles sur la même ligne : centrées entre elles (les pilules
   n'ont pas la ligne de base du texte) et espacées, l'espace suffit à séparer. */
.crb-member-card--list .crb-member-card__line { align-items: center; gap: 4px 8px; }
/* Les lignes ne passent plus par `__info` en gabarit Liste (le corps porte
   directement la colonne de texte) : la ville y garde sa teinte secondaire. */
.crb-member-card--list .crb-member-card__loc { color: var(--crb-text-muted); }
/* L'accroche revient dans le fil du texte : alignée à gauche sous l'identité, sur
   une seule ligne. Centrée et sur 42 px de haut, elle creusait la rangée d'un
   vide que le regard devait traverser pour rien. */
.crb-member-card--list .crb-member-card__hook {
  grid-area: hook;
  min-width: 0;
  padding: 0;
  min-height: 0;
  justify-content: flex-start;
  text-align: left;
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
}
.crb-member-card--list .crb-member-card__hook .crb-member-card__hook-text {
  -webkit-line-clamp: 1;
  line-clamp: 1;
}
/* Score : colonne à lui, ancré au bord droit de la zone de texte. Il n'a plus
   besoin d'être en surimpression pour être « en haut à droite ». */
.crb-member-card--list .crb-member-card__compat {
  grid-area: score;
  position: static;
  justify-self: end;
  /* Au rang du pseudo tant que la rangée s'empile : un score flottant au milieu
     d'un bloc de texte n'a plus de sujet. Recentré dès que score et boutons
     partagent leur propre colonne. */
  align-self: start;
  margin-top: 3px;
  background: color-mix(in srgb, var(--crb-primary) 10%, var(--crb-surface));
  box-shadow: none;
  font-size: var(--crb-fs-sm);
  padding: 5px 10px;
}
@media (min-width: 640px) {
  .crb-member-card--list .crb-member-card__compat { align-self: center; margin-top: 0; }
}
/* Boutons : rangs à part sous 640 px (seuls éléments à largeur incompressible),
   colonne de droite au-delà. Empilés, ils gardent la hauteur de la rangée. */
.crb-member-card--list .crb-member-card__actions {
  grid-area: actions;
  padding: 0;
  min-height: 0;
  margin-top: 8px;
}
@media (min-width: 640px) {
  .crb-member-card--list .crb-member-card__actions {
    margin-top: 0;
    flex-wrap: nowrap;
    justify-self: end;
  }
  .crb-member-card--list .crb-member-card__action { flex: 0 0 auto; }
}
/* Sur fond clair, un aplat de primaire pleine puissance à côté du pseudo lui
   dispute la lecture. Teinté, le badge reste identifiable sans prendre le pas
   sur l'identité — c'est le pseudo qu'on parcourt, pas le signe. */
.crb-member-card--list .crb-astro-badge {
  background: color-mix(in srgb, var(--crb-primary) 12%, var(--crb-surface));
  color: var(--crb-primary);
  box-shadow: none;
}
/* Idem pour les goûts : le blanc-sur-blanc avec ombre portée est un style de
   surimpression photo, illisible posé sur la surface de la rangée. */
.crb-member-card--list .crb-card-badge {
  background: var(--crb-surface-alt);
  color: var(--crb-text-muted);
  border: 1px solid var(--crb-border);
  box-shadow: none;
}
.crb-member-card--list .crb-member-card__badges { margin-top: 4px; }
/* Hors overlay, la ville est une info secondaire : atténuée, pas blanche. */
.crb-member-card__info .crb-member-card__loc { color: var(--crb-text-muted); }
/* Statut : la pastille se suffit posée sur une photo, où le vert est le seul
   signal coloré ; au fil d'une ligne de texte elle ne dit rien seule, le libellé
   l'accompagne donc dans le gabarit Liste. */
.crb-member-card__status {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.crb-member-card__status-label { display: none; }
.crb-member-card--list .crb-member-card__status-label {
  display: inline;
  font-size: var(--crb-fs-xs);
  color: var(--crb-success);
  font-weight: var(--crb-fw-semibold);
}

/* ─── Layout : compact ──────────────────────────────────────────────────── */
.crb-members-grid--compact {
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}
@media (min-width: 480px) { .crb-members-grid--compact { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 768px) { .crb-members-grid--compact { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1024px) { .crb-members-grid--compact { grid-template-columns: repeat(4, 1fr); } }
.crb-member-card--compact { min-height: unset; }
.crb-member-card--compact .crb-member-card__info { padding: 2px 10px 6px; }
/* Vignette dense : le pseudo doit tenir sur une ligne, tronqué à l'ellipsis
   plutôt que de faire grandir la carte. Le padding dégage l'arc des coins
   arrondis, sinon les premières lettres sont rognées. */
.crb-member-card--compact .crb-member-card__line { flex-wrap: nowrap; }
.crb-member-card--compact .crb-member-card__name {
  display: block;
  min-width: 0;
  font-size: var(--crb-fs-2xs);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ─── Skeleton screens (UX-05) ──────────────────────────────────────────── */
/* (Redéfinition assumée : ce bloc, plus bas dans la feuille, l'emporte sur celui
   de la section « Skeleton screens » et fixe le rayon sur le token. Le @keyframes
   en double a été retiré — un seul jeu d'étapes, déclaré plus haut.) */
.crb-skeleton {
  background: linear-gradient(90deg,
                var(--crb-skeleton-bg) 25%,
                var(--crb-skeleton-sheen) 50%,
                var(--crb-skeleton-bg) 75%);
  background-size: 840px 100%;
  animation: crb-shimmer 1.6s infinite var(--crb-ease);
  border-radius: var(--crb-radius);
}
.crb-skeleton--card {
  height: 120px;
  margin-bottom: 12px;
}
.crb-skeleton--member-card {
  aspect-ratio: 1;
  border-radius: var(--crb-radius-lg);
}
.crb-skeleton--conv {
  height: 68px;
  margin-bottom: 8px;
  border-radius: var(--crb-radius);
}
.crb-skeleton--swipe-card {
  height: 60dvh;
  border-radius: 16px;
  max-width: 400px;
  margin: 0 auto;
}
.crb-skeleton--profile-header { height: 200px; border-radius: var(--crb-radius-lg); }
.crb-skeleton--profile-fields { height: 120px; border-radius: var(--crb-radius); }
.crb-skeleton--inline         { display: inline-block; width: 80px; height: 16px; border-radius: 4px; }

/* ─── Bottom-sheet drawer filtres (UX-08) ───────────────────────────────── */
.crb-bottom-sheet {
  position: fixed;
  inset: 0;
  z-index: var(--crb-z-nav);
  pointer-events: none;
}
.crb-bottom-sheet--open { pointer-events: auto; }

.crb-bottom-sheet__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,.35);
  opacity: 0;
  transition: opacity .25s;
}
.crb-bottom-sheet--open .crb-bottom-sheet__backdrop { opacity: 1; }

.crb-bottom-sheet__panel {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: var(--crb-surface);
  border-radius: var(--crb-radius-lg) var(--crb-radius-lg) 0 0;
  padding: 12px 20px 24px;
  transform: translateY(100%);
  transition: transform var(--crb-dur-slow) var(--crb-ease-emphasized);
  max-height: 85dvh;
  overflow-y: auto;
  /* Arête haute éclairée : c'est le seul bord visible d'une feuille qui monte du
     bas de l'écran, et donc le seul endroit où sa tranche peut se lire. */
  box-shadow: var(--crb-edge-highlight), var(--crb-shadow-lg);
}
.crb-bottom-sheet--open .crb-bottom-sheet__panel { transform: none; }
.crb-bottom-sheet__handle {
  width: 40px; height: 4px;
  background: var(--crb-border);
  border-radius: 2px;
  margin: 0 auto 16px;
}
.crb-bottom-sheet__title { font-size: var(--crb-fs-xl); font-weight: var(--crb-fw-bold); margin-bottom: 16px; }
.crb-bottom-sheet__actions {
  display: flex;
  gap: 12px;
  justify-content: flex-end;
  margin-top: 20px;
}

/* ─── Desktop (≥768) — adaptation UX (mobile-first conservé) ──────────────── */
/* Placé après les bases qu'il surcharge (dashboard, bottom-sheet) pour gagner
   par l'ordre source. On adapte la présentation aux grands écrans. */
@media (min-width: 768px) {
  /* Bottom-sheet (filtres) : slab pleine largeur → carte
     centrée bornée, glisse depuis le bas, coins entièrement arrondis. */
  .crb-bottom-sheet__panel {
    left: 50%;
    right: auto;
    bottom: var(--crb-space-5);
    width: min(440px, calc(100vw - var(--crb-space-6)));
    border-radius: var(--crb-radius-lg);
    max-height: min(80dvh, 640px);
    transform: translate(-50%, calc(100% + var(--crb-space-5)));
  }
  .crb-bottom-sheet--open .crb-bottom-sheet__panel { transform: translateX(-50%); }
  /* Affordance de glisse tactile inutile au pointeur. */
  .crb-bottom-sheet__handle { display: none; }
}

/* ─── Champs de formulaire (partagés : inscription + Mon Compte) ──────────── */
/* Ces classes étaient utilisées par register.php et my-account.php SANS aucun
   style (les champs héritaient du thème). Tokenisées → palette + skin. */
.crb-form__group { margin-bottom: var(--crb-space-4); }
.crb-form__group > label {
  display: block;
  margin-bottom: var(--crb-space-2);
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text);
}
/* Champ exigé par la règle « profil rempli pour écrire » (ProfileMessagingGate). */
.crb-form__req { color: var(--crb-danger); }
/* Compteur de caractères temps réel — même contrat de markup et même rendu que le
   tunnel d'inscription (.crb-onb-live) : le membre retrouve l'indicateur qu'il a
   déjà vu à l'inscription. Moteur commun dans app.js ([data-crb-live-for]). */
.crb-form__live {
  margin: 6px 0 0;
  font-size: 12.5px;
  font-style: italic;
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text-muted);
}
.crb-form__live:empty { margin: 0; }
.crb-form__live.is-ok { color: #0f7b34; }
.crb-form__live.is-ko { color: #b3261e; }
/* Scopé sous .crb-plugin (spécificité 0,2,0) pour l'emporter sur les règles de thème
   du type input[type="text"] (0,1,1) qui imposeraient un fond gris / une bordure
   différente aux <input> sans toucher les <textarea>. */
.crb-plugin .crb-form__input,
.crb-plugin .crb-form__select,
.crb-plugin .crb-form__textarea {
  display: block;
  width: 100%;
  min-height: var(--crb-touch-min);
  padding: 10px 14px;
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius);
  background: var(--crb-surface);
  color: var(--crb-text);
  font-size: var(--crb-fs-lg);
  line-height: 1.4;
  transition: border-color var(--crb-transition), box-shadow var(--crb-transition);
}
.crb-plugin .crb-form__input::placeholder,
.crb-plugin .crb-form__textarea::placeholder { color: var(--crb-text-muted); opacity: .7; }
.crb-plugin .crb-form__input:focus,
.crb-plugin .crb-form__select:focus,
.crb-plugin .crb-form__textarea:focus {
  outline: none;
  border-color: var(--crb-primary);
  box-shadow: 0 0 0 3px var(--crb-focus-ring);
}
.crb-plugin .crb-form__textarea { min-height: 96px; resize: vertical; }

/* Champ de filtre verrouillé par le plan (état upsell). */
.crb-filter-locked__cta {
  display: flex;
  align-items: center;
  gap: var(--crb-space-2);
  padding: 10px 14px;
  border: 1px dashed var(--crb-border);
  border-radius: var(--crb-radius);
  background: var(--crb-surface);
  color: var(--crb-text-muted);
  font-size: var(--crb-fs-sm);
  text-decoration: none;
  transition: border-color var(--crb-transition), color var(--crb-transition);
}
.crb-filter-locked__cta:hover {
  border-color: var(--crb-premium, var(--crb-primary));
  color: var(--crb-premium, var(--crb-primary));
}
.crb-filter-locked__cta svg { width: 16px; height: 16px; flex-shrink: 0; }

/* Filtre multi-signes astrologiques : chips sélectionnables. */
.crb-filter-astro .crb-form__label-text {
  display: block;
  margin-bottom: var(--crb-space-2);
  font-size: var(--crb-fs-sm);
  font-weight: 600;
  color: var(--crb-text);
}
.crb-astro-options {
  display: flex;
  flex-wrap: wrap;
  gap: var(--crb-space-2);
}
.crb-astro-option { position: relative; cursor: pointer; }
.crb-astro-option input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}
.crb-astro-option span {
  display: inline-block;
  padding: 6px 12px;
  border: 1px solid var(--crb-border);
  border-radius: 999px;
  background: var(--crb-surface);
  color: var(--crb-text);
  font-size: var(--crb-fs-sm);
  line-height: 1.2;
  transition: border-color var(--crb-transition), background var(--crb-transition), color var(--crb-transition);
}
.crb-astro-option input:checked + span {
  border-color: var(--crb-primary);
  background: var(--crb-primary);
  color: #fff;
}
.crb-astro-option input:focus-visible + span {
  outline: 2px solid var(--crb-primary);
  outline-offset: 2px;
}
.crb-plugin .crb-form__select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 38px;
  /* Chevron en currentColor (text-muted), pas d'emoji */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 18px;
}
/* État invalide (aria-invalid posé par le JS) */
.crb-form__input[aria-invalid="true"],
.crb-form__select[aria-invalid="true"],
.crb-form__textarea[aria-invalid="true"] {
  border-color: var(--crb-danger);
}
.crb-form__input[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--crb-danger) 35%, transparent);
}
/* État valide (champ vérifié OK — ex. email disponible) */
.crb-plugin .crb-form__input--valid { border-color: var(--crb-success); }
.crb-form__hint  { display: block; margin-top: 6px; font-size: var(--crb-fs-xs); color: var(--crb-text-muted); }
.crb-form__error {
  display: block;
  margin-top: 6px;
  font-size: var(--crb-fs-xs);
  color: var(--crb-danger);
  font-weight: var(--crb-fw-medium);
}
.crb-form__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--crb-space-3);
}
/* Champ mot de passe avec bouton œil */
.crb-form__password-wrap { position: relative; }
.crb-form__password-wrap .crb-form__input { padding-right: 46px; }
.crb-form__pw-toggle {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  cursor: pointer;
  color: var(--crb-text-muted);
  border-radius: var(--crb-radius-sm);
  transition: color var(--crb-transition), background var(--crb-transition);
}
.crb-form__pw-toggle:hover { color: var(--crb-text); background: var(--crb-bg-hover); }
.crb-form__pw-toggle svg { width: 20px; height: 20px; }

/* ─── Formulaire inscription multi-étapes (UX-03) ───────────────────────── */
.crb-register {
  max-width: 480px;
  margin: 0 auto;
  padding: 0 16px 40px;
}
.crb-register__progress {
  position: sticky;
  top: 0;
  z-index: var(--crb-z-sticky);
  background: var(--crb-surface);
  padding: 12px 0 8px;
  border-bottom: 1px solid var(--crb-border);
  margin-bottom: 24px;
}
.crb-register__progress-bar {
  height: 4px;
  background: var(--crb-primary);
  border-radius: 2px;
  transition: width .3s ease;
  margin-bottom: 10px;
}
.crb-register__steps {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
}
.crb-register__step {
  width: 28px; height: 28px;
  border-radius: 50%;
  border: 2px solid var(--crb-border);
  display: flex; align-items: center; justify-content: center;
  font-weight: var(--crb-fw-bold); font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
  transition: all var(--crb-transition);
}
.crb-register__step--active {
  border-color: var(--crb-primary);
  background: var(--crb-primary);
  color: #fff;
}
.crb-register__step--done {
  border-color: var(--crb-success);
  background: var(--crb-success);
  color: #fff;
}
.crb-register__step--current-label {
  margin-top: 6px;
  text-align: center;
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
  font-weight: var(--crb-fw-medium);
}
.crb-register__step-sep { color: var(--crb-border); }
.crb-register__pane { animation: crb-slide-in .2s ease; }
.crb-register__title {
  font-size: var(--crb-fs-3xl);
  font-weight: var(--crb-fw-bold);
  margin-bottom: 8px;
}
.crb-register__subtitle {
  color: var(--crb-text-muted);
  margin-bottom: 20px;
}
.crb-register__nav {
  display: flex;
  gap: 12px;
  justify-content: space-between;
  align-items: center;
  margin-top: 24px;
}
.crb-register__skip {
  text-align: center;
  margin-top: 12px;
}
.crb-register__success {
  text-align: center;
  padding: 40px 0;
}
.crb-register__success-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 72px;
  height: 72px;
  margin-bottom: 12px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary-tint);
  color: var(--crb-success);
  animation: crb-pop-in .3s var(--crb-ease-out) both;
}
.crb-register__success-icon svg { width: 40px; height: 40px; }
@keyframes crb-pop-in {
  from { transform: scale(.5); opacity: 0; }
  to   { transform: scale(1);  opacity: 1; }
}
.crb-register__error-banner {
  background: var(--crb-danger-tint);
  color: var(--crb-danger);
  border-left: 4px solid var(--crb-danger);
  border-radius: var(--crb-radius);
  padding: 12px 16px;
  margin-top: 16px;
  font-size: var(--crb-fs-base);
}

.crb-gender-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-bottom: 20px;
}
.crb-gender-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 80px;
  padding: 12px;
  border-radius: var(--crb-radius-lg);
  border: 2px solid var(--crb-border);
  background: var(--crb-surface);
  cursor: pointer;
  font-size: var(--crb-fs-base);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-text);
  transition: all var(--crb-transition);
}
.crb-gender-btn:hover {
  border-color: var(--crb-primary);
  background: var(--crb-primary-tint);
  color: var(--crb-primary);
}
.crb-gender-btn:active { transform: scale(.97); }
.crb-gender-btn--selected,
.crb-gender-btn--selected:hover {
  border-color: var(--crb-primary);
  background: var(--crb-primary);
  color: #fff;
}
.crb-gender-btn__icon { display: inline-flex; }
.crb-gender-btn__icon svg { width: 28px; height: 28px; }

.crb-photo-upload {
  border: 2px dashed var(--crb-border);
  border-radius: var(--crb-radius-lg);
  padding: 32px;
  text-align: center;
  cursor: pointer;
  min-height: 160px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color var(--crb-transition), background var(--crb-transition);
}
.crb-photo-upload:hover,
.crb-photo-upload--dragover { border-color: var(--crb-primary); background: var(--crb-primary-tint); }
.crb-photo-upload__input { display: none; }
.crb-photo-upload__placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: var(--crb-text-muted);
  font-size: var(--crb-fs-md);
}
.crb-photo-upload__placeholder svg { width: 36px; height: 36px; }
.crb-photo-upload__preview { width: 100%; }
.crb-photo-upload__preview img {
  max-width: 100%;
  max-height: 240px;
  border-radius: var(--crb-radius);
  object-fit: cover;
}

/* GPS — bouton avec icône */
#crb-gps-btn svg { width: 18px; height: 18px; }

/* Flèches de navigation des étapes */
.crb-reg-next svg, .crb-reg-back svg { width: 18px; height: 18px; }

/* Densité desktop : la carte d'inscription respire davantage */
@media (min-width: 768px) {
  .crb-register { max-width: 520px; }
  .crb-register__title { font-size: var(--crb-fs-4xl); }
  .crb-gender-btn { min-height: 92px; }
}

/* ─── Mon Compte ─────────────────────────────────────────────────────────── */
.crb-my-account { max-width: 700px; margin: 0 auto; padding: 16px; }
.crb-account-header {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}
.crb-account-header__avatar {
  position: relative;
  width: 80px;
  height: 80px;
  flex: 0 0 80px;
}
.crb-account-header__img {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  object-fit: cover;
  display: block;
}
.crb-account-header__avatar--pending .crb-account-header__img {
  filter: grayscale(.35);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--crb-premium) 55%, var(--crb-surface));
}
.crb-account-header__moderation {
  position: absolute;
  bottom: -4px;
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 8px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-premium-tint);
  color: var(--crb-premium-dark);
  font-size: var(--crb-fs-3xs);
  font-weight: var(--crb-fw-semibold);
  line-height: 1.2;
  white-space: nowrap;
  box-shadow: var(--crb-shadow-sm);
}
.crb-account-header__moderation .crb-icon { width: 13px; height: 13px; }
.crb-account-header__name { font-size: var(--crb-fs-2xl); font-weight: var(--crb-heading-weight); letter-spacing: var(--crb-heading-tracking); margin-bottom: 4px; }
.crb-account-header__email { color: var(--crb-text-muted); font-size: var(--crb-fs-base); margin-bottom: 6px; }
.crb-account-header__expiry { font-size: var(--crb-fs-sm); color: var(--crb-text-muted); margin-left: 8px; }

/* ─── Édition photo de profil ──────────────────────────────────────────── */
.crb-photo-edit {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
}
.crb-photo-edit__preview {
  position: relative;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--crb-bg-subtle, #f3f4f6);
  border: 1px solid var(--crb-border);
}
/* Pastille cliquable : ouvre le sélecteur de fichier (cf. #crb-photo-preview
   dans my-account.php). Le survol assombrit l'image / éclaire le placeholder
   pour signaler l'action, sans ajouter de DOM (le contenu est réécrit en JS). */
.crb-photo-edit__preview--clickable { cursor: pointer; }
.crb-photo-edit__preview--clickable:hover { border-color: var(--crb-primary); }
.crb-photo-edit__preview--clickable:hover .crb-photo-edit__img { filter: brightness(.82); }
.crb-photo-edit__preview--clickable:hover .crb-photo-edit__placeholder { opacity: .85; }
.crb-photo-edit__img {
  width: 120px;
  height: 120px;
  object-fit: cover;
  display: block;
}
.crb-photo-edit__placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--crb-fs-6xl);
  color: var(--crb-text-muted);
  opacity: .55;
}
/* Badge de modération : masqué par défaut, affiché quand la photo est en attente */
.crb-photo-edit__moderation { display: none; }
.crb-photo-edit__preview--pending .crb-photo-edit__img { filter: grayscale(.4) brightness(.92); }
.crb-photo-edit__preview--pending .crb-photo-edit__moderation {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 5px 4px;
  background: color-mix(in srgb, var(--crb-premium-dark) 88%, transparent);
  color: #fff;
  font-size: var(--crb-fs-3xs);
  font-weight: var(--crb-fw-semibold);
  letter-spacing: .02em;
}
.crb-photo-edit__moderation-icon { display: inline-flex; }
.crb-photo-edit__moderation .crb-icon,
.crb-photo-edit__moderation-icon .crb-icon { width: 13px; height: 13px; }
.crb-photo-edit__placeholder .crb-icon { width: 2.4rem; height: 2.4rem; }
.crb-photo-edit__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  position: relative;
}

/* Règles de publication des photos (Personnalisation → Affichage textes).
   Rendu par PhotoRules::render() à partir de l'éditeur admin : paragraphes,
   listes et citations, sans classes internes — le bloc habille donc ses enfants
   directs. Partagé avec le tunnel d'inscription, qui n'ajuste que l'échelle
   typographique (cf. onboarding.css). */
.crb-photo-rules {
  margin-top: 16px;
  padding: 12px 14px;
  background: color-mix(in srgb, var(--crb-text-muted) 7%, transparent);
  border-radius: var(--crb-radius);
  font-size: var(--crb-fs-sm);
  line-height: 1.5;
  color: var(--crb-text-muted);
  text-align: left;
}
.crb-photo-rules > * { margin: 0 0 8px; }
.crb-photo-rules > :last-child { margin-bottom: 0; }
.crb-photo-rules h3,
.crb-photo-rules h4 {
  margin: 0 0 6px;
  font-size: var(--crb-fs-base);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text);
}
.crb-photo-rules ul,
.crb-photo-rules ol { padding-left: 18px; }
.crb-photo-rules ul { list-style: disc; }
.crb-photo-rules ol { list-style: decimal; }
.crb-photo-rules li { margin: 0 0 4px; }
.crb-photo-rules li:last-child { margin-bottom: 0; }
.crb-photo-rules blockquote {
  margin: 0 0 8px;
  padding-left: 10px;
  border-left: 2px solid var(--crb-border);
  font-style: italic;
}
.crb-photo-rules a { color: inherit; text-decoration: underline; }

.crb-account-tabs {
  display: flex;
  border-bottom: 1px solid var(--crb-border);
  margin-bottom: 20px;
  gap: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.crb-account-tab {
  padding: 10px 16px;
  border: none;
  background: none;
  cursor: pointer;
  font-size: var(--crb-fs-base);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-text-muted);
  border-bottom: 3px solid transparent;
  white-space: nowrap;
  min-height: var(--crb-touch-min);
  transition: color var(--crb-transition), border-color var(--crb-transition);
}
.crb-account-tab--active {
  color: var(--crb-primary);
  border-bottom-color: var(--crb-primary);
}
.crb-account-panel--active { display: block; }

/* ── Onglet « Affichage » : choix du gabarit de fiche profil ─────────────────
   Chaque option montre le SCHÉMA (mobile) de la mise en page réelle : les noms
   seuls ne disent rien tant qu'on n'a pas vu la forme. Wireframes redessinés
   d'après .crb-profile--full / --compact / --minimal, comme le sélecteur admin
   (.crb-wf__* dans admin.css) — les faire diverger revient à montrer au membre
   une forme qu'il n'obtiendra pas. */
.crb-tplchoice {
  display: grid;
  /* auto-fit : une colonne sur mobile, puis autant que la largeur en admet —
     les trois gabarits tiennent de front sur un écran large. */
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: var(--crb-space-3);
  margin: var(--crb-space-3) 0;
}
.crb-tplchoice__opt {
  position: relative;                  /* ancre le radio masqué */
  display: flex;
  gap: var(--crb-space-3);
  align-items: center;
  padding: var(--crb-space-3);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius);
  background: var(--crb-surface);
  cursor: pointer;
  transition: border-color var(--crb-transition), background var(--crb-transition);
}
.crb-tplchoice__opt:hover { border-color: var(--crb-primary); }
.crb-tplchoice__opt.is-active {
  border-color: var(--crb-primary);
  box-shadow: inset 0 0 0 1px var(--crb-primary);
}
/* Le radio reste dans le DOM (navigation clavier, état coché) mais l'étiquette
   entière est la cible du clic : la vignette EST le bouton. */
.crb-tplchoice__radio { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; }
.crb-tplchoice__opt:has(.crb-tplchoice__radio:focus-visible) {
  outline: 2px solid var(--crb-primary);
  outline-offset: 2px;
}
.crb-tplchoice__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.crb-tplchoice__name { font-weight: var(--crb-fw-semibold); }
.crb-tplchoice__desc { font-size: var(--crb-fs-sm); color: var(--crb-text-muted); line-height: 1.4; }

/* ─── Wireframe d'un gabarit (vue mobile) ─── */
.crb-tplwire {
  position: relative;
  display: block;
  flex: 0 0 auto;
  width: 62px;
  height: 108px;
  overflow: hidden;
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-sm, 4px);
}
/* Variante rail droit (fiche profil) : trois vignettes de front dans une colonne
   de 320 px — la largeur est celle de la cellule, la hauteur suit le rapport du
   modèle 62 × 108 pour que le dessin reste le même à toute taille. */
.crb-tplwire--rail {
  width: 100%;
  height: auto;
  aspect-ratio: 62 / 108;
}
.crb-tplwire__photo {
  display: block;
  position: relative;
  background: linear-gradient(135deg, var(--crb-primary), color-mix(in srgb, var(--crb-primary) 55%, #fff));
  opacity: .85;
}
.crb-tplwire__photo--tall { height: 58%; }
.crb-tplwire__photo--band { height: 26%; }
.crb-tplwire__overlay { position: absolute; inset: auto 0 0 0; padding: 4px; }
.crb-tplwire__line {
  display: block;
  height: 3px;
  border-radius: 2px;
  background: var(--crb-border);
  margin-bottom: 3px;
}
.crb-tplwire__line:last-child { width: 62%; margin-bottom: 0; }
.crb-tplwire__line--light { background: rgba(255, 255, 255, .92); }
.crb-tplwire__stack { display: block; padding: 5px; }
.crb-tplwire__stack--grow { flex: 1; padding: 0; min-width: 0; }
.crb-tplwire__stack--center .crb-tplwire__line { margin-left: auto; margin-right: auto; }
.crb-tplwire__stack--center .crb-tplwire__line:last-child { width: 45%; }
.crb-tplwire__medallion {
  display: block;
  width: 20px;
  height: 20px;
  margin: -11px auto 0;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--crb-primary), color-mix(in srgb, var(--crb-primary) 55%, #fff));
  border: 2px solid var(--crb-surface);
}
.crb-tplwire__identrow { display: flex; align-items: center; gap: 5px; padding: 5px; }
.crb-tplwire__thumb {
  display: block;
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  border-radius: 3px;
  background: linear-gradient(135deg, var(--crb-primary), color-mix(in srgb, var(--crb-primary) 55%, #fff));
}
/* Barre d'actions en pied d'écran : le seul élément commun aux trois gabarits. */
.crb-tplwire__bar {
  display: block;
  position: absolute;
  inset: auto 0 0 0;
  height: 9px;
  background: var(--crb-bg);
  border-top: 1px solid var(--crb-border);
}

/* ─── Wireframe d'un gabarit de LISTE (écran Découvrir) ─────────────────────
   Même boîte 62 × 108 et même vocabulaire que les wireframes de fiche ci-dessus
   — les deux cartes de l'onglet « Affichage » se lisent d'un seul coup d'œil.
   Ce qui est dessiné : la barre de filtres en haut, puis le feed tel que le
   gabarit le compose (cf. MemberCard::wireframeHtml).
     grille  — grandes cartes photo, pseudo posé dessus ;
     liste   — une rangée par membre (réutilise .crb-tplwire__identrow) ;
     compact — mosaïque dense de vignettes légendées. */
.crb-tplwire__toolbar {
  display: block;
  height: 9px;
  background: var(--crb-bg);
  border-bottom: 1px solid var(--crb-border);
}
.crb-tplwire__feed {
  display: grid;
  gap: 4px;
  padding: 5px;
}
.crb-tplwire__feed--grid    { grid-template-columns: repeat(2, 1fr); }
.crb-tplwire__feed--compact { grid-template-columns: repeat(3, 1fr); gap: 3px; }
.crb-tplwire__cell          { display: block; min-width: 0; }
.crb-tplwire__tile {
  display: block;
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: 3px;
  background: linear-gradient(135deg, var(--crb-primary), color-mix(in srgb, var(--crb-primary) 55%, #fff));
  opacity: .85;
}
.crb-tplwire__tile--square { aspect-ratio: 1; margin-bottom: 3px; }
/* Pseudo en surimpression : le trait qui distingue la grille des deux autres. */
.crb-tplwire__tileline {
  display: block;
  position: absolute;
  inset: auto 8px 3px 3px;
  height: 3px;
  border-radius: 2px;
  background: rgba(255, 255, 255, .92);
}

.crb-plan-info { margin-bottom: 16px; }
.crb-plan-info__name {
  font-size: var(--crb-fs-3xl);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text-muted);
}
.crb-plan-info__name--premium { color: var(--crb-premium); }

.crb-plan-features {
  list-style: none;
  padding: 0;
  margin: 0 0 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.crb-plan-features li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--crb-fs-base);
  color: var(--crb-danger);
}
.crb-plan-features li .crb-plan-features__text { color: var(--crb-text); }
.crb-plan-features__item--ok     { color: var(--crb-success); }
.crb-plan-features__item--locked { color: var(--crb-text-muted); }
.crb-plan-features__icon { flex-shrink: 0; }
.crb-plan-features__icon .crb-icon { width: var(--crb-icon-sm); height: var(--crb-icon-sm); }

/* ─── Détail complet du plan courant (Mon compte › Abonnement) ───────────
   <details> natif : dépliable sans JS, imprimable, accessible au clavier. */
.crb-plan-detail {
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  background: var(--crb-surface-alt);
  margin: 0 0 20px;
}
.crb-plan-detail__summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  min-height: var(--crb-touch-min);
  cursor: pointer;
  list-style: none;
  font-size: var(--crb-fs-base);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text);
  border-radius: var(--crb-radius-lg);
}
.crb-plan-detail__summary::-webkit-details-marker { display: none; }
.crb-plan-detail__summary:hover { background: var(--crb-bg-hover); }
.crb-plan-detail__summary:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--crb-focus-ring);
}
.crb-plan-detail__summary-label { flex: 1; min-width: 0; }
.crb-plan-detail__count {
  flex-shrink: 0;
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-text-muted);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-pill);
  padding: 2px 9px;
  white-space: nowrap;
}
/* Chevron : pivote à l'ouverture (indique l'état sans texte supplémentaire). */
.crb-plan-detail__chev {
  flex-shrink: 0;
  width: 8px; height: 8px;
  border-right: 2px solid var(--crb-text-muted);
  border-bottom: 2px solid var(--crb-text-muted);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--crb-transition);
}
.crb-plan-detail[open] .crb-plan-detail__chev { transform: rotate(-135deg) translate(-2px, -2px); }
.crb-plan-detail[open] .crb-plan-detail__summary {
  border-bottom: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg) var(--crb-radius-lg) 0 0;
}

.crb-plan-detail__body { padding: 4px 16px 14px; }
.crb-plan-detail__section + .crb-plan-detail__section { margin-top: 6px; }
.crb-plan-detail__section-title {
  margin: 14px 0 4px;
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-bold);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--crb-text-muted);
}
.crb-plan-detail__list { list-style: none; padding: 0; margin: 0; }
.crb-plan-detail__row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 9px 0;
  border-bottom: 1px solid var(--crb-border-soft);
}
.crb-plan-detail__list > .crb-plan-detail__row:last-child { border-bottom: none; }
.crb-plan-detail__text { flex: 1; min-width: 0; }
.crb-plan-detail__label {
  display: block;
  font-size: var(--crb-fs-base);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-text);
}
/* Explication en langage simple : c'est elle qui fait le « détail » de la vue,
   elle reste donc toujours lisible (pas de survol, pas de fenêtre à ouvrir). */
.crb-plan-detail__help {
  display: block;
  margin-top: 2px;
  font-size: var(--crb-fs-2xs);
  line-height: var(--crb-lh-base);
  color: var(--crb-text-muted);
}
.crb-plan-detail__row--off .crb-plan-detail__label { color: var(--crb-text-muted); }

.crb-plan-detail__value {
  flex-shrink: 0;
  align-self: center;
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-pill);
  padding: 3px 10px;
  white-space: nowrap;
  text-align: center;
}
.crb-plan-detail__value--on {
  color: var(--crb-success);
  border-color: color-mix(in srgb, var(--crb-success) 45%, var(--crb-surface));
  background: color-mix(in srgb, var(--crb-success) 10%, var(--crb-surface));
}
.crb-plan-detail__mark {
  flex-shrink: 0;
  align-self: center;
  display: inline-flex;
}
.crb-plan-detail__mark .crb-icon { width: var(--crb-icon-sm); height: var(--crb-icon-sm); }
.crb-plan-detail__mark--yes { color: var(--crb-success); }
.crb-plan-detail__mark--no  { color: var(--crb-text-muted); opacity: .6; }

.crb-plan-detail__foot {
  margin: 14px 0 0;
  font-size: var(--crb-fs-2xs);
  color: var(--crb-text-muted);
}

.crb-upgrade-cta {
  background: linear-gradient(135deg, var(--crb-premium-tint), color-mix(in srgb, var(--crb-premium) 22%, var(--crb-surface)));
  border: 1px solid color-mix(in srgb, var(--crb-premium) 45%, var(--crb-surface));
  border-radius: var(--crb-radius-lg);
  padding: 20px;
  text-align: center;
  margin-top: 16px;
}
.crb-upgrade-cta h4 { font-size: var(--crb-fs-xl); margin-bottom: 6px; }
.crb-upgrade-cta p  { color: var(--crb-text-muted); font-size: var(--crb-fs-base); margin-bottom: 16px; }

/* (doublon `.crb-status--*` retiré — défini une seule fois, tokenisé, plus haut) */

/* ─── Conversation list ────────────────────────────────────────────────── */
.crb-conv-item {
  border-bottom: 1px solid var(--crb-border);
}
.crb-conv-link {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  text-decoration: none;
  color: var(--crb-text);
  min-height: var(--crb-touch-min);
  transition: background var(--crb-transition),
              transform var(--crb-dur-slow) var(--crb-ease-spring);
}
.crb-conv-link:hover { background: var(--crb-bg-hover); }
/* Une ligne de liste ne se soulève pas (elle est dans un flux) : elle s'enfonce.
   L'amplitude est celle des grandes surfaces — sur une ligne pleine largeur, le
   ratio des petits boutons se lirait comme un saut. */
.crb-conv-link:active {
  transform: scale(var(--crb-press-scale-lg));
  transition: transform var(--crb-dur-fast) var(--crb-ease-exit);
}
.crb-conv-item--unread .crb-conv-link { font-weight: var(--crb-fw-bold); }
.crb-conv-avatar {
  width: 44px; height: 44px;
  border-radius: 50%;
  background: var(--crb-primary);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--crb-fs-xl); font-weight: var(--crb-fw-bold);
  flex-shrink: 0;
  overflow: hidden;
}
.crb-conv-avatar img {
  width: 100%; height: 100%;
  object-fit: cover;
  border-radius: 50%;
  display: block;
}
.crb-conv-meta { flex: 1; min-width: 0; }
.crb-conv-name    { display: block; font-size: var(--crb-fs-base); }
.crb-conv-preview { display: block; font-size: var(--crb-fs-xs); color: var(--crb-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.crb-conv-badge   { background: var(--crb-primary); color: #fff; border-radius: 50px; font-size: var(--crb-fs-2xs); font-weight: var(--crb-fw-bold); padding: 2px 7px; flex-shrink: 0; }

/* ─── Search toolbar ─────────────────────────────────────────────────────── */
.crb-search-toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.crb-search-count   { color: var(--crb-text-muted); font-size: var(--crb-fs-sm); }
.crb-range-pair     { display: flex; align-items: center; gap: 8px; }

/* ─── Scroll sentinel (infinite scroll) ─────────────────────────────────── */
.crb-scroll-sentinel { height: 1px; width: 100%; }

/* ─── UX-E6 : États grille recherche (vide / erreur) ─────────────────────── */
/* Span toutes les colonnes de .crb-members-grid (display:grid) ; en mode liste
   (flex) le width:100% suffit. Même langage visuel que crb-swipe-empty/error. */
.crb-grid-state {
  grid-column: 1 / -1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--crb-space-2);
  padding: var(--crb-space-6) var(--crb-space-4);
  width: 100%;
}
.crb-grid-state__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px; height: 64px;
  margin-bottom: var(--crb-space-1);
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary-tint);
  color: var(--crb-primary);
}
.crb-grid-state--error .crb-grid-state__icon {
  background: var(--crb-danger-tint);
  color: var(--crb-danger);
}
.crb-grid-state__icon svg { width: 32px; height: 32px; }
.crb-grid-state__title {
  margin: 0;
  font-size: var(--crb-fs-xl);
  font-weight: var(--crb-heading-weight);
  letter-spacing: var(--crb-heading-tracking);
}
.crb-grid-state__text {
  margin: 0 0 var(--crb-space-2);
  color: var(--crb-text-muted);
  max-width: 32ch;
}
/* Erreur de page suivante (infinite scroll) — bandeau inline */
.crb-grid-append-error {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--crb-space-3);
  padding: var(--crb-space-4);
  font-size: var(--crb-fs-base);
}

/* ─── Section title ──────────────────────────────────────────────────────── */
.crb-section-title {
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-text-muted);
  text-transform: uppercase;
  letter-spacing: .06em;
  margin-bottom: 14px;
}

/* ─── Lien texte ─────────────────────────────────────────────────────────── */
.crb-link {
  background: none;
  border: none;
  color: var(--crb-primary);
  cursor: pointer;
  text-decoration: underline;
  font-size: inherit;
  padding: 0;
}

/* ─── Table responsive ───────────────────────────────────────────────────── */
.crb-table-wrap { overflow-x: auto; }
.crb-table { width: 100%; border-collapse: collapse; font-size: var(--crb-fs-sm); }
.crb-table th, .crb-table td {
  padding: 10px 12px;
  text-align: left;
  border-bottom: 1px solid var(--crb-border);
  white-space: nowrap;
}
.crb-table th { font-weight: var(--crb-fw-semibold); background: var(--crb-bg); }

/* Nudge banner inline */
.crb-nudge-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
  background: #fffbe6;
  border-left: 4px solid var(--crb-premium);
  border-radius: var(--crb-radius);
  margin-bottom: 16px;
  font-size: var(--crb-fs-base);
  color: #92400e;
}
.crb-nudge-banner p { margin: 0; flex: 1; }
/* `display: flex` l'emporterait sur l'attribut [hidden] (bandeau de limite de
   swipes révélé par swipe.js quand le quota tombe à 0). */
.crb-nudge-banner[hidden] { display: none; }

/* ── E2 — GALERIE PUBLIQUE [crb_gallery] ──────────────────────────────────
   Entièrement tokenisée (palette héritée d'Impreza, personnalité par skin).
   Rendu serveur : le « skeleton » est un shimmer CSS pur derrière chaque image
   lazy-loadée (l'image opaque le recouvre une fois peinte) — aucun JS requis,
   donc fonctionne aussi pour les visiteurs non connectés. */
.crb-gallery-wrap { max-width: 960px; margin: 0 auto; padding: 0 var(--crb-space-4); }
.crb-gallery-header {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--crb-space-3); margin-bottom: var(--crb-space-5);
}
.crb-gallery-title {
  margin: 0;
  font-size: var(--crb-fs-2xl);
  font-weight: var(--crb-heading-weight);
  letter-spacing: var(--crb-heading-tracking);
}
.crb-gallery-empty { text-align: center; color: var(--crb-text-muted); padding: var(--crb-space-6); }

.crb-gallery-grid {
  display: grid;
  /* Nombre de colonnes gouverné par l'admin (onglet Galerie → Design de la carte) :
     --crb-gallery-cols-mobile en dessous de 768px, --crb-gallery-cols au-delà.
     minmax(0,1fr) empêche les longues chaînes (annonce) de faire déborder la piste. */
  grid-template-columns: repeat(var(--crb-gallery-cols-mobile, 2), minmax(0, 1fr));
  gap: var(--crb-space-3);
}
@media (min-width: 768px) {
  .crb-gallery-grid {
    grid-template-columns: repeat(var(--crb-gallery-cols, 4), minmax(0, 1fr));
    gap: var(--crb-space-4);
  }
}

.crb-gallery-card {
  display: block;
  text-decoration: none;
  color: inherit;
  border-radius: var(--crb-gallery-radius, var(--crb-radius));
  overflow: hidden;
  background: var(--crb-surface);
  box-shadow: var(--crb-edge-highlight), var(--crb-shadow-sm);
  transition: transform var(--crb-dur-slow) var(--crb-ease-spring),
              box-shadow var(--crb-dur-base) var(--crb-ease);
  position: relative;
}
.crb-gallery-card:hover {
  transform: translateY(var(--crb-lift));
  box-shadow: var(--crb-edge-highlight), var(--crb-shadow-md);
}
/* La galerie est la première chose qu'un visiteur voit du site : elle doit répondre
   au doigt comme le reste de l'espace membre, sans quoi la promesse de qualité
   s'arrête au seuil. */
.crb-gallery-card:active {
  transform: scale(var(--crb-press-scale-lg));
  transition: transform var(--crb-dur-fast) var(--crb-ease-exit);
}
.crb-gallery-card__img { transition: transform var(--crb-dur-slower) var(--crb-ease-emphasized); }
.crb-gallery-card:hover .crb-gallery-card__img { transform: scale(1.045); }
.crb-gallery-card:focus-visible {
  outline: 2px solid var(--crb-focus-ring);
  outline-offset: 2px;
}
/* Un seul lien par carte : le <a> englobe photo ET textes, aucun lien imbriqué.
   Il ne doit donc jamais RESSEMBLER à un lien. Les thèmes (Impreza) stylent `a`
   avec une spécificité supérieure à une classe seule et rajoutent souvent un
   soulignement au survol : on préfixe par .crb-plugin pour repasser devant, et on
   couvre tous les états. text-decoration se propage depuis le <a> et ne peut pas
   être annulée par les descendants — c'est donc bien ici qu'il faut la neutraliser.
   NB : on ne touche pas à `color` des descendants, sinon les règles de rôle
   (__age, __city… en couleur primaire) seraient écrasées par spécificité. */
.crb-plugin .crb-gallery-card,
.crb-plugin .crb-gallery-card:link,
.crb-plugin .crb-gallery-card:visited,
.crb-plugin .crb-gallery-card:hover,
.crb-plugin .crb-gallery-card:focus,
.crb-plugin .crb-gallery-card:active {
  text-decoration: none;
  color: inherit;
}
/* Anneau « en ligne » dérivé de la couleur de succès (cohérent E7/swipe). */
.crb-gallery-card--online { box-shadow: 0 0 0 2px var(--crb-success), var(--crb-shadow-sm); }
.crb-gallery-card--online:hover { box-shadow: 0 0 0 2px var(--crb-success), var(--crb-shadow-md); }

.crb-gallery-card__photo {
  position: relative;
  aspect-ratio: var(--crb-gallery-ratio, 1 / 1);
  overflow: hidden;
  /* Placeholder shimmer : visible tant que l'image lazy n'est pas peinte. */
  background: linear-gradient(90deg,
                var(--crb-skeleton-bg) 25%,
                var(--crb-skeleton-sheen) 50%,
                var(--crb-skeleton-bg) 75%);
  background-size: 840px 100%;
  animation: crb-shimmer 1.6s infinite var(--crb-ease);
}
.crb-gallery-card__img {
  width: 100%; height: 100%;
  object-fit: cover; display: block;
  background: var(--crb-surface-alt);   /* recouvre le shimmer une fois peinte */
}
.crb-gallery-card__no-photo {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  background: var(--crb-surface-alt);   /* statique, pas de shimmer permanent */
  color: var(--crb-text-muted);
}
.crb-gallery-card__sex-icon { width: 40%; height: 40%; }
.crb-gallery-card__sex-icon .crb-icon,
.crb-gallery-card__sex-icon svg { width: 100%; height: 100%; }

.crb-gallery-card__online-dot {
  position: absolute; top: var(--crb-space-2); right: var(--crb-space-2);
  width: 10px; height: 10px; border-radius: var(--crb-radius-pill);
  background: var(--crb-success);
  box-shadow: 0 0 0 2px var(--crb-surface);
}

.crb-gallery-card__overlay {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.35);
  color: #fff;
  font-size: var(--crb-fs-2xs); font-weight: var(--crb-fw-semibold);
  letter-spacing: .05em; text-transform: uppercase;
}

/* ── Carte galerie : orientation + zones de contenu ────────────────────────────
   Le contenu est réparti en zones (ligne 1/2/3, accroche, corps, coin) pilotées
   par l'admin (onglet Galerie → Design de la carte). La structure DOM est
   identique en vertical et horizontal ; seule la géométrie du conteneur change. */
.crb-gallery-card--horizontal {
  display: flex;
  flex-direction: row;
  min-height: 96px;
}
.crb-gallery-card--horizontal .crb-gallery-card__photo {
  width: 38%;
  flex-shrink: 0;
  aspect-ratio: auto;   /* la hauteur suit le contenu (annonce) → carte moins aplatie */
  align-self: stretch;
}
.crb-gallery-card--horizontal .crb-gallery-card__info { flex: 1; min-width: 0; }

.crb-gallery-card__info {
  padding: var(--crb-space-2) 10px;
  display: flex; flex-direction: column; gap: 3px;
  min-width: 0;
}
.crb-gallery-card__head { display: flex; gap: var(--crb-space-2); align-items: flex-start; }
.crb-gallery-card__main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.crb-gallery-card__line {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; min-width: 0;
}
.crb-gallery-card__accroche {
  text-align: right; flex-shrink: 0; max-width: 45%;
  font-weight: var(--crb-fw-semibold); font-size: var(--crb-fs-xs);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.crb-gallery-card__pseudo {
  font-weight: var(--crb-fw-semibold);
  font-size: var(--crb-fs-base);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
/* Identité « chiffrée/lieu » reprend la primaire (rappel visuel du gabarit fourni). */
.crb-gallery-card__age,
.crb-gallery-card__city,
.crb-gallery-card__country { font-size: var(--crb-fs-2xs); color: var(--crb-primary); font-weight: var(--crb-fw-semibold); }
.crb-gallery-card__astro,
.crb-gallery-card__flag { font-size: var(--crb-fs-2xs); color: var(--crb-text-muted); }
.crb-gallery-card__title { font-size: var(--crb-fs-xs); font-weight: var(--crb-fw-semibold); }
/* Textes libres (annonce / « je cherche ») : tronqués à N lignes réglées par l'admin. */
.crb-gallery-card__text {
  font-size: var(--crb-fs-2xs); color: var(--crb-text-muted); margin: 4px 0 0;
  display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--crb-gallery-body-lines, 2);
  line-clamp: var(--crb-gallery-body-lines, 2);
  overflow: hidden;
}
.crb-gallery-card__text-label { color: var(--crb-text); font-weight: var(--crb-fw-semibold); }

/* La galerie libre n'est plus paginée (réglage gallery_max_total) : les règles
   .crb-gallery-pagination ont été retirées avec le balisage correspondant. */

/* ─── Statistiques membres ───────────────────────────────────────────────── */
.crb-stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 12px;
  margin-top: 16px;
}
.crb-stat-card {
  background: var(--crb-bg);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius);
  padding: 16px 12px;
  text-align: center;
}
.crb-stat-card__value {
  font-size: var(--crb-fs-4xl);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-primary);
  line-height: 1.1;
}
.crb-stat-card__label {
  font-size: var(--crb-fs-2xs);
  color: var(--crb-text-muted);
  margin-top: 6px;
}
.crb-skeleton--stats { height: 120px; border-radius: var(--crb-radius); }

/* ─── Boost profil ─────────────────────────────────────────────────────────
   .crb-boost-section / .crb-boost-status ont disparu avec l'ancien bloc inline
   de my-account.php : le widget est désormais rendu par le partial partagé
   (cf. .crb-boost-widget plus bas). */
.crb-badge--boost {
  background: #7c3aed;
  color: #fff;
  padding: 4px 10px;
  border-radius: 20px;
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-semibold);
}
.crb-text-sm { font-size: var(--crb-fs-xs); }

/* ─── Widget Boost (partial boost-widget.php) ─────────────────────────────
   Deux variantes du MÊME markup :
     --card   : colonne droite du swipe (desktop) et onglet Abonnement ;
     --inline : barre d'une ligne au-dessus du stack, MOBILE uniquement — la
                colonne droite n'existe pas sous 1024px, sans elle le boost
                serait inatteignable depuis la vue swipe.
   ------------------------------------------------------------------------- */
.crb-boost-widget {
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-2);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-left: 3px solid #7c3aed;
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
  padding: var(--crb-space-4);
}
.crb-boost-widget.is-active { border-left-color: #22c55e; }

.crb-boost-widget__title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-bold);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--crb-text-muted);
}
.crb-boost-widget__icon { color: #7c3aed; flex: none; }
.crb-boost-widget__pitch,
.crb-boost-widget__quota {
  margin: 0;
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
}
.crb-boost-widget__status {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.crb-boost-widget__status[hidden] { display: none; }
.crb-boost-widget__until { font-size: var(--crb-fs-xs); color: var(--crb-text-muted); }
.crb-boost-widget__btn { justify-content: center; }
.crb-boost-widget__feedback:empty { display: none; }
.crb-boost-widget__feedback {
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
}
.crb-boost-widget__perks {
  margin: 0;
  padding-left: 1.1em;
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
}
.crb-boost-widget__perks li { margin-bottom: 2px; }

/* Le conteneur de détail n'existe QUE pour la barre compacte (il s'y replie).
   En variante carte il s'efface du rendu : ses enfants redeviennent des items
   directs de la colonne, la mise en page ne bouge pas d'un pixel. */
.crb-boost-widget__details { display: contents; }
.crb-boost-widget__toggle { display: none; }

/* Variante CTA : la carte entière est cliquable (c'est un <a>). Même piège que
   .crb-gallery-card : Impreza souligne `.no-touch a:hover` en (0,2,1), ce qui bat une
   classe seule, et `text-decoration` se propage du <a> vers TOUS ses descendants sans
   qu'un enfant puisse l'annuler. Au survol, titre, argumentaire ET liste d'arguments
   se soulignaient d'un bloc — la carte se lisait comme un pavé de lien brut. On
   repasse devant en (0,3,x), sans !important, sur tous les états. */
.crb-plugin .crb-boost-widget--upsell,
.crb-plugin .crb-boost-widget--upsell:link,
.crb-plugin .crb-boost-widget--upsell:visited,
.crb-plugin .crb-boost-widget--upsell:hover,
.crb-plugin .crb-boost-widget--upsell:focus,
.crb-plugin .crb-boost-widget--upsell:active {
  text-decoration: none;
  color: inherit;
}
.crb-boost-widget--upsell:hover { box-shadow: var(--crb-shadow-md); }
/* Le seul retour de survol qui parle d'action reste le bouton : la carte se lève et
   le CTA prend son état survolé, comme s'il était pointé directement. */
.crb-boost-widget--upsell:hover .crb-boost-widget__btn.crb-btn--primary {
  background: var(--crb-cta-bg-hover);
  color: var(--crb-cta-text-hover);
}

/* Variante promo : l'encart est posé DANS le comparateur, sous le tableau. Il n'est
   plus cliquable (le template rend un <div>) — d'où le retrait de l'ombre au survol,
   qui promettrait une action inexistante. Il se distingue à la place par un fond
   teinté violet et une largeur contenue, pour se lire comme un argument mis en avant
   et non comme une n-ième carte de la page. */
.crb-boost-widget--promo {
  max-width: 620px;
  margin: var(--crb-space-5) auto 0;
  border-color: color-mix(in srgb, #7c3aed 35%, var(--crb-border));
  background: linear-gradient(135deg,
              color-mix(in srgb, #7c3aed 8%, var(--crb-surface)),
              var(--crb-surface));
  box-shadow: none;
}
.crb-boost-widget--promo:hover { box-shadow: none; }
.crb-boost-widget--promo .crb-boost-widget__title { color: #7c3aed; }

/* Variante compacte mobile : une seule rangée, hauteur minimale, masquée dès
   que la colonne droite prend le relais. */
.crb-boost-widget--inline {
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--crb-space-2);
  padding: var(--crb-space-2) var(--crb-space-3);
  margin-bottom: var(--crb-space-3);
}
.crb-boost-widget--inline .crb-boost-widget__btn { margin-left: auto; flex: none; }

/* Quota + motif de blocage repliés derrière un résumé d'une ligne : déployés,
   ils faisaient cinq lignes de texte au-dessus de la carte de profil, sur l'écran
   où la carte et les boutons like/pass sont l'essentiel. Repli CSS uniquement —
   les nœuds restent dans le DOM et CrbBoost.apply() continue de les mettre à jour,
   dépliés ou non. */
.crb-boost-widget--inline .crb-boost-widget__details {
  display: none;
  flex-basis: 100%;
  flex-direction: column;
  gap: 4px;
}
.crb-boost-widget--inline.is-expanded .crb-boost-widget__details { display: flex; }

.crb-boost-widget--inline .crb-boost-widget__toggle {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  flex: 1 1 auto;
  padding: 2px 0;
  border: 0;
  background: none;
  color: var(--crb-text-muted);
  font-family: inherit;
  font-size: var(--crb-fs-xs);
  text-align: left;
  cursor: pointer;
}
.crb-boost-widget--inline .crb-boost-widget__toggle[hidden] { display: none; }
.crb-boost-widget__summary {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.crb-boost-widget__chevron {
  flex: none;
  width: 14px;
  height: 14px;
  transition: transform .15s ease;
}
.crb-boost-widget--inline.is-expanded .crb-boost-widget__chevron { transform: rotate(180deg); }
.crb-boost-widget--inline .crb-boost-widget__icon-wrap { color: #7c3aed; display: inline-flex; }
.crb-boost-widget__inline-text { display: flex; flex-direction: column; line-height: 1.25; }
.crb-boost-widget__inline-text strong { font-size: var(--crb-fs-sm); }
.crb-boost-widget__inline-text span {
  font-size: var(--crb-fs-xs);
  color: #7c3aed;
  font-weight: var(--crb-fw-semibold);
}
.crb-boost-widget--upsell.crb-boost-widget--inline { justify-content: flex-start; }

/* Boost EN COURS, variante compacte : il ne reste rien à faire. Le bouton est
   grisé par construction, le message de succès et le quota répètent une échéance
   déjà donnée par le badge (« Boost actif — jusqu'à 14 h 07 »). Ces deux lignes
   supplémentaires coûtaient ~80px pris sur la carte ET sur la rangée like/pass,
   qui sortait de l'écran en swipe mobile. On ne garde donc que l'état.
   Masquage CSS seulement : les nœuds restent dans le DOM et CrbBoost.apply()
   continue de les repiloter — à l'expiration, `is-active` tombe et le bouton
   « Activer le boost » réapparaît de lui-même. */
.crb-boost-widget--inline.is-active .crb-boost-widget__btn,
.crb-boost-widget--inline.is-active .crb-boost-widget__toggle,
.crb-boost-widget--inline.is-active .crb-boost-widget__details { display: none; }

@media (min-width: 1024px) {
  /* Desktop : la barre s'efface UNIQUEMENT là où la colonne droite prend le
     relais (shell SPA). En vue swipe autonome, sans colonne droite, elle reste
     affichée — sinon le boost n'aurait plus aucun point d'entrée. */
  .crb-boost-widget--mobile-only { display: none; }
}

/* ─── Badge Super-like (étoile bleue sur la carte) ──────────────────────── */
.crb-superlike-badge {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: #1d6ef5;
  color: #fff;
  font-size: var(--crb-fs-xl);
  line-height: 36px;
  text-align: center;
  box-shadow: 0 2px 8px rgba(29,110,245,.45);
  pointer-events: none;
  z-index: var(--crb-z-raised);
}

/* ─── Toast (feedback envoi smile / erreurs messagerie) ─────────────────── */
.crb-error-toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  max-width: 90vw;
  padding: 12px 18px;
  border-radius: var(--crb-radius);
  background: var(--crb-danger);
  color: #fff;
  font-size: var(--crb-fs-md);
  box-shadow: var(--crb-shadow);
  z-index: var(--crb-z-toast);
  animation: crb-toast-in var(--crb-transition);
}
.crb-error-toast--success { background: var(--crb-success); }

@keyframes crb-toast-in {
  from { opacity: 0; transform: translate(-50%, 12px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

.crb-btn--sent {
  background: var(--crb-success) !important;
  color: #fff !important;
  border-color: var(--crb-success) !important;
}

/* ═══════════════════════════════════════════════════════════════════════════
   E3 — DÉCOUVRIR / SWIPE  (Phase 3, refonte écran par écran)
   Entièrement tokenisé (palette héritée d'Impreza, personnalité par skin).
   ═══════════════════════════════════════════════════════════════════════════ */

.crb-swipe-app {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--crb-space-4);
  width: 100%;
  max-width: 420px;
  margin: 0 auto;
  padding: var(--crb-space-4) var(--crb-space-3) var(--crb-space-5);
}

/* ── Compteur de swipes restants (non-premium) ── */
.crb-swipe-counter {
  align-self: center;
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
  font-weight: var(--crb-fw-medium);
}

/* ── Stack de cartes ─────────────────────────────────────────────────────── */
.crb-swipe-stack {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 4;
  /* borne haute pour éviter une carte démesurée en desktop / écran haut */
  max-height: min(68dvh, 560px);
  touch-action: pan-y;
}

/* Skeleton de chargement : reprend la forme empilée de la stack. */
.crb-swipe-skeleton { position: absolute; inset: 0; }
.crb-swipe-skeleton .crb-skeleton--card {
  position: absolute;
  inset: 0;
  height: auto;
  margin: 0;
  border-radius: var(--crb-radius-lg);
}
.crb-swipe-skeleton .crb-skeleton--back1 { transform: scale(.96) translateY(10px); opacity: .7; }
.crb-swipe-skeleton .crb-skeleton--back2 { transform: scale(.92) translateY(20px); opacity: .45; }

/* ── Carte ───────────────────────────────────────────────────────────────── */
.crb-swipe-card {
  position: absolute;
  inset: 0;
  background: var(--crb-surface-alt);
  border-radius: var(--crb-radius-lg);
  overflow: hidden;
  box-shadow: var(--crb-shadow-lg);
  cursor: grab;
  user-select: none;
  will-change: transform;
  /* cartes du fond empilées et reculées */
  transform: scale(.94) translateY(16px);
  transition: transform var(--crb-dur-slow) var(--crb-ease-emphasized);
}
/* La carte SUIVANTE avance à mesure que celle du dessus s'écarte. `--crb-swipe-progress`
   (0 → 1) est écrite frame par frame sur la pile par swipe.js, à partir de la position
   RÉELLE de la carte tenue — pas à la fin du geste.
   Ce n'est pas un ornement : pendant qu'on hésite entre garder et passer, la pile
   répond, et l'on voit qu'il y a une suite. Le retour n'est plus seulement « j'ai
   compris ton geste », il devient « voilà ce qui arrive si tu vas au bout ». */
.crb-swipe-card:nth-last-child(2) {
  transform:
    scale(calc(.97 + .03 * var(--crb-swipe-progress, 0)))
    translateY(calc(8px * (1 - var(--crb-swipe-progress, 0))));
}
/* Pendant que le doigt ou un ressort pilote la pile, les transitions sont coupées :
   une valeur réécrite à chaque frame ET transitionnée sur 320 ms traîne en
   permanence — soit exactement le défaut que ce suivi cherche à supprimer. Elles
   reprennent au repos, où elles servent enfin (réagencement après un départ). */
.crb-swipe-stack.is-swiping .crb-swipe-card { transition: none; }
.crb-swipe-card--top {
  transform: none;
  cursor: grab;
  z-index: var(--crb-z-raised);
}
.crb-swipe-card--top:active { cursor: grabbing; }

/* Mouvement réduit : la pile cesse de respirer sous le doigt (déplacement de masses
   à l'écran), mais le VOILE de couleur et les étiquettes J'aime / Passer restent —
   ce sont eux qui portent l'information, et les retirer priverait le membre du seul
   retour qui lui dit ce qu'il est en train de faire. */
@media (prefers-reduced-motion: reduce) {
  .crb-swipe-card:nth-last-child(2) { transform: scale(.97) translateY(8px); }
}

.crb-swipe-card__photo {
  position: absolute;
  inset: 0;
  background-color: var(--crb-bg-hover);
  background-size: cover;
  background-position: center;
}
/* Aucune photo : dégradé doux dérivé de la primaire + initiale. */
.crb-swipe-card__photo--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background-image: linear-gradient(135deg,
                      var(--crb-primary-tint),
                      color-mix(in srgb, var(--crb-primary) 22%, var(--crb-surface)));
  color: color-mix(in srgb, var(--crb-primary) 70%, var(--crb-text));
  font-size: var(--crb-fs-7xl);
  font-weight: var(--crb-fw-bold);
  text-transform: uppercase;
}
.crb-swipe-card__photo .crb-skeleton { position: absolute; inset: 0; border-radius: 0; }

/* Voile bas pour lisibilité du texte sur la photo. */
.crb-swipe-card__info {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  /* Au-dessus du voile de couleur (.crb-swipe-tint, z-index 1) : le nom/âge
     reste lisible même quand la carte est teintée pendant le glissement. */
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 10px;
  padding: var(--crb-space-6) var(--crb-space-4) var(--crb-space-4);
  color: #fff;
  background: linear-gradient(to top,
               rgba(0,0,0,calc(.86 * var(--crb-scrim))) 0%,
               rgba(0,0,0,calc(.66 * var(--crb-scrim))) 28%,
               rgba(0,0,0,calc(.34 * var(--crb-scrim))) 62%,
               rgba(0,0,0,0) 100%);
  text-shadow: 0 1px 2px rgba(0,0,0,.6), 0 2px 10px rgba(0,0,0,.4);
}
/* Badges noir sur blanc : pas d'ombre héritée du voile. */
.crb-swipe-card__info .crb-card-badge { text-shadow: none; }
/* Badges « mis en avant » (goûts choisis par le membre) : noir sur blanc, en tête
   du bandeau d'infos de la carte. Le membre en sélectionne jusqu'à 4 dans l'onglet
   « mes goûts » du profil détaillé. */
.crb-swipe-card__badges {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 4px;
}
.crb-card-badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: var(--crb-radius-pill, 999px);
  background: #fff;
  color: #000;
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-semibold);
  line-height: 1.3;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .28);
  white-space: nowrap;
}
.crb-swipe-card__name {
  font-size: var(--crb-fs-3xl);
  font-weight: var(--crb-heading-weight);
  letter-spacing: var(--crb-heading-tracking);
  line-height: 1.1;
}
.crb-swipe-card__age  { font-size: var(--crb-fs-2xl); font-weight: var(--crb-fw-medium); }
.crb-swipe-card__city {
  flex-basis: 100%;
  font-size: var(--crb-fs-base);
  opacity: .9;
  display: flex;
  align-items: center;
  gap: 5px;
}
.crb-swipe-card .crb-online-dot {
  width: 12px; height: 12px;
  box-shadow: 0 0 0 2px rgba(255,255,255,.85);
}

/* Score de compatibilité (premium). */
.crb-compat-score {
  margin-left: auto;
  align-self: center;
  padding: 3px 10px;
  border-radius: var(--crb-radius-pill);
  background: color-mix(in srgb, var(--crb-like) 88%, #000);
  color: #fff;
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-bold);
}

/* Carte promo Premium insérée dans la pile de swipe (membres au plan gratuit,
   réglage « Carte promo Premium tous les N profils » de l'onglet Matching). */
.crb-swipe-card--promo {
  background: linear-gradient(150deg,
                var(--crb-primary-tint),
                color-mix(in srgb, var(--crb-primary) 26%, var(--crb-surface)));
  cursor: grab;
}
.crb-swipe-promo {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--crb-space-3);
  text-align: center;
  padding: var(--crb-space-6) var(--crb-space-5);
}
/* Variante avec image : photo plein cadre + corps ancré en bas sur un voile. */
.crb-swipe-promo--has-image {
  justify-content: flex-end;
  padding: 0;
  background-size: cover;
  background-position: center;
}
.crb-swipe-promo__body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--crb-space-3);
  text-align: center;
}
.crb-swipe-promo--has-image .crb-swipe-promo__body {
  width: 100%;
  padding: var(--crb-space-6) var(--crb-space-5) var(--crb-space-5);
  background: linear-gradient(to top, rgba(0,0,0,.78) 0%, rgba(0,0,0,.4) 60%, rgba(0,0,0,0) 100%);
}
.crb-swipe-promo--has-image .crb-swipe-promo__title,
.crb-swipe-promo--has-image .crb-swipe-promo__text { color: #fff; }
.crb-swipe-promo__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 999px;
  background: var(--crb-primary);
  color: #fff;
  margin-bottom: var(--crb-space-2);
  box-shadow: var(--crb-shadow-md);
}
.crb-swipe-promo__icon svg { width: 32px; height: 32px; }
.crb-swipe-promo__title {
  font-size: var(--crb-fs-3xl);
  font-weight: var(--crb-heading-weight);
  letter-spacing: var(--crb-heading-tracking);
  color: var(--crb-text);
  margin: 0;
}
.crb-swipe-promo__text {
  font-size: var(--crb-fs-base);
  color: var(--crb-text-muted);
  max-width: 28ch;
  margin: 0;
}
.crb-swipe-promo__cta { margin-top: var(--crb-space-3); }
.crb-swipe-promo__skip { margin-top: calc(var(--crb-space-2) * -1); }

/* Carte promo Premium en feed (galerie + recherche/Découvrir) : occupe UNE cellule,
   exactement comme une carte membre du gabarit courant. Rendu serveur (gallery.php)
   et client (app.js buildPromoCard).

   L'image est TOUJOURS le fond `cover` d'un conteneur dont la géométrie est imposée
   par le gabarit — jamais une image à ses dimensions naturelles. Sans modificateur,
   une seule règle (carré) s'appliquait à tous les gabarits : en mode liste (conteneur
   flex COLONNE) la carte prenait toute la largeur du feed et l'image devenait un pavé
   plein écran. Chaque gabarit a donc désormais sa variante :
     --grid    → photo 3/2, comme .crb-member-card--rich (Découvrir, vue grille) ;
     --compact → vignette carrée dense, corps resserré (Découvrir, vue compacte) ;
     --list    → rangée vignette + texte, comme .crb-member-card--list ;
     --gallery → suit le design de la carte galerie (--crb-gallery-ratio / radius),
                 avec sa variante horizontale.
   Le modificateur est posé par celui qui rend la carte ; sans lui on retombe sur la
   géométrie « grille » (3/2), jamais sur une image non contrainte. */
.crb-promo-card {
  display: flex;
  flex-direction: column;
  border-radius: var(--crb-radius-lg);
  overflow: hidden;
  background: var(--crb-surface);
  border: 1px solid color-mix(in srgb, var(--crb-primary) 35%, var(--crb-border, #e2e2e2));
  box-shadow: var(--crb-shadow-md);
  /* Ne jamais élargir la piste de grille : une image large ne doit pas pousser la
     colonne (min-width auto d'un item de grid/flex). */
  min-width: 0;
}
.crb-promo-card__media {
  aspect-ratio: 3 / 2;
  background-size: cover;
  background-position: center;
  background-color: var(--crb-primary-tint);
  flex: 0 0 auto;
}
.crb-promo-card__media--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background-image: linear-gradient(150deg,
                      var(--crb-primary-tint),
                      color-mix(in srgb, var(--crb-primary) 30%, var(--crb-surface)));
  color: var(--crb-primary);
}
.crb-promo-card__media--empty svg { width: 42px; height: 42px; }
.crb-promo-card__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--crb-space-2);
  padding: var(--crb-space-4);
  flex: 1 1 auto;
  min-width: 0;
}
.crb-promo-card__title {
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-heading-weight);
  margin: 0;
  color: var(--crb-text);
  overflow-wrap: anywhere;
}
/* Un texte long ne doit pas faire grandir la cellule au-delà des cartes voisines. */
.crb-promo-card__text {
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
  margin: 0;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Le CTA reste collé en bas et tient dans la cellule quel que soit son libellé. */
.crb-promo-card__cta {
  margin-top: auto;
  max-width: 100%;
  white-space: normal;
  text-align: center;
}

/* ── Variante « grille riche » (Découvrir, vue grille) ─────────────────────── */
.crb-promo-card--grid .crb-promo-card__media { aspect-ratio: 3 / 2; }

/* ── Variante « compacte » (Découvrir, vue compacte) ───────────────────────── */
.crb-promo-card--compact .crb-promo-card__media { aspect-ratio: 1 / 1; }
.crb-promo-card--compact .crb-promo-card__body {
  gap: var(--crb-space-1);
  padding: var(--crb-space-2) 10px var(--crb-space-3);
  align-items: stretch;
}
.crb-promo-card--compact .crb-promo-card__title { font-size: var(--crb-fs-sm); }
.crb-promo-card--compact .crb-promo-card__text {
  font-size: var(--crb-fs-2xs);
  -webkit-line-clamp: 2;
  line-clamp: 2;
}
.crb-promo-card--compact .crb-promo-card__cta { justify-content: center; }
/* Colonnes très étroites (3 par ligne sous 480px) : le titre + le CTA suffisent ;
   le texte y serait illisible et ferait doubler la hauteur de la vignette. */
@media (max-width: 479px) {
  .crb-promo-card--compact .crb-promo-card__text { display: none; }
}

/* ── Variante « liste » (Découvrir, vue liste) ─────────────────────────────── */
/* Le conteneur .crb-members-grid--list est un flex COLONNE : la carte occupe donc
   toute la largeur du feed. Elle doit se lire comme une rangée (vignette bornée +
   texte), sur le modèle de .crb-member-card--list, pas comme un pavé plein cadre. */
.crb-promo-card--list {
  flex-direction: row;
  align-items: center;
  gap: 12px;
  padding: 8px;
}
.crb-promo-card--list .crb-promo-card__media {
  flex: 0 0 96px;
  width: 96px;
  aspect-ratio: 4 / 3;
  border-radius: var(--crb-radius);
}
.crb-promo-card--list .crb-promo-card__media--empty svg { width: 28px; height: 28px; }
.crb-promo-card--list .crb-promo-card__body {
  padding: 0;
  gap: 4px;
  justify-content: center;
}
.crb-promo-card--list .crb-promo-card__title { font-size: var(--crb-fs-base); }
.crb-promo-card--list .crb-promo-card__text {
  font-size: var(--crb-fs-xs);
  -webkit-line-clamp: 2;
  line-clamp: 2;
}
.crb-promo-card--list .crb-promo-card__cta { margin-top: 2px; align-self: flex-start; }
@media (max-width: 479px) {
  .crb-promo-card--list .crb-promo-card__media { flex-basis: 72px; width: 72px; }
}

/* ── Variante « galerie » ([crb_gallery], page d'accueil) ──────────────────── */
/* Le design de la carte galerie est réglé en admin (colonnes, ratio, rayon) : la
   promo emprunte les mêmes variables pour ne pas trancher dans la grille. */
.crb-promo-card--gallery {
  border-radius: var(--crb-gallery-radius, var(--crb-radius));
}
.crb-promo-card--gallery .crb-promo-card__media {
  aspect-ratio: var(--crb-gallery-ratio, 1 / 1);
}
.crb-promo-card--gallery .crb-promo-card__body {
  gap: var(--crb-space-1);
  padding: var(--crb-space-2) 10px var(--crb-space-3);
  align-items: stretch;
}
.crb-promo-card--gallery .crb-promo-card__title { font-size: var(--crb-fs-sm); }
.crb-promo-card--gallery .crb-promo-card__text {
  font-size: var(--crb-fs-2xs);
  -webkit-line-clamp: 2;
  line-clamp: 2;
}
.crb-promo-card--gallery .crb-promo-card__cta { justify-content: center; }
/* Carte galerie horizontale : photo à gauche sur 38 %, même géométrie que
   .crb-gallery-card--horizontal. */
.crb-promo-card--gallery-horizontal {
  flex-direction: row;
  min-height: 96px;
}
.crb-promo-card--gallery-horizontal .crb-promo-card__media {
  flex: 0 0 38%;
  width: 38%;
  aspect-ratio: auto;
  align-self: stretch;
  border-radius: 0;
}
.crb-promo-card--gallery-horizontal .crb-promo-card__body { justify-content: center; }

/* ════════════════════════════════════════════════════════════════════════════
   Date de naissance : trois listes jour / mois / année.
   Chaque liste hérite de la classe d'input de son contexte (crb-onb-input,
   crb-form__input…) ; ici on ne gère que la répartition et la cible tactile.
   ════════════════════════════════════════════════════════════════════════════ */
.crb-dob { display: flex; flex-wrap: wrap; gap: var(--crb-space-2); align-items: stretch; }
.crb-dob__sel { flex: 1 1 0; min-width: 0; }
.crb-dob__sel--day   { flex-grow: .8; }
.crb-dob__sel--month { flex-grow: 1.5; }
/* Ligne de message sous les trois listes : rappel de la règle en gris, qui vire
   au rouge quand la date saisie donne un âge insuffisant (même convention que
   .crb-onb-hint.is-warn du tunnel). */
.crb-dob__msg {
  flex: 1 0 100%;
  margin: 0;
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
}
.crb-dob__msg[hidden] { display: none; }
.crb-dob.is-invalid .crb-dob__msg { color: var(--crb-danger); font-weight: var(--crb-fw-semibold); }
.crb-dob.is-invalid .crb-dob__sel { border-color: var(--crb-danger); }
@media (max-width: 767px) {
  /* 16px minimum : en dessous, iOS zoome à l'ouverture de la liste. */
  .crb-dob__sel { min-height: var(--crb-touch-min); font-size: 16px; }
}

/* ════════════════════════════════════════════════════════════════════════════
   Comparateur de formules (Free vs Premium) — cible des CTA promo.
   Table responsive : colonne fonctionnalités figée, colonnes de plans
   scrollables, plan recommandé mis en bande d'accent, détail dépliable.
   ════════════════════════════════════════════════════════════════════════════ */
.crb-compare {
  margin-top: var(--crb-space-5);
  padding: var(--crb-space-5) var(--crb-space-5) var(--crb-space-4);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-md);
}
.crb-compare__head { text-align: center; margin-bottom: var(--crb-space-5); }
.crb-compare__title {
  font-size: var(--crb-fs-3xl);
  font-weight: var(--crb-heading-weight);
  letter-spacing: var(--crb-heading-tracking);
  margin: 0 0 4px;
}
.crb-compare__sub {
  color: var(--crb-text-muted);
  max-width: 52ch;
  margin: 0 auto;
  font-size: var(--crb-fs-base);
}

/* Sélecteur mensuel / annuel (segmented control) */
.crb-compare__period {
  display: inline-flex;
  /* Jusqu'à 4 périodicités (mensuel, 3 mois, 6 mois, annuel) : le groupe passe à
     la ligne au lieu de déborder de l'écran sur mobile. */
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px;
  margin-top: var(--crb-space-4);
  padding: 3px;
  background: var(--crb-surface-alt);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-pill);
}
.crb-compare__period-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 0;
  background: transparent;
  color: var(--crb-text-muted);
  font: inherit;
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-semibold);
  padding: 7px 16px;
  border-radius: var(--crb-radius-pill);
  cursor: pointer;
  transition: background var(--crb-dur-fast, .15s) var(--crb-ease, ease), color var(--crb-dur-fast, .15s);
}
.crb-compare__period-btn.is-active {
  background: var(--crb-surface);
  color: var(--crb-text);
  box-shadow: var(--crb-shadow-sm, 0 1px 3px rgba(0,0,0,.12));
}
.crb-compare__period-save {
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-bold);
  color: var(--crb-success);
  background: color-mix(in srgb, var(--crb-success) 15%, var(--crb-surface));
  padding: 1px 7px;
  border-radius: var(--crb-radius-pill);
}

/* Zone scrollable + table */
.crb-compare__scroll { overflow-x: auto; margin: 0 calc(var(--crb-space-5) * -1); padding: 0 var(--crb-space-5); }
.crb-compare__table {
  width: 100%;
  min-width: 520px;
  border-collapse: separate;
  border-spacing: 0;
}
.crb-compare__table th,
.crb-compare__table td { padding: 12px 14px; text-align: center; vertical-align: middle; }

/* Colonne fonctionnalités : figée à gauche */
.crb-compare__corner,
.crb-compare__feature {
  position: sticky;
  left: 0;
  z-index: 1;
  text-align: left;
  background: var(--crb-surface);
  min-width: 150px;
}
.crb-compare__feature {
  font-weight: var(--crb-fw-medium);
  font-size: var(--crb-fs-sm);
  color: var(--crb-text);
  border-top: 1px solid var(--crb-border);
}

/* En-têtes de plan */
.crb-compare__planhead {
  min-width: 128px;
  border-bottom: 2px solid var(--crb-border);
  vertical-align: top;
  padding-top: var(--crb-space-4);
}
.crb-compare__badge {
  display: inline-block;
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-bold);
  text-transform: uppercase;
  letter-spacing: .04em;
  color: #fff;
  background: var(--crb-primary);
  padding: 3px 10px;
  border-radius: var(--crb-radius-pill);
  margin-bottom: 6px;
}
.crb-compare__planname {
  display: block;
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-heading-weight);
}
.crb-compare__price { display: block; margin: 4px 0 10px; line-height: 1.25; }
.crb-compare__amount { display: block; font-size: var(--crb-fs-xl); font-weight: var(--crb-fw-bold); }
.crb-compare__per { font-size: var(--crb-fs-sm); font-weight: var(--crb-fw-medium); color: var(--crb-text-muted); }
.crb-compare__billed { display: block; font-size: var(--crb-fs-xs); color: var(--crb-text-muted); margin-top: 2px; }
/* `display: block` ci-dessus l'emporte sur l'attribut [hidden] : sans ces deux
   règles, les prix mensuel ET annuel s'empilent (bascule de période inopérante). */
.crb-compare__amount[hidden],
.crb-compare__billed[hidden] { display: none; }
.crb-compare__current {
  display: inline-block;
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text-muted);
  padding: 6px 0;
}
.crb-compare__cta { width: 100%; }

/* Pied de colonne : rappel du CTA sous la dernière ligne comparée. La colonne
   du plan gratuit n'y porte que « Votre plan » (rien à souscrire). */
.crb-compare__table .crb-compare__planfoot {
  vertical-align: top;
  padding: var(--crb-space-4) 14px;
  border-top: 1px solid var(--crb-border);
}
/* Le filet de séparation traverse aussi la colonne des libellés, sinon il
   s'arrête net au milieu du tableau. */
.crb-compare__footrow .crb-compare__corner { border-top: 1px solid var(--crb-border); }
.crb-compare__footname {
  display: block;
  margin-bottom: 8px;
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text-muted);
}

/* Plan recommandé : bande d'accent verticale (en-tête + cellules + pied) */
.crb-compare__planhead.is-reco,
.crb-compare__cell.is-reco,
.crb-compare__planfoot.is-reco {
  background: var(--crb-primary-tint);
  border-left: 1px solid color-mix(in srgb, var(--crb-primary) 30%, transparent);
  border-right: 1px solid color-mix(in srgb, var(--crb-primary) 30%, transparent);
}
.crb-compare__planhead.is-reco {
  border-top: 3px solid var(--crb-primary);
  border-bottom-color: var(--crb-primary);
  border-radius: var(--crb-radius-lg) var(--crb-radius-lg) 0 0;
  padding-top: calc(var(--crb-space-4) - 3px);
}
/* Ferme la colonne d'accent en bas, symétrique de l'en-tête. */
.crb-compare__planfoot.is-reco {
  border-top-color: color-mix(in srgb, var(--crb-primary) 30%, transparent);
  border-bottom: 3px solid var(--crb-primary);
  border-radius: 0 0 var(--crb-radius-lg) var(--crb-radius-lg);
  padding-bottom: calc(var(--crb-space-4) - 3px);
}
.crb-compare__planfoot.is-reco .crb-compare__footname { color: var(--crb-primary); }

/* Lignes / cellules */
.crb-compare__cell { border-top: 1px solid var(--crb-border); }
.crb-compare__row:hover .crb-compare__feature,
.crb-compare__row:hover .crb-compare__cell { background-color: var(--crb-bg-hover, color-mix(in srgb, var(--crb-text) 4%, var(--crb-surface))); }
.crb-compare__row:hover .crb-compare__cell.is-reco { background-color: color-mix(in srgb, var(--crb-primary) 16%, var(--crb-surface)); }

/* En-tête de section (mode détail) */
.crb-compare__section {
  text-align: left;
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-bold);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--crb-text-muted);
  background: var(--crb-surface-alt);
  padding: 9px 14px;
  position: sticky;
  left: 0;
}

/* Marques oui / non + valeurs */
.crb-compare__mark { display: inline-flex; align-items: center; justify-content: center; }
.crb-compare__mark svg { width: 20px; height: 20px; }
.crb-compare__mark--yes { color: var(--crb-success); }
.crb-compare__mark--no  { color: color-mix(in srgb, var(--crb-text-muted) 55%, transparent); }
.crb-compare__val { font-size: var(--crb-fs-sm); color: var(--crb-text-muted); }
.crb-compare__val--on { color: var(--crb-primary); font-weight: var(--crb-fw-semibold); }

/* Détail masqué par défaut */
.crb-compare__row--detail { display: none; }
.crb-compare.is-expanded .crb-compare__row--detail { display: table-row; }

/* Pied : bouton déplier + feedback */
.crb-compare__footer { text-align: center; margin-top: var(--crb-space-4); }
.crb-compare__toggle {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 1px solid var(--crb-border);
  background: var(--crb-surface);
  color: var(--crb-text);
  font: inherit;
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-semibold);
  padding: 9px 18px;
  border-radius: var(--crb-radius-pill);
  cursor: pointer;
  transition: border-color var(--crb-dur-fast, .15s), background var(--crb-dur-fast, .15s);
}
.crb-compare__toggle:hover { border-color: var(--crb-primary); }
.crb-compare__chev {
  width: 8px; height: 8px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translateY(-1px);
  transition: transform var(--crb-dur-base, .2s) var(--crb-ease, ease);
}
.crb-compare.is-expanded .crb-compare__chev { transform: rotate(-135deg) translateY(-1px); }
.crb-compare__toggle-label--less { display: none; }
.crb-compare.is-expanded .crb-compare__toggle-label--more { display: none; }
.crb-compare.is-expanded .crb-compare__toggle-label--less { display: inline; }
.crb-compare__note { color: var(--crb-text-muted); font-size: var(--crb-fs-sm); margin: 10px 0 0; }
.crb-compare__feedback { color: var(--crb-danger, #c0392b); font-size: var(--crb-fs-sm); margin: 10px 0 0; }

/* Barre mobile (choix de la formule comparée + filtre différences) : hors mobile
   la table complète suffit, on la masque. */
.crb-compare__mobilebar { display: none; }

@media (max-width: 600px) {
  .crb-compare { padding: var(--crb-space-4) var(--crb-space-3) var(--crb-space-3); }
  .crb-compare__scroll { margin: 0 calc(var(--crb-space-3) * -1); padding: 0 var(--crb-space-3); }
  .crb-compare__table th,
  .crb-compare__table td { padding: 10px 8px; }
  .crb-compare__feature, .crb-compare__corner { min-width: 120px; }
}

/* ════════════════════════════════════════════════════════════════════════════
   Mobile : la grille de comparaison n'est plus une table.
   Sur 390px, 3 colonnes (libellé + 2 plans) laissent ~110px par colonne : tout
   s'enroule sur 2-3 lignes et l'écart devient illisible. On adopte donc le
   pattern des comparateurs mobiles : une CARTE pour la formule sélectionnée,
   puis une LISTE où chaque fonctionnalité prend toute la largeur, avec sous
   elle deux pastilles « Gratuit » → « Premium » lues de gauche à droite.
   Les éléments de table sont repassés en block/grid ; la table complète reste
   inchangée au-dessus du point de rupture.
   ════════════════════════════════════════════════════════════════════════════ */
@media (max-width: 767px) {
  /* ── Barre de contrôle : onglets de formule + filtre ─────────────────── */
  .crb-compare__mobilebar {
    display: flex;
    flex-direction: column;
    gap: var(--crb-space-3);
    margin-bottom: var(--crb-space-4);
  }
  .crb-compare__mlegend {
    margin: 0;
    font-size: var(--crb-fs-sm);
    color: var(--crb-text-muted);
    text-align: center;
  }
  /* Défilement horizontal cantonné à CETTE barre courte, jamais à la liste. */
  .crb-compare__mplans {
    display: flex;
    gap: 6px;
    overflow-x: auto;
    scrollbar-width: none;
    padding: 3px;
    background: var(--crb-surface-alt);
    border: 1px solid var(--crb-border);
    border-radius: var(--crb-radius-pill);
  }
  .crb-compare__mplans::-webkit-scrollbar { display: none; }
  .crb-compare__mplan {
    flex: 1 0 auto;
    min-height: var(--crb-touch-min);
    border: 0;
    background: transparent;
    color: var(--crb-text-muted);
    font: inherit;
    font-size: var(--crb-fs-sm);
    font-weight: var(--crb-fw-semibold);
    padding: 8px 16px;
    border-radius: var(--crb-radius-pill);
    white-space: nowrap;
    cursor: pointer;
    transition: background var(--crb-dur-fast, .15s) var(--crb-ease, ease), color var(--crb-dur-fast, .15s);
  }
  .crb-compare__mplan.is-active { background: var(--crb-primary); color: #fff; }

  .crb-compare__difftoggle {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    min-height: var(--crb-touch-min);
    font-size: var(--crb-fs-sm);
    color: var(--crb-text-muted);
    cursor: pointer;
  }
  .crb-compare__difftoggle input {
    width: 20px; height: 20px;
    accent-color: var(--crb-primary);
    flex: 0 0 auto;
  }

  /* ── Démontage de la table ───────────────────────────────────────────── */
  .crb-compare__scroll { overflow-x: visible; margin: 0; padding: 0; }
  .crb-compare__table,
  .crb-compare__table > thead,
  .crb-compare__table > tbody,
  .crb-compare__table > tfoot,
  .crb-compare__table > tfoot > tr,
  .crb-compare__table > thead > tr { display: block; width: 100%; min-width: 0; }

  /* ── En-tête = carte de la formule sélectionnée ──────────────────────── */
  /* Le libellé du plan gratuit n'a plus besoin de colonne : il est rappelé
     sur chaque pastille (data-col-label). */
  .crb-compare__corner,
  .crb-compare__planhead { display: none; }
  .crb-compare__planhead.is-msel {
    display: block;
    width: auto;
    min-width: 0;
    text-align: center;
    padding: var(--crb-space-4);
    margin-bottom: var(--crb-space-4);
    background: var(--crb-primary-tint);
    border: 1px solid color-mix(in srgb, var(--crb-primary) 30%, transparent);
    border-top: 3px solid var(--crb-primary);
    border-radius: var(--crb-radius-lg);
  }
  .crb-compare__planhead.is-msel .crb-compare__planname { font-size: var(--crb-fs-xl); }
  .crb-compare__planhead.is-msel .crb-compare__amount { font-size: var(--crb-fs-3xl); }
  .crb-compare__planhead.is-msel .crb-compare__cta {
    max-width: 320px;
    margin: 0 auto;
    min-height: var(--crb-touch-min);
  }
  /* La variante `outline` (plan non recommandé) devient illisible sur le fond
     teinté de la carte : on lui rend une surface pleine. */
  .crb-compare__planhead.is-msel .crb-compare__cta.crb-btn--outline {
    background: var(--crb-surface);
    border-color: var(--crb-primary);
  }

  /* ── Pied = CTA de la seule formule sélectionnée ─────────────────────── */
  /* Les autres colonnes (et le plan gratuit, qui n'a rien à vendre) sortent du
     flux : la liste mobile ne compare qu'une formule à la fois. */
  .crb-compare__table .crb-compare__planfoot { display: none; }
  .crb-compare__table .crb-compare__planfoot.is-msel {
    display: block;
    width: auto;
    padding: var(--crb-space-4) 0 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    text-align: center;
  }
  .crb-compare__planfoot.is-msel .crb-compare__cta {
    max-width: 320px;
    margin: 0 auto;
    min-height: var(--crb-touch-min);
  }

  /* ── Titres de section ───────────────────────────────────────────────── */
  .crb-compare__sectionrow { display: block; }
  .crb-compare__section {
    display: block;
    position: static;
    margin-top: var(--crb-space-4);
    padding: 8px 12px;
    border-radius: var(--crb-radius-sm);
  }

  /* ── Une fonctionnalité = un bloc pleine largeur + 2 pastilles ───────── */
  .crb-compare__row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--crb-space-2);
    padding: var(--crb-space-3) 0;
    border-top: 1px solid var(--crb-border);
  }
  .crb-compare__row:first-child { border-top: 0; }
  /* `.crb-compare__table th` (0,1,1) centrait le libellé : on rétablit un bord
     gauche de lecture commun à toute la liste. */
  .crb-compare__table .crb-compare__feature {
    grid-column: 1 / -1;
    display: block;
    position: static;
    min-width: 0;
    padding: 0 2px 2px;
    border: 0;
    background: transparent;
    text-align: left;
    font-size: var(--crb-fs-md);
    font-weight: var(--crb-fw-semibold);
    line-height: 1.35;
  }
  .crb-compare__cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    min-height: 62px;
    padding: 9px 8px;
    border: 1px solid var(--crb-border);
    border-radius: var(--crb-radius);
    background: var(--crb-surface-alt);
    text-align: center;
  }
  /* Nom du plan rappelé sur la pastille (l'en-tête de colonne n'existe plus). */
  .crb-compare__cell::before {
    content: attr(data-col-label);
    font-size: var(--crb-fs-2xs);
    font-weight: var(--crb-fw-bold);
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--crb-text-muted);
  }
  .crb-compare__cell.is-mhidden { display: none; }
  .crb-compare__cell.is-msel {
    background: var(--crb-primary-tint);
    border-color: color-mix(in srgb, var(--crb-primary) 35%, transparent);
  }
  .crb-compare__cell.is-msel::before { color: var(--crb-primary); }
  /* Le survol table-wide brouillerait la lecture des pastilles au tap. */
  .crb-compare__row:hover .crb-compare__feature,
  .crb-compare__row:hover .crb-compare__cell { background-color: var(--crb-surface-alt); }
  .crb-compare__row:hover .crb-compare__cell.is-msel { background-color: var(--crb-primary-tint); }

  .crb-compare__val { font-size: var(--crb-fs-base); line-height: 1.25; }
  .crb-compare__mark svg { width: 22px; height: 22px; }
  .crb-compare__help { width: 22px; height: 22px; }

  /* ── Rétablissement des display : les règles de base (masquage du détail,
        dépliage) visent none/table-row et sont écrites AVANT ce bloc ; il faut
        donc les rejouer dans l'ordre pour cette mise en page. ───────────── */
  .crb-compare__row--detail { display: none; }
  .crb-compare.is-expanded .crb-compare__row--detail { display: block; }
  .crb-compare.is-expanded .crb-compare__row.crb-compare__row--detail { display: grid; }

  /* ── Filtre « seulement les différences » (doit primer sur ci-dessus) ── */
  .crb-compare.is-diffonly .crb-compare__row.is-same,
  .crb-compare.is-expanded.is-diffonly .crb-compare__row.is-same { display: none; }
  .crb-compare.is-diffonly .crb-compare__sectionrow.is-empty,
  .crb-compare.is-expanded.is-diffonly .crb-compare__sectionrow.is-empty { display: none; }
}

/* Badge super-like reçu (réutilise .crb-superlike-badge déjà défini plus haut). */

/* Badge signe astrologique (viewer avec recherche astro). Symbole Unicode du
   zodiaque forcé en présentation TEXTE (monochrome) : il hérite ainsi du blanc
   (currentColor) sur le fond couleur d'accent, au lieu du glyphe emoji couleur
   (à fond violet) non recolorable. Le suffixe U+FE0E (côté JS) renforce ce rendu.

   Le badge ne se positionne PLUS lui-même : il se pose là où on l'écrit. La
   surimpression est déclarée par le seul contexte qui la veut (la photo de la
   carte de swipe, plus bas). Un badge qui portait `position:absolute` en propre
   n'avait aucun ancrage garanti dans les gabarits où il tombe au fil du texte :
   son bloc conteneur devenait le premier ancêtre transformé — donc la carte
   pendant l'animation d'apparition, plus rien du tout une fois celle-ci
   terminée, et de nouveau la carte au survol (qui la soulève). Le badge
   « sautait » ainsi en haut de la page après une seconde, puis suivait le profil
   survolé. C'est le placement qui appartient au conteneur, jamais au badge. */
.crb-astro-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  /* Hauteur calée sur le badge % cœur (.crb-member-card__compat) : pas de hauteur
     fixe, on reprend padding/font-size/line-height pour un rendu identique. */
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--crb-primary);
  color: #fff;
  font-size: var(--crb-fs-xs);
  line-height: 1;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--crb-primary) 45%, transparent);
  pointer-events: none;
  z-index: var(--crb-z-raised);
}
/* Carte de swipe : là, et là seulement, le badge est une surimpression de photo.
   Coin haut-gauche pour ne pas chevaucher le super-like (coin haut-droit).
   `.crb-swipe-card__photo` est en `position:absolute; inset:0` — l'ancrage est
   donc explicite et ne dépend d'aucune animation. */
.crb-swipe-card__photo .crb-astro-badge {
  position: absolute;
  top: 8px;
  left: 8px;
}

.crb-astro-badge__symbol {
  font-size: .9em;
  line-height: 1;
  font-variant-emoji: text;
}

.crb-astro-badge__label {
  font-size: var(--crb-fs-xs);
  font-weight: 600;
  white-space: nowrap;
  /* Casse verrouillée sur la source (Titre : Lion, Bélier…) : neutralise tout
     text-transform hérité du thème/conteneur, cause de l'incohérence majuscules
     vs minuscules selon le contexte de rendu. */
  text-transform: none;
  letter-spacing: normal;
}

/* ── Voile de couleur progressif (rouge/vert) révélé au drag ────────────────
   Rempli en dégradé depuis le bord concerné (droite = J'aime/vert,
   gauche = Passer/rouge). L'opacité est pilotée en direct par swipe.js
   (proportionnelle à l'amplitude du glissement). Placé au-dessus de la photo
   mais sous le bandeau d'infos, qui reste lisible. */
.crb-swipe-tint {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
  z-index: 1;
  transition: opacity var(--crb-dur-fast, .12s) linear;
}
.crb-swipe-tint--like {
  background: linear-gradient(to left,
               color-mix(in srgb, var(--crb-like) 78%, transparent) 0%,
               color-mix(in srgb, var(--crb-like) 34%, transparent) 45%,
               transparent 82%);
}
.crb-swipe-tint--pass {
  background: linear-gradient(to right,
               color-mix(in srgb, var(--crb-pass) 78%, transparent) 0%,
               color-mix(in srgb, var(--crb-pass) 34%, transparent) 45%,
               transparent 82%);
}
/* Pas de transition pendant le glissement actif : le voile suit le doigt. */
.crb-swipe-card--top.crb-swipe-card--dragging .crb-swipe-tint { transition: none; }

/* ── Étiquettes J'aime / Passer (révélées au drag) ──────────────────────────
   Pastille blanche opaque + texte coloré : lisible même sur une photo claire. */
.crb-like-indicator,
.crb-pass-indicator {
  position: absolute;
  top: 28px;
  padding: 8px 18px;
  border: 4px solid currentColor;
  border-radius: var(--crb-radius);
  background: #fff;
  font-size: var(--crb-fs-3xl);
  font-weight: var(--crb-fw-bold);
  letter-spacing: .04em;
  text-transform: uppercase;
  opacity: 0;
  pointer-events: none;
  box-shadow: 0 4px 16px rgba(0, 0, 0, .3);
  z-index: var(--crb-z-sticky);
}
.crb-like-indicator {
  right: 20px;
  color: var(--crb-like);
  transform: rotate(14deg);
}
.crb-pass-indicator {
  left: 20px;
  color: var(--crb-pass);
  transform: rotate(-14deg);
}

/* ── Boutons d'action ────────────────────────────────────────────────────── */
.crb-swipe-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--crb-space-4);
}
.crb-swipe-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  border-radius: var(--crb-radius-pill);
  border: 1px solid var(--crb-border);
  background: var(--crb-surface);
  color: var(--crb-text-muted);
  cursor: pointer;
  box-shadow: var(--crb-shadow-sm);
  transition: transform var(--crb-dur-fast) var(--crb-ease),
              box-shadow var(--crb-dur-base) var(--crb-ease),
              color var(--crb-dur-base) var(--crb-ease);
}
.crb-swipe-btn svg { width: 26px; height: 26px; }
.crb-swipe-btn:hover  { box-shadow: var(--crb-shadow-md); }
.crb-swipe-btn:active { transform: scale(.9); }

.crb-swipe-btn--rewind:hover { color: var(--crb-premium); }
.crb-swipe-btn--pass {
  width: 64px; height: 64px;
  color: var(--crb-pass);
}
.crb-swipe-btn--pass:hover  { background: var(--crb-danger-tint); }
.crb-swipe-btn--super:hover { color: var(--crb-superlike); }
.crb-swipe-btn--like {
  width: 72px; height: 72px;
  border-color: transparent;
  background: var(--crb-like);
  color: #fff;
  box-shadow: 0 6px 18px color-mix(in srgb, var(--crb-like) 40%, transparent);
}
.crb-swipe-btn--like svg { width: 32px; height: 32px; }
.crb-swipe-btn--like:hover {
  box-shadow: 0 8px 24px color-mix(in srgb, var(--crb-like) 52%, transparent);
}

/* Le bloc « extras » (.crb-swipe-extras / .crb-blur-preview / .crb-nudge-label)
   a été supprimé avec le nudge flouté « Voir avec Premium » : la carte compagnon
   « Qui m'a liké » de la colonne droite porte seule cet upsell. */

/* ── États : vide & erreur ───────────────────────────────────────────────── */
.crb-swipe-empty,
.crb-swipe-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--crb-space-2);
  padding: var(--crb-space-6) var(--crb-space-4);
  width: 100%;
}
.crb-swipe-empty__icon,
.crb-swipe-error__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px; height: 64px;
  margin-bottom: var(--crb-space-1);
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary-tint);
  color: var(--crb-primary);
}
.crb-swipe-error__icon { background: var(--crb-danger-tint); color: var(--crb-danger); }
.crb-swipe-empty__icon svg,
.crb-swipe-error__icon svg { width: 32px; height: 32px; }
.crb-swipe-empty h3,
.crb-swipe-error h3 {
  margin: 0;
  font-size: var(--crb-fs-xl);
  font-weight: var(--crb-heading-weight);
  letter-spacing: var(--crb-heading-tracking);
}
.crb-swipe-empty p,
.crb-swipe-error p { margin: 0 0 var(--crb-space-2); color: var(--crb-text-muted); max-width: 30ch; }
/* Panneau de critères ouvert depuis « Élargir mes critères » : largeur lisible, aligné à gauche */
.crb-swipe-empty .crb-swipe-prefs {
  width: 100%;
  max-width: 360px;
  margin: var(--crb-space-2) 0 0;
  text-align: left;
}

/* ── Overlay de Match (SWP-09) ───────────────────────────────────────────── */
.crb-match-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--crb-z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--crb-space-4);
  background: color-mix(in srgb, var(--crb-primary) 30%, rgba(0,0,0,.78));
  opacity: 0;
  transition: opacity var(--crb-dur-slow) var(--crb-ease);
}
.crb-match-overlay--visible { opacity: 1; }
.crb-match-content {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--crb-space-3);
  max-width: 340px;
  width: 100%;
  text-align: center;
  transform: scale(.86);
  transition: transform var(--crb-dur-slow) var(--crb-ease);
}
.crb-match-overlay--visible .crb-match-content { transform: scale(1); }
.crb-match-title {
  font-size: var(--crb-fs-5xl);
  font-weight: var(--crb-fw-bold);
  letter-spacing: var(--crb-heading-tracking);
  color: #fff;
  background: linear-gradient(135deg, #fff, var(--crb-premium));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.crb-match-sub { color: rgba(255,255,255,.92); margin: 0; }
.crb-match-photos {
  display: flex;
  justify-content: center;
  margin: var(--crb-space-2) 0;
}
.crb-match-photo {
  width: 96px; height: 96px;
  border-radius: var(--crb-radius-pill);
  border: 3px solid #fff;
  background: var(--crb-surface-alt) center/cover no-repeat;
  box-shadow: var(--crb-shadow-lg);
}
/* Membre sans photo (et sans avatar par défaut de genre) : initiale du pseudo,
   même traitement que la carte de swipe vide. */
.crb-match-photo--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background-image: linear-gradient(135deg,
                      var(--crb-primary-tint),
                      color-mix(in srgb, var(--crb-primary) 22%, var(--crb-surface)));
  color: color-mix(in srgb, var(--crb-primary) 70%, var(--crb-text));
  font-size: var(--crb-fs-3xl);
  font-weight: var(--crb-fw-bold);
  text-transform: uppercase;
}
.crb-match-photo--them { margin-left: -22px; }
.crb-match-content .crb-btn { width: 100%; max-width: 280px; }
.crb-match-content .crb-btn--ghost,
.crb-match-content .crb-btn--ghost:hover {
  color: #fff;
  background: color-mix(in srgb, #fff 14%, transparent);
}

/* Confetti CSS léger (n'anime que transform/opacity). */
.crb-match-confetti {
  position: absolute;
  top: 0; left: 50%;
  width: 1px; height: 1px;
  pointer-events: none;
}
.crb-match-confetti::before,
.crb-match-confetti::after {
  content: '';
  position: absolute;
  width: 10px; height: 10px;
  border-radius: 2px;
  background: var(--crb-premium);
  opacity: 0;
}
.crb-match-overlay--visible .crb-match-confetti::before {
  animation: crb-confetti 1s var(--crb-ease-out) .15s both;
  background: var(--crb-like);
}
.crb-match-overlay--visible .crb-match-confetti::after {
  animation: crb-confetti 1.1s var(--crb-ease-out) .05s both;
  left: 12px;
}
@keyframes crb-confetti {
  0%   { opacity: 1; transform: translateY(-10px) rotate(0); }
  100% { opacity: 0; transform: translateY(60px) rotate(220deg); }
}

/* ── Modale « note de Super-like » (message de mise en relation) ──────────── */
.crb-sl-note-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--crb-z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--crb-space-4);
  background: color-mix(in srgb, #1d6ef5 24%, rgba(0,0,0,.78));
  opacity: 0;
  transition: opacity var(--crb-dur-base) var(--crb-ease);
}
.crb-sl-note-overlay--visible { opacity: 1; }
.crb-sl-note-modal {
  width: 100%;
  max-width: 380px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--crb-space-2);
  padding: var(--crb-space-5);
  text-align: center;
  background: var(--crb-surface);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-lg);
  transform: scale(.9);
  transition: transform var(--crb-dur-base) var(--crb-ease);
}
.crb-sl-note-overlay--visible .crb-sl-note-modal { transform: scale(1); }
.crb-sl-note-modal__star {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: #1d6ef5;
  color: #fff;
  box-shadow: 0 2px 10px rgba(29,110,245,.45);
}
.crb-sl-note-modal__star svg { width: 26px; height: 26px; }
.crb-sl-note-modal__title {
  margin: var(--crb-space-1) 0 0;
  font-size: var(--crb-fs-xl);
  font-weight: var(--crb-fw-bold);
}
.crb-sl-note-modal__sub {
  margin: 0;
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
}
.crb-sl-note-modal__input {
  width: 100%;
  margin-top: var(--crb-space-2);
  padding: var(--crb-space-3);
  font: inherit;
  color: var(--crb-text);
  background: var(--crb-bg);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius);
  resize: vertical;
}
.crb-sl-note-modal__input:focus {
  outline: none;
  border-color: #1d6ef5;
  box-shadow: 0 0 0 3px rgba(29,110,245,.18);
}
.crb-sl-note-modal__count {
  align-self: flex-end;
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
}
.crb-sl-note-modal__actions {
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-2);
  width: 100%;
  margin-top: var(--crb-space-2);
}
.crb-sl-note-modal__actions .crb-btn { width: 100%; }

/* ── Bulle « note de Super-like » dans la conversation ───────────────────── */
.crb-bubble--superlike {
  border-left: 3px solid #1d6ef5;
}
.crb-bubble__sl-head {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 2px;
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-bold);
  text-transform: uppercase;
  letter-spacing: .04em;
  color: #1d6ef5;
}
.crb-bubble__sl-head svg { width: 13px; height: 13px; }

/* ── Densité desktop ─────────────────────────────────────────────────────── */
@media (min-width: 768px) {
  .crb-swipe-app { max-width: 460px; gap: var(--crb-space-5); }
  .crb-swipe-stack { max-height: min(64dvh, 600px); }
  .crb-swipe-btn--like { width: 76px; height: 76px; }
}

/* ── Mobile : la vue entière tient dans un écran ──────────────────────────────
   En flux libre, la somme barre boost + carte (68dvh) + rangée d'actions
   dépassait la hauteur visible : les boutons like/pass tombaient sous la ligne
   de flottaison, sur l'écran même où ils SONT l'interaction principale. Borner la
   carte plus bas ne ferait que déplacer le problème — le flux ne connaît pas la
   hauteur restante et rien n'oblige un bloc à céder sa place à un autre.
   La vue devient donc une colonne bornée au viewport : le chrome (boost,
   compteur, bandeaux, actions) garde sa taille naturelle et la CARTE absorbe ce
   qui reste. Vrai aussi quand un bloc s'ajoute — compteur non-premium, bandeau
   « limite atteinte », nudge « qui m'a liké » : la carte rétrécit, les actions
   restent à l'écran.
   Scopé au shell SPA (classe posée par activateTab) : la hauteur retranchée est
   celle de SA barre mobile, et le pied de page est masqué en dessous. La vue
   standalone [crb_swipe], qui vit sous le header du thème, garde le flux. */
@media (max-width: 1023px) {
  body.crb-tab-swipe .crb-swipe-app {
    /* Chrome vertical au-dessus/au-dessous : barre mobile + les 16px ×2 de
       .crb-panel__inner. Les paddings propres de l'app passent dans le gap. */
    height: calc(100dvh - var(--crb-mobilebar-height) - 2 * var(--crb-space-4));
    padding-top: 0;
    padding-bottom: 0;
    gap: var(--crb-space-3);
  }
  /* La carte est la seule variable d'ajustement. `min-height: 0` est ce qui
     l'autorise à passer sous sa hauteur de contenu (un enfant flex refuse de
     rétrécir en dessous par défaut) ; aspect-ratio et max-height ne pilotent
     plus rien ici, c'est la place restante qui décide. Le cadrage portrait est
     préservé : la photo de la carte est en `cover`. */
  body.crb-tab-swipe .crb-swipe-stack {
    flex: 1 1 auto;
    min-height: 0;
    aspect-ratio: auto;
    max-height: none;
  }
  /* Chrome incompressible : jamais rogné au profit de la carte. */
  body.crb-tab-swipe .crb-swipe-actions,
  body.crb-tab-swipe .crb-swipe-counter,
  body.crb-tab-swipe .crb-nudge-banner,
  body.crb-tab-swipe .crb-boost-widget--inline { flex: none; }
  /* Sa marge basse ferait doublon avec le gap de la colonne. */
  body.crb-tab-swipe .crb-boost-widget--inline { margin-bottom: 0; }
  /* États alternatifs (file vide / erreur) : swipe.js masque la stack, ces blocs
     prennent sa place. Ils défilent seuls plutôt que d'allonger la vue — le
     panneau « Élargir mes critères » reste atteignable sans repousser le bas. */
  body.crb-tab-swipe .crb-swipe-empty,
  body.crb-tab-swipe .crb-swipe-error {
    flex: 1 1 auto;
    min-height: 0;
    justify-content: center;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   E4 — MESSAGES  (inbox plein écran + fenêtre de chat, `messages.php`)
   Le layout `.crb-messages-layout` était stylé, mais l'intérieur (inbox__*,
   chat__form/input/send, typing, gif-picker, médias) ne l'était pas. Tokenisé.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Inbox : liste des conversations ─────────────────────────────────────── */
/* L'aside ne scrolle plus en entier : l'en-tête (titre/filtres/recherche) reste
   fixe et seule la liste défile (cf. surcharge .crb-inbox__list ci-dessous). */
.crb-inbox { overflow: hidden; }

/* En-tête : titre + sous-titre + badges de filtre + barre de recherche. */
.crb-inbox__header {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-3);
  padding: var(--crb-space-4);
  border-bottom: 1px solid var(--crb-border);
  background: var(--crb-surface);
}
.crb-inbox__title {
  display: inline-flex;
  align-items: center;
  gap: var(--crb-space-2);
  margin: 0;
  font-size: var(--crb-fs-2xl);
  font-weight: var(--crb-heading-weight);
  letter-spacing: var(--crb-heading-tracking);
}
.crb-inbox__sparkle { width: 22px; height: 22px; color: var(--crb-primary); flex-shrink: 0; }
.crb-inbox__subtitle {
  margin: 0;
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
}

/* Badges de filtre : rangée scrollable horizontalement sur petit écran. */
.crb-inbox__filters {
  display: flex;
  align-items: center;
  gap: var(--crb-space-2);
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  margin: 0 calc(-1 * var(--crb-space-1));
  padding: 0 var(--crb-space-1) 2px;
}
.crb-inbox__filters::-webkit-scrollbar { display: none; }
.crb-inbox__filter {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  padding: 6px 12px;
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-pill);
  background: var(--crb-bg);
  color: var(--crb-text);
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-medium);
  white-space: nowrap;
  cursor: pointer;
  transition: border-color .15s, color .15s, background .15s;
}
.crb-inbox__filter:hover { border-color: var(--crb-primary); color: var(--crb-primary); }
.crb-inbox__filter--active {
  border-color: var(--crb-primary);
  color: var(--crb-primary);
  background: var(--crb-primary-tint);
  font-weight: var(--crb-fw-semibold);
}
.crb-inbox__filter-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-surface-alt);
  color: var(--crb-text-muted);
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-bold);
  line-height: 1;
}
.crb-inbox__filter--active .crb-inbox__filter-count {
  background: var(--crb-primary);
  color: #fff;
}
.crb-inbox__filter-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--crb-success, #16a34a);
  flex-shrink: 0;
}

/* Barre de recherche : loupe à gauche, bouton « lancer » à droite. */
.crb-inbox__search {
  position: relative;
  display: flex;
  align-items: center;
}
.crb-inbox__search-icon {
  position: absolute;
  left: 12px;
  display: inline-flex;
  color: var(--crb-text-muted);
  pointer-events: none;
}
.crb-inbox__search-icon svg { width: 18px; height: 18px; }
/* Scopé sous .crb-plugin (spécificité 0,2,0) pour l'emporter sur les règles de
   thème input[type="search"]/[type="text"] (cf. .crb-form__input). Aligné sur
   l'input de recherche de la topbar (fond surface, pilule). */
.crb-plugin .crb-inbox__search-input {
  flex: 1;
  min-width: 0;
  height: 42px;
  padding: 0 48px 0 38px;
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-pill);
  background: var(--crb-surface);
  color: var(--crb-text);
  font-size: var(--crb-fs-sm);
}
.crb-plugin .crb-inbox__search-input::placeholder { color: var(--crb-text-muted); opacity: .7; }
.crb-plugin .crb-inbox__search-input:focus {
  outline: none;
  border-color: var(--crb-primary);
  background: var(--crb-surface);
  box-shadow: 0 0 0 3px var(--crb-focus-ring);
}
.crb-inbox__search-input::-webkit-search-cancel-button { cursor: pointer; }
/* Bouton « lancer la recherche ». Scopé par l'id du formulaire pour l'emporter
   sur la règle du thème qui colore en bleu les submit d'un conteneur role=search
   (spécificité [role=search] button[type=submit] > simple classe). Fond CTA corail
   cohérent avec le bouton d'envoi du chat (.crb-chat__send). */
#crb-inbox-search .crb-inbox__search-btn {
  position: absolute;
  right: 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px; height: 34px;
  flex-shrink: 0;
  border: none;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-cta-bg);
  color: #fff;
  box-shadow: var(--crb-cta-shadow);
  cursor: pointer;
  transition: transform var(--crb-dur-fast, .12s) var(--crb-ease, ease), box-shadow var(--crb-transition);
}
#crb-inbox-search .crb-inbox__search-btn:hover { box-shadow: var(--crb-shadow-md); }
#crb-inbox-search .crb-inbox__search-btn:active { transform: scale(.92); }
#crb-inbox-search .crb-inbox__search-btn svg { width: 18px; height: 18px; }

/* Liste : seule zone défilante de la colonne. */
.crb-inbox__list { list-style: none; margin: 0; padding: 0; flex: 1; overflow-y: auto; }
.crb-inbox__item {
  display: flex;
  align-items: center;
  position: relative;
  border-bottom: 1px solid var(--crb-border-soft);
}
.crb-inbox__item[hidden] { display: none; }
.crb-inbox__item--active { background: var(--crb-primary-tint); }
.crb-inbox__item--pinned { background: var(--crb-surface-alt); }
.crb-inbox__item--pinned.crb-inbox__item--active { background: var(--crb-primary-tint); }
.crb-inbox__link {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--crb-space-3);
  padding: var(--crb-space-3) var(--crb-space-4);
  text-decoration: none;
  color: var(--crb-text);
  min-height: var(--crb-touch-min);
  transition: background var(--crb-transition);
}
.crb-inbox__link:hover { background: var(--crb-bg-hover); }
.crb-inbox__avatar {
  position: relative;
  width: 48px; height: 48px;
  border-radius: var(--crb-radius-pill);
  flex-shrink: 0;
  background: var(--crb-surface-alt);
}
.crb-inbox__avatar .crb-avatar { overflow: hidden; }
.crb-avatar { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: inherit; }
/* Pastille « en ligne » : visible uniquement si la ligne est marquée online. */
.crb-inbox__online {
  position: absolute;
  right: 1px; bottom: 1px;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--crb-success, #16a34a);
  border: 2px solid var(--crb-surface);
  display: none;
}
.crb-inbox__item[data-online="1"] .crb-inbox__online { display: block; }
.crb-inbox__info { flex: 1; min-width: 0; }
.crb-inbox__name {
  display: block;
  font-weight: var(--crb-fw-semibold);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.crb-inbox__badge {
  flex-shrink: 0;
  min-width: 20px;
  padding: 1px 7px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary);
  color: #fff;
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-bold);
  text-align: center;
}

/* État de modération de la conversation : signalé / bloqué (icônes sous le nom). */
.crb-inbox__status {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 2px;
}
.crb-inbox__status-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.crb-inbox__status-icon svg { width: 14px; height: 14px; }
.crb-inbox__status-icon--reported { color: var(--crb-primary); }
.crb-inbox__status-icon--blocked  { color: var(--crb-danger); }
.crb-inbox__item--blocked .crb-inbox__avatar { opacity: .55; }

/* Actions par ligne : épingler / favori. Discrètes au repos, révélées au survol ;
   un état actif (épinglé/favori) reste toujours visible pour signaler l'état. */
.crb-inbox__actions {
  display: flex;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
  padding-right: var(--crb-space-2);
}
.crb-inbox__action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  border: none;
  border-radius: var(--crb-radius-pill);
  background: transparent;
  color: var(--crb-text-muted);
  cursor: pointer;
  opacity: 0;
  transition: opacity .15s, color .15s, background .15s;
}
.crb-inbox__action svg { width: 18px; height: 18px; }
.crb-inbox__action:hover { background: var(--crb-bg-hover); color: var(--crb-text); }
.crb-inbox__item:hover .crb-inbox__action,
.crb-inbox__item:focus-within .crb-inbox__action { opacity: 1; }
/* États actifs : toujours visibles + colorés. */
.crb-inbox__action[aria-pressed="true"] { opacity: 1; }
.crb-inbox__action--pin[aria-pressed="true"] { color: var(--crb-primary); }
.crb-inbox__action--fav[aria-pressed="true"] { color: var(--crb-warning, #f5a623); }
/* Touch : pas de survol fiable → actions toujours visibles. */
@media (hover: none) {
  .crb-inbox__action { opacity: 1; }
}

.crb-inbox__empty,
.crb-inbox__noresults,
.crb-inbox__error {
  padding: var(--crb-space-4);
  color: var(--crb-text-muted);
  font-size: var(--crb-fs-base);
}
.crb-inbox__noresults[hidden] { display: none; }
.crb-inbox__error { display: flex; flex-direction: column; align-items: flex-start; gap: var(--crb-space-2); }

/* ── Chat : en-tête ──────────────────────────────────────────────────────── */
.crb-chat__back {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px; height: 36px;
  flex-shrink: 0;
  border-radius: var(--crb-radius-pill);
  color: var(--crb-text);
  text-decoration: none;
  transition: background var(--crb-transition);
}
.crb-chat__back:hover { background: var(--crb-bg-hover); }
.crb-chat__back svg { width: 22px; height: 22px; }
.crb-chat__avatar {
  width: 40px; height: 40px;
  border-radius: var(--crb-radius-pill);
  overflow: hidden;
  flex-shrink: 0;
  background: var(--crb-surface-alt);
}
/* Avatar + pseudo = zone cliquable vers la fiche du correspondant. Elle porte le
   `flex: 1` de l'en-tête : la pastille de présence et le bouton d'appel restent
   collés à droite, exactement comme avant l'ajout du lien. */
.crb-chat__identity {
  flex: 1;
  min-width: 0;
  display: flex; align-items: center; gap: 12px;
  margin: -4px -8px; padding: 4px 8px;
  border-radius: var(--crb-radius-pill);
  color: inherit; text-decoration: none;
  transition: background var(--crb-transition);
}
.crb-chat__identity:hover,
.crb-chat__identity:focus-visible { background: var(--crb-bg-hover); }
.crb-chat__partner {
  flex: 1;
  min-width: 0;
  display: inline-flex; align-items: center; gap: 6px;
}
/* Chevron d'affordance : la fiche est atteignable au clic sur l'en-tête. Réservé
   au mobile/tablette — au-dessus de 1024px le rail droit affiche « Voir le profil ». */
.crb-chat__identity-chevron {
  display: inline-flex; align-items: center;
  flex-shrink: 0;
  color: var(--crb-text-muted);
  transform: rotate(-90deg);   /* seul chevron du jeu d'icônes : vers le bas */
}
.crb-chat__identity-chevron svg { width: 18px; height: 18px; }
@media (min-width: 1024px) {
  .crb-chat__identity-chevron { display: none; }
}
.crb-chat__partner-name {
  min-width: 0;
  font-weight: var(--crb-fw-semibold);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* ── Chat : options de conversation (mobile) ─────────────────────────────────
   Bouton « ⋯ » + panneau déroulant qui accueille le bloc « Sécurité & confiance »
   (signaler / bloquer). Réservé au mobile/tablette : au-dessus de 1024px le bloc
   reste dans le rail droit, où app.js le remet (cf. app.js, syncChatSafetySheet).
   Le panneau s'ancre sur l'en-tête, qui est déjà positionné (sticky). */
.crb-chat__more {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px; height: 36px;
  flex-shrink: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--crb-text);
  border-radius: var(--crb-radius-pill);
  cursor: pointer;
  transition: background var(--crb-transition);
}
.crb-chat__more:hover,
.crb-chat__more[aria-expanded="true"] { background: var(--crb-bg-hover); }
.crb-chat__more svg { width: 20px; height: 20px; }
.crb-chat__sheet {
  position: absolute;
  top: calc(100% + 6px);
  right: var(--crb-space-3);
  width: min(300px, calc(100vw - 2 * var(--crb-space-4)));
  border-radius: var(--crb-radius-lg);
  /* Ombre portée du popover : la carte interne fournit fond, bordure et rayon. */
  box-shadow: var(--crb-shadow-lg);
  z-index: var(--crb-z-dropdown);
}
.crb-chat__sheet[hidden] { display: none; }
.crb-chat__sheet .crb-rail-safety { box-shadow: none; }
@media (min-width: 1024px) {
  .crb-chat__more,
  .crb-chat__sheet { display: none; }
}

.crb-chat__online-dot {
  width: 10px; height: 10px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-success);
  flex-shrink: 0;
  display: none;   /* affiché uniquement si présence confirmée (modificateur --online) */
}
.crb-chat__online-dot--online { display: inline-block; }
.crb-chat__no-messages {
  margin: auto;
  text-align: center;
  color: var(--crb-text-muted);
}

/* ── Médias dans les bulles ──────────────────────────────────────────────── */
.crb-gif,
.crb-photo-msg {
  display: block;
  max-width: 220px;
  width: 100%;
  border-radius: var(--crb-radius);
  margin: 2px 0;
}

/* ── Indicateur « en train d'écrire » ────────────────────────────────────── */
.crb-typing-indicator {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 12px 14px;
  border-radius: 18px;
  border-bottom-left-radius: 4px;
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
}
.crb-typing-indicator span {
  width: 7px; height: 7px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-text-muted);
  animation: crb-typing-bounce 1.2s infinite ease-in-out;
}
.crb-typing-indicator span:nth-child(2) { animation-delay: .18s; }
.crb-typing-indicator span:nth-child(3) { animation-delay: .36s; }
@keyframes crb-typing-bounce {
  0%, 60%, 100% { transform: translateY(0);   opacity: .4; }
  30%           { transform: translateY(-4px); opacity: 1;  }
}

/* ── Barre de saisie (form) ──────────────────────────────────────────────── */
/* Champ + outils (émoji / GIF / photo) réunis dans une « pilule » unique, le
   bouton d'envoi corail détaché à droite — façon messagerie moderne. */
.crb-chat__form {
  display: flex;
  align-items: flex-end;
  gap: var(--crb-space-2);
  /* Retrait bas = padding normal + zone sûre (encoche / barre d'accueil iOS). L'inset
     vaut 0 dans Safari avec sa barre d'outils (le viewport visible s'arrête au-dessus),
     et devient réel une fois le site ajouté à l'écran d'accueil (mode standalone, cf.
     service worker) où plus aucune chrome navigateur ne protège le bas de l'écran. */
  padding: var(--crb-space-3) var(--crb-space-3) calc(var(--crb-space-3) + env(safe-area-inset-bottom));
  border-top: 1px solid var(--crb-border);
  background: var(--crb-surface);
  position: sticky;
  bottom: 0;
}
/* Conteneur champ + outils : bordure unique qui s'illumine au focus du textarea. */
.crb-chat__field {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: flex-end;
  gap: 2px;
  padding: 4px 4px 4px 6px;
  border: 1px solid var(--crb-border);
  border-radius: 24px;
  background: var(--crb-bg);
  transition: border-color var(--crb-transition), box-shadow var(--crb-transition);
}
.crb-chat__field:focus-within {
  border-color: var(--crb-primary);
  background: var(--crb-surface);
  box-shadow: 0 0 0 3px var(--crb-primary-tint);
}
/* Scopé par l'id du formulaire : le textarea ne porte aucune bordure ni halo
   propre (c'est .crb-chat__field qui s'illumine) — on neutralise le focus ring
   bleu que le thème applique par défaut aux textarea. */
#crb-message-form .crb-chat__input {
  flex: 1;
  min-width: 0;
  /* Le thème impose « height: calc(--inputs-height * 3) » à tout textarea, ce qui
     écrase rows="1" et affiche 3 lignes au repos : on rend la main à la hauteur
     intrinsèque (1 ligne), le JS posant ensuite une hauteur inline à la frappe. */
  height: auto;
  min-height: 38px;
  max-height: 120px;
  overflow-y: auto;
  padding: 8px 6px;
  border: none;
  background: transparent;
  color: var(--crb-text);
  font-size: var(--crb-fs-md);
  line-height: 1.4;
  resize: none;
}
#crb-message-form .crb-chat__input:focus,
#crb-message-form .crb-chat__input:focus-visible {
  outline: none;
  border: none;
  box-shadow: none;
}

/* Outils : boutons ronds icône-seule, sobres au repos, corail au survol. */
.crb-chat__tools {
  display: flex;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
}
.crb-chat__tool {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px; height: 38px;
  flex-shrink: 0;
  margin: 0;
  padding: 0;
  border: none;
  border-radius: var(--crb-radius-pill);
  background: transparent;
  color: var(--crb-text-muted);
  font-size: var(--crb-fs-xs);
  font-weight: var(--crb-fw-bold);
  letter-spacing: .02em;
  cursor: pointer;
  transition: background var(--crb-transition), color var(--crb-transition);
}
.crb-chat__tool:hover { background: var(--crb-bg-hover); color: var(--crb-primary); }
.crb-chat__tool[aria-expanded="true"] { background: var(--crb-primary-tint); color: var(--crb-primary); }
/* Bouton photo indisponible (plan Free seul sans droit d'envoi) : inerte, pas d'upsell. */
.crb-chat__tool--disabled { opacity: 0.4; cursor: not-allowed; pointer-events: none; }
.crb-chat__tool--disabled:hover { background: transparent; color: var(--crb-text-muted); }
.crb-chat__tool svg { width: 22px; height: 22px; }
.crb-chat__tool--gif {
  font-size: 11px;
  line-height: 1;
  border: 1.5px solid currentColor;
  width: auto;
  padding: 0 8px;
  height: 26px;
  align-self: center;
}

/* Bouton d'envoi corail. Scopé par l'id du formulaire pour l'emporter sur la
   règle générique du thème qui colore les submit en bleu. */
#crb-message-form .crb-chat__send {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--crb-touch-min);
  height: var(--crb-touch-min);
  flex-shrink: 0;
  border: none;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-cta-bg);
  color: #fff;
  box-shadow: var(--crb-cta-shadow);
  cursor: pointer;
  transition: transform var(--crb-dur-fast) var(--crb-ease), box-shadow var(--crb-transition);
}
#crb-message-form .crb-chat__send:hover  { box-shadow: var(--crb-shadow-md); transform: translateY(-1px); }
#crb-message-form .crb-chat__send:active { transform: scale(.92); }
#crb-message-form .crb-chat__send svg { width: 20px; height: 20px; }

/* Bandeau « correspondant bloqué » + formulaire désactivé (plus d'envoi). */
.crb-chat__blocked-banner { text-align: center; }
.crb-chat__form--blocked { opacity: .55; }
.crb-chat__form--blocked .crb-chat__input,
.crb-chat__form--blocked .crb-chat__send { cursor: not-allowed; }
#crb-message-form .crb-chat__send:disabled {
  box-shadow: none;
  transform: none;
}

/* ── Sélecteur d'émojis ──────────────────────────────────────────────────── */
/* Même principe que le sélecteur de GIF : panneau flex au-dessus de la saisie.
   En absolu, clavier ouvert, l'en-tête du panneau (et donc son bouton de
   fermeture) sortait de l'écran — le picker devenait impossible à refermer. */
.crb-emoji-picker {
  flex: 0 1 auto;
  min-height: 0;
  max-height: min(300px, 50%);
  display: none;
  flex-direction: column;
  background: var(--crb-surface);
  border-top: 1px solid var(--crb-border);
  overflow: hidden;
}
.crb-emoji-picker--open { display: flex; }
.crb-emoji-picker__header {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--crb-space-2) var(--crb-space-3);
  border-bottom: 1px solid var(--crb-border);
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text-muted);
}
.crb-emoji-picker__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  border: none;
  border-radius: var(--crb-radius);
  background: transparent;
  color: var(--crb-text-muted);
  cursor: pointer;
}
.crb-emoji-picker__close:hover { background: var(--crb-bg-hover); color: var(--crb-text); }
.crb-emoji-picker__close svg { width: 18px; height: 18px; }
.crb-emoji-picker__grid {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  align-content: start;
  gap: 2px;
  padding: var(--crb-space-2);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.crb-emoji-picker__cat {
  grid-column: 1 / -1;
  padding: 6px 4px 2px;
  font-size: var(--crb-fs-2xs);
  font-weight: var(--crb-fw-bold);
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--crb-text-muted);
}
.crb-emoji-picker__item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  border: none;
  border-radius: var(--crb-radius-sm);
  background: transparent;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  transition: background var(--crb-dur-fast) var(--crb-ease), transform var(--crb-dur-fast) var(--crb-ease);
}
.crb-emoji-picker__item:hover { background: var(--crb-bg-hover); transform: scale(1.15); }

/* ── Émojis : plein écran sous 1024px, SAUF la barre de saisie ────────────
   Même sortie du flux que le sélecteur de GIF, et pour la même raison (50% de
   la hauteur du chat ne laissait qu'une ou deux rangées sur un téléphone), avec
   une différence voulue : on s'arrête au-dessus du composeur au lieu de couvrir
   l'écran entier. Un GIF part dès qu'on le touche, alors qu'on pioche plusieurs
   émojis d'affilée — masquer le champ reviendrait à écrire à l'aveugle.
   D'où `top` + `height` calculés sur la zone réellement visible plutôt qu'un
   `bottom` : clavier ouvert, le bas du viewport de MISE EN PAGE est sous le
   clavier, et le panneau se serait décalé d'autant. --crb-composer-height est
   mesurée par messaging.js (ResizeObserver) ; le repli couvre le cas où
   ResizeObserver manque, la barre faisant 64px au repos. */
@media (max-width: 1023.98px) {
  .crb-emoji-picker--open {
    position: fixed;
    top: var(--crb-vv-top, 0px);
    left: 0;
    right: 0;
    height: calc(var(--crb-vvh, 100dvh) - var(--crb-composer-height, 64px));
    max-height: none;
    z-index: var(--crb-z-modal);
    border-top: none;
  }
  /* Moins de colonnes, cibles plus grandes : la largeur entière est disponible. */
  .crb-emoji-picker--open .crb-emoji-picker__grid {
    grid-template-columns: repeat(6, 1fr);
    gap: 4px;
    padding: var(--crb-space-3);
  }
  .crb-emoji-picker--open .crb-emoji-picker__item { font-size: 28px; }
}

/* ── Sélecteur de GIF (GIPHY) ────────────────────────────────────────────── */
/* Panneau intercalé dans la colonne flex du chat, juste au-dessus de la barre de
   saisie — et non plus posé en absolu par-dessus elle. En absolu (`bottom: 64px`
   + `max-height: 320px`), la hauteur du panneau ignorait la place réellement
   disponible : clavier virtuel ouvert, le viewport visible se réduit (--crb-vvh),
   et le HAUT du panneau — donc le champ de recherche — passait sous l'en-tête de
   conversation, hors écran. En flex, le panneau partage la hauteur avec la liste
   des messages et reste toujours entièrement visible. */
.crb-gif-picker {
  flex: 0 1 auto;
  min-height: 0;
  /* Jamais plus de la moitié du chat : la conversation reste lisible derrière. */
  max-height: min(320px, 50%);
  display: none;
  flex-direction: column;
  overflow: hidden;
  background: var(--crb-surface);
  border-top: 1px solid var(--crb-border);
}
.crb-gif-picker--open { display: flex; }
.crb-gif-picker__header {
  /* `flex: none` : quand la place manque, c'est la grille qui se comprime, jamais
     la barre de recherche — elle doit rester atteignable en toutes circonstances. */
  flex: none;
  display: flex;
  gap: var(--crb-space-2);
  padding: var(--crb-space-2);
  border-bottom: 1px solid var(--crb-border);
}
.crb-gif-picker__header input {
  flex: 1;
  min-height: 38px;
  padding: 0 12px;
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius);
  background: var(--crb-bg);
  color: var(--crb-text);
}
.crb-gif-picker__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px; height: 38px;
  flex-shrink: 0;
  border: none;
  border-radius: var(--crb-radius);
  background: transparent;
  color: var(--crb-text-muted);
  cursor: pointer;
}
.crb-gif-picker__close:hover { background: var(--crb-bg-hover); color: var(--crb-text); }
.crb-gif-picker__close svg { width: 18px; height: 18px; }
.crb-gif-picker__grid {
  flex: 1;
  min-height: 0;                     /* autorise la compression sous le contenu */
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-content: start;
  gap: var(--crb-space-1);
  padding: var(--crb-space-2);
  overflow-y: auto;
  overscroll-behavior: contain;      /* le scroll ne fuit pas vers la conversation */
}
.crb-gif-picker__item {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--crb-radius-sm);
  cursor: pointer;
  transition: transform var(--crb-dur-fast) var(--crb-ease);
}
.crb-gif-picker__item:hover { transform: scale(1.04); }

/* ── GIF : plein écran sous 1024px ────────────────────────────────────────
   En panneau intégré, le sélecteur se partage la hauteur du chat (50% au plus)
   et la recherche ouvre le clavier par-dessus : il ne restait qu'une rangée de
   vignettes sur un téléphone. Sous le seuil desktop il passe donc AU-DESSUS de
   la page, en plein écran, et la conversation n'a plus rien à céder.
   Plaqué sur la zone RÉELLEMENT visible (--crb-vv-top / --crb-vvh, publiés par
   messaging.js) et non sur `inset: 0`, pour la même raison que .crb-dashboard :
   un élément `fixed` reste calé sur le viewport de MISE EN PAGE, or iOS ne le
   redimensionne pas à l'ouverture du clavier — il fait glisser la fenêtre
   visible, et la modale sortirait par le haut.
   Le picker reste un enfant de #crb-chat : aucun ancêtre ne porte de `transform`
   persistant (l'animation .crb-panel--active dure 180ms sans fill), donc rien ne
   le transforme en bloc conteneur ni ne le rogne — cf. note du bloc mobile. */
@media (max-width: 1023.98px) {
  .crb-gif-picker--open {
    position: fixed;
    top: var(--crb-vv-top, 0px);
    left: 0;
    right: 0;
    height: var(--crb-vvh, 100dvh);
    max-height: none;
    z-index: var(--crb-z-modal);
    border-top: none;
    padding-bottom: env(safe-area-inset-bottom);
  }
  .crb-gif-picker--open .crb-gif-picker__header { padding: var(--crb-space-3); }
  /* Deux colonnes : l'écran entier est disponible, autant des vignettes lisibles. */
  .crb-gif-picker--open .crb-gif-picker__grid {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--crb-space-2);
    padding: var(--crb-space-3);
  }
}

/* ── Skeletons messagerie ────────────────────────────────────────────────── */
.crb-skeleton--messages { display: flex; flex-direction: column; gap: 8px; padding: 8px 0; }
.crb-skeleton__line {
  height: 14px;
  border-radius: var(--crb-radius-sm);
  background: linear-gradient(90deg,
                var(--crb-skeleton-bg) 25%,
                var(--crb-skeleton-sheen) 50%,
                var(--crb-skeleton-bg) 75%);
  background-size: 840px 100%;
  animation: crb-shimmer 1.6s infinite var(--crb-ease);
}
.crb-skeleton__line:nth-child(1) { width: 60%; }
.crb-skeleton__line:nth-child(2) { width: 80%; align-self: flex-end; }
.crb-skeleton__line:nth-child(3) { width: 50%; }
.crb-skeleton--gif { aspect-ratio: 1; border-radius: var(--crb-radius-sm); }

/* ── Densité desktop ─────────────────────────────────────────────────────── */
@media (min-width: 600px) {
  .crb-bubble { max-width: 60%; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   E7 — FICHE PROFIL  (galerie tokenisée + lightbox composant, `profile.php`)
   Phase 3, refonte écran par écran. Styles & JS extraits du template :
   plus aucun style inline ni <script> dans `profile.php`.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Icône / libellé de bouton (jeu vectoriel cohérent, `currentColor`) ───── */
.crb-icon {
  width: var(--crb-icon-md, 20px);
  height: var(--crb-icon-md, 20px);
  flex-shrink: 0;
  display: inline-block;
  vertical-align: middle;
}
.crb-btn__label { display: inline-block; }

/* ── Galerie de la fiche profil ───────────────────────────────────────────
   Classe dédiée (≠ .crb-gallery-grid de [crb_gallery]) pour ne pas entrer en
   collision avec la grille publique. */
.crb-profile__gallery { margin-bottom: 20px; }
.crb-profile__gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
  gap: var(--crb-space-2);
}
.crb-profile__gallery-item {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: none;
  border-radius: var(--crb-radius);
  overflow: hidden;
  background: var(--crb-surface-alt);
  aspect-ratio: 1;
  cursor: zoom-in;
  transition: transform var(--crb-dur-fast) var(--crb-ease);
}
button.crb-profile__gallery-item:hover { transform: scale(1.03); }
.crb-profile__gallery-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Galerie verrouillée : le flou provient du fichier flouté généré côté PHP. */
.crb-profile__gallery-item--locked { cursor: default; }
/* thumbnails_only : vignettes en clair mais sans agrandissement — pas de zoom-in
   trompeur, les éléments ne sont pas cliquables (aucun [data-full] rendu). */
.crb-profile__gallery-grid--thumbs .crb-profile__gallery-item { cursor: default; }
.crb-profile__gallery-nudge { margin-top: var(--crb-space-2); }
.crb-profile__gallery-skeleton { aspect-ratio: 1; border-radius: var(--crb-radius); }

/* ── Lightbox (composant générique, monté par app.js, hors .crb-plugin) ────
   Sémantique `role="dialog"` + fermeture clic/Échap/bouton. z-index tokenisé. */
.crb-lightbox {
  position: fixed;
  inset: 0;
  z-index: var(--crb-z-lightbox);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  /* La photo est le sujet : le voile est franc et neutre (on veut un fond de
     projection, pas une teinte qui déteindrait sur les couleurs de l'image).
     Il se matérialise au lieu d'apparaître d'un coup. */
  background: rgba(0, 0, 0, .88);
  cursor: zoom-out;
  animation: crb-fade-in var(--crb-dur-base) var(--crb-ease-out);
}
.crb-lightbox[hidden] { display: none; }
.crb-lightbox__img {
  max-width: 92vw;
  max-height: 92vh;
  object-fit: contain;
  border-radius: var(--crb-radius-sm);
  box-shadow: var(--crb-shadow-lg);
  cursor: default;
  animation: crb-lightbox-in var(--crb-dur-base) var(--crb-ease-out);
}
.crb-lightbox__close {
  position: absolute;
  top: 16px;
  right: 16px;
  width: var(--crb-touch-min);
  height: var(--crb-touch-min);
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--crb-radius-pill);
  background: rgba(0, 0, 0, .5);
  color: #fff;
  cursor: pointer;
  transition: background var(--crb-dur-fast) var(--crb-ease);
}
.crb-lightbox__close:hover { background: rgba(0, 0, 0, .75); }
.crb-lightbox__close .crb-icon { width: 24px; height: 24px; }
body.crb-lightbox-open { overflow: hidden; }
@keyframes crb-lightbox-in {
  from { opacity: 0; transform: scale(.96); }
  to   { opacity: 1; transform: none; }
}

/* ── Demande à trois issues (enregistrer / abandonner / rester) ─────────────
   Un confirm() natif n'en offre que deux : il faudrait faire porter « rester »
   à « ne pas enregistrer », c'est-à-dire perdre la saisie sur un réflexe.
   Monté par my-account.php (#crb-unsaved), piloté par guardUnsaved().
   Même voile et même z-index que la lightbox : c'est la même couche. */
.crb-confirm {
  position: fixed;
  inset: 0;
  z-index: var(--crb-z-lightbox);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(0, 0, 0, .6);
  animation: crb-fade-in var(--crb-dur-base) var(--crb-ease-out);
}
.crb-confirm[hidden] { display: none; }
.crb-confirm__box {
  width: 100%;
  max-width: 420px;
  padding: 24px;
  border-radius: var(--crb-radius);
  background: var(--crb-surface, #fff);
  color: var(--crb-text);
  box-shadow: var(--crb-shadow-lg);
  animation: crb-lightbox-in var(--crb-dur-base) var(--crb-ease-out);
}
/* Impreza impose sa couleur aux h1-h6 : la couleur de la boîte ne descend pas
   jusqu'au titre sans cette déclaration explicite. */
.crb-confirm__title {
  margin: 0 0 8px;
  font-size: var(--crb-fs-lg);
  color: inherit;
}
.crb-confirm__text {
  margin: 0 0 20px;
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
}
/* Empilés, pas en rangée : trois libellés français (« Ne pas enregistrer »…) ne
   tiennent pas côte à côte dans 420 px — la troisième action retombait seule sur
   une ligne étirée. Empilés, l'ordre lit aussi la hiérarchie : agir, abandonner,
   revenir en arrière. */
.crb-confirm__actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   E8 — MON COMPTE  (`my-account.php`)
   Phase 3, refonte écran par écran. Tous les styles inline du template sont
   sortis ici et tokenisés (palette héritée d'Impreza, personnalité par skin) :
   composants jusqu'ici non stylés (toggle push, alertes, séparateur, sections
   RGPD, feedback de formulaire) + grilles ebooks / galerie. Onglet « Profil
   détaillé » renommé (data-tab="profile-details", plus de legacy « hobbies »).
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Input fichier visuellement masqué (déclenché par un <label> bouton) ───── */
.crb-file-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
  opacity: 0;
}

/* ── Feedback inline des formulaires (photo, galerie, profil, boost, RGPD) ─── */
.crb-form__feedback {
  display: block;
  min-height: 1.1em;
  margin-top: var(--crb-space-2);
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-medium);
  color: var(--crb-text-muted);
}

/* ── Alertes contextuelles (notifications push : non supporté / bloqué / off) ─ */
.crb-alert {
  display: flex;
  align-items: flex-start;
  gap: var(--crb-space-2);
  padding: var(--crb-space-3) var(--crb-space-4);
  border-radius: var(--crb-radius);
  font-size: var(--crb-fs-base);
  border: 1px solid transparent;
}
.crb-alert .crb-icon { width: var(--crb-icon-md); height: var(--crb-icon-md); flex-shrink: 0; }
.crb-alert--info {
  background: var(--crb-primary-tint);
  border-color: color-mix(in srgb, var(--crb-primary) 30%, var(--crb-surface));
  color: color-mix(in srgb, var(--crb-primary) 70%, #000);
}
.crb-alert--warning {
  background: var(--crb-premium-tint);
  border-color: color-mix(in srgb, var(--crb-premium) 40%, var(--crb-surface));
  color: var(--crb-premium-dark);
}
.crb-alert--danger {
  background: var(--crb-danger-tint);
  border-color: color-mix(in srgb, var(--crb-danger) 30%, var(--crb-surface));
  color: color-mix(in srgb, var(--crb-danger) 65%, #000);
}

/* ── Séparateur ───────────────────────────────────────────────────────────── */
.crb-divider {
  border: none;
  border-top: 1px solid var(--crb-border);
  margin: var(--crb-space-5) 0;
}

/* ── Toggle (interrupteur accessible — présence, notifications push) ─────────
   Sélecteurs préfixés `.crb-plugin` (spécificité 0,2,0) : Impreza impose
   `input[type=checkbox]{width:1.5em;height:1.5em;appearance:none}` (0,1,1), qui
   l'emportait sur `.crb-toggle-input` (0,1,0) et redonnait une boîte à la case
   censée être masquée. Le rail est en outre `inline-block` avec `flex:0 0 auto` :
   il conserve ses 44×26 même si le thème neutralise le flex du <label>, sinon il
   s'effondre et sa pastille blanche (absolue) se peint PAR-DESSUS le libellé. */
.crb-plugin .crb-toggle-label {
  display: inline-flex;
  align-items: center;
  gap: var(--crb-space-3);
  cursor: pointer;
  min-height: var(--crb-touch-min, 44px);
  font-size: var(--crb-fs-base);
}
/* Masquage accessible : la case reste focalisable au clavier mais n'occupe aucune
   place et ne peut pas être repeinte par le thème. */
.crb-plugin .crb-toggle-input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
  pointer-events: none;
  -webkit-appearance: none;
  appearance: none;
}
.crb-plugin .crb-toggle-track {
  position: relative;
  display: inline-block;
  flex: 0 0 auto;
  width: 44px;
  height: 26px;
  border-radius: var(--crb-radius-pill);
  background: color-mix(in srgb, var(--crb-text) 22%, var(--crb-surface));
  transition: background var(--crb-dur-base) var(--crb-ease);
}
.crb-plugin .crb-toggle-track::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: var(--crb-radius-pill);
  background: #fff;
  box-shadow: var(--crb-shadow-sm);
  transition: transform var(--crb-dur-base) var(--crb-ease);
}
.crb-plugin .crb-toggle-text { flex: 1 1 auto; min-width: 0; }
.crb-plugin .crb-toggle-input:checked + .crb-toggle-track { background: var(--crb-primary); }
.crb-plugin .crb-toggle-input:checked + .crb-toggle-track::after { transform: translateX(18px); }
.crb-plugin .crb-toggle-input:focus-visible + .crb-toggle-track {
  outline: 2px solid var(--crb-focus-ring);
  outline-offset: 2px;
}
.crb-push-status { margin-top: var(--crb-space-3); }

/* ── Notifications emails (liste d'interrupteurs, un par type) ───────────────
   Chaque ligne = un interrupteur + son explication. L'explication est alignée sur
   le libellé (et non sur le rail) : la largeur du rail plus sa gouttière, en dur,
   parce qu'aucune des deux ne dépend du contenu. La règle de séparation s'arrête
   avant la dernière ligne pour ne pas doubler le bord de la carte. */
.crb-mailprefs { margin-top: var(--crb-space-3); margin-bottom: var(--crb-space-3); }
.crb-mailprefs__row { padding: var(--crb-space-2) 0; }
.crb-mailprefs__row + .crb-mailprefs__row { border-top: 1px solid var(--crb-border); }
.crb-plugin .crb-mailprefs .crb-toggle-label { display: flex; width: 100%; }
.crb-mailprefs__desc {
  margin: 0;
  padding-left: calc(44px + var(--crb-space-3));
}

/* ── Sections RGPD (confidentialité) ──────────────────────────────────────── */
.crb-privacy-actions { display: flex; flex-direction: column; }
.crb-privacy-section h4 { margin: 0 0 var(--crb-space-2); font-size: var(--crb-fs-xl); }
.crb-privacy-section p  { margin: 0 0 var(--crb-space-3); }
.crb-privacy-section .crb-btn .crb-icon { width: var(--crb-icon-sm); height: var(--crb-icon-sm); }

/* Libellés longs (« Supprimer définitivement mon compte ») : `.crb-btn` impose
   `white-space: nowrap`, si bien que sur mobile le bouton dépassait de la carte au
   lieu de s'y adapter. Ici le texte passe à la ligne, la hauteur suit et le bouton
   reste borné à la largeur disponible. */
.crb-privacy-section .crb-btn {
  max-width: 100%;
  white-space: normal;
  text-align: left;
  height: auto;
  padding-top: var(--crb-space-2);
  padding-bottom: var(--crb-space-2);
  line-height: 1.3;
}
.crb-privacy-section .crb-btn .crb-icon { flex: 0 0 auto; }

/* ── Questionnaire de départ (suppression de compte) ──────────────────────────
   Panneau ouvert par le bouton « Supprimer mon compte », d'où part la suppression
   réelle. Teinté de la couleur d'alerte et non de la surface courante : la carte
   « Mes données personnelles » contient aussi l'export, geste anodin, et rien ne
   devait laisser croire que ces cases-là appartiennent au même registre. */
.crb-quit {
  margin-top: var(--crb-space-3);
  padding: var(--crb-space-4);
  border: 1px solid color-mix(in srgb, var(--crb-danger) 35%, var(--crb-border));
  border-radius: var(--crb-radius);
  background: color-mix(in srgb, var(--crb-danger) 4%, var(--crb-surface));
}
.crb-quit__fieldset { margin: 0; padding: 0; border: 0; }
.crb-quit__legend {
  padding: 0;
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-fw-semibold);
  letter-spacing: var(--crb-track-title);
}
.crb-plugin .crb-quit__hint { margin: var(--crb-space-1) 0 var(--crb-space-3); }

/* Une colonne tant que la place manque, deux dès qu'elle existe : ces libellés
   sont des phrases, pas des étiquettes — les serrer plus tôt les ferait tous
   passer à la ligne, et la liste se lirait moins vite qu'en une seule colonne. */
.crb-quit__options {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--crb-space-1);
  margin-bottom: var(--crb-space-4);
}
@media (min-width: 700px) {
  .crb-quit__options { grid-template-columns: 1fr 1fr; gap: var(--crb-space-1) var(--crb-space-4); }
}

.crb-quit__option {
  display: flex;
  align-items: flex-start;
  gap: var(--crb-space-2);
  min-height: var(--crb-touch-min);
  padding: var(--crb-space-2);
  border-radius: var(--crb-radius-sm);
  font-size: var(--crb-fs-base);
  line-height: var(--crb-lh-base);
  cursor: pointer;
  transition: background var(--crb-dur-fast) var(--crb-ease);
}
.crb-quit__option:hover { background: color-mix(in srgb, var(--crb-text) 5%, transparent); }
.crb-plugin .crb-quit__check {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  margin: 2px 0 0;
  accent-color: var(--crb-danger);
  cursor: pointer;
}
.crb-quit__option:focus-within {
  outline: 2px solid var(--crb-focus-ring);
  outline-offset: 1px;
}

.crb-quit__other-label {
  display: block;
  margin-bottom: var(--crb-space-2);
  font-weight: var(--crb-fw-medium);
}

/* Les deux boutons ont la même importance visuelle mais pas le même poids : le
   retour en arrière vient en second, jamais sous le pouce par défaut sur mobile. */
.crb-quit__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--crb-space-2);
  margin-top: var(--crb-space-4);
}
.crb-quit__actions .crb-btn { flex: 1 1 auto; justify-content: center; text-align: center; }
@media (min-width: 700px) {
  .crb-quit__actions .crb-btn { flex: 0 0 auto; }
}

/* ── Galerie photos éditable (onglet Profil) ──────────────────────────────── */
.crb-gallery-grid--editable {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: var(--crb-space-3);
  margin: var(--crb-space-3) 0;
}
.crb-gallery-item {
  position: relative;
  margin: 0;
  cursor: grab;
}
.crb-gallery-item.crb-gallery-item--dragging { opacity: .4; }
.crb-gallery-item__img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--crb-radius);
  display: block;
  pointer-events: none;
}
.crb-gallery-item--pending .crb-gallery-item__img { opacity: .6; }
.crb-gallery-item__badge {
  position: absolute;
  top: var(--crb-space-1);
  left: var(--crb-space-1);
  background: color-mix(in srgb, #000 65%, transparent);
  color: #fff;
  font-size: var(--crb-fs-3xs);
  font-weight: var(--crb-fw-semibold);
  padding: 2px 6px;
  border-radius: var(--crb-radius-pill);
}
.crb-gallery-item__delete {
  position: absolute;
  top: var(--crb-space-1);
  right: var(--crb-space-1);
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--crb-radius-pill);
  background: color-mix(in srgb, #000 55%, transparent);
  color: #fff;
  cursor: pointer;
  transition: background var(--crb-dur-fast) var(--crb-ease);
}
.crb-gallery-item__delete:hover { background: var(--crb-danger); }
.crb-gallery-item__delete .crb-icon { width: 14px; height: 14px; }
.crb-gallery-item__edit {
  position: absolute;
  top: var(--crb-space-1);
  right: calc(var(--crb-space-1) + 30px);
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--crb-radius-pill);
  background: color-mix(in srgb, #000 55%, transparent);
  color: #fff;
  cursor: pointer;
  transition: background var(--crb-dur-fast) var(--crb-ease);
}
.crb-gallery-item__edit:hover { background: var(--crb-primary); }
.crb-gallery-item__edit .crb-icon { width: 14px; height: 14px; }

/* ─── Photo de BANDEAU (carte « Photo de bandeau » de l'onglet Profil) ───────
   Seconde photo du membre, recadrée en 3:1 par l'éditeur d'image. L'aperçu
   reprend exactement ce rapport : ce que le membre voit ici est ce que le
   gabarit « Bandeau » affichera en haut de sa fiche (cf. BannerPhoto). */
.crb-banner-edit { margin-top: var(--crb-space-3); }
.crb-banner-edit__preview {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 1;
  border-radius: var(--crb-radius-md);
  overflow: hidden;
  background: var(--crb-surface-alt);
  border: 1px dashed var(--crb-border);
  display: flex;
  align-items: center;
  justify-content: center;
}
.crb-banner-edit__preview--clickable { cursor: pointer; }
.crb-banner-edit__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.crb-banner-edit__placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--crb-text-muted);
  opacity: .55;
}
.crb-banner-edit__placeholder .crb-icon { width: 2.4rem; height: 2.4rem; }
.crb-banner-edit__preview--clickable:hover .crb-banner-edit__placeholder { opacity: .85; }
/* Bandeau « En attente » : masqué tant que la photo n'est pas en modération —
   même mécanique (et même habillage) que la pastille de la photo de profil. */
.crb-banner-edit__moderation { display: none; }
.crb-banner-edit__preview--pending .crb-banner-edit__img { filter: grayscale(.4) brightness(.92); }
.crb-banner-edit__preview--pending .crb-banner-edit__moderation {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 5px 4px;
  background: color-mix(in srgb, var(--crb-premium-dark) 88%, transparent);
  color: #fff;
  font-size: var(--crb-fs-3xs);
  font-weight: var(--crb-fw-semibold);
}
.crb-banner-edit__moderation-icon { display: inline-flex; }
.crb-banner-edit__moderation .crb-icon,
.crb-banner-edit__moderation-icon .crb-icon { width: 13px; height: 13px; }
.crb-banner-edit .crb-photo-edit__actions { margin-top: var(--crb-space-2); }

/* ═══════════════════════════════════════════════════════════════════════════
   Éditeur d'image (modale Recadrer / Redimensionner / Rotation)
   Utilisé par l'onglet « Profil » (photo de profil + galerie). Pur canvas,
   sans dépendance externe. Le recadrage se fait dans une « scène » qui affiche
   l'image (rotation déjà appliquée) à l'échelle ; la boîte de recadrage est un
   calque positionné en pixels-scène.
   ═══════════════════════════════════════════════════════════════════════════ */
.crb-img-editor {
  position: fixed;
  inset: 0;
  z-index: var(--crb-z-lightbox);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(0, 0, 0, .8);
}
.crb-img-editor[hidden] { display: none; }
.crb-img-editor__dialog {
  display: flex;
  flex-direction: column;
  width: min(640px, 100%);
  max-height: 92vh;
  background: var(--crb-surface);
  border-radius: var(--crb-radius);
  box-shadow: var(--crb-shadow-lg);
  overflow: hidden;
  animation: crb-lightbox-in var(--crb-dur-base) var(--crb-ease-out);
}
.crb-img-editor__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--crb-border);
}
.crb-img-editor__title { margin: 0; font-size: var(--crb-fs-lg); }
.crb-img-editor__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: none;
  background: transparent;
  color: var(--crb-text-muted);
  border-radius: var(--crb-radius-pill);
  cursor: pointer;
}
.crb-img-editor__close:hover { background: var(--crb-bg-subtle, #f3f4f6); }
.crb-img-editor__close .crb-icon { width: 20px; height: 20px; }

/* Scène (zone d'affichage de l'image + recadrage) */
.crb-img-editor__stage {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  padding: 16px;
  background: repeating-conic-gradient(#e9ebee 0% 25%, #f6f7f8 0% 50%) 50% / 20px 20px;
  overflow: hidden;
  touch-action: none;
  user-select: none;
}
/* Cadre = référentiel de positionnement de la boîte de recadrage. Dimensionné
   par JS à la taille d'affichage exacte de l'image (dispW × dispH) ; la boîte
   `position:absolute` s'y rattache, ce qui aligne le rendu sur le calcul du
   pointeur (qui utilise le rect du cadre). */
.crb-img-editor__frame {
  position: relative;
  flex: 0 0 auto;
}
.crb-img-editor__canvas {
  display: block;
  width: 100%;
  height: 100%;
}
/* Boîte de recadrage (positionnée par JS en px relatifs au cadre) */
.crb-img-editor__crop {
  position: absolute;
  box-sizing: border-box;
  border: 1px solid rgba(255, 255, 255, .9);
  box-shadow: 0 0 0 100vmax rgba(0, 0, 0, .45);
  cursor: move;
  touch-action: none;
}
.crb-img-editor__handle { touch-action: none; }
.crb-img-editor__crop::before,
.crb-img-editor__crop::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  border: 0 dashed rgba(255, 255, 255, .35);
}
/* Grille tiers */
.crb-img-editor__crop::before {
  background-image:
    linear-gradient(to right, rgba(255,255,255,.3) 1px, transparent 1px),
    linear-gradient(to right, rgba(255,255,255,.3) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255,255,255,.3) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255,255,255,.3) 1px, transparent 1px);
  background-position: 33.33% 0, 66.66% 0, 0 33.33%, 0 66.66%;
  background-size: 1px 100%, 1px 100%, 100% 1px, 100% 1px;
  background-repeat: no-repeat;
}
.crb-img-editor__handle {
  position: absolute;
  width: 14px;
  height: 14px;
  background: #fff;
  border: 1px solid var(--crb-primary);
  border-radius: 2px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .4);
}
.crb-img-editor__handle[data-h="nw"] { top: -7px; left: -7px; cursor: nwse-resize; }
.crb-img-editor__handle[data-h="ne"] { top: -7px; right: -7px; cursor: nesw-resize; }
.crb-img-editor__handle[data-h="sw"] { bottom: -7px; left: -7px; cursor: nesw-resize; }
.crb-img-editor__handle[data-h="se"] { bottom: -7px; right: -7px; cursor: nwse-resize; }
.crb-img-editor__handle[data-h="n"]  { top: -7px; left: 50%; margin-left: -7px; cursor: ns-resize; }
.crb-img-editor__handle[data-h="s"]  { bottom: -7px; left: 50%; margin-left: -7px; cursor: ns-resize; }
.crb-img-editor__handle[data-h="w"]  { left: -7px; top: 50%; margin-top: -7px; cursor: ew-resize; }
.crb-img-editor__handle[data-h="e"]  { right: -7px; top: 50%; margin-top: -7px; cursor: ew-resize; }

/* Barre d'outils */
.crb-img-editor__tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 18px;
  padding: 12px 18px;
  border-top: 1px solid var(--crb-border);
  background: var(--crb-bg, #f6f7f7);
}
.crb-img-editor__tool {
  display: flex;
  align-items: center;
  gap: 8px;
}
.crb-img-editor__tool-label {
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-semibold);
  color: var(--crb-text-muted);
}
.crb-img-editor__iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--crb-border);
  background: var(--crb-surface);
  border-radius: var(--crb-radius-sm);
  cursor: pointer;
  color: var(--crb-text);
}
.crb-img-editor__iconbtn:hover { border-color: var(--crb-primary); color: var(--crb-primary); }
.crb-img-editor__iconbtn .crb-icon { width: 18px; height: 18px; }
.crb-img-editor__select {
  height: 36px;
  padding: 0 8px;
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-sm);
  background: var(--crb-surface);
  font-size: var(--crb-fs-sm);
}
.crb-img-editor__range { width: 130px; }
.crb-img-editor__size {
  font-size: var(--crb-fs-sm);
  color: var(--crb-text-muted);
  font-variant-numeric: tabular-nums;
  min-width: 86px;
}
.crb-img-editor__foot {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding: 12px 18px;
  border-top: 1px solid var(--crb-border);
}
body.crb-img-editor-open { overflow: hidden; }

/* ── Bibliothèque d'ebooks (onglet Ebooks) ────────────────────────────────── */
.crb-ebooks-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--crb-space-4);
  margin-top: var(--crb-space-3);
}
.crb-ebook-item {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius);
  overflow: hidden;
  background: var(--crb-surface);
  box-shadow: var(--crb-shadow-sm);
  transition: transform var(--crb-dur-fast) var(--crb-ease),
              box-shadow var(--crb-dur-fast) var(--crb-ease);
}
.crb-ebook-item:hover { transform: translateY(-2px); box-shadow: var(--crb-shadow-md); }
.crb-ebook-item__cover {
  width: 100%;
  height: 160px;
  object-fit: cover;
  display: block;
}
.crb-ebook-item__cover-placeholder {
  width: 100%;
  height: 160px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--crb-surface-alt);
  color: var(--crb-text-muted);
}
.crb-ebook-item__cover-placeholder .crb-icon { width: 40px; height: 40px; }
.crb-ebook-item__body {
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-2);
  padding: var(--crb-space-3);
  flex: 1;
}
.crb-ebook-item__desc { flex: 1; }
.crb-ebook-item__price { font-weight: var(--crb-fw-bold); }
.crb-ebook-item .crb-btn .crb-icon { width: var(--crb-icon-sm); height: var(--crb-icon-sm); }

/* ── Densité desktop ──────────────────────────────────────────────────────── */
@media (min-width: 768px) {
  /*.crb-my-account { padding: var(--crb-space-5) var(--crb-space-4); }*/
}

/* ═══════════════════════════════════════════════════════════════════════════
   PHASE 5 — LARGEUR & MISE EN PAGE DESKTOP
   Problème corrigé : la refonte mobile-first verrouillait des colonnes en
   largeur « téléphone » (profil 640px, compte 700px, grilles 4 col) qui
   flottaient dans le vide sur grand écran (effet « étriqué »). Ici on élargit
   les conteneurs et on passe profil + compte en VRAIE mise en page 2 colonnes
   à partir de ≥1024px. Mobile (<1024) strictement inchangé.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─── MON COMPTE : rail d'onglets vertical à gauche ─────────────────────────── */
@media (min-width: 1024px) {
  .crb-my-account {
    max-width: 1400px;
    display: grid;
    grid-template-columns: 220px minmax(0, 1fr);
    grid-template-rows: auto auto;
    column-gap: var(--crb-space-6);
    align-items: start;
  }
  .crb-account-header { grid-column: 1 / -1; }

  /* La barre d'onglets devient un rail vertical collant. */
  .crb-account-tabs {
    grid-column: 1;
    grid-row: 2;
    flex-direction: column;
    align-items: stretch;
    border-bottom: none;
    overflow: visible;
    gap: 2px;
    margin-bottom: 0;
    position: sticky;
    top: var(--crb-topbar-clearance);
  }
  .crb-account-tab {
    text-align: left;
    border-bottom: none;
    border-left: 3px solid transparent;
    border-radius: var(--crb-radius-sm);
    padding: 10px 14px;
  }
  .crb-account-tab:hover { background: var(--crb-bg-hover); color: var(--crb-text); }
  .crb-account-tab--active {
    border-bottom-color: transparent;
    border-left-color: var(--crb-primary);
    background: var(--crb-primary-tint);
  }

  /* Tous les panneaux partagent la cellule de droite ; seul l'actif (sans
     [hidden]) génère une boîte, donc pas de chevauchement. */
  .crb-account-panel {
    grid-column: 2;
    grid-row: 2;
    align-self: start;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   GABARITS DE FICHE PROFIL (Personnalisation → Templates → Fiche profil)

   Trois MISES EN PAGE réellement distinctes, mobile ET desktop — la sélection
   des blocs affichés (zones) est un réglage indépendant, cumulable avec chacune.

     .crb-profile--full     « Immersif » : photo plein cadre, identité en
                            surimpression. Desktop : 2 colonnes, photo collante.
     .crb-profile--compact  « Bandeau »  : photo panoramique + médaillon,
                            identité sur la surface. Desktop : une colonne large,
                            actions en regard du pseudo, catégories sur 2 colonnes.
     .crb-profile--minimal  « Fiche »    : pas de grande photo, vignette + texte.
                            Desktop : rail d'identité collant + contenu large.
   ═════════════════════════════════════════════════════════════════════════ */

/* ─── « Bandeau » (compact) : mobile ─────────────────────────────────────────
   Le bandeau est volontairement bas (16/9, borné à 32vh) : contrairement à
   l'immersif, le premier écran doit montrer le pseudo ET le début du contenu. */
.crb-profile--compact .crb-profile__header--banner {
  aspect-ratio: 16 / 9;
  max-height: 32vh;
}
/* La barre d'identité remonte sur le bandeau : le médaillon le chevauche, et le
   texte, qui le suit en colonne, retombe entièrement sous la photo. */
.crb-profile--compact .crb-profile__ident--bar {
  flex-direction: column;
  align-items: center;
  text-align: center;
  margin-top: -48px;
  padding-bottom: var(--crb-space-2);
  position: relative;
  z-index: 1;
}
.crb-profile--compact .crb-profile__name { justify-content: center; flex-wrap: wrap; }
/* Identité centrée sous le médaillon : la ligne de goûts suit le pseudo. */
.crb-profile--compact .crb-profile__badges { justify-content: center; }

/* ─── « Fiche » (minimal) : mobile ───────────────────────────────────────────
   Aucun hero : la fiche s'ouvre sur l'identité en une ligne, le contenu est
   lisible sans faire défiler. */
.crb-profile--minimal .crb-profile__ident--row {
  padding: var(--crb-space-4);
  border-bottom: 1px solid var(--crb-border);
}
.crb-profile--minimal .crb-profile__ident .crb-profile__name { font-size: var(--crb-fs-xl); }
.crb-profile--minimal .crb-profile__blur-nudge-flat { margin: var(--crb-space-4) 20px 0; }

/* ─── FICHE PROFIL ≥ 1024 px ─────────────────────────────────────────────── */
@media (min-width: 1024px) {

  /* ── « Immersif » : 2 colonnes (photo collante | infos) ── */
  .crb-profile--full {
    max-width: 1100px;
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    grid-template-rows: auto 1fr;
    column-gap: var(--crb-space-6);
    align-items: start;
    /* On dissout la carte unique : chaque colonne devient sa propre surface. */
    background: transparent;
    box-shadow: none;
    overflow: visible;
    padding-bottom: var(--crb-space-6);
  }

  /* Colonne gauche : la photo + identité, collante au scroll. */
  .crb-profile--full .crb-profile__header {
    grid-column: 1;
    grid-row: 1 / span 2;
    position: sticky;
    top: var(--crb-topbar-clearance);
    aspect-ratio: 4 / 5;                 /* annule le 16/9 du ≥600px */
    border-radius: var(--crb-radius-lg);
    box-shadow: var(--crb-shadow-lg);
  }

  /* Colonne droite : le contenu, en carte autonome. */
  .crb-profile--full .crb-profile__body {
    grid-column: 2;
    grid-row: 1;
    background: var(--crb-surface);
    border-radius: var(--crb-radius-lg);
    box-shadow: var(--crb-shadow);
    padding: var(--crb-space-6);
  }

  /* Le CTA n'est plus une barre fixe pleine largeur : il devient une carte
     collante en bas de la colonne droite. */
  .crb-profile--full .crb-profile__cta-sticky {
    grid-column: 2;
    grid-row: 2;
    position: sticky;
    bottom: var(--crb-space-4);
    left: auto; right: auto;
    margin-top: var(--crb-space-4);
    border-radius: var(--crb-radius-lg);
    border: 1px solid var(--crb-border);
    box-shadow: var(--crb-shadow-md);
    padding: var(--crb-space-4);
  }

  /* ── « Bandeau » : une seule colonne large, actions en regard du pseudo ──
     La carte reste d'un seul tenant : le médaillon chevauche le bandeau, ce qui
     interdit de dissoudre la surface comme en immersif. Les actions quittent le
     pied de page pour se poser à côté de l'identité — sur une fiche large, une
     barre pleine largeur en bas de page tombe hors du champ de lecture. */
  .crb-profile--compact {
    max-width: 900px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "banner banner"
      "ident  cta"
      "body   body";
    padding-bottom: 0;                   /* plus de barre fixe à compenser */
  }
  .crb-profile--compact .crb-profile__header--banner {
    grid-area: banner;
    aspect-ratio: 3 / 1;
    max-height: none;
  }
  .crb-profile--compact .crb-profile__ident--bar {
    grid-area: ident;
    flex-direction: row;
    align-items: flex-end;               /* le texte retombe sous le bandeau */
    text-align: left;
    margin-top: -56px;
    padding: 0 var(--crb-space-6) var(--crb-space-4);
  }
  .crb-profile--compact .crb-profile__avatar { width: 132px; height: 132px; }
  .crb-profile--compact .crb-profile__name { justify-content: flex-start; }
  .crb-profile--compact .crb-profile__badges { justify-content: flex-start; }
  .crb-profile--compact .crb-profile__body {
    grid-area: body;
    padding: var(--crb-space-6);
  }
  .crb-profile--compact .crb-profile__cta-sticky {
    grid-area: cta;
    position: static;
    align-self: end;
    background: transparent;
    border-top: 0;
    box-shadow: none;
    padding: 0 var(--crb-space-6) var(--crb-space-4);
  }
  .crb-profile--compact .crb-profile__cta-btn { flex: 0 0 auto; }
  /* Les catégories d'attributs passent sur deux colonnes : sur 900 px, une
     colonne unique laisserait la moitié de la fiche vide. */
  .crb-profile--compact .crb-profile__attributes {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--crb-space-3);
    align-items: start;
  }
  .crb-profile--compact .crb-profile__cat + .crb-profile__cat { margin-top: 0; }

  /* ── « Fiche » : rail d'identité collant + contenu large ──
     L'inverse de l'immersif : la photo se réduit à une carte d'identité étroite
     et c'est le TEXTE qui prend la largeur. */
  /* Le rail est UN SEUL élément collant (identité + incitation + actions).
     Deux éléments collants distincts dans cette colonne ne pouvaient pas
     fonctionner : chacun n'avait pour marge de manœuvre que sa propre piste de
     grille, haute comme son contenu, si bien que la barre d'actions restait
     accrochée au flux et finissait par recouvrir la carte d'identité épinglée. */
  .crb-profile--minimal {
    max-width: 1000px;
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    column-gap: var(--crb-space-6);
    align-items: start;
    background: transparent;
    box-shadow: none;
    overflow: visible;
    padding-bottom: var(--crb-space-6);
  }
  .crb-profile--minimal .crb-profile__rail {
    grid-column: 1;
    grid-row: 1;
    position: sticky;
    top: var(--crb-topbar-clearance);
    /* Profil très long + petit écran : le rail défile en interne plutôt que de
       laisser les boutons hors du champ. */
    max-height: calc(100vh - var(--crb-topbar-clearance) - var(--crb-space-6));
    overflow-y: auto;
  }
  .crb-profile--minimal .crb-profile__ident--row {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--crb-space-3);
    padding: var(--crb-space-5);
    border-bottom: 0;
    background: var(--crb-surface);
    border-radius: var(--crb-radius-lg);
    box-shadow: var(--crb-shadow);
  }
  .crb-profile--minimal .crb-profile__avatar--square {
    width: 100%;
    height: auto;
    aspect-ratio: 1;
  }
  .crb-profile--minimal .crb-profile__name { justify-content: center; flex-wrap: wrap; }
  .crb-profile--minimal .crb-profile__badges { justify-content: center; }
  .crb-profile--minimal .crb-profile__blur-nudge-flat { margin: var(--crb-space-4) 0 0; }
  .crb-profile--minimal .crb-profile__body {
    grid-column: 2;
    grid-row: 1;
    background: var(--crb-surface);
    border-radius: var(--crb-radius-lg);
    box-shadow: var(--crb-shadow);
    padding: var(--crb-space-6);
  }
  /* Actions empilées dans le rail, sous la carte d'identité : elles suivent le
     bloc collant, elles ne collent plus pour leur propre compte. */
  .crb-profile--minimal .crb-profile__cta-sticky {
    position: static;
    flex-direction: column;
    margin-top: var(--crb-space-4);
    border-radius: var(--crb-radius-lg);
    border: 1px solid var(--crb-border);
    border-top: 1px solid var(--crb-border);
    box-shadow: var(--crb-shadow-md);
    padding: var(--crb-space-4);
  }
}
/* ─── GRILLES & GALERIE : profiter de la largeur sur très grand écran ───────── */
@media (min-width: 1280px) {
  .crb-members-grid          { grid-template-columns: repeat(3, 1fr); gap: var(--crb-space-4); }
  .crb-members-grid--compact { grid-template-columns: repeat(6, 1fr); }
  .crb-gallery-wrap          { max-width: 1200px; }
}

/* ─── SWIPE : carte centrée + compagnon (colonne droite du shell, Phase B) ─────
   Le compagnon (matchs / qui m'a liké) a migré du panneau swipe vers la colonne
   droite contextuelle (.crb-shell__rail). La vue swipe redevient mono-colonne. */

.crb-swipe-layout__main { min-width: 0; }

@media (min-width: 1024px) {
  /* Carte swipe centrée dans la colonne principale (plus de grille 2-col interne). */
  .crb-swipe-layout__main .crb-swipe-app {
    max-width: 460px;
    margin-inline: auto;
  }
}

/* Compagnon : pile verticale de cartes. Sa visibilité (et sa sticky) est gérée
   par le rail droit (.crb-shell__rail), masqué <1024px. */
.crb-swipe-companion {
  display: flex;
  flex-direction: column;
  gap: var(--crb-space-4);
}

/* Groupes de widgets contextuels du rail : un seul visible selon le panneau actif
   (attribut [hidden] posé par activateTab dans app.js). */
.crb-rail-widgets[hidden] { display: none; }

/* Cartes du compagnon */
.crb-companion-card {
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
  padding: var(--crb-space-4);
}
.crb-companion__title {
  margin: 0 0 var(--crb-space-3);
  font-size: var(--crb-fs-sm);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--crb-text-muted);
  font-weight: var(--crb-fw-bold);
}
.crb-companion__note { margin: 0; font-size: var(--crb-fs-sm); color: var(--crb-text-muted); }
.crb-companion__avatars { display: flex; flex-wrap: wrap; gap: var(--crb-space-2); }
.crb-companion-avatar {
  width: 48px; height: 48px;
  border-radius: var(--crb-radius-pill);
  background-size: cover; background-position: center;
  background-color: var(--crb-surface-alt);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--crb-text-muted); font-weight: var(--crb-fw-bold);
  text-decoration: none;
  box-shadow: 0 0 0 1px var(--crb-border) inset;
  transition: transform var(--crb-dur-fast) var(--crb-ease);
}
.crb-companion-avatar:hover { transform: scale(1.08); }
.crb-companion-avatar--empty { font-size: var(--crb-fs-lg); }
.crb-companion__skeleton { width: 48px; height: 48px; border-radius: var(--crb-radius-pill); }

/* Encart « profil en cours » — réduit au seul bouton « Voir le profil » */
.crb-companion-current__link { width: 100%; justify-content: center; }

/* ─────────────────────────────────────────────────────────────────────────
   Rail droit de l'ACCUEIL — « Mon activité », « Membres premium », « À la une »
   (cf. templates/frontend/partials/home-rail.php). Même recette de surface que
   .crb-companion-card / .crb-chat-about : les trois rails du shell partagent le
   langage visuel, chacun garde son bloc de classes.
   Visible ≥1024px seulement (la colonne elle-même est masquée en dessous).
   ───────────────────────────────────────────────────────────────────────── */
.crb-home-widget {
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-edge-highlight), var(--crb-shadow-sm);
  padding: var(--crb-space-4);
}
.crb-home-widget__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--crb-space-2);
  margin-bottom: var(--crb-space-3);
}
/* Une suite de capitales n'a ni jambage ni hampe pour séparer ses lettres : c'est
   l'approche qui fait tout le travail de lisibilité. Valeur tokenisée pour que les
   trois eyebrows du produit (rail, spotlight, activité) restent identiques. */
.crb-home-widget__title {
  margin: 0;
  font-size: var(--crb-fs-sm);
  text-transform: uppercase;
  letter-spacing: var(--crb-track-label);
  color: var(--crb-text-muted);
  font-weight: var(--crb-fw-bold);
}
/* Sert autant à un <a> (Mes stats) qu'à un <button> SPA (Voir tout) : neutraliser
   l'apparence native du bouton pour que les deux soient indiscernables. */
.crb-home-widget__link {
  flex: none;
  background: none; border: none; padding: 0;
  font: inherit; cursor: pointer;
  font-size: var(--crb-fs-xs);
  color: var(--crb-primary);
  text-decoration: none;
}
.crb-home-widget__link:hover { text-decoration: underline; }
.crb-home-widget__note {
  margin: calc(var(--crb-space-3) * -1 + 2px) 0 var(--crb-space-3);
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
}

/* ── Mon activité ─────────────────────────────────────────────────────────
   Une colonne par compteur : à 320px de rail, trois colonnes écraseraient les
   nombres à 4 chiffres. */
.crb-home-activity__grid {
  display: grid;
  gap: var(--crb-space-3);
}
.crb-home-activity__item {
  display: grid;
  grid-template-columns: 32px 1fr;
  grid-template-areas:
    "icon value"
    "icon label"
    "icon delta";
  align-items: center;
  column-gap: var(--crb-space-3);
}
.crb-home-activity__icon {
  grid-area: icon;
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-surface-alt);
  color: var(--crb-text-muted);
}
.crb-home-activity__icon svg { width: 17px; height: 17px; }
.crb-home-activity__icon--likes   { background: var(--crb-primary-tint); color: var(--crb-primary); }
.crb-home-activity__icon--matches { background: var(--crb-primary-tint); color: var(--crb-primary); }
/* `tabular-nums` : les chiffres prennent tous la même chasse. Sans lui, trois
   compteurs alignés se décalent dès qu'un « 1 » remplace un « 8 », et une valeur
   qui s'incrémente en direct fait tressauter sa propre ligne. C'est le détail
   qu'on ne remarque que lorsqu'il manque. */
.crb-home-activity__value {
  grid-area: value;
  font-size: var(--crb-fs-lg);
  font-weight: var(--crb-fw-bold);
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--crb-track-title);
}
.crb-home-activity__label {
  grid-area: label;
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
}
.crb-home-activity__delta {
  grid-area: delta;
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
}
.crb-home-activity__delta--up { color: var(--crb-success); font-weight: var(--crb-fw-bold); }

/* ── À la une (ebook ou carte promo) ──────────────────────────────────────── */
.crb-home-feature__cover {
  display: block;
  width: 100%;
  max-height: 140px;
  object-fit: cover;
  border-radius: var(--crb-radius);
  margin-bottom: var(--crb-space-3);
}
.crb-home-feature__title {
  margin: 0 0 4px;
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-bold);
}
.crb-home-feature__text {
  margin: 0 0 var(--crb-space-3);
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
}
.crb-home-feature__cta { width: 100%; justify-content: center; }

/* ─────────────────────────────────────────────────────────────────────────
   ACCUEIL — modules propres au panneau (hors rail droit)

   Deux familles, à ne pas confondre :

   1. `.crb-spotlight` — SPOTLIGHT PREMIUM, rendu à TOUTES les largeurs
      (templates/frontend/partials/home-spotlight.php). Il a remplacé en v3.27.0 la
      carte verticale du rail droit : plafonnée à six profils dans 320px, et
      purement absente sous 1024px puisque le rail n'y existe pas. Le carrousel
      règle les deux à la fois. Une seule instance dans le DOM : aucun doublon
      possible avec le rail, qui ne porte plus ce module.

   2. `.crb-home-mobile` — REPRISES MOBILES des deux modules restés dans le rail
      (home-{activity,feature}-mobile.php) : activité en rangée de trois compteurs,
      « à la une » en bande compacte. Celles-là sont bien un second rendu, et
      s'effacent au seuil exact où le rail apparaît — les deux ne coexistent jamais.
   ───────────────────────────────────────────────────────────────────────── */
.crb-home-mobile { margin-bottom: var(--crb-space-5); }

@media (min-width: 1024px) {
  /* Le rail droit prend le relais — masquer, pas seulement dépiler : deux fois la
     même information sur la même page se contrediraient au premier décalage. */
  .crb-home-mobile { display: none !important; }
}

/* En-tête commun aux deux modules à titre (spotlight, activité) : même graisse et
   même casse que .crb-section-title, pour que les sections de l'accueil se lisent
   comme une seule liste et non comme des cartes rapportées. */
.crb-spotlight__head,
.crb-mactivity__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--crb-space-2);
  margin-bottom: var(--crb-space-2);
}
.crb-spotlight__title,
.crb-mactivity__title {
  margin: 0;
  font-size: var(--crb-fs-sm);
  text-transform: uppercase;
  letter-spacing: var(--crb-track-label);
  color: var(--crb-text-muted);
  font-weight: var(--crb-fw-bold);
}
/* <button> (SPA) et <a> (lien compte) doivent être indiscernables. */
.crb-spotlight__link,
.crb-mactivity__link {
  flex: none;
  background: none; border: none; padding: 0;
  font: inherit; cursor: pointer;
  font-size: var(--crb-fs-xs);
  color: var(--crb-primary);
  text-decoration: none;
}
.crb-spotlight__link:hover,
.crb-mactivity__link:hover { text-decoration: underline; }

/* ── Membres premium : carrousel horizontal ───────────────────────────────── */
/* Retrait volontairement plus court que le rythme habituel des sections (space-5) :
   la piste ne finit pas sur un bord de carte mais sur une ligne de méta minuscule,
   au-dessus de laquelle le blanc du hero remonte encore — l'écart PERÇU est plus
   grand que l'écart mesuré, et « Bonjour » décrochait du carrousel au lieu de le
   suivre. Le retrait bas de la piste s'ajoute à celui-ci. */
.crb-spotlight { margin-bottom: var(--crb-space-3); }
.crb-spotlight__note {
  margin: 0 0 var(--crb-space-3);
  font-size: var(--crb-fs-xs);
  color: var(--crb-text-muted);
}
/* Contexte de positionnement des flèches, qui débordent la piste. */
.crb-spotlight__viewport { position: relative; }
/* Mobile : `.crb-panel__inner` pose la DERNIÈRE gouttière (16px, celle de
   .crb-dashboard__content est annulée sous 1024px) ; la piste la déborde puis la
   restitue en padding, pour que les vignettes filent jusqu'au bord de l'écran —
   une vignette coupée par le bord est ce qui dit « ça défile ». La valeur est
   reprise telle quelle de .crb-panel__inner ; les deux doivent bouger ensemble.
   Desktop : gouttière remise à 0 plus bas — la piste s'aligne alors sur le hero,
   et déborder irait mordre la colonne de droite. */
.crb-spotlight__track {
  --crb-spotlight-gutter: 16px;
  list-style: none;
  margin: 0 calc(var(--crb-spotlight-gutter) * -1);
  /* `overflow-x: auto` fait basculer l'axe vertical en `auto` lui aussi : ces deux
     retraits sont ce qui empêche l'anneau primaire et le badge de se faire rogner
     en haut et en bas. Les réduire encore les couperait. */
  padding: 3px var(--crb-spotlight-gutter) 4px;
  display: flex;
  gap: var(--crb-space-3);
  overflow-x: auto;
  overscroll-behavior-x: contain;   /* pas de navigation « retour » par swipe */
  scroll-snap-type: x proximity;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.crb-spotlight__track::-webkit-scrollbar { display: none; }
.crb-spotlight__track:focus-visible { outline: 2px solid var(--crb-primary); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .crb-spotlight__track { scroll-behavior: auto; }
}
/* Largeur fixe : c'est elle qui décide du nombre de vignettes entières visibles
   (≈3,5 sur 360px) — donc de l'amorce de la suivante, seule promesse qu'il y en a
   d'autres derrière. */
.crb-spotlight__cell {
  flex: 0 0 auto;
  width: 92px;
  scroll-snap-align: start;
}
.crb-spotlight__item {
  display: flex; flex-direction: column; align-items: center;
  gap: 2px;
  text-decoration: none;
  color: inherit;
}
.crb-spotlight__avatar {
  position: relative;
  width: 68px; height: 68px;
  border-radius: var(--crb-radius-pill);
  background-size: cover; background-position: center;
  background-color: var(--crb-surface-alt);
  /* Anneau primaire : marque « premium » lisible même sans le badge. Posé en
     box-shadow pour ne pas entamer les 68px de photo. */
  box-shadow: 0 0 0 2px var(--crb-surface), 0 0 0 4px var(--crb-primary-tint);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--crb-text-muted);
  font-size: var(--crb-fs-xl);
  font-weight: var(--crb-fw-bold);
  margin-bottom: var(--crb-space-1);
  transition: transform var(--crb-dur-fast) var(--crb-ease);
}
.crb-spotlight__item:hover .crb-spotlight__avatar { transform: scale(1.06); }
/* Vignettes du carrousel premium : elles se parcourent au pouce sur mobile, donc
   l'enfoncement est le SEUL retour visuel disponible (il n'y a pas de survol). */
.crb-spotlight__item:active .crb-spotlight__avatar {
  transform: scale(var(--crb-press-scale));
  transition: transform var(--crb-dur-fast) var(--crb-ease-exit);
}
.crb-spotlight__badge {
  position: absolute;
  right: -2px; bottom: -2px;
  width: 20px; height: 20px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary);
  color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  box-shadow: 0 0 0 2px var(--crb-surface);
}
.crb-spotlight__badge svg { width: 11px; height: 11px; }
/* Une seule ligne chacun : sur 92px, un pseudo long qui passe à la ligne
   décalerait verticalement toute la rangée. */
.crb-spotlight__name,
.crb-spotlight__meta {
  max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  text-align: center;
}
.crb-spotlight__name { font-size: var(--crb-fs-2xs); font-weight: var(--crb-fw-bold); }
.crb-spotlight__meta { font-size: var(--crb-fs-3xs); color: var(--crb-text-muted); }

/* Flèches de défilement : masquées par défaut (au doigt on balaie), révélées en
   desktop par app.js seulement si la piste déborde. `[hidden]` doit gagner sur le
   `display:flex` de l'état desktop, d'où l'ordre et la spécificité. */
.crb-spotlight__nav { display: none; }

@media (min-width: 1024px) {
  /* Colonne large et pas de doigt : vignettes plus grandes (l'échelle mobile y
     paraissait timide au milieu du hero et des cartes de matchs), gouttière de
     débordement annulée, et flèches de défilement. */
  .crb-spotlight__track { --crb-spotlight-gutter: 0px; }
  .crb-spotlight__cell   { width: 116px; }
  .crb-spotlight__avatar { width: 88px; height: 88px; font-size: var(--crb-fs-2xl); }
  .crb-spotlight__badge  { width: 24px; height: 24px; }
  .crb-spotlight__badge svg { width: 13px; height: 13px; }
  .crb-spotlight__name { font-size: var(--crb-fs-sm); }
  .crb-spotlight__meta { font-size: var(--crb-fs-2xs); }

  .crb-spotlight__nav {
    position: absolute;
    top: 46px;                     /* centré sur l'avatar (2px de padding + 88/2), pas sur la piste */
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px;
    border: 1px solid var(--crb-border);
    border-radius: var(--crb-radius-pill);
    background: var(--crb-surface);
    box-shadow: var(--crb-shadow-sm);
    color: var(--crb-text);
    cursor: pointer;
    z-index: 1;
    transition: background var(--crb-dur-fast) var(--crb-ease);
  }
  .crb-spotlight__nav:hover { background: var(--crb-surface-alt); }
  .crb-spotlight__nav[hidden] { display: none; }
  .crb-spotlight__nav svg { width: 18px; height: 18px; }
  /* Le sprite ne fournit qu'un chevron « bas » : on le tourne. */
  .crb-spotlight__nav--prev { left: -10px;  transform: translateY(-50%) rotate(90deg); }
  .crb-spotlight__nav--next { right: -10px; transform: translateY(-50%) rotate(-90deg); }
}

/* ── Mon activité : trois compteurs sur une rangée ────────────────────────── */
.crb-mactivity__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--crb-space-2);
}
.crb-mactivity__item {
  display: flex; flex-direction: column; align-items: center;
  gap: 2px;
  text-align: center;
  padding: var(--crb-space-3) var(--crb-space-1);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
}
.crb-mactivity__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-surface-alt);
  color: var(--crb-text-muted);
  margin-bottom: var(--crb-space-1);
}
.crb-mactivity__icon svg { width: 15px; height: 15px; }
.crb-mactivity__icon--likes   { background: var(--crb-primary-tint); color: var(--crb-primary); }
.crb-mactivity__icon--matches { background: var(--crb-primary-tint); color: var(--crb-primary); }
.crb-mactivity__value {
  font-size: var(--crb-fs-2xl);
  font-weight: var(--crb-fw-bold);
  line-height: 1.1;
}
/* Le libellé est le seul texte qui peut légitimement passer sur deux lignes
   (« Visites reçues » ne tient pas sur un tiers de 360px). */
.crb-mactivity__label {
  font-size: var(--crb-fs-3xs);
  color: var(--crb-text-muted);
  line-height: 1.25;
}
.crb-mactivity__delta {
  font-size: var(--crb-fs-3xs);
  color: var(--crb-text-muted);
  white-space: nowrap;
}
.crb-mactivity__delta--up { color: var(--crb-success); font-weight: var(--crb-fw-bold); }

/* ── À la une : bande cliquable compacte ──────────────────────────────────── */
.crb-mfeature {
  /* La grille de matchs qui la précède n'a pas de marge basse : sans ce retrait,
     la bande se colle à la dernière carte et se lit comme une carte de plus. */
  margin-top: var(--crb-space-5);
  display: flex; align-items: center;
  gap: var(--crb-space-3);
  padding: var(--crb-space-3);
  background: var(--crb-surface);
  border: 1px solid var(--crb-border);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-sm);
  text-decoration: none;
  color: inherit;
}
.crb-mfeature__cover {
  flex: none;
  width: 48px; height: 62px;
  object-fit: cover;
  border-radius: var(--crb-radius-sm);
  background: var(--crb-surface-alt);
}
.crb-mfeature__body { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.crb-mfeature__kicker {
  font-size: var(--crb-fs-3xs);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--crb-text-muted);
  font-weight: var(--crb-fw-bold);
}
/* Deux lignes maximum : au-delà, la bande cesse d'être une bande. */
.crb-mfeature__title {
  font-size: var(--crb-fs-sm);
  font-weight: var(--crb-fw-bold);
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.crb-mfeature__cta { font-size: var(--crb-fs-2xs); color: var(--crb-primary); }
.crb-mfeature__chevron {
  flex: none; margin-left: auto;
  display: inline-flex;
  color: var(--crb-text-muted);
  transform: rotate(-90deg);   /* le sprite ne fournit qu'un chevron « bas » */
}
.crb-mfeature__chevron svg { width: 18px; height: 18px; }

/* ─────────────────────────────────────────────────────────────────────────
   Chat webcam P2P (WebRTC) — bouton d'appel, modale d'appel entrant,
   fenêtre d'appel (vidéo distante plein cadre + vignette locale), bandeau d'erreur.
   ───────────────────────────────────────────────────────────────────────── */

/* Bouton « Appel vidéo » dans l'en-tête de conversation (poussé à droite). */
.crb-chat__call-btn {
  margin-left: auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  border: none; cursor: pointer;
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary-tint);
  color: var(--crb-primary);
  transition: background .15s ease, transform .15s ease;
}
.crb-chat__call-btn:hover { background: color-mix(in srgb, var(--crb-primary) 22%, var(--crb-surface)); }
.crb-chat__call-btn:active { transform: scale(.94); }
.crb-chat__call-btn svg { width: 22px; height: 22px; }

/* Boutons ronds partagés (accepter / refuser / mute / caméra / raccrocher). */
.crb-call-btn-round {
  display: inline-flex; align-items: center; justify-content: center;
  width: 56px; height: 56px;
  border: none; cursor: pointer;
  border-radius: var(--crb-radius-pill);
  background: rgba(255, 255, 255, .18);
  color: #fff;
  transition: background .15s ease, transform .15s ease;
}
.crb-call-btn-round:hover { background: rgba(255, 255, 255, .3); }
.crb-call-btn-round:active { transform: scale(.94); }
.crb-call-btn-round svg { width: 26px; height: 26px; }
.crb-call-btn-round--accept  { background: var(--crb-success, #2e9e5b); }
.crb-call-btn-round--accept:hover  { background: color-mix(in srgb, var(--crb-success, #2e9e5b) 85%, #000); }
.crb-call-btn-round--decline { background: var(--crb-danger, #d63638); }
.crb-call-btn-round--decline:hover { background: color-mix(in srgb, var(--crb-danger, #d63638) 85%, #000); }
.crb-call-btn-round--off { background: rgba(255, 255, 255, .42); color: var(--crb-text, #111); }

/* ── Modale d'appel entrant ───────────────────────────────────────────── */
.crb-call-incoming {
  position: fixed; inset: 0; z-index: var(--crb-z-modal, 1000);
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, .55);
  padding: var(--crb-space-4, 16px);
}
.crb-call-incoming[hidden] { display: none; }
.crb-call-incoming__card {
  background: var(--crb-surface);
  border-radius: var(--crb-radius-lg);
  box-shadow: var(--crb-shadow-lg, 0 12px 40px rgba(0,0,0,.25));
  padding: 28px 24px;
  text-align: center;
  max-width: 320px; width: 100%;
  animation: crb-call-pop .2s ease;
}
@keyframes crb-call-pop { from { transform: scale(.92); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.crb-call-incoming__avatar {
  width: 96px; height: 96px; border-radius: var(--crb-radius-pill);
  object-fit: cover; background: var(--crb-surface-alt);
  margin: 0 auto 12px;
}
.crb-call-incoming__name { margin: 0; font-weight: var(--crb-fw-bold, 700); font-size: var(--crb-fs-lg, 18px); }
.crb-call-incoming__sub  { margin: 4px 0 20px; color: var(--crb-text-muted); font-size: var(--crb-fs-sm, 14px); }
.crb-call-incoming__actions { display: flex; gap: 32px; justify-content: center; }

/* ── Fenêtre d'appel ──────────────────────────────────────────────────── */
.crb-call-window {
  position: fixed; inset: 0; z-index: var(--crb-z-modal, 1000);
  background: #0c0c0f;
}
.crb-call-window[hidden] { display: none; }
.crb-call-window__remote {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; background: #0c0c0f;
}
.crb-call-window__local {
  position: absolute; right: 16px; top: 16px;
  width: 28vw; max-width: 180px; aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: var(--crb-radius);
  box-shadow: 0 4px 16px rgba(0, 0, 0, .4);
  background: #1a1a1f;
  transform: scaleX(-1); /* miroir, comme l'aperçu d'une webcam */
}
.crb-call-window__status {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  color: #fff; font-size: var(--crb-fs-lg, 18px);
  background: rgba(0, 0, 0, .4); padding: 8px 18px; border-radius: var(--crb-radius-pill);
}
.crb-call-window__controls {
  position: absolute; left: 0; right: 0; bottom: 32px;
  display: flex; gap: 24px; justify-content: center;
}

/* ── Bandeau d'erreur d'appel ─────────────────────────────────────────── */
.crb-call-error {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
  z-index: calc(var(--crb-z-modal, 1000) + 1);
  max-width: min(440px, calc(100vw - 32px));
  background: var(--crb-danger, #d63638); color: #fff;
  padding: 12px 18px; border-radius: var(--crb-radius);
  box-shadow: var(--crb-shadow-lg, 0 12px 40px rgba(0,0,0,.25));
  font-size: var(--crb-fs-sm, 14px); line-height: 1.4;
}
.crb-call-error[hidden] { display: none; }

@media (max-width: 600px) {
  .crb-call-window__local { width: 34vw; }
  .crb-call-incoming__actions { gap: 24px; }
}

/* ─── Fenêtre de reconnexion (session expirée) ───────────────────────────── */
/* Remplace l'ancien message brut « Vous devez être connecté… » des shortcodes
   membres. Pleine hauteur sous le header (jamais de hauteur codée en dur :
   cf. --crb-header-height), carte centrée mobile-first. */
.crb-authgate {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: calc(100dvh - var(--crb-header-height));
  padding: var(--crb-space-5) var(--crb-space-4);
  background: var(--crb-bg);
}
.crb-authgate__card {
  width: 100%;
  max-width: 420px;
  text-align: center;
  box-shadow: var(--crb-shadow-lg);
}
.crb-authgate__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  margin-bottom: var(--crb-space-4);
  border-radius: var(--crb-radius-pill);
  background: var(--crb-primary-tint);
  color: var(--crb-primary);
}
.crb-authgate__icon svg { width: 26px; height: 26px; }

.crb-authgate__title {
  margin: 0 0 var(--crb-space-2);
  font-size: var(--crb-fs-2xl);
  font-weight: var(--crb-heading-weight);
  line-height: var(--crb-lh-tight);
  color: var(--crb-text);
}
.crb-authgate__lead {
  margin: 0 0 var(--crb-space-5);
  font-size: var(--crb-fs-md);
  line-height: var(--crb-lh-base);
  color: var(--crb-text-muted);
}

.crb-authgate__form { text-align: left; }

/* Autofill : Safari/Chrome imposent un fond jaune (`-webkit-autofill`) qui écrase
   --crb-surface — visible d'emblée ici, seul écran où le navigateur remplit
   systématiquement les champs. On repeint via un inset large (le fond lui-même
   n'est pas modifiable) pour rester dans la palette, et on redonne la couleur du
   texte. La transition longue empêche le flash jaune au moment du remplissage. */
.crb-plugin .crb-authgate__form .crb-form__input:-webkit-autofill,
.crb-plugin .crb-authgate__form .crb-form__input:-webkit-autofill:hover {
  -webkit-box-shadow: 0 0 0 1000px var(--crb-surface) inset;
  box-shadow: 0 0 0 1000px var(--crb-surface) inset;
  -webkit-text-fill-color: var(--crb-text);
  caret-color: var(--crb-text);
  transition: background-color 5000s ease-in-out 0s;
}
/* Focus : on conserve l'anneau de focus tokenisé PAR-DESSUS le repeint. */
.crb-plugin .crb-authgate__form .crb-form__input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 1000px var(--crb-surface) inset, 0 0 0 3px var(--crb-focus-ring);
  box-shadow: 0 0 0 1000px var(--crb-surface) inset, 0 0 0 3px var(--crb-focus-ring);
}
.crb-authgate__submit { width: 100%; margin-top: var(--crb-space-2); }
.crb-authgate__submit.is-loading { opacity: .6; cursor: progress; }

.crb-authgate__error {
  margin: 0 0 var(--crb-space-3);
  padding: 10px 12px;
  border-radius: var(--crb-radius-sm);
  background: var(--crb-danger-tint);
  color: var(--crb-danger);
  font-size: var(--crb-fs-sm);
  line-height: var(--crb-lh-base);
}
.crb-authgate__error[hidden] { display: none; }

/* Message d'état du parcours « mot de passe oublié » (auth-gate-recover.php).
   Rendu côté serveur, contrairement à .crb-authgate__error qui est posé en JS
   après un échec de connexion : les deux ne coexistent jamais sur un écran. */
.crb-authgate__message {
  margin: 0 0 var(--crb-space-4);
  padding: 10px 12px;
  border-radius: var(--crb-radius-sm);
  text-align: left;
  font-size: var(--crb-fs-sm);
  line-height: var(--crb-lh-base);
}
.crb-authgate__message--error {
  background: var(--crb-danger-tint);
  color: var(--crb-danger);
}
.crb-authgate__message--success {
  background: color-mix(in srgb, var(--crb-success) 12%, var(--crb-surface));
  color: color-mix(in srgb, var(--crb-success) 65%, #000);
}
/* WP-Members pose une ancre vide devant chacun de ses formulaires (<a id="pwdreset">) :
   sans cette neutralisation, elle ajoute une ligne de texte vide dans la carte. */
.crb-authgate__card > a[id]:empty { display: none; }

.crb-authgate__hint {
  margin: var(--crb-space-3) 0 0;
  text-align: center;
  font-size: var(--crb-fs-2xs);
  color: var(--crb-text-muted);
}
.crb-authgate__links {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--crb-space-2);
  margin-top: var(--crb-space-5);
  padding-top: var(--crb-space-4);
  border-top: 1px solid var(--crb-border);
  font-size: var(--crb-fs-sm);
}
.crb-authgate__links a { color: var(--crb-primary); text-decoration: none; }
.crb-authgate__links a:hover { text-decoration: underline; }
.crb-authgate__links span { color: var(--crb-text-muted); }

/* ═══════════════════════════════════════════════════════════════════════════
   MATIÈRE & ÉLAN — couche de finition premium (v3.28.0)

   Ce bloc ne déplace rien et n'invente aucun écran : il ne travaille QUE la
   perception. Les emplacements (zones premium, publicités, rails, panneaux) et
   la structure des vues sont inchangés ; les couleurs restent gouvernées par
   l'admin — tout ici dérive de `--crb-primary` / `--crb-surface` / `--crb-text`
   ou de tokens de personnalité qu'un skin peut redéfinir.

   Quatre leviers, dans cet ordre de priorité :

     1. RÉPONSE     — l'interface répond au pointer-DOWN, jamais au relâchement.
                      C'est le socle : dès qu'un délai apparaît, la sensation de
                      direct s'effondre et aucune animation ne la rattrape.
     2. MATIÈRE     — les couches de chrome sont translucides et le contenu passe
                      dessous ; les surfaces levées accrochent la lumière sur leur
                      arête haute. La profondeur ne vient pas de l'ombre seule.
     3. CONTINUITÉ  — ce qui entre entre depuis son déclencheur et repart par où
                      il est venu, sur des courbes nommées par usage (--crb-ease-*).
     4. CRAFT TYPO  — l'approche suit la taille, les chiffres ont une chasse fixe,
                      l'interlignage se resserre quand le corps grossit.

   Placé en fin de feuille : il affine des composants déclarés plus haut, et
   l'ordre de la cascade suffit — aucune règle d'ici n'a besoin de !important.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 1. Typographie : l'approche est fonction de la taille ─────────────────
   Une valeur unique de letter-spacing pour toute une interface est fausse quelque
   part par construction. Plus le corps grandit, plus le blanc entre deux lettres
   grandit avec lui : à 2rem, une approche neutre se lit délavée. Inversement, une
   légende à .75rem a besoin d'air. On applique donc le token du PALIER de taille
   de chaque rôle, jamais une valeur globale. */
.crb-plugin :where(h1, h2, h3) {
  letter-spacing: var(--crb-heading-tracking, var(--crb-track-title));
}
/* Gros corps (≥ 2rem) : serrage franc et interlignage resserré. Un titre composé
   avec l'interligne du corps « flotte » entre ses deux lignes. */
.crb-plugin :where(.crb-profile__name, .crb-home-hero__title, .crb-match-title) {
  letter-spacing: var(--crb-track-display);
  line-height: var(--crb-lh-tight);
}
/* Petit corps : un soupçon d'air, jamais de serrage. */
.crb-plugin :where(.crb-member-card__age,
                   .crb-member-card__country,
                   .crb-member-card__loc,
                   .crb-form__help,
                   .crb-inbox__preview,
                   .crb-conv-preview) {
  letter-spacing: var(--crb-track-caption);
}
/* Eyebrow en capitales : c'est l'approche qui la rend lisible (une capitale n'a ni
   jambage ni hampe pour se détacher de sa voisine). */
.crb-plugin .crb-section-title { letter-spacing: var(--crb-track-label); }

/* Chiffres à chasse fixe partout où un nombre est LU comme une donnée : compteurs,
   pastilles, jauges, prix, KPI. Sans cela, remplacer un « 8 » par un « 1 » décale
   la ligne entière — et un compteur qui s'incrémente en direct fait tressauter son
   propre voisinage. Personne ne sait nommer ce défaut ; tout le monde le voit. */
.crb-plugin :where(.crb-topbar__badge,
                   .crb-rail-nav__badge,
                   .crb-conv-badge,
                   .crb-inbox__badge,
                   .crb-rail-card__pct,
                   .crb-completion__pct,
                   .crb-mactivity__value,
                   .crb-home-activity__value,
                   .crb-member-card__compat,
                   .crb-swipe-counter) {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* ── 2. Révélation à l'entrée dans le champ ────────────────────────────────
   Les grilles et les listes n'apparaissent pas d'un bloc : chaque élément monte de
   quelques pixels, décalé de son voisin. Le décalage n'est pas un ornement — il
   donne à l'œil un ORDRE de lecture, et transforme une grille qui « surgit » en
   une grille qui « se pose ».

   L'état de repos est celui qui est VISIBLE : rien n'est masqué par le CSS seul.
   Si le JS ne tourne pas, si l'IntersectionObserver manque, si l'animation est
   refusée — le contenu est là, entier, tout de suite. La classe `is-armed` posée
   par app.js est ce qui autorise le masquage initial, et elle n'est jamais posée
   sans que son retrait soit garanti (cf. app.js › armReveal). */
@keyframes crb-rise-in {
  from { opacity: 0; transform: translateY(12px) scale(.985); }
  to   { opacity: 1; transform: none; }
}
.crb-reveal.is-armed > * {
  /* `--crb-i` est l'index posé par app.js. Le décalage est PLAFONNÉ : au-delà de
     huit éléments, l'attente cumulée deviendrait une latence subie — et la §1 de
     ce fichier vaut aussi pour l'apparition du contenu. */
  animation: crb-rise-in var(--crb-dur-slow) var(--crb-ease-emphasized)
             calc(min(var(--crb-i, 0), 8) * 45ms) both;
}

/* ── 2 bis. Arrivée d'un message ───────────────────────────────────────────
   Une bulle qui apparaît d'un coup ne dit pas d'où elle vient. Celle-ci grandit
   depuis SON côté (`transform-origin` ancré au bord dont elle dépend) et monte de
   huit pixels : le mouvement dit à la fois « c'est nouveau » et « ça vient de là ».
   La classe est posée par messaging.js sur les seules arrivées en direct, jamais
   sur l'ouverture d'un fil. */
@keyframes crb-bubble-in {
  from { opacity: 0; transform: translateY(8px) scale(.94); }
  to   { opacity: 1; transform: none; }
}
.crb-bubble--new {
  animation: crb-bubble-in var(--crb-dur-slow) var(--crb-ease-emphasized) both;
}
.crb-bubble--mine.crb-bubble--new   { transform-origin: bottom right; }
.crb-bubble--theirs.crb-bubble--new { transform-origin: bottom left; }

/* ── 3. Lisière de défilement plutôt que trait de séparation ───────────────
   Sous une barre translucide, une bordure de 1px dessine une frontière franche là
   où l'on veut justement dire « le contenu continue dessous ». Un dégradé de
   quelques pixels dit la même chose sans couper.
   Positionné en absolu : dans un conteneur flex, un ::after en flux deviendrait un
   ITEM de la barre et en décalerait le contenu. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .crb-topbar::after,
  .crb-shell__mobilebar::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    height: 12px;
    pointer-events: none;
    background: linear-gradient(to bottom,
                  color-mix(in srgb, var(--crb-text) 6%, transparent),
                  transparent);
  }
  /* Le trait s'efface là où la lisière prend le relais : garder les deux
     reviendrait à dire au même endroit « le contenu continue dessous » et « la
     barre s'arrête ici ». */
  .crb-plugin .crb-topbar,
  .crb-plugin .crb-shell__mobilebar { border-bottom-color: transparent; }
}

/* ── 4. Petites surfaces interactives : répondre au doigt ──────────────────
   Toutes les commandes rondes ou carrées du produit (notifications, hamburger,
   outils de messagerie, actions d'une ligne d'inbox, flèches du carrousel)
   partagent le même retour : enfoncement instantané, retour à ressort. Groupées
   ici pour qu'elles ne puissent pas diverger composant par composant.
   `transform` figure dans la transition de REPOS : une transition déclarée dans le
   seul `:active` ne joue qu'à l'aller, et le retour — le moment où le ressort se
   voit — se ferait d'un coup. */
.crb-plugin :where(.crb-topbar__icon-btn,
                   .crb-shell__menu-toggle,
                   .crb-chat__tool,
                   .crb-spotlight__nav,
                   .crb-inbox__action) {
  transition: background var(--crb-transition),
              color var(--crb-transition),
              box-shadow var(--crb-dur-base) var(--crb-ease),
              transform var(--crb-dur-slow) var(--crb-ease-spring);
}
.crb-plugin :where(.crb-topbar__icon-btn,
                   .crb-shell__menu-toggle,
                   .crb-chat__tool,
                   .crb-spotlight__nav,
                   .crb-inbox__action):active {
  transform: scale(var(--crb-press-scale));
  transition: transform var(--crb-dur-fast) var(--crb-ease-exit);
}
/* Boutons de swipe : les plus gros et les plus engageants du produit. Ils gardent
   leur enfoncement franc (.9, déclaré plus haut) mais reviennent au ressort, et
   leur halo se resserre avec eux — un objet qu'on presse se rapproche de son ombre. */
.crb-plugin .crb-swipe-btn {
  transition: transform var(--crb-dur-slow) var(--crb-ease-spring),
              box-shadow var(--crb-dur-base) var(--crb-ease),
              background var(--crb-dur-base) var(--crb-ease),
              color var(--crb-dur-base) var(--crb-ease);
}
.crb-plugin .crb-swipe-btn:active {
  box-shadow: var(--crb-shadow-sm);
  transition: transform var(--crb-dur-fast) var(--crb-ease-exit),
              box-shadow var(--crb-dur-fast) var(--crb-ease-exit);
}

/* ── 5. Focus : lisible même posé sur une photo ────────────────────────────
   Sur une carte à photo sombre, un anneau translucide peut se perdre. Le second
   anneau (couleur de surface, posé en box-shadow sous l'outline) garantit le
   contraste quelle que soit la luminosité de l'image, sans dépendre d'elle. */
.crb-plugin :where(.crb-member-card__media,
                   .crb-gallery-card,
                   .crb-spotlight__item,
                   .crb-profile__gallery-item):focus-visible {
  box-shadow: 0 0 0 2px var(--crb-surface);
}

/* ── 6. Accessibilité : trois signaux indépendants ─────────────────────────
   « Mouvement réduit » ne veut pas dire « aucun retour » : cela veut dire un retour
   NON VESTIBULAIRE. On garde ce qui aide à comprendre (opacité, couleur, changement
   d'état) et on retire ce qui déplace des masses à l'écran.
   NB : le bloc générique du haut de la feuille écrase déjà toutes les durées ; ces
   règles-ci neutralisent en plus les DÉPLACEMENTS, qu'une durée nulle laisserait
   sinon s'appliquer instantanément (un saut vaut un mouvement). */
@media (prefers-reduced-motion: reduce) {
  /* Le décalage en cascade saute en premier : mouvement pur, sans valeur
     informative. Le contenu s'affiche entier, immédiatement. */
  .crb-reveal.is-armed > * { animation: none; }
  .crb-member-card:hover,
  .crb-gallery-card:hover,
  .crb-member-card:active,
  .crb-gallery-card:active,
  .crb-conv-link:active,
  .crb-rail-nav__item:active { transform: none; }
  .crb-member-card:hover .crb-member-card__photo,
  .crb-gallery-card:hover .crb-gallery-card__img { transform: none; }
  /* Le squelette reste, mais cesse de balayer : la bande qui traverse est du
     mouvement large, et une surface immobile dit exactement la même chose. */
  .crb-skeleton { animation: none; background: var(--crb-skeleton-bg); }
}

/* Transparence réduite : les couches de verre deviennent opaques. On retire AUSSI
   le flou — le garder sur un fond opaque ne coûterait que du GPU pour rien. */
@media (prefers-reduced-transparency: reduce) {
  /* Le menu du compte n'est plus listé ici : il est opaque en toutes circonstances,
     ce réglage n'a plus rien à lui retirer. */
  .crb-plugin :where(.crb-shell__mobilebar,
                     .crb-shell__aside) {
    background: var(--crb-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .crb-plugin .crb-topbar {
    background: var(--crb-nav-bg);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .crb-topbar::after,
  .crb-shell__mobilebar::after { display: none; }
}

/* Contraste renforcé : fonds pleins, bords définis. Une translucidité, même légère,
   fait varier le contraste du texte avec ce qui passe dessous — exactement ce que
   ce réglage demande d'éliminer. */
@media (prefers-contrast: more) {
  .crb-plugin :where(.crb-shell__mobilebar,
                     .crb-shell__aside,
                     .crb-topbar__avatar-menu,
                     .crb-bottom-sheet__panel) {
    background: var(--crb-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border-color: var(--crb-text);
  }
  .crb-plugin .crb-topbar {
    background: var(--crb-nav-bg);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .crb-plugin :where(.crb-card, .crb-member-card, .crb-gallery-card, .crb-home-widget) {
    border: 1px solid var(--crb-text);
  }
}
