/* ══════════════════════════════════════════════════════════════
   List Hero — Hero compact pour pages de listing (ressources, formations…)
   ══════════════════════════════════════════════════════════════ */

.list-hero {
    /* Stacking context dedie : sans cela, le dropdown `_rss_button` (menu
       absolute avec z-index: 50 dans le topbar) est rabattu sous les
       cards suivantes (ex: .article-card du listing /actualites) parce
       que le wrapper feed (z-index: 2 du root body) perd l'arbitrage
       d'ordre DOM contre tout ce qui suit. Position relative + z-index
       eleve elevent l'enveloppe hero au-dessus du contenu de liste. */
    position: relative;
    z-index: 10;
    /* AUCUN fond ni bordure : la bande de tete est portee par le degrade de
       `.front-main` (app.css), qui traverse le hero et s'eteint plus bas. Un
       fond ici le masquerait, et une hairline dessinerait precisement la
       limite que le degrade a pour but de ne pas dessiner. */
    padding: var(--spacing-xs) 0 var(--spacing-lg);
}

/* Breadcrumb integre dans le hero : fond transparent + padding compact.
   Le padding vertical est porte par `.list-hero__topbar` (parent) pour
   permettre l'alignement vertical exact des actions a droite (les deux
   enfants - breadcrumb et feed - partagent la meme baseline mediane). */
.list-hero .breadcrumb-bar {
    background: transparent;
    border: 0;
    margin-bottom: 0;
}

.list-hero .breadcrumb__list {
    padding: 0;
}

/* Topbar : breadcrumb a gauche + bouton flux (RSS dropdown) a droite.
   Le breadcrumb porte deja son propre `.container` interne ; on superpose
   un `.container` jumeau pour aligner le bouton sur la meme grille, puis
   on centre le feed verticalement via `top: 50%; translateY(-50%)`. Le
   padding vertical est sur le topbar parent (et plus sur le breadcrumb)
   pour que le milieu vertical = milieu de la ligne de texte breadcrumb. */
.list-hero__topbar {
    position: relative;
    padding: var(--spacing-sm) 0;
}

.list-hero__feed-wrapper {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    position: absolute;
    top: 50%;
    left: 0;
    right: 0;
    z-index: 2;
    padding-top: 0;
    transform: translateY(-50%);
    pointer-events: none;
}

.list-hero__feed {
    pointer-events: auto;
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-xs);
}

/* Sur mobile : le bouton repasse sous le breadcrumb pour eviter
   le chevauchement avec un breadcrumb qui wrappe sur plusieurs lignes. */
@media (max-width: 47.9375em) {
    .list-hero__feed-wrapper {
        position: static;
        padding-top: 0;
        transform: none;
        margin-bottom: var(--spacing-sm);
    }
}

/* Bouton « Imprimer » du topbar — icone seule sans bordure ni fond.
   Cohabitation avec le bouton RSS via le meme slot `.list-hero__feed`.
   Label rendu en aria-label/title pour l'accessibilite uniquement. */
.list-hero__print {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.25rem;
    color: currentColor;
    background: none;
    border: 0;
    border-radius: var(--radius-sm);
    cursor: pointer;
    opacity: 0.7;
    transition: opacity 0.15s ease, color 0.15s ease;
}

.list-hero__print:hover,
.list-hero__print:focus-visible {
    opacity: 1;
    color: var(--color-primary);
    outline: none;
}

/* Share buttons en topbar : style discret aligne sur `.list-hero__print`,
   pas de cercles outline (qui surchargent visuellement la zone breadcrumb).
   Override du `.share-buttons__btn` global. */
.list-hero__share-buttons {
    gap: 0.125rem;
}

.list-hero__share-buttons .share-buttons__btn {
    width: auto;
    height: auto;
    padding: 0.35rem;
    border: 0;
    background: transparent;
    color: var(--color-text-light);
    border-radius: var(--radius-sm);
    opacity: 0.8;
    transition: opacity 0.15s ease, color 0.15s ease, background-color 0.15s ease;
}

.list-hero__share-buttons .share-buttons__btn:hover,
.list-hero__share-buttons .share-buttons__btn:focus-visible {
    opacity: 1;
    color: var(--color-primary);
    background: transparent;
    border-color: transparent;
}

/* Etat « Lien copie » : feedback discret en couleur primary, pas de fond. */
.list-hero__share-buttons .share-buttons__btn--active {
    opacity: 1;
    color: var(--color-primary);
    background: transparent;
    border-color: transparent;
}

/* Bookmark actif : meme rythme (couleur accent, pas de fond plein). */
.list-hero__share-buttons .share-buttons__btn--bookmark.share-buttons__btn--active {
    color: var(--color-accent);
    background: transparent;
    border-color: transparent;
}

.list-hero__share-buttons .share-buttons__btn--bookmark.share-buttons__btn--active:hover {
    background: transparent;
}

.list-hero__container {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--spacing-md);
    padding-top: var(--spacing-lg);
    width: 100%;
}

.list-hero__eyebrow {
    font-size: var(--font-size-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-primary);
    margin: 0;
}

.list-hero__title {
    font-size: clamp(1.875rem, 4vw, 3rem);
    line-height: 1.1;
    font-weight: 700;
    color: var(--color-primary-dark);
    margin: 0;
    letter-spacing: -0.01em;
    max-width: 24ch;
}

.list-hero__lead {
    font-size: var(--font-size-lg);
    color: var(--color-text-light);
    line-height: 1.55;
    margin: 0;
    max-width: 52ch;
}

/* Wrapper title + lead : groupe semantique (le lead complete le titre,
   pas une section autonome). Espacement interne reduit a `--spacing-xs`,
   independant du `gap` parent `.list-hero__content`. Le wrapper se
   comporte lui-meme comme un flex item de `.list-hero__content` et
   herite donc du gap nominal entre lui et les voisins (eyebrow, tags,
   metrics, chips). */
.list-hero__head {
    display: flex;
    flex-direction: column;
    align-items: inherit;
    gap: var(--spacing-xs);
    width: 100%;
}

.list-hero__search {
    width: 100%;
    max-width: 36rem;
    /* L'espacement vertical est porte par le `gap` du `.list-hero__content`
       parent — pas de margin-top override ici, sinon il s'additionne au
       gap et casse l'harmonie avec les autres items (lead, metrics). */
}

/* ─── Tags / thematiques cliquables (rangee 1, juste sous le lead) ──
   Pills outline discretes en couleur primary, optimisees pour
   accueillir N thematiques avec wrap doux. Variante visuelle des
   chips meta (rangee 2), plus discrete, pour permettre une lecture
   rapide "domaine -> titre -> de quoi ca parle". */
.list-hero__tags {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    justify-content: center;
    max-width: 56rem;
}

.list-hero__tag {
    display: inline-flex;
    align-items: center;
    padding: 0.25rem 0.625rem;
    border-radius: 100px;
    border: 1px solid color-mix(in srgb, var(--color-primary) 28%, transparent);
    background: transparent;
    color: var(--color-primary-dark);
    font-size: var(--font-size-xs);
    font-weight: 500;
    line-height: 1.2;
    text-decoration: none;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

a.list-hero__tag:hover,
a.list-hero__tag:focus-visible {
    background: color-mix(in srgb, var(--color-primary) 10%, #fff);
    border-color: var(--color-primary);
    outline: none;
}

/* En mode card editoriale, les tags s'alignent a gauche comme le
   reste du contenu. */
.list-hero--with-chips .list-hero__tags {
    justify-content: flex-start;
}

/* ─── Chips compactes sous les tags (rangee 2 meta) ────────────────
   Rangee de chips utilisee pour porter les metadonnees structurelles
   d'une fiche : duree, modalite, capacite, etc. Pills plus marques
   que les tags (fond plein primary 10%), avec icone optionnelle. */
.list-hero__chips {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    justify-content: center;
    max-width: 56rem;
}

/* En mode card editoriale, les chips s'alignent a gauche. */
.list-hero--with-chips .list-hero__chips {
    justify-content: flex-start;
}

.list-hero__chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.3125rem 0.625rem;
    border-radius: 100px;
    background: color-mix(in srgb, var(--color-primary) 10%, #fff);
    border: 1px solid color-mix(in srgb, var(--color-primary) 22%, transparent);
    color: var(--color-primary-dark);
    font-size: var(--font-size-xs);
    font-weight: 500;
    line-height: 1.2;
    text-decoration: none;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.list-hero__chip svg {
    flex-shrink: 0;
    opacity: 0.75;
}

.list-hero__chip--link:hover,
.list-hero__chip--link:focus-visible {
    background: color-mix(in srgb, var(--color-primary) 18%, #fff);
    border-color: var(--color-primary);
    color: var(--color-primary-dark);
    outline: none;
}

.list-hero__chip--accent {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}

.list-hero__chip--accent svg {
    opacity: 1;
}

.list-hero__chip--accent.list-hero__chip--link:hover,
.list-hero__chip--accent.list-hero__chip--link:focus-visible {
    background: var(--color-primary-dark);
    border-color: var(--color-primary-dark);
    color: #fff;
}

.list-hero__chip--ghost {
    background: transparent;
    border-color: color-mix(in srgb, var(--color-primary-dark) 22%, transparent);
    color: var(--color-primary-dark);
}

/* Variante "trust" : badges de certification / verification
   (Qualiopi, DPC, Simulation HAS, accessibilite). Plus poids visuel
   que la pill par defaut : fond vert tendre + icone teintee. Pattern
   "verified seal". */
.list-hero__chip--trust {
    padding: 0.45rem 0.85rem;
    font-size: var(--font-size-sm);
    font-weight: 600;
    background: color-mix(in srgb, #16a34a 12%, #fff);
    border-color: color-mix(in srgb, #16a34a 30%, transparent);
    color: #14532d;
}

.list-hero__chip--trust svg {
    opacity: 1;
    color: #16a34a;
}

.list-hero__chip--trust.list-hero__chip--link:hover,
.list-hero__chip--trust.list-hero__chip--link:focus-visible {
    background: #16a34a;
    border-color: #16a34a;
    color: #fff;
}

.list-hero__chip--trust.list-hero__chip--link:hover svg,
.list-hero__chip--trust.list-hero__chip--link:focus-visible svg {
    color: #fff;
}

.list-hero--background-image .list-hero__chip--trust {
    background: rgba(255, 255, 255, 0.95);
    border-color: rgba(255, 255, 255, 0.95);
    color: #14532d;
}

.list-hero--background-image .list-hero__chip--trust svg { color: #16a34a; }

/* Variante "action" : chips actionnables type call-to-action
   (telephone, site web, itineraire, reseaux sociaux). Padding plus
   genereux, icone plus marquee, hover prononce — pattern Google
   Business / LinkedIn org page. */
.list-hero__chip--action {
    padding: 0.45rem 0.85rem;
    font-size: var(--font-size-sm);
    font-weight: 600;
    background: #fff;
    border-color: color-mix(in srgb, var(--color-primary) 18%, transparent);
    color: var(--color-primary-dark);
}

.list-hero__chip--action svg {
    opacity: 1;
    color: var(--color-primary);
}

.list-hero__chip--action.list-hero__chip--link:hover,
.list-hero__chip--action.list-hero__chip--link:focus-visible {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}

.list-hero__chip--action.list-hero__chip--link:hover svg,
.list-hero__chip--action.list-hero__chip--link:focus-visible svg {
    color: #fff;
}

.list-hero--background-image .list-hero__chip--action {
    background: rgba(255, 255, 255, 0.95);
    border-color: rgba(255, 255, 255, 0.95);
    color: var(--color-primary-dark);
}

.list-hero--background-image .list-hero__chip--action svg {
    color: var(--color-primary);
}

.list-hero--background-image .list-hero__chip--action.list-hero__chip--link:hover,
.list-hero--background-image .list-hero__chip--action.list-hero__chip--link:focus-visible {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}

.list-hero--background-image .list-hero__chip--action.list-hero__chip--link:hover svg,
.list-hero--background-image .list-hero__chip--action.list-hero__chip--link:focus-visible svg {
    color: #fff;
}

/* ──────────────────────────────────────────────────────────
   Hero nav chips — bandeau de navigation integre en bas du
   hero card (pattern fiche profile : CESU, RESU, partner).
   Live INSIDE .list-hero, sous le contenu et l'aside, full width.
   Filet superieur subtil pour decoller du contenu hero.
   ────────────────────────────────────────────────────────── */
.list-hero__nav {
    margin-top: var(--spacing-md);
}

.list-hero__nav-list {
    list-style: none;
    margin: 0;
    padding: var(--spacing-sm) 0 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 4px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.list-hero__nav-sep {
    width: 1px;
    height: 1.25rem;
    background: color-mix(in srgb, var(--color-primary) 18%, transparent);
    margin: 0 var(--spacing-xs);
    flex-shrink: 0;
}

.list-hero__nav-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-xs);
    padding: 6px 12px;
    border-radius: 999px;
    font-size: var(--font-size-sm);
    font-weight: 500;
    color: var(--color-text);
    text-decoration: none;
    white-space: nowrap;
    transition: background var(--transition-fast), color var(--transition-fast);
}

.list-hero__nav-chip-icon {
    flex-shrink: 0;
    color: var(--color-text-light);
    transition: color var(--transition-fast);
}

.list-hero__nav-chip-count {
    flex-shrink: 0;
    min-width: 1.25rem;
    padding: 1px 6px;
    background: color-mix(in srgb, var(--color-primary) 8%, #fff);
    border-radius: 999px;
    font-size: var(--font-size-xs);
    font-weight: 600;
    color: var(--color-text-light);
    text-align: center;
}

.list-hero__nav-chip:hover {
    background: color-mix(in srgb, var(--color-primary) 8%, #fff);
    color: var(--color-text);
}

.list-hero__nav-chip:hover .list-hero__nav-chip-icon { color: var(--color-primary); }

.list-hero__nav-chip--active {
    background: var(--color-primary);
    color: #fff;
    font-weight: 600;
}

.list-hero__nav-chip--active .list-hero__nav-chip-icon { color: #fff; }

.list-hero__nav-chip--active .list-hero__nav-chip-count {
    background: rgba(255, 255, 255, 0.22);
    color: #fff;
}

/* Variante hero avec background image : la nav devient blanche tendre. */
.list-hero--background-image .list-hero__nav-chip {
    color: #fff;
}

.list-hero--background-image .list-hero__nav-chip-icon { color: rgba(255, 255, 255, 0.7); }

.list-hero--background-image .list-hero__nav-chip:hover {
    background: rgba(255, 255, 255, 0.12);
}

.list-hero--background-image .list-hero__nav-chip:hover .list-hero__nav-chip-icon { color: #fff; }

.list-hero--background-image .list-hero__nav-chip--active {
    background: #fff;
    color: var(--color-primary-dark);
}

.list-hero--background-image .list-hero__nav-chip--active .list-hero__nav-chip-icon {
    color: var(--color-primary);
}

.list-hero--background-image .list-hero__nav-sep {
    background: rgba(255, 255, 255, 0.25);
}

/* Variante "hero" du search-field : plus grande, plus contrastee.
   Radius `--radius-lg` aligne avec la card editoriale parente (zero
   pill complet) — coherent avec le rythme visuel du hero. */
.search-field--hero .search-field__group {
    border: 1px solid color-mix(in srgb, var(--color-primary) 18%, transparent);
    border-radius: var(--radius-lg);
    box-shadow: 0 4px 18px color-mix(in srgb, var(--color-primary) 12%, transparent);
    background: #fff;
}

.search-field--hero .search-field__group:focus-within {
    border-color: var(--color-primary);
    box-shadow: 0 6px 22px color-mix(in srgb, var(--color-primary) 22%, transparent);
}

.search-field--hero .search-field__input {
    padding: 0.85rem var(--spacing-lg) 0.85rem calc(var(--spacing-lg) + 1.5rem);
    font-size: var(--font-size-base);
    border-radius: var(--radius-lg);
}

.search-field--hero .search-field__icon {
    left: var(--spacing-lg);
}

/* Submit visible : bouton integre a droite du champ, fond primary, blanc.
   Meme radius `--radius-lg` que le groupe parent — coherence stricte
   d'arrondi sur l'ensemble du champ recherche et la card editoriale. */
.search-field--hero .search-field__submit.btn {
    position: relative;
    margin: 0.25rem;
    margin-left: -2.5rem;
    padding: 0.6rem 1.25rem;
    border: 0;
    border-radius: var(--radius-lg);
    background: var(--color-primary);
    color: #fff;
    font-size: var(--font-size-sm);
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    font-family: inherit;
    transition: background-color 0.15s ease;
    z-index: 1;
}

.search-field--hero .search-field__submit.btn:hover,
.search-field--hero .search-field__submit.btn:focus-visible {
    background: var(--color-primary-dark);
    outline: none;
}

/* Quand un submit est present, on ajoute du padding-right a l'input
   pour eviter que le texte saisi passe sous le bouton. */
.search-field--hero:has(.search-field__submit) .search-field__input {
    padding-right: 7rem;
}

@media (max-width: 47.9375em) {
    .list-hero {
        padding-bottom: var(--spacing-xl);
        margin-bottom: var(--spacing-lg);
    }
    .list-hero__container {
        padding-top: var(--spacing-md);
        gap: var(--spacing-sm);
    }
    .search-field--hero .search-field__input {
        padding-block: 0.65rem;
        /* Mobile : pas de loupe a gauche (redondante avec le bouton
           submit a droite qui est aussi une loupe). On retire le
           padding-left dedie a l'icone pour gagner de la place. */
        padding-left: var(--spacing-md);
    }
    .search-field--hero .search-field__icon {
        display: none;
    }
    /* Mobile : bouton submit en icone-only (loupe blanche sur fond
       primary). Le label "Rechercher" est cache visuellement via
       `font-size: 0`, le content text reste expose pour les screen
       readers. L'icone est rendue via `mask-image` (SVG inline)
       pour heriter de la couleur blanche. */
    .search-field--hero .search-field__submit.btn {
        font-size: 0;
        padding: 0;
        width: 2.5rem;
        height: 2.5rem;
        margin: 0.25rem 0.25rem 0.25rem -2.75rem;
        flex-shrink: 0;
        position: relative;
    }
    .search-field--hero .search-field__submit.btn::before {
        content: "";
        position: absolute;
        inset: 0;
        background-color: #fff;
        -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E") center / 18px no-repeat;
                mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E") center / 18px no-repeat;
    }
    .search-field--hero:has(.search-field__submit) .search-field__input {
        padding-right: 3.5rem;
    }
}

/* ══════════════════════════════════════════════════════════════
   Variante hero split — visuel en card a droite, body editorial
   integre a gauche
   ══════════════════════════════════════════════════════════════
   Activee par `aside_image_hash_id` et/ou `lead_body` sur
   `_list_hero.html.twig`. Sur >= 64em, le `.list-hero__container`
   passe en flex row (texte | visuel), texte aligne a gauche. Sur
   mobile, le visuel passe sous le texte en pleine largeur.
   `.list-hero__body` rend le TipTap directement dans la colonne
   gauche pour les pages categorie/taxonomie (ex: /formations/domaines/*).
   ══════════════════════════════════════════════════════════════ */

.list-hero__content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--spacing-md);
    width: 100%;
}

.list-hero__aside {
    position: relative;
    width: 100%;
    margin-top: var(--spacing-md);
}

/* ─── Avatar circulaire (fiche profil personne) ────────────────────
   Optionnel via `avatar_image_url` / `avatar_initials`. Rendu en tete
   de la colonne contenu (flex column, espacement via le `gap` parent).
   Anneau blanc + ombre pour ressortir sur l'image de fond couvrante
   comme sur le gradient navy de fallback. */
.list-hero__avatar {
    width: 6rem;
    height: 6rem;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    overflow: hidden;
    background: color-mix(in srgb, var(--color-primary) 12%, #fff);
    box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.92), 0 14px 30px rgba(15, 23, 42, 0.24);
}

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

.list-hero__avatar-initials {
    font-size: 1.85rem;
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0.02em;
    color: var(--color-primary-dark);
}

.list-hero__aside-image {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    border-radius: var(--radius-lg);
    box-shadow: 0 12px 32px rgba(15, 23, 42, 0.16);
}

/* ─── Nuage de thematiques (aside hero alternatif) ──────────────────
   Cloud "badges discrets" : chaque thematique en pastille tres
   legere (fond primary 6%, sans bordure, texte muted), taille de
   police modeste (11→16px) et poids regulier (400 partout, sauf
   le top bucket en 500 pour signaler la frequence). Le rendu reste
   un nuage (gap serre, flex-wrap) mais en mode "etagere de tags"
   plutot qu'en composition typographique massive.
   Pattern signe-faible-couplage : le rendu ne suppose rien sur la
   source des tags (thematiques training, mais reutilisable pour
   library/event si besoin futur). */
.thematique-cloud {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.35rem 0.4rem;
    line-height: 1.15;
}

.thematique-cloud__item {
    margin: 0;
    display: inline-flex;
}

/* Badge discret : fond primary tres pale (~6%), pas de bordure
   (purete visuelle), padding modere. Le texte reste en muted
   par defaut, ne passe en primary qu'au hover. */
.thematique-tag {
    display: inline-block;
    padding: 0.2em 0.65em;
    border-radius: 999px;
    background: color-mix(in srgb, var(--color-primary) 7%, transparent);
    color: color-mix(in srgb, var(--color-primary) 55%, var(--color-text));
    text-decoration: none;
    line-height: 1.4;
    letter-spacing: 0;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.thematique-tag:hover,
.thematique-tag:focus-visible {
    background: color-mix(in srgb, var(--color-primary) 18%, transparent);
    color: var(--color-primary-dark, var(--color-primary));
    outline: none;
}

/* Echelle 5 buckets — variation modeste sur la taille uniquement
   (11→16px). Le poids reste 400 sur tous les buckets sauf w5 en
   500 pour signaler la frequence sans alourdir la composition.
   Couleurs alignees sur le pattern badge : tous les buckets gardent
   le meme `color`/`background` (defini sur `.thematique-tag`), seule
   la typo varie. */
.thematique-tag--w1 { font-size: 0.7rem;   font-weight: 400; }   /* ~11.2px */
.thematique-tag--w2 { font-size: 0.78rem;  font-weight: 400; }   /* ~12.5px */
.thematique-tag--w3 { font-size: 0.85rem;  font-weight: 400; }   /* ~13.5px */
.thematique-tag--w4 { font-size: 0.93rem;  font-weight: 400; }   /* ~14.8px */
.thematique-tag--w5 { font-size: 1rem;     font-weight: 500; }   /* 16px */

/* Override `align-self: stretch` du parent — voir bloc media query
   `@media (min-width: 64em)` plus bas. Declaree apres cette regle pour
   que la cascade donne raison a `center` a specificite egale. */

/* Body TipTap integre au hero — typo compacte, lisible, en
   continuite avec `.list-hero__lead`. */
.list-hero__body {
    color: var(--color-text);
    font-size: var(--font-size-md);
    line-height: var(--line-height-base);
    max-width: 62ch;
}

.list-hero__body > * + * {
    margin-top: var(--spacing-md);
}

.list-hero__body p {
    margin: 0;
}

.list-hero__body ul,
.list-hero__body ol {
    margin: 0;
    padding-left: 1.25rem;
}

.list-hero__body li + li {
    margin-top: 0.2rem;
}

.list-hero__body h2,
.list-hero__body h3 {
    color: var(--color-primary-dark);
    font-weight: 700;
    font-size: var(--font-size-base);
    line-height: 1.3;
    margin-top: var(--spacing-md);
}

.list-hero__body a {
    color: var(--color-primary);
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

/* En mode split editorial, le `.list-hero__container` devient une card
   centree avec fond bleute subtil, pas de bordure, padding genereux.
   Pattern inspire Branfere : zone editoriale clairement delimitee, sans
   crier visuellement. Le `.container` parent gere les gutters externes.
   Active aussi quand seules les `metrics` sont presentes (page index
   catalogue Training en attente d'une image admin). */
.list-hero--with-aside .list-hero__container,
.list-hero--with-body .list-hero__container,
.list-hero--with-metrics .list-hero__container,
.list-hero--with-chips .list-hero__container,
.list-hero--article .list-hero__container,
.list-hero--page .list-hero__container {
    background: color-mix(in srgb, var(--color-primary) 4%, var(--color-bg));
    border-radius: var(--radius-lg);
    padding: var(--spacing-xl);
    margin-top: var(--spacing-md);
    margin-bottom: var(--spacing-xl);
    text-align: left;
    align-items: flex-start;
    gap: var(--spacing-md);
}

.list-hero--with-aside .list-hero__container .list-hero__title,
.list-hero--with-body .list-hero__container .list-hero__title,
.list-hero--with-metrics .list-hero__container .list-hero__title,
.list-hero--with-chips .list-hero__container .list-hero__title,
.list-hero--article .list-hero__container .list-hero__title,
.list-hero--page .list-hero__container .list-hero__title {
    text-align: left;
}

.list-hero--with-aside .list-hero__content,
.list-hero--with-body .list-hero__content,
.list-hero--with-metrics .list-hero__content,
.list-hero--with-chips .list-hero__content,
.list-hero--article .list-hero__content,
.list-hero--page .list-hero__content {
    align-items: flex-start;
    text-align: left;
    /* Espacement vertical uniforme entre tous les items du content
       (eyebrow, title, lead, body, metrics, search) dans la card
       editoriale — donne plus d'air que le `spacing-md` du mode hero
       centre standard, coherent avec le padding `spacing-2xl` de la
       card au breakpoint desktop. */
    gap: var(--spacing-lg);
}

/* Metriques rapides (formations, sessions a venir, CESUs proposants…)
   rendues sous le body TipTap dans la card editoriale. Pattern Branfere :
   chiffre tres gros navy sobre + label majuscule serre dessous +
   separateurs verticaux entre items. Semantique HTML conservee
   (<dt> label puis <dd> value), ordre visuel inverse via
   `flex-direction: column-reverse`. */
.list-hero__metrics {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-md) 0;
    /* Pas de `margin-top` ici : l'espacement avec l'item precedent (lead /
       body) est porte par le `gap` du `.list-hero__content` parent. Un
       margin-top s'ajouterait au gap et casserait l'harmonie verticale. */
    margin: 0;
    padding: 0;
}

.list-hero__metric {
    display: flex;
    flex-direction: column-reverse;
    gap: 0.4rem;
    padding: 0 var(--spacing-lg);
    border-left: 1px solid var(--color-border);
    min-width: 7rem;
}

.list-hero__metric:first-child {
    padding-left: 0;
    border-left: 0;
}

.list-hero__metric-value {
    margin: 0;
    font-size: clamp(2rem, 4vw, 2.75rem);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    color: var(--color-primary-dark);
}

/* Variante compacte : pour les fiches qui portent un mix chiffre + texte
   ("Présentiel", "Hybride", "12 personnes"). Le clamp standard
   (2-2.75rem) ferait sortir un mot long du cadre — on reduit la value
   et on serre le padding lateral pour densifier la rangee. */
.list-hero__metrics--compact .list-hero__metric {
    padding: 0 var(--spacing-md);
    min-width: 6rem;
}

.list-hero__metrics--compact .list-hero__metric-value {
    font-size: clamp(1.125rem, 1.6vw, 1.375rem);
    letter-spacing: -0.01em;
}

.list-hero__metrics--compact .list-hero__metric-label {
    font-size: 0.65rem;
    letter-spacing: 0.06em;
}

/* Mobile : abandonne le layout "chiffre saillant + label dessous"
   (les labels se chevauchent sur 375px meme avec font reduite). On
   bascule en format inline "[chiffre] [label]" sur une ligne, items
   separes par un point mediant. Pattern naturel en mobile, occupe
   moins de hauteur verticale et evite tout wrap. */
@media (max-width: 47.9375em) {
    .list-hero__metrics {
        gap: 0;
        flex-direction: row;
        flex-wrap: wrap;
        align-items: baseline;
    }
    .list-hero__metric {
        flex-direction: row-reverse;
        align-items: baseline;
        gap: 0.35rem;
        padding: 0 var(--spacing-sm);
        border-left: 0;
        min-width: 0;
        flex: 0 0 auto;
    }
    .list-hero__metric:first-child {
        padding-left: 0;
    }
    /* `::after`, pas `::before` : l'item est en `row-reverse`, donc l'ordre
       visuel des enfants flex est inverse. Un `::before` (premier enfant DOM)
       se rendait a DROITE de l'item — le point median se retrouvait apres
       chaque metrique, y compris la derniere, et manquait avant la premiere.
       C'est ce qui donnait « 8 formations · 0 session · 1 CESU · ». */
    .list-hero__metric:not(:first-child)::after {
        content: "·";
        margin-left: var(--spacing-sm);
        color: var(--color-border);
        font-weight: 700;
    }
    .list-hero__metric-value {
        font-size: 1rem;
        font-weight: 700;
    }
    .list-hero__metric-label {
        font-size: 0.85rem;
        text-transform: none;
        letter-spacing: 0;
        font-weight: 400;
        color: var(--color-text-light);
        white-space: nowrap;
    }
}

.list-hero__metric-label {
    margin: 0;
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 600;
    line-height: 1.3;
    color: var(--color-text-light);
}

/* Eyebrow en pill navy/blanc — dynamise le coin haut de la card editoriale
   sans crier (zero bordure, radius mediums). */
.list-hero--with-aside .list-hero__eyebrow,
.list-hero--with-body .list-hero__eyebrow,
.list-hero--with-metrics .list-hero__eyebrow,
.list-hero--with-chips .list-hero__eyebrow,
.list-hero--article .list-hero__eyebrow,
.list-hero--page .list-hero__eyebrow {
    display: inline-block;
    align-self: flex-start;
    margin: 0 0 calc(var(--spacing-md) * -0.7) 0;
    padding: 0.35rem 0.75rem;
    background: var(--color-primary);
    color: #fff;
    border-radius: var(--radius-md);
    font-size: 0.7rem;
    line-height: 1.1;
}

@media (min-width: 64em) {
    /* Padding genereux dans la card editoriale (avec ou sans aside). */
    .list-hero--with-aside .list-hero__container,
    .list-hero--with-body .list-hero__container,
    .list-hero--with-metrics .list-hero__container,
    .list-hero--with-chips .list-hero__container,
    .list-hero--article .list-hero__container,
    .list-hero--page .list-hero__container {
        padding: var(--spacing-2xl);
    }
    /* Split horizontal — uniquement quand une aside (photo) est presente.
       Modifier `--aside-left` inverse l'ordre visuel (photo a gauche) sans
       toucher au DOM : le markup reste content puis aside, le rendu reste
       accessible (lecture lineaire conservee), seul l'axe principal flex
       est inverse. */
    .list-hero--with-aside .list-hero__container {
        flex-direction: row;
        align-items: stretch;
        justify-content: space-between;
        gap: var(--spacing-2xl);
    }
    .list-hero--with-aside.list-hero--aside-left .list-hero__container {
        flex-direction: row-reverse;
    }
    .list-hero--with-aside .list-hero__content {
        flex: 1 1 auto;
        max-width: 44rem;
    }
    .list-hero--with-aside .list-hero__title,
    .list-hero--with-body .list-hero__title,
    .list-hero--with-aside .list-hero__lead,
    .list-hero--with-body .list-hero__lead {
        max-width: none;
    }
    /* Body sans aside : reste en flex column, contenu plus large pour
       remplir la card (pas de colonne photo a droite). */
    .list-hero--with-body:not(.list-hero--with-aside) .list-hero__content {
        max-width: 60rem;
    }
    .list-hero--with-aside .list-hero__aside {
        position: relative;
        flex: 0 0 26rem;
        max-width: 26rem;
        margin-top: 0;
        align-self: stretch;
    }
    /* Image absolue : ne contribue plus a la hauteur du parent, c'est
       donc le content (colonne texte) qui dicte la hauteur de la card.
       Si l'image a un ratio plus haut que le content, elle est cropp.e
       proprement par `object-fit: cover` au lieu d'allonger la card. */
    .list-hero--with-aside .list-hero__aside-image {
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
        aspect-ratio: auto;
    }
    /* Override pour le mode nuage : pas de stretch (qui plaque le nuage
       sur la hauteur totale et fait remonter le contenu en haut), mais
       centrage vertical dans la card pour une composition equilibree.
       Declaree apres le `stretch` pour gagner la cascade a specificite
       egale (2 classes). */
    .list-hero--with-aside .list-hero__aside--cloud {
        align-self: center;
    }
}

/* ══════════════════════════════════════════════════════════════
   Variante hero card avec image de fond plein cadre
   ══════════════════════════════════════════════════════════════
   Activee par `background_image_hash_id` sur `_list_hero.html.twig`.
   La vignette DAM occupe toute la card, sous un overlay sombre qui
   garantit le contraste AA des titres et metriques. Le texte passe
   en blanc, les chips/tags en outline blanc, l'eyebrow en pill
   inverse (fond clair + texte navy).
   ══════════════════════════════════════════════════════════════ */

.list-hero--background-image .list-hero__container {
    position: relative;
    overflow: hidden;
    isolation: isolate; /* contient les z-index dans la card */
    background: var(--color-primary-dark);
    color: #fff;
    min-height: 18rem;
}

.list-hero__background-image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: 0;
    border-radius: inherit;
}

/* Overlay : gradient sombre du haut vers le bas, garantit le contraste
   du titre (zone haute) et reste lisible jusqu'aux metrics (zone basse). */
.list-hero--background-image .list-hero__container::after {
    content: '';
    position: absolute;
    inset: 0;
    background:
        linear-gradient(180deg,
            color-mix(in srgb, var(--color-primary-dark) 72%, transparent) 0%,
            color-mix(in srgb, var(--color-primary-dark) 84%, transparent) 100%);
    z-index: 1;
    border-radius: inherit;
}

.list-hero--background-image .list-hero__content {
    position: relative;
    z-index: 2;
}

/* Texte editorial en blanc — titre, lead, body herite. */
.list-hero--background-image .list-hero__title,
.list-hero--background-image .list-hero__lead {
    color: #fff;
}

.list-hero--background-image .list-hero__body,
.list-hero--background-image .list-hero__body * {
    color: rgba(255, 255, 255, 0.9);
}

/* Eyebrow : inverse de l'etat normal — fond clair, texte navy. */
.list-hero--background-image .list-hero__eyebrow {
    background: #fff;
    color: var(--color-primary-dark);
}

/* Tags outline blanc translucide. */
.list-hero--background-image .list-hero__tag {
    border-color: rgba(255, 255, 255, 0.55);
    color: #fff;
    background: rgba(255, 255, 255, 0.08);
}

.list-hero--background-image a.list-hero__tag:hover,
.list-hero--background-image a.list-hero__tag:focus-visible {
    background: rgba(255, 255, 255, 0.18);
    border-color: #fff;
    color: #fff;
}

/* Metriques : value blanc saillant, label clair, separateur clair. */
.list-hero--background-image .list-hero__metric-value,
.list-hero--background-image .list-hero__metric-label {
    color: #fff;
}

.list-hero--background-image .list-hero__metric-label {
    color: rgba(255, 255, 255, 0.85);
}

.list-hero--background-image .list-hero__metric {
    border-left-color: rgba(255, 255, 255, 0.35);
}

/* Chips conservent leur fond couleur primary par defaut, mais on
   adoucit les variantes par defaut pour qu'elles soient lisibles
   sur fond sombre. */
.list-hero--background-image .list-hero__chip {
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.45);
    color: #fff;
}

/* Note : le topbar (breadcrumb + actions share/print/bookmark / RSS)
   conserve volontairement sa position par defaut AU-DESSUS de la
   card hero, sur le gradient navy clair de l'enveloppe `.list-hero`,
   meme quand l'image de fond couvre la card. Pattern aligne sur le
   listing /actualites : la zone breadcrumb + actions reste visuellement
   separee du visuel editorial pour preserver la lisibilite et eviter
   de chevaucher le titre. Pas d'override --background-image sur le
   topbar : laisser le pattern par defaut faire son travail. */

.list-hero--background-image .list-hero__chip svg {
    opacity: 0.95;
}

.list-hero--background-image .list-hero__chip--accent {
    background: #fff;
    border-color: #fff;
    color: var(--color-primary-dark);
}

/* ── Modifier `dossier` : card hero arrondie alignee sur la fiche formation
   (`list-hero--training`). Contrairement a la formation qui porte toujours
   des metriques (`--with-metrics` => mode card editoriale), un dossier peut
   n'avoir ni metrique ni thematique. On force donc le mode card (aligne a
   gauche + eyebrow pastille + padding genereux) directement sur le modifier,
   sans dependre de `--with-chips` / `--with-metrics` qui ne s'activent que
   quand la donnee correspondante est presente. ── */
/* Modifier `helpcenter` (accueil /faq) : meme card editoriale arrondie que
   `dossier` (cover sombre + eyebrow pastille verte + alignement gauche). Les
   selecteurs ci-dessous sont partages — ne PAS diverger sans raison, sinon les
   deux heros derivent. */
.list-hero--dossier .list-hero__container,
.list-hero--helpcenter .list-hero__container {
    border-radius: 1.5rem;
}

/* Ces deux variantes forcaient un fond blanc pour fuir le degrade navy clair
   du `.list-hero` partage, « qui se lit comme une bande grise derriere le
   breadcrumb ». Ce degrade n'existe plus, et la bande grise est desormais
   VOULUE : l'override n'a plus d'objet, il ferait de ces deux pages les
   seules du site sans bande de tete. Elles heritent donc du `.list-hero`
   commun. Contre-exemple assume : `.list-hero--event` (minisite evenement),
   qui garde son fond blanc par choix editorial. */

/* Contenu / titre alignes a gauche meme sans thematiques (override du
   centrage par defaut de `.list-hero__content` / `.list-hero__container`). */
.list-hero--dossier .list-hero__content,
.list-hero--helpcenter .list-hero__content {
    align-items: flex-start;
    text-align: left;
    gap: var(--spacing-lg);
}

.list-hero--dossier .list-hero__container .list-hero__title,
.list-hero--helpcenter .list-hero__container .list-hero__title {
    text-align: left;
}

/* Eyebrow en pastille verte ANCESU (fond vert, texte blanc) — coherent avec
   la couleur de section « dossier » et lisible sur le cover sombre. Override
   du fond navy generique (`--with-chips`) et du fond blanc `--background-image`. */
.list-hero--dossier .list-hero__eyebrow,
.list-hero--helpcenter .list-hero__eyebrow {
    display: inline-block;
    align-self: flex-start;
    margin: 0 0 calc(var(--spacing-md) * -0.7) 0;
    padding: 0.35rem 0.75rem;
    background: var(--color-section-ancesu);
    color: #fff;
    border-radius: var(--radius-md);
    font-size: 0.7rem;
    line-height: 1.1;
}

/* Padding genereux dans la card editoriale au breakpoint desktop, comme les
   autres modes card (`--with-chips` / `--with-metrics`). */
@media (min-width: 64em) {
    .list-hero--dossier .list-hero__container,
    .list-hero--helpcenter .list-hero__container {
        padding: var(--spacing-2xl);
    }
}

/* Ligne meta (date de mise a jour) sous le titre/chapo. Texte discret,
   passe en blanc translucide sur le cover sombre. */
.list-hero__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-md);
    margin: 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-light);
}

.list-hero__meta-item {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.list-hero--background-image .list-hero__meta {
    color: rgba(255, 255, 255, 0.85);
}

/* ══════════════════════════════════════════════════════════════
   Content List — Page de liste générique CMS
   ══════════════════════════════════════════════════════════════ */

.content-list {
    /* Le rembourrage BAS etait `--spacing-3xl` (64 px), et le bloc d'abonnement
       qui suit porte deja son propre `--section-gap` en haut : 96 px de blanc
       entre la derniere publication et la carte « La lettre du reseau », la ou
       la maquette en pose 40.

       Un ecart entre deux blocs appartient a UN SEUL des deux — c'est la meme
       regle que pour les etiquettes et pour les freres d'une colonne. Ici c'est
       le bloc SUIVANT qui le porte, parce qu'il le porte deja sur toutes les
       pages ou il apparait : la liste ne garde RIEN en bas.

       Les 8 px qui restaient ici ne se lisaient pas comme une respiration, ils
       se lisaient comme une desynchronisation — la colonne bat a 16 px d'un
       bout a l'autre (barre, une a la une, grille, pagination), et la frontiere
       tombait a 40. */
    padding: var(--spacing-xl) 0 0;
    /* Offset pour les scroll-anchors (ex: `#catalogue` cible la liste
       paginee depuis le CTA hero) — evite que la section soit masquee
       par la navbar scrolled sticky en haut. */
    scroll-margin-top: calc(var(--header-height) + var(--spacing-md));
}

/* Quand un hero precede la page liste, on neutralise le padding-top : sinon la
   marge basse du hero s'additionne au `padding-top` de la `.content-list` et
   cree un gros espace blanc entre les deux.

   Le strip de cards du catalogue formations avait la meme regle ; il est parti
   avec la landing, et sa feuille avec lui. */
.list-hero + .content-list,
/* Idem pour le nouvel en-tete : il se termine deja par 24 px sous sa carte, et
   la rangee de controles qui suit fait partie du meme mobilier — pas d'une
   seconde section. Les deux paddings s'additionnaient a 48 px. */
.content-header + .content-list {
    padding-top: 0;
}

/* Header */
.content-list__header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--spacing-md);
    margin-bottom: var(--spacing-xl);
    padding-bottom: var(--spacing-lg);
    border-bottom: 1px solid var(--color-border);
}

.content-list__title {
    font-size: var(--font-size-2xl);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text);
    margin: 0;
}

@media (min-width: 40em) {
    .content-list__title {
        font-size: var(--font-size-3xl);
    }
}

.content-list__subtitle {
    margin-top: var(--spacing-xs);
    font-size: var(--font-size-base);
    color: var(--color-text-light);
}

/* Briques design-system : list_header (composant) */
.content-list__header-top {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--spacing-md);
}

.content-list__header-actions {
    margin-left: auto;
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-sm);
}

.list-filters__bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-md);
    margin-bottom: var(--spacing-md);
}

.list-filters__bar .search-field {
    flex: 1 1 18rem;
    min-width: 0;
}

.list-filters__count {
    font-size: var(--font-size-sm);
    color: var(--color-text-light);
    flex-shrink: 0;
}

.list-filters__extra {
    flex-shrink: 0;
    display: flex;
    gap: var(--spacing-sm);
}

/* Layout 2 colonnes desktop */
.content-list__layout {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-lg);
}

@media (min-width: 64em) {
    .content-list__layout {
        flex-direction: row;
        /* 24 px, la gouttiere de la maquette entre le rail et la liste. Elle
           valait 48 : deux fois l'ecart qui separe deux cartes de la grille,
           donc le rail se lisait comme un bloc etranger a la page plutot que
           comme sa premiere colonne. */
        gap: var(--card-gap);
    }
}

/* Sidebar filtres (desktop) */
.content-list__sidebar {
    display: none;
}

@media (min-width: 64em) {
    .content-list__sidebar {
        display: flex;
        flex-direction: column;
        flex-shrink: 0;
        width: 17.5rem;
        position: sticky;
        top: 5rem;
        align-self: flex-start;
        max-height: calc(100vh - 6rem);
        overflow-y: auto;
        /* `overflow-x: hidden` evite que le contenu de 17.5rem deborde
           hors du cadre pendant la transition de width vers 2.5rem.
           Le panel `_facet_multiselect` passe en `position: fixed`
           (coords JS), donc cet overflow ne le clippe pas. */
        overflow-x: hidden;
        /* Easing Material « emphasized » pour une expansion plus
           gracieuse qu'un linear/ease basique. */
        transition: width 320ms cubic-bezier(0.4, 0, 0.2, 1);
        /* Scrollbar discrete cross-browser. */
        scrollbar-width: thin;
        scrollbar-color: color-mix(in srgb, var(--color-text-light) 35%, transparent) transparent;
    }

    .content-list__sidebar::-webkit-scrollbar {
        width: 6px;
        height: 6px;
    }

    .content-list__sidebar::-webkit-scrollbar-track {
        background: transparent;
    }

    .content-list__sidebar::-webkit-scrollbar-thumb {
        background: color-mix(in srgb, var(--color-text-light) 35%, transparent);
        border-radius: 999px;
    }

    .content-list__sidebar::-webkit-scrollbar-thumb:hover {
        background: color-mix(in srgb, var(--color-text-light) 55%, transparent);
    }

    /* Repliée — width reduit a la taille de la card toggle (icone +
       libelle vertical « Filtres »). */
    .content-list__sidebar[data-collapsed="true"] {
        width: 2.5rem;
        overflow: hidden;
    }
}

/* ── Rail de filtres ──
   La colonne qui accueille `components/_filter_panel`. Elle ne porte AUCUN
   style de panneau : la carte, ses groupes et sa bascule vivent dans la brique
   partagee. Ici, seulement la place qu'elle occupe dans la page.

   Sous 64em, elle n'est pas masquee : c'est le panneau lui-meme qui se replie,
   et son declencheur doit rester visible. La masquer ici retirerait le bouton
   avec le panneau — et c'est ce que fait `.content-list__sidebar`, l'ancien
   rail, qui n'est plus rendu par aucun gabarit. */
.content-list__side {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-md);
    min-width: 0;
}

/* SOUS LE PALIER, LA COLONNE CESSE D'ETRE UNE BOITE.

   Elle ne peut pas etre `display: none` : elle porte la feuille de filtres, qui
   doit rester atteignable — c'est justement elle qu'on ouvre sur telephone.
   Mais laissee en element de flex, elle valait une hauteur NULLE et une
   gouttiere de 24 px avec la colonne principale : un ecart pour un objet qui
   n'occupe rien.

   `display: contents` la retire du flux sans retirer son contenu. Le rail est
   masque, la feuille est en `position: fixed` — ni l'un ni l'autre ne contribue
   a la hauteur, et la gouttiere disparait avec la boite.

   Meme defaut que la colonne du hero une heure plus tot, un cran plus haut :
   un conteneur vide coute sa gouttiere tant qu'il reste une boite. */
@media (width < 64em) {
    .content-list__side {
        display: contents;
    }

    /* LE PROCHAIN RENDEZ-VOUS NE SUIT PAS. La colonne se dissout ici : ses
       enfants tombent directement dans la liste, et cette carte se glisserait
       entre la barre de controles et les publications — au milieu de la lecture,
       la ou elle est censee l'accompagner depuis le cote.

       C'est la seule chose du rail qu'on retire : la feuille de filtres, elle,
       reste atteignable par son tiroir. Un rendez-vous a venir se trouve dans
       l'agenda, qui est a un lien du pied de page ; un filtre inaccessible
       n'aurait aucun recours. */
    .rail-card--rail {
        display: none;
    }

    /* LE RAIL AUSSI CESSE D'ETRE UNE BOITE. Sa colonne parente passe en
       `display: contents` juste au-dessus ; laisser ce conteneur en boite
       aurait rendu a la colonne principale la gouttiere qu'on venait de lui
       retirer, pour un element qui n'occupe rien. Meme defaut, un cran plus
       bas — c'est la troisieme fois qu'il se paye sur cette page. */
    .content-list__rail {
        display: contents;
    }
}

@media (min-width: 64em) {
    .content-list__side {
        flex: 0 0 17.5rem;
        width: 17.5rem;
    }

    /* LE COLLANT EST SUR LE PANNEAU, PAS SUR LA COLONNE, et c'est la seule
       disposition qui marche.

       Un element `sticky` ne voyage que dans SON conteneur. Pose sur la colonne,
       il avait deux etats faux et aucun bon :
         · avec `align-self: flex-start`, la colonne se reduisait a la hauteur du
           panneau (341 px) — passe 341 px de defilement, le rail decrochait et
           remontait avec la page (`top: -227` mesure a 1600) ;
         · sans lui, la colonne s'etirait sur toute la rangee — et un element
           aussi haut que son conteneur n'a aucune course : il ne collait plus du
           tout (`top: -705`).

       La colonne s'etire donc (statique), et le PANNEAU colle dedans : il a
       toute la hauteur de la liste pour voyager.

       6 rem et non 5 : la barre condensee occupe 86 px du haut de la fenetre,
       pas 56. A 80 px le panneau passait SOUS elle de six pixels, et son titre
       « FILTRES » etait coupe des qu'on defilait. */
    /* LE COLLANT EST SUR LE RAIL ENTIER, plus seulement sur le panneau. Depuis
       que la colonne porte deux blocs — les filtres puis le prochain
       rendez-vous — le collant pose sur le seul panneau laissait le second
       partir avec la page : il n'etait sticky pour personne.

       DEUX FRERES COLLANTS N'AURAIENT PAS MARCHE non plus. Chacun s'arrete a son
       propre seuil, donc le second rattrape le premier et se pose DESSUS. Un
       conteneur unique les fait voyager d'un bloc.

       Le defilement interne passe du panneau au rail : quand la colonne depasse
       la fenetre, c'est l'ensemble qui defile, et la carte reste atteignable. */
    .content-list__rail {
        position: sticky;
        top: 6rem;
        max-height: calc(100vh - 7rem);
        display: flex;
        flex-direction: column;
        gap: var(--spacing-md);
    }

    /* L'ASCENSEUR EST DANS LE PANNEAU, PAS SUR LA COLONNE.
       Porte par la colonne, il faisait defiler TOUT le rail : la carte
       « Acces adherent » qui suit les filtres partait avec eux, alors qu'elle
       est justement ce qu'on veut garder sous les yeux. Dans le panneau, seule
       la liste des facettes defile et la carte reste posee dessous.

       `min-height: 0` EST CE QUI FAIT MORDRE la hauteur maximale du parent : un
       enfant flex refuse par defaut de descendre sous son contenu, donc le
       panneau depassait la colonne au lieu de defiler. Meme propriete que pour
       le sommaire d'une fiche, et elle ne se devine pas. */
    .content-list__rail .filter-panel--rail {
        min-height: 0;
        flex: 0 1 auto;
        overflow-y: auto;
    }
}

/* Contenu principal.

   UNE COLONNE FLEX A GOUTTIERE UNIQUE, et non une pile de marges. La maquette
   pose 16 px entre la barre, la grille et la pagination ; chacun de ces blocs
   portait sa propre marge basse, donc trois valeurs a tenir d'accord et une
   fusion de marges a chaque jonction. Un `gap` unique les remplace : il ne
   fusionne pas, et il n'a qu'un endroit ou etre change. */
.content-list__main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-md);
}

/* Sous 640 px, `.dropdown__label` est masquée depuis longtemps (règle plus bas
   dans ce fichier) : « Trier par » et « Regrouper par » disparaissent. Mes deux
   étiquettes ne suivaient pas cette convention, et « Affichage » restait donc
   seule au-dessus de la rangée, à désigner un contrôle parmi quatre — ce qui se
   lit comme un titre de section, pas comme une étiquette de champ.

   `sr-only` et NON `display: none` : le champ de recherche est nommé par un
   `<label for>`, le retirer de l'arbre le rendrait anonyme. La bascule, elle,
   est déjà nommée par le `aria-label` de son groupe. */

/* Le menu d'une liste déroulante est calé à DROITE de son déclencheur
   (`.dropdown__menu { right: 0 }`), ce qui convient quand le déclencheur est
   lui-même à droite. Dans la rangée de contrôles en petit écran, il se retrouve
   à gauche : le menu, plus large que lui, débordait alors de 52 px hors de
   l'écran, du côté où l'on ne peut pas défiler. Il se cale à gauche et se borne
   à la largeur disponible. */

/* ── Bascule d'affichage ── */
/* Pas de `gap` ici : l'étiquette porte déjà sa propre marge basse
   (`.content-list__filters-label`). Les deux s'additionnaient, et la bascule
   partait cinq pixels plus haut que ses voisines — un écart invisible sur les
   contrôles, mais lisible sur la ligne des étiquettes. */

/* Le déclencheur d'une liste déroulante tient sa hauteur de son propre
   `padding` : 30 px, deux de moins que ses voisines. Dans cette rangée, la
   hauteur vient de la rangée. */

/* ── Sections du panneau ── */

/* Dans une section « Regroupement » ou « Tri », l'étiquette du contrôle répète
   le titre. Elle est masquée à l'œil mais CONSERVÉE : c'est elle que vise le
   `aria-labelledby` du déclencheur, la retirer le laisserait sans nom. */

/* Le duo regroupement + tri du panneau n'existe que sous 48em : au-dessus, il
   vit dans la rangée, où il est atteignable sans ouvrir quoi que ce soit. */

/* ── Proximité dans le panneau ──
   Le bloc vient du rail, où il portait sa propre carte grise, un titre en gras
   navy et des intitulés en minuscules. Posé sous cinq listes déroulantes à
   l'étiquette grise en capitales de 11 px, il ressemblait à une pièce
   rapportée. On ne touche PAS aux classes `sidebar-filters__*` elles-mêmes :
   elles servent encore les rails de /dossiers et /newsletters. */

/* Les deux champs se partagent la ligne, chacun aligné sur le gabarit des
   listes déroulantes : intitulé au-dessus, contrôle pleine largeur. */

/* ── Panneau de filtres ──
   Tiroir latéral au-dessus de 48em, feuille qui remonte du bas en dessous.
   Un panneau plutôt qu'une rangée : le nombre de facettes va de deux
   (glossaire) à sept (catalogue), et une rangée qui s'allonge finit par
   déborder — ses menus déroulants sortaient alors du cadre. */

/* Sous 48em : feuille depuis le bas. */

/* À partir de 48em : tiroir latéral, pleine hauteur, à droite — du côté de la
   main qui vient de cliquer sur « Filtres ». */

/* Dans le panneau, chaque contrôle occupe la ligne : c'est un formulaire, plus
   une rangée. */

/* La lettre était en `width: 100%` — juste dans la grille à six colonnes du
   rail d'où elle vient, une lettre par ligne ici. Elle redevient un carré. */

/* Verrou de défilement pendant que le panneau est ouvert. Posé sur `<html>`
   par `filtersPanel`. */

/* ── Actions de l'en-tête en icônes seules (sous 48em) ──
   Deux boutons libellés occupaient toute la largeur du téléphone pour des
   gestes secondaires. Le bouton d'abonnement n'en est pas : il est masqué sous
   64em par `components/rss-button.css`, décision assumée — lui écrire une règle
   d'icône ici serait du code que rien ne peut atteindre.

   Les intitulés passent en `sr-only`, PAS en `display: none` : ces boutons
   n'ont pas d'`aria-label`, leur nom vient du texte, le retirer du DOM les
   rendrait muets. */
@media (max-width: 47.9375em) {
    .content-header__actions .share-dropdown-group__btn > span,
    .content-header__actions .share-dropdown__summary > span {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }

    .content-header__actions .share-dropdown__summary > svg:last-of-type {
        display: none;
    }

    .content-header__actions .share-dropdown-group__btn,
    .content-header__actions .share-dropdown__summary {
        justify-content: center;
        width: 2.75rem;
        height: 2.75rem;
        padding: 0;
    }
}

/* Toolbar (compteur + tri + chips + toggle filtres)
   Deux rangees verticales :
     - Rangee 1 : compteur a gauche + tri/filtre a droite.
     - Rangee 2 : chips pleine largeur (wrap si nombreux).
   Pas de border-bottom — l'enchainement avec la liste se fait par
   le margin-bottom standard, sans separateur visible. */

/* Conteneur des chips — pleine largeur sous la rangee compteur/tri. */

.content-list__header-right {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--spacing-xs);
    flex-shrink: 0;
}

/* .content-list__rss supprime — bouton RSS vit desormais dans
   components/rss-button.css (brique design-system, dropdown 3 formats). */

.content-list__filter-toggle {
    display: flex;
    align-items: center;
    gap: var(--spacing-xs);
    padding: var(--spacing-sm) var(--spacing-md);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-sm);
    font-weight: 500;
    background: #fff;
    cursor: pointer;
    white-space: nowrap;
    margin-left: auto;
    transition: border-color 0.15s ease, color 0.15s ease;
}

.content-list__filter-toggle:hover {
    border-color: var(--color-primary);
    color: var(--color-primary);
}

@media (min-width: 64em) {
    .content-list__filter-toggle {
        display: none;
    }
}

/* Grille de cards */
.content-list__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--spacing-lg);
}

@media (min-width: 40em) {
    .content-list__grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

.content-list__rows {
    display: flex;
    flex-direction: column;
    /* Pas de border-top : la toolbar n'a plus de border-bottom (cf. content-list__toolbar),
       et les cards portent leur propre cadre. Un trait orphelin entre les deux est du
       bruit visuel sans valeur d'enchainement. */
}

/* Header de section quand la liste est regroupee (Twig insere un <h2> au
   changement de groupValue dans la boucle items). Visuellement discret
   pour rester un repere de navigation, pas un titre rivalisant avec le
   hero. */






/* ── ÉTAT VIDE — composant 14 de la maquette ──
   « Aucun résultat avec ces filtres / Retirez un critère, ou parcourez le
   catalogue complet / Effacer les filtres ». Une CARTE, alignée à gauche, et
   non un bloc centré : la maquette la traite comme une surface de service, au
   même titre que l'accès réservé et le squelette de chargement.

   ALIGNÉ À GAUCHE parce qu'on y lit une phrase et qu'on y clique un bouton. Le
   centrage convient à un pictogramme seul ; dès qu'il y a deux lignes et une
   action, il fait chercher le début de chaque ligne.

   La classe est partagée par seize gabarits, et c'est voulu : la maquette pose
   UN état vide pour tout le site. */
.content-list__empty {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--spacing-ms);
    padding: var(--spacing-2xl);
    background: var(--surface-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    color: var(--color-text-light);
    text-align: left;
}

/* Le pictogramme reste possible, mais il n'est plus le sujet : il annonçait
   l'absence avant qu'on ait lu de quoi. */
.content-list__empty svg {
    opacity: 0.4;
}

.content-list__empty .empty-state__title {
    margin: 0;
    font-family: var(--font-title);
    font-size: var(--font-size-xl);
    font-weight: 700;
    line-height: 1.25;
    color: var(--color-primary-dark);
}

/* La phrase se borne en LARGEUR DE LECTURE : dans une colonne de neuf cents
   pixels, « Retirez un critère, ou parcourez les 118 ressources du centre »
   courait sur une seule ligne trop longue pour être relue. */
.content-list__empty p {
    margin: 0;
    max-width: 52ch;
    font-size: var(--font-size-md);
    line-height: 1.55;
}

/* ══════════════════════════════════════════════════════════════
   Featured Card — Premier article mis en avant
   ══════════════════════════════════════════════════════════════ */

.content-card-featured {
    margin-bottom: var(--spacing-xl);
    border-radius: var(--radius-md);
    overflow: hidden;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
    transition: box-shadow 0.2s ease;
}

.content-card-featured:hover {
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.1);
}

.content-card-featured__link {
    display: flex;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
}

@media (min-width: 40em) {
    .content-card-featured__link {
        flex-direction: row;
    }
}

.content-card-featured__image {
    position: relative;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--color-bg-light);
}

@media (min-width: 40em) {
    .content-card-featured__image {
        width: 55%;
        flex-shrink: 0;
        aspect-ratio: auto;
        min-height: 16rem;
    }
}

.content-card-featured__image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.3s ease;
}

.content-card-featured:hover .content-card-featured__image img {
    transform: scale(1.03);
}

.content-card-featured__body {
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: var(--spacing-lg);
    background: #fff;
}

@media (min-width: 40em) {
    .content-card-featured__body {
        padding: var(--spacing-xl);
        flex: 1;
    }
}

.content-card-featured__title {
    font-size: var(--font-size-xl);
    font-weight: 700;
    line-height: var(--line-height-tight);
    color: var(--color-text);
    margin: var(--spacing-sm) 0;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

@media (min-width: 40em) {
    .content-card-featured__title {
        font-size: var(--font-size-2xl);
    }
}

.content-card-featured__excerpt {
    font-size: var(--font-size-sm);
    color: var(--color-text-light);
    line-height: var(--line-height-base);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin: 0;
}

.content-card-featured__cta {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-xs);
    margin-top: var(--spacing-md);
    font-size: var(--font-size-sm);
    font-weight: 600;
    color: var(--color-primary);
    transition: gap 0.2s ease;
}

.content-card-featured:hover .content-card-featured__cta {
    gap: var(--spacing-sm);
}

/* ══════════════════════════════════════════════════════════════
   Sidebar Filters — Facettes en colonne (desktop aside)

   Chaque groupe est presente comme une mini-carte plate (fond bg-light,
   pas de bordure) avec un titre clair et des options aerees. Les counts
   sont des pills neutres qui basculent vers le primary au survol/actif.
   ══════════════════════════════════════════════════════════════ */

.sidebar-filters__search {
    display: flex;
    align-items: center;
    position: relative;
    margin-bottom: var(--spacing-lg);
}

.sidebar-filters__search-icon {
    position: absolute;
    left: var(--spacing-sm);
    color: var(--color-text-light);
    pointer-events: none;
}

.sidebar-filters__search-input {
    width: 100%;
    padding: var(--spacing-sm) var(--spacing-sm) var(--spacing-sm) 2.25rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-sm);
    background: #fff;
    transition: border-color 0.15s ease;
}

.sidebar-filters__search-input:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 2px var(--color-primary-light);
}

.sidebar-filters__group {
    background: var(--color-bg-light);
    border-radius: var(--radius-md);
    padding: var(--spacing-sm) var(--spacing-md);
    /* L'espacement inter-cards est porte par `.aside-content { gap }` —
       pas de margin-bottom ici sinon double-respiration. */
}

/* La `nav.sidebar-filters__facets` (wrap des templates CMS list comme
   `articles.html.twig`, `default.html.twig`) rassemble les
   `.sidebar-filters__group`. Sans style flex sur ce wrap, les cards
   s'empilent en `display: block` collées — le `gap` du parent
   `.aside-content` ne descend pas à travers le wrap.

   Sur /ressources (library/list.html.twig), les groupes sont posés
   DIRECTEMENT dans `.aside-content` (pas de wrap nav) et bénéficient
   du `gap: var(--spacing-sm)` du parent. On reproduit ici le même
   espacement visuel sur le wrap nav pour aligner les deux pages. */
.sidebar-filters__facets {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-sm);
}

/* Variante dropdown — le composant `_dropdown.html.twig` est inline-flex
   par défaut (label + trigger côte à côte). En sidebar on garde le pattern
   visuel des autres facettes : titre uppercase au-dessus, trigger en
   pleine largeur sous le titre. */
.sidebar-filters__group--dropdown .dropdown {
    display: block;
    width: 100%;
}

.sidebar-filters__group--dropdown .dropdown__wrapper {
    width: 100%;
}

.sidebar-filters__group--dropdown .dropdown__trigger {
    width: 100%;
    justify-content: space-between;
}

.sidebar-filters__group-title {
    display: block;
    font-size: var(--eyebrow-size);
    font-weight: var(--eyebrow-weight);
    text-transform: uppercase;
    letter-spacing: var(--eyebrow-tracking);
    color: var(--color-primary-dark);
    margin: 0 0 var(--spacing-sm);
    padding: 0;
    border-bottom: 0;
}

.sidebar-filters__options {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

.sidebar-filters__option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-sm);
    padding: 0.3125rem 0.5625rem;
    border-radius: var(--radius-sm);
    font-size: var(--font-size-xs);
    line-height: 1.4;
    text-decoration: none;
    color: var(--color-text);
    transition: background-color 0.15s ease, color 0.15s ease;
}

.sidebar-filters__option:hover {
    background: #fff;
    color: var(--color-primary);
}

/* Indentation hierarchique pour les tags enfants (parent_slug present).
   Visuel : ligne verticale subtile + decalage gauche par niveau. */
.sidebar-filters__option--depth-1 {
    padding-left: 1.25rem;
    position: relative;
}
.sidebar-filters__option--depth-2 {
    padding-left: 2rem;
    position: relative;
}
.sidebar-filters__option--depth-1::before,
.sidebar-filters__option--depth-2::before {
    content: '';
    position: absolute;
    left: 0.625rem;
    top: 50%;
    width: 0.5rem;
    height: 1px;
    background: color-mix(in srgb, var(--color-primary) 30%, transparent);
}
.sidebar-filters__option--depth-2::before {
    left: 1.375rem;
}

.sidebar-filters__option:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
}

/* Etat actif : fond teinte primary doux + texte navy. Choix sobre vs
   un fond plein primary : la facette reste un repere de navigation,
   pas un CTA — l'attention focale appartient aux resultats. */
.sidebar-filters__option--active {
    background: color-mix(in srgb, var(--color-primary) 12%, #fff);
    color: var(--color-navy);
    font-weight: 600;
}

.sidebar-filters__option--active:hover {
    background: color-mix(in srgb, var(--color-primary) 18%, #fff);
    color: var(--color-navy);
}

.sidebar-filters__count {
    margin-left: auto;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.625rem;
    height: 1.25rem;
    padding: 0 0.4375rem;
    border-radius: 100px;
    font-size: 0.6875rem;
    font-weight: 600;
    line-height: 1;
    color: var(--color-text-light);
    background: #fff;
    border: 1px solid var(--color-border);
    transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

/* Bloc proximité : code postal + rayon cote a cote (grille 2 colonnes),
   auto-submit en JS au change. Le bouton Appliquer ne sert qu'au fallback
   noscript. */
.sidebar-filters__proximity-form {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-sm);
}

.sidebar-filters__proximity-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--spacing-sm);
    align-items: end;
}

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

.sidebar-filters__field-label {
    font-size: var(--font-size-xs);
    font-weight: 600;
    color: var(--color-text-light);
}

.sidebar-filters__input {
    width: 100%;
    height: 2.125rem;
    padding: 0 0.5625rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: #fff;
    font-family: inherit;
    font-size: var(--font-size-sm);
    line-height: 1.4;
    color: var(--color-text);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
    box-sizing: border-box;
    appearance: none;
}

.sidebar-filters__input:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary) 25%, transparent);
}

.sidebar-filters__submit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.4375rem 0.875rem;
    border: 0;
    border-radius: var(--radius-sm);
    background: var(--color-primary);
    color: #fff;
    font-size: var(--font-size-xs);
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.sidebar-filters__submit:hover,
.sidebar-filters__submit:focus-visible {
    background: var(--color-primary-dark);
}

/* Header de groupe avec lien aligne a droite (Proximite -> Trouver votre CESU). */
.sidebar-filters__group-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-sm);
    margin: 0 0 var(--spacing-sm);
}

.sidebar-filters__group-header .sidebar-filters__group-title {
    margin: 0;
}

.sidebar-filters__group-link {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0;
    border: 0;
    background: transparent;
    font-family: inherit;
    font-size: var(--font-size-xs);
    font-weight: 500;
    color: var(--color-primary);
    text-decoration: none;
    cursor: pointer;
    transition: color 0.15s ease;
    white-space: nowrap;
}

.sidebar-filters__group-link:hover,
.sidebar-filters__group-link:focus-visible {
    color: var(--color-primary-dark);
    text-decoration: underline;
}

.sidebar-filters__group-link-icon {
    flex-shrink: 0;
}

/* Override dropdown dans la colonne rayon : pleine largeur, aligne sur l'input CP. */
.sidebar-filters__field--radius .dropdown {
    display: block;
    width: 100%;
}

.sidebar-filters__field--radius .dropdown__wrapper {
    width: 100%;
}

.sidebar-filters__field--radius .dropdown__trigger {
    width: 100%;
    height: 2.125rem;
    justify-content: space-between;
    padding: 0 0.5625rem;
    font-family: inherit;
    font-size: var(--font-size-sm);
    line-height: 1.4;
    box-sizing: border-box;
}

/* Segment control binaire (Toutes / Sessions a venir). Deux boutons colles
   dans un conteneur arrondi a bordure unique. */
.sidebar-filters__segment {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    overflow: hidden;
    padding: 0;
}

.sidebar-filters__segment-option {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.375rem;
    padding: 0.4375rem 0.5rem;
    font-size: var(--font-size-xs);
    font-weight: 500;
    line-height: 1.3;
    color: var(--color-text-light);
    text-decoration: none;
    transition: background-color 0.15s ease, color 0.15s ease;
    cursor: pointer;
}

.sidebar-filters__segment-option + .sidebar-filters__segment-option {
    border-left: 1px solid var(--color-border);
}

.sidebar-filters__segment-option:hover {
    background: color-mix(in srgb, var(--color-primary) 6%, transparent);
    color: var(--color-primary);
}

.sidebar-filters__segment-option--active {
    background: var(--color-primary);
    color: #fff;
}

.sidebar-filters__segment-option--active:hover {
    background: var(--color-primary-dark);
    color: #fff;
}

.sidebar-filters__segment-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.25rem;
    height: 1.125rem;
    padding: 0 0.3rem;
    border-radius: 999px;
    background: color-mix(in srgb, currentColor 18%, transparent);
    font-size: 0.6875rem;
    font-weight: 600;
    line-height: 1;
}

.sidebar-filters__segment-option--active .sidebar-filters__segment-count {
    background: rgba(255, 255, 255, 0.22);
}

.sidebar-filters__option:hover .sidebar-filters__count {
    border-color: color-mix(in srgb, var(--color-primary) 30%, var(--color-border));
    color: var(--color-primary);
}

/* Count d'une option active : bg blanc + texte primary + bordure primary
   plus marquee. Cible aussi `:hover` (specificity 0,2,0 superieure a la
   hover generique 0,2,0 — ordre source apres == gagne) pour eviter le
   bug ou le compteur disparaissait au survol d'une option deja active. */
.sidebar-filters__option--active .sidebar-filters__count,
.sidebar-filters__option--active:hover .sidebar-filters__count {
    background: #fff;
    color: var(--color-primary);
    border-color: color-mix(in srgb, var(--color-primary) 35%, var(--color-border));
}

/* ══════════════════════════════════════════════════════════════
   Filters Overlay — Drawer mobile plein écran
   ══════════════════════════════════════════════════════════════ */

.filters-overlay {
    position: fixed;
    inset: 0;
    z-index: var(--z-drawer-backdrop);
}

@media (min-width: 64em) {
    .filters-overlay {
        display: none !important;
    }
}

.filters-overlay__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
}

.filters-overlay__panel {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    max-height: 85vh;
    background: #fff;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    display: flex;
    flex-direction: column;
    box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.15);
}

.filters-overlay__panel--enter { transition: transform 0.3s ease; }
.filters-overlay__panel--enter-start { transform: translateY(100%); }
.filters-overlay__panel--enter-end { transform: translateY(0); }
.filters-overlay__panel--leave { transition: transform 0.2s ease; }
.filters-overlay__panel--leave-start { transform: translateY(0); }
.filters-overlay__panel--leave-end { transform: translateY(100%); }

.filters-overlay__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--spacing-md) var(--spacing-lg);
    border-bottom: 1px solid var(--color-border);
    flex-shrink: 0;
}

.filters-overlay__title {
    font-size: var(--font-size-lg);
    font-weight: 700;
    margin: 0;
}

.filters-overlay__close {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    border: none;
    background: var(--color-bg-light);
    cursor: pointer;
    color: var(--color-text);
    transition: background-color 0.15s ease;
}

.filters-overlay__close:hover {
    background: var(--color-border);
}

.filters-overlay__body {
    flex: 1;
    overflow-y: auto;
    padding: var(--spacing-lg);
}

.filters-overlay__footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-md);
    padding: var(--spacing-md) var(--spacing-lg);
    border-top: 1px solid var(--color-border);
    flex-shrink: 0;
}

/* Rendu soit en lien (remise à zéro serveur, cas majoritaire), soit en
   bouton quand le filtrage est client — d'où les neutralisations de bouton,
   sans effet sur la variante lien. */
.filters-overlay__reset {
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    font: inherit;
    font-size: var(--font-size-sm);
    color: var(--color-text-light);
    text-decoration: none;
    transition: color 0.15s ease;
}

.filters-overlay__reset:hover {
    color: var(--color-text);
}

.filters-overlay__apply {
    padding: var(--spacing-sm) var(--spacing-xl);
    border: none;
    border-radius: var(--radius-sm);
    font-size: var(--font-size-sm);
    font-weight: 600;
    background: var(--color-primary);
    color: #fff;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.filters-overlay__apply:hover {
    background: var(--color-primary-dark);
}

/* ══════════════════════════════════════════════════════════════
   Content Card — Card de contenu réutilisable
   ══════════════════════════════════════════════════════════════ */

.content-card {
    width: 100%;
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    overflow: hidden;
    transition: box-shadow 0.2s ease, transform 0.15s ease, border-color 0.2s ease;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}

/* ── SANS CADRE ──
   Fond, filet, rayon et ombre partent : la carte devient un visuel suivi d'un
   texte. Forme de la maquette pour « A lire aussi », et elle se defend — ces
   cartes sont DEJA sur le fond gris de la page, hors de la carte de l'article.
   Encadrees, elles pesaient autant que ce qu'on venait de lire.

   Le RAYON reste sur le visuel seul : c'est lui qui porte la forme, le texte
   n'a plus de boite a arrondir. */
.content-card--plain {
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    overflow: visible;
}

.content-card--plain .content-card__image {
    border-radius: var(--radius-md);
    overflow: hidden;
}

/* Le corps retrouve une gouttiere propre : sans cadre, il n'y a plus de
   rembourrage de carte pour l'ecarter du visuel. */
.content-card--plain .content-card__body {
    padding-inline: 0;
}

.content-card:hover {
    border-color: transparent;
}

.content-card:hover {
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
    transform: translateY(-2px);
}

.content-card__link {
    display: flex;
    flex-direction: column;
    height: 100%;
    text-decoration: none;
    color: inherit;
}

/* Image */
.content-card__image {
    position: relative;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--color-bg-light);
}

.content-card__image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.3s ease;
}

.content-card:hover .content-card__image img {
    transform: scale(1.03);
}

/* ══════════════════════════════════════════════════════════════
   Resource card — composant dédié pour les listes de ressources
   ══════════════════════════════════════════════════════════════ */
.resource-card { border-bottom: 1px solid var(--color-border); }
.resource-card:last-child { border-bottom: none; }

.resource-card__link {
    display: flex;
    align-items: center;
    gap: var(--spacing-md);
    padding: var(--spacing-md) 0;
    text-decoration: none;
    color: inherit;
    transition: background 0.15s ease;
}
.resource-card__link:hover { background: var(--color-bg-light); margin: 0 calc(-1 * var(--spacing-md)); padding: var(--spacing-md); border-radius: var(--radius-md); }

/* Visual : thumbnail ou icône type */
.resource-card__visual { flex-shrink: 0; width: 5rem; height: 5rem; }

.resource-card__thumb {
    width: 100%;
    height: 100%;
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: linear-gradient(135deg, var(--color-bg-light) 0%, #e8edf3 100%);
    border: 1px solid rgba(0, 0, 0, 0.06);
}
.resource-card__thumb img { width: 100%; height: 100%; object-fit: contain; }

.resource-card__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    border-radius: var(--radius-sm);
    background: var(--color-bg-light);
}

.resource-card__icon--pdf { background: #fef2f2; color: #dc2626; }
.resource-card__icon--video { background: #fefce8; color: #ca8a04; }
.resource-card__icon--link { background: #eff6ff; color: #2563eb; }
.resource-card__icon--default { background: var(--color-bg-light); color: var(--color-text-light); }

/* Body */
.resource-card__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.125rem; }

.resource-card__meta { display: flex; align-items: center; gap: var(--spacing-xs); }

.resource-card__badge {
    display: inline-flex;
    padding: 0.0625rem 0.375rem;
    border-radius: var(--radius-sm);
    font-size: 0.625rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.resource-card__badge--pdf { background: #fef2f2; color: #dc2626; }
.resource-card__badge--video { background: #fefce8; color: #ca8a04; }
.resource-card__badge--link { background: #eff6ff; color: #2563eb; }

.resource-card__date { font-size: var(--font-size-xs); color: var(--color-text-light); }

.resource-card__title { font-size: var(--font-size-base); font-weight: 600; color: var(--color-text); }
.resource-card__link:hover .resource-card__title { color: var(--color-navy); }

.resource-card__excerpt { font-size: var(--font-size-xs); color: var(--color-text-light); line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

.resource-card__file-info { display: flex; align-items: center; gap: var(--spacing-xs); margin-top: 0.125rem; }
.resource-card__filename { font-size: var(--font-size-xs); color: var(--color-text-light); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 15rem; }
.resource-card__filesize { font-size: var(--font-size-xs); color: var(--color-text-light); white-space: nowrap; }
.resource-card__filename + .resource-card__filesize::before { content: '·'; margin-right: var(--spacing-xs); }

/* Flèche */
.resource-card__action { flex-shrink: 0; color: var(--color-text-light); transition: color 0.15s ease, transform 0.15s ease; }
.resource-card__link:hover .resource-card__action { color: var(--color-navy); transform: translateX(2px); }

@media (max-width: 47.9375em) {
    .resource-card__visual { width: 3.5rem; height: 3.5rem; }
    .resource-card__excerpt { display: none; }
    .resource-card__file-info { display: none; }
}

.content-card__placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    background: linear-gradient(135deg, var(--color-bg-light) 0%, #e8edf3 100%);
    color: var(--color-text-light);
}

/* Badge « Accès réservé » (components/_restricted_badge.html.twig) — pilule
   inline posée à côté du type de ressource quand l'accès est réservé pour le
   viewer courant (resolvers : isRestricted true). Partagé par `.content-card`
   et `.media-card`. Le tooltip explicatif vient de `[data-tooltip]` (shared.css). */
/* Ambre, et non navy : le navy est deja la couleur des etiquettes de type et
   des thematiques — un cadenas de la meme teinte se lisait comme une categorie
   de plus. L'ambre est la couleur que `/ressources` utilisait deja pour
   « Reserve » ; c'est elle qu'on generalise, pour que le badge soit reconnu du
   premier coup d'oeil quelle que soit la page. */
/* LE CADENAS REJOINT LE VOCABULAIRE FERME DES ETATS (composant 65). Il portait
   un aplat d'accent, une encre a 55 % de noir ET un filet : trois marques pour
   un etat, la ou les huit pastilles de la maquette n'en portent qu'une. A cote
   d'une pastille de rubrique discrete, il criait — signale a l'ecran.

   Il tombe dans la famille `warn`, « ce qui demande une action » : se connecter.
   Fond dilue, texte en encre, pas de filet — c'est la regle du composant, et
   elle vaut ici comme ailleurs. Le filet etait la piece de trop : une pastille
   se distingue par son fond, pas par un contour. */
.restricted-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3125rem;
    padding: var(--spacing-2xs) var(--spacing-sm);
    border-radius: var(--radius-pill);
    background: var(--tint-warning);
    color: var(--color-text);
    font-size: var(--font-size-2xs);
    font-weight: 700;
    line-height: 1.4;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* ══════════════════════════════════════════════════════════════
   Mode TABLEAU du bloc de contenus (`contentBlock`, displayMode=table)
   Le tableau herite du style des tableaux du corps editorial
   (`.prose-content table`, app.css) : un tableau de renvoi et un tableau
   saisi a la main ne doivent pas se lire comme deux objets differents.
   Ne reste ici que ce qui lui est propre.
   ─────────────────────────────────────────────────────────────── */

/* Filet, et rien de plus : `overflow-x` ne se declenche que si un contenu
   insecable deborde vraiment (une reference sans espace, une URL brute).
   Le tableau n'a PAS de `min-width` — il en avait une, et c'est elle qui
   fabriquait une barre de defilement sur telephone alors que trois colonnes
   courtes tiennent tres bien dans 390 px en laissant le titre passer a la
   ligne. Une barre de defilement qu'on n'a pas demandee se lit comme un
   defaut de mise en page, pas comme un service. */
.cb-table-wrap {
    overflow-x: auto;
    margin: var(--spacing-lg) 0;
    -webkit-overflow-scrolling: touch;
}

.cb-table {
    width: 100%;
}

/* Les mots tres longs se coupent plutot que d'elargir la colonne : c'est ce
   qui permet de se passer de `min-width` sans risquer le debordement. */
.cb-table__title {
    overflow-wrap: anywhere;
}

.cb-table__type {
    white-space: nowrap;
    color: var(--color-text-light);
}

/* La date ne se coupe jamais : « 03/08/ » sur une ligne et « 2026 » sur la
   suivante se lit comme deux valeurs. */
.cb-table__date {
    white-space: nowrap;
    color: var(--color-text-light);
    text-align: right;
}

.cb-table__title a {
    font-weight: 600;
}

/* Le badge suit le titre sans se coller a lui ni retomber sur la ligne du
   dessous quand le titre occupe toute la cellule. */
.cb-table__title .restricted-badge {
    margin-left: 0.4rem;
    vertical-align: middle;
}

/* ── Cadenas dans une liste a puces ou numerotee ── */
.cb-list-item .restricted-badge {
    margin-left: 0.25rem;
    vertical-align: middle;
}

.restricted-badge svg {
    display: block;
    width: 0.75rem;
    height: 0.75rem;
    flex-shrink: 0;
    fill: none;
    stroke: currentColor;
}

/* Le tooltip par défaut est en nowrap et centré : la phrase complète
   déborderait du card (overflow: hidden). Ancré à gauche du badge, largeur
   bornée et retour à la ligne autorisé.

   LA BORNE SUIT LA FENÊTRE, et pas seulement le confort de lecture. Ancré à
   gauche, le tooltip part du badge : sa largeur maximale décide donc s'il tient
   dans l'écran, et 15 rem ne tenaient pas — 207 px depuis un badge à 177 px
   donnaient 384 px sur un écran de 375, soit onze pixels de défilement
   horizontal sur toute la page. Le coupable est invisible à `querySelectorAll`
   (un pseudo-élément), et il ne se manifestait qu'à densité d'affichage 2 : à
   densité 1 le texte mesure onze pixels de moins et rentre tout juste.

   45vw ne suffisait pas : dans une rangée du composant 60, la pastille de
   rubrique pousse le cadenas à 215 px sur un écran de 375, où il ne reste que
   144 px jusqu'au bord. 34vw en laisse 127, soit une marge de trente pixels
   pour les mises en page à venir. Ce n'est pas un réglage fin : ancré à gauche,
   le tooltip ne peut être borné que par une valeur qui tienne DEPUIS la
   position la plus à droite qu'un badge puisse prendre, et le CSS ne sait pas
   la lire. */
.restricted-badge[data-tooltip]::after {
    white-space: normal;
    width: max-content;
    max-width: min(15rem, 34vw);
    left: 0;
    transform: translateX(0) translateY(-4px);
}

.restricted-badge[data-tooltip]:hover::after,
.restricted-badge[data-tooltip]:focus-visible::after {
    transform: translateX(0) translateY(0);
}

.restricted-badge[data-tooltip]::before {
    left: 0.75rem;
    transform: translateX(-50%);
}

/* Body */
.content-card__body {
    display: flex;
    flex-direction: column;
    flex: 1;
    padding: var(--spacing-md);
}

.content-card__meta-top {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    margin-bottom: var(--spacing-xs);
}

.content-card__type {
    font-size: var(--font-size-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-primary);
}

.content-card__date {
    font-size: var(--font-size-xs);
    color: var(--color-text-light);
}

.content-card__type + .content-card__date::before {
    content: '·';
    margin-right: var(--spacing-sm);
    color: var(--color-border);
}

.content-card__title {
    font-size: var(--font-size-base);
    font-weight: 600;
    line-height: var(--line-height-tight);
    color: var(--color-text);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

@media (min-width: 40em) {
    .content-card__title {
        font-size: var(--font-size-lg);
    }
}

.content-card__excerpt {
    margin-top: var(--spacing-sm);
    font-size: var(--font-size-sm);
    color: var(--color-text-light);
    line-height: var(--line-height-base);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Variante compact (sans image, card horizontale sur mobile) */
.content-card--compact .content-card__image {
    aspect-ratio: 3 / 2;
}

/* Type entre parentheses dans les listes a puces / numerotees
   (modes `bullets` / `numbered` du contentBlock). */
.cb-list-type {
    color: var(--color-text-light);
    font-weight: 400;
    font-size: 0.92em;
}

/* ──────────────────────────────────────────────────────────────
   Rendu print du badge « Accès réservé ».
   ────────────────────────────────────────────────────────────── */
@media print {

    .restricted-badge svg,
    .restricted-badge[data-tooltip]::before,
    .restricted-badge[data-tooltip]::after {
        display: none !important;
        content: none !important;
    }
}

/* ──────────────────────────────────────────────────────────────
   Variante horizontale — la « liste-card » de la maquette
   ──────────────────────────────────────────────────────────────
   Forme du composant 2c de `Cards decorees` : une VIGNETTE ETROITE en bandeau
   vertical, puis une colonne de texte. Elle se scanne verticalement et tient
   quatre a huit entrees sans casser la page, la ou une grille de cartes en
   tiendrait trois.

   La vignette passe de 9,5 rem a 4,875 rem (78 px, la valeur de la maquette) :
   a 152 px elle prenait un tiers de la ligne pour une image qu'on ne regarde
   pas — dans cette forme, elle sert de REPERE de couleur, pas d'illustration.
   C'est aussi ce qui la rend franchement differente de la carte en grille, au
   lieu d'en etre une version tassee. */
.content-card--horizontal .content-card__link {
    flex-direction: row;
    align-items: stretch;
    min-height: 0;
}

.content-card--horizontal .content-card__image {
    width: 4.875rem;
    min-width: 4.875rem;
    aspect-ratio: auto;
}

/* SANS VISUEL, LA VIGNETTE EST HACHUREE, et c'est la brique partagee
   (`.ui-hatch` est posee par le gabarit sur les cartes de liste). Ici le repli
   par defaut est une icone centree, qui a 78 px de large n'a plus la place
   d'etre lue : la hachure dit « pas d'image » sans rien demander a l'oeil. */
.content-card--horizontal .content-card__placeholder {
    background-image: repeating-linear-gradient(
        135deg,
        var(--hatch-ground) 0 var(--hatch-band),
        var(--hatch-ink) var(--hatch-band) calc(var(--hatch-band) * 2)
    );
}

.content-card--horizontal .content-card__placeholder svg {
    display: none;
}

/* LE SUR-TITRE PREND LA COULEUR DE SA RUBRIQUE et la casse des capitales : dans
   une liste, c'est lui qui donne le repere de famille d'une entree a l'autre.
   Le point de rubrique part avec — a cette taille, un rond de 8 px a cote d'un
   texte de 10 pese autant que le mot. */
.content-card--horizontal .content-card__type {
    font-size: var(--font-size-2xs);
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--section-color, var(--color-primary));
}

.content-card--horizontal .content-card__meta-top .ui-dot {
    display: none;
}

/* COMPACTE, c'est sa raison d'etre. Le corps prend le rembourrage de la
   maquette (14/16) et une gouttiere de 5 px : la variante existait pour tenir
   quatre a huit entrees dans la hauteur d'une grille de trois cartes, et elle
   rendait 114 px par entree. */
.content-card--horizontal .content-card__body {
    justify-content: flex-start;
    gap: 0.3125rem;
    padding: var(--spacing-sm) var(--spacing-md);
    min-width: 0;
}

/* PAS DE CHEVRON : la ligne entiere est cliquable et son titre le dit. La
   maquette n'en pose pas, et il coutait une colonne de 40 px sur une carte qui
   existe pour etre compacte. */
.content-card--horizontal .content-card__action {
    display: none;
}

/* PAS DE CREDIT sur une vignette de 78 px : l'etiquette y est plus large que
   l'image et se tronque en « Credit : Ha… », qui n'attribue rien. Le credit
   reste sur la fiche, ou l'image est lisible. */
.content-card--horizontal .dam-credit {
    display: none;
}


/* Meta-top : autorise le wrap pour eviter "ÉVÉNEM\nENT" et
   garde chaque libellé sur une ligne entière. */
.content-card--horizontal .content-card__meta-top {
    flex-wrap: wrap;
    margin-bottom: 0;
}

.content-card--horizontal .content-card__type,
.content-card--horizontal .content-card__date {
    white-space: nowrap;
}

/* Quand le type est suivi d'une date wrappée sur la ligne
   suivante, le séparateur "·" historique reste sur l'ancienne
   ligne — masquer pour eviter un point orphelin. */
.content-card--horizontal .content-card__type + .content-card__date::before {
    content: none;
}

/* LE TITRE PERD SA MARGE. La carte verticale l'ecarte de 32 px de la ligne de
   meta, parce qu'elle a une image au-dessus et de la place ; en liste-card,
   cette marge tripleit la hauteur de l'entree — 32 px de blanc entre deux
   lignes de texte qui se lisent ensemble. La gouttiere de la colonne suffit. */
.content-card--horizontal .content-card__title {
    -webkit-line-clamp: 2;
    line-clamp: 2;
    margin: 0;
    font-size: var(--font-size-base);
}

@media (min-width: 40em) {
    .content-card--horizontal .content-card__title {
        font-size: var(--font-size-md);
    }
}

/* Excerpt masqué en horizontal : la card vise la compacité, le
   chevron + titre + meta suffisent. */
.content-card--horizontal .content-card__excerpt {
    display: none;
}

/* Chevron d'accès — affiché uniquement en variante horizontale. */
.content-card__action {
    display: none;
}


@media (max-width: 39.9375em) {
    .content-card--horizontal .content-card__link {
        flex-direction: column;
        align-items: stretch;
        min-height: 0;
    }

    .content-card--horizontal .content-card__image {
        width: 100%;
        min-width: auto;
        aspect-ratio: 16 / 9;
    }

    .content-card--horizontal .content-card__action {
        display: none;
    }
}

/* ══════════════════════════════════════════════════════════════
   Pagination — Plus aeree, bordures plus douces, etat actif plus marque.
   ══════════════════════════════════════════════════════════════ */

.pagination {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--spacing-md);
    margin-top: var(--spacing-2xl);
    padding-top: var(--spacing-xl);
    border-top: 1px solid var(--color-border);
}

.pagination__info {
    font-size: var(--font-size-sm);
    color: var(--color-text-light);
}

.pagination__list {
    display: flex;
    align-items: center;
    /* Enroule et recentre : sur un telephone etroit, dix numeros de page
       debordaient horizontalement du conteneur au lieu de passer a la
       ligne. Le corps de page ne doit jamais defiler lateralement. */
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.375rem;
    list-style: none;
    padding: 0;
    margin: 0;
}

.pagination__link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-xs);
    min-width: 2.5rem;
    height: 2.5rem;
    padding: 0 var(--spacing-sm);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    font-size: var(--font-size-sm);
    font-weight: 500;
    text-decoration: none;
    color: var(--color-text);
    background: transparent;
    transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.pagination__link:hover:not(.pagination__link--disabled):not(.pagination__link--active) {
    background-color: var(--color-bg-light);
    border-color: var(--color-border);
    color: var(--color-primary);
}

.pagination__link:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.pagination__link--active {
    background-color: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
    font-weight: 600;
    box-shadow: 0 2px 6px color-mix(in srgb, var(--color-primary) 28%, transparent);
}

/* Pas de border permanente ni de fond blanc sur Précédent/Suivant : on
   reste sur le pattern ghost des chiffres (border-color transparent par
   défaut, hover seul porte l'affordance). Le cadre permanent créait un
   effet « double border » dissonant avec le `border-top` du wrapper
   `.pagination`. Le label texte + chevron suffit à différencier les nav
   des numéros. */
.pagination__link--prev,
.pagination__link--next {
    gap: var(--spacing-xs);
}

.pagination__link--prev:hover:not(.pagination__link--disabled),
.pagination__link--next:hover:not(.pagination__link--disabled) {
    background-color: var(--color-bg-light);
    border-color: var(--color-border);
    color: var(--color-primary);
}

.pagination__link--disabled {
    opacity: 0.35;
    cursor: default;
}

/* Label "Precedent" / "Suivant" : visible >= sm, masque sur mobile. */
.pagination__nav-label {
    display: none;
}

@media (min-width: 40em) {
    .pagination__nav-label {
        display: inline;
    }
}

.pagination__ellipsis {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    font-size: var(--font-size-sm);
    color: var(--color-text-light);
}

@media (max-width: 39.9375em) {
    /* AU DOIGT, LA LISTE SE CENTRE. A 44 px la cible, les huit reperes ne
       tiennent plus sur 366 : le dernier numero et la fleche passent a la
       ligne. Cales a droite ils y restaient orphelins ; centres, les deux
       rangees se lisent comme un bloc. Une seconde rangee vaut mieux qu'une
       cible manquee, mais elle doit avoir l'air voulue. */
    .pagination--card .pagination__list,
    .pagination__list {
        justify-content: center;
    }

    /* ── AU DOIGT : PRECEDENT, LA PAGE COURANTE, SUIVANT ──
       Le calcul ne laisse pas le choix. A 375 px, la carte offre 334 px utiles
       et la cible tactile fait 44 : huit reperes en demandent 352 plus les
       gouttieres, donc la rangee se coupait en deux. Reduire la cible etait
       l'autre issue, et c'est celle qu'on ne prend pas.

       Ce qui reste suffit a se deplacer, et la ligne au-dessus porte deja
       l'echelle : « 1 a 20 sur 118 · page 1/6 » dit ou l'on est et combien il
       reste, ce qu'une file de jetons ne dit qu'en la comptant.

       Les numeros intermediaires et les points de suspension restent dans le
       DOM : `display: none` les sort de l'arbre d'accessibilite comme du
       rendu, donc rien n'est annonce a vide. */
    .pagination__item {
        display: none;
    }

    .pagination__item:has(.pagination__link--prev),
    .pagination__item:has(.pagination__link--next),
    .pagination__item:has(.pagination__link--active) {
        display: block;
    }

    /* 2,75rem ET NON 2,25 : cette regle RETRECISSAIT la cible a 36 px la ou
       `mobile.css` pose 44 pour tout ce qui se touche, et elle gagnait — elle
       vient plus tard dans le bundle. Mesure a 390 px : 36 de large pour 44 de
       haut, soit la moitie d'une cible manquee. Deux regles qui se contredisent
       sur le meme selecteur, et c'est l'ORDRE des fichiers qui tranchait.

       Seule la police reste reduite : elle n'est pas la cible. */
    .pagination__link {
        min-width: 2.75rem;
        height: 2.75rem;
        font-size: var(--font-size-xs);
    }
    .pagination__ellipsis {
        width: 1.75rem;
        height: 2.25rem;
    }
}

/* Chips filtres actifs */
.content-list__active-filters {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-sm);
    margin-bottom: var(--spacing-lg);
}

/* .filter-chip vit désormais dans components/active-filters.css (global). */

/* Reset link (état vide avec filtres) */
.content-list__reset-link {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-xs);
    padding: var(--spacing-sm) var(--spacing-lg);
    margin-top: var(--spacing-sm);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-sm);
    font-weight: 500;
    text-decoration: none;
    background: var(--color-primary);
    color: #fff;
    transition: background-color 0.15s ease;
}

.content-list__reset-link:hover {
    background: var(--color-primary-dark);
}

@media (max-width: 39.9375em) {
    .dropdown__label {
        display: none;
    }
}

/* ══════════════════════════════════════════════════════════════
   Dropdown — Composant select custom (remplace <select> natif)
   ══════════════════════════════════════════════════════════════ */

.dropdown {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-xs);
    position: relative;
}

.dropdown__label {
    font-size: var(--font-size-sm);
    color: var(--color-text-light);
    white-space: nowrap;
}

.dropdown__wrapper {
    position: relative;
}

.dropdown__trigger {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-sm);
    padding: 0.4375rem 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-sm);
    font-weight: 500;
    line-height: 1.4;
    color: var(--color-text);
    background: #fff;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
    appearance: none;
}

.dropdown__trigger:hover {
    border-color: var(--color-primary);
}

.dropdown__trigger:focus-visible {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 2px var(--color-primary-light);
}

.dropdown__value {
    flex: 1;
    text-align: left;
}

.dropdown__chevron {
    flex-shrink: 0;
    color: var(--color-text-light);
    transition: transform 0.2s ease;
}

.dropdown__chevron--open {
    transform: rotate(180deg);
}

/* Menu déroulant */
.dropdown__menu {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    min-width: 100%;
    max-height: 280px;
    overflow-y: auto;
    padding: 0.25rem;
    margin: 0;
    list-style: none;
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.06);
    z-index: 50;
}

/* Menu teleporte vers <body> (coords fixed posees en inline par Alpine) :
   echappe a l'`overflow: auto` de la sidebar qui clipperait le menu absolu
   et declencherait un ascenseur parasite. `right: auto` annule le `right: 0`
   du menu absolu (sinon conflit avec le `left` inline). */
.dropdown__menu--teleported {
    position: fixed;
    right: auto;
    /* Au-dessus du panneau de filtres (2001) : la teleportation existe
       PRECISEMENT pour echapper au conteneur qui defile, et a 200 le menu en
       sortait pour se ranger DERRIERE lui — invisible, alors que le clic
       fonctionnait. Sous le toaster (2500), qui doit rester lisible par-dessus
       tout.

       Un z-index ne se lit jamais dans l'absolu : celui-ci n'avait rien de faux
       tant qu'aucune couche au-dessus de 200 n'accueillait de liste
       deroulante. */
    z-index: var(--z-overlay-menu);
}

/* Transitions Alpine.js */
.dropdown__menu--enter {
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.dropdown__menu--enter-start {
    opacity: 0;
    transform: translateY(-4px);
}

.dropdown__menu--enter-end {
    opacity: 1;
    transform: translateY(0);
}

.dropdown__menu--leave {
    transition: opacity 0.1s ease, transform 0.1s ease;
}

.dropdown__menu--leave-start {
    opacity: 1;
    transform: translateY(0);
}

.dropdown__menu--leave-end {
    opacity: 0;
    transform: translateY(-4px);
}

/* Options */
.dropdown__option {
    list-style: none;
}

.dropdown__option-link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-md);
    width: 100%;
    padding: 0.5rem 0.75rem;
    border: none;
    border-radius: var(--radius-sm);
    font-size: var(--font-size-sm);
    text-align: left;
    text-decoration: none;
    color: var(--color-text);
    background: transparent;
    cursor: pointer;
    white-space: nowrap;
    transition: background-color 0.1s ease, color 0.1s ease;
}

.dropdown__option-link:hover {
    background: var(--color-bg-light);
    color: var(--color-primary);
}

.dropdown__option--active .dropdown__option-link {
    color: var(--color-primary);
    font-weight: 600;
}

.dropdown__check {
    flex-shrink: 0;
    color: var(--color-primary);
}

/* État loading — spinner + barre de progression */
.dropdown__trigger--loading {
    pointer-events: none;
    opacity: 0.7;
}

.dropdown__spinner {
    flex-shrink: 0;
    color: var(--color-primary);
    animation: dropdown-spin 0.7s linear infinite;
}

@keyframes dropdown-spin {
    to { transform: rotate(360deg); }
}

.dropdown__loading-bar {
    position: absolute;
    bottom: -1px;
    left: 0;
    right: 0;
    height: 2px;
    border-radius: 1px;
    overflow: hidden;
    background: var(--color-primary-light);
}

.dropdown__loading-bar::after {
    content: '';
    display: block;
    width: 40%;
    height: 100%;
    background: var(--color-primary);
    border-radius: 1px;
    animation: dropdown-loading 1s ease-in-out infinite;
}

@keyframes dropdown-loading {
    0%   { transform: translateX(-100%); }
    50%  { transform: translateX(200%); }
    100% { transform: translateX(-100%); }
}

/* Variante sm (compacte) */
.dropdown--sm .dropdown__trigger {
    padding: 0.3125rem 0.625rem;
    font-size: var(--font-size-xs);
}

.dropdown--sm .dropdown__option-link {
    padding: 0.375rem 0.625rem;
    font-size: var(--font-size-xs);
}

/* ══════════════════════════════════════════
   Teaser wall — paywall souple
   ══════════════════════════════════════════ */

/* Corps tronqué : masque le débordement */
.article-single__body--teaser {
    position: relative;
    overflow: hidden;
    max-height: none;
}

/* Bandeau teaser */
.teaser-wall {
    position: relative;
    margin-top: -8rem;
    padding-top: 8rem;
    text-align: center;
}

/* Sans fondu : le mur se pose normalement dans le flux. La remontee de 8 rem
   n'a de sens que s'il y a du texte a dissoudre au-dessus. */
.teaser-wall--flat {
    margin-top: var(--spacing-xl);
    padding-top: 0;
}

.teaser-wall__gradient {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 8rem;
    background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.85) 50%, rgba(255, 255, 255, 1) 100%);
    pointer-events: none;
}

.teaser-wall__content {
    background: var(--color-bg-light);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--spacing-xl) var(--spacing-lg);
    max-width: 32rem;
    margin: 0 auto;
}

.teaser-wall__icon {
    color: var(--color-primary);
    margin-bottom: var(--spacing-sm);
}

.teaser-wall__title {
    font-size: var(--font-size-lg);
    font-weight: 700;
    color: var(--color-text);
    margin: 0 0 var(--spacing-xs);
}

.teaser-wall__description {
    font-size: var(--font-size-sm);
    color: var(--color-text-light);
    margin: 0 0 var(--spacing-lg);
    line-height: 1.5;
}

.teaser-wall__actions {
    display: flex;
    gap: var(--spacing-sm);
    justify-content: center;
    flex-wrap: wrap;
}

/* « Pas encore de compte ? » — les deux voies d'acces, sous les boutons et
   separees d'eux : ce sont des explications, pas des actions concurrentes.
   Alignees a gauche parce qu'on les LIT, alors que le titre et les boutons
   au-dessus se balaient. Un paragraphe centre de trois lignes se relit mal :
   l'oeil doit rechercher le debut de chaque ligne. */
.teaser-wall__aside {
    margin-top: var(--spacing-lg);
    padding-top: var(--spacing-lg);
    border-top: 1px solid var(--color-border);
    text-align: left;
}

.teaser-wall__aside-title {
    margin: 0 0 var(--spacing-sm);
    font-size: 0.9375rem;
    font-weight: 700;
    color: var(--color-text);
}

.teaser-wall__aside-list {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-sm);
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--color-text-light);
}

.teaser-wall__aside-list strong {
    color: var(--color-text);
}

.teaser-wall__aside-list a {
    display: inline-block;
    margin-top: 0.15rem;
    font-weight: 600;
    color: var(--color-primary);
}


/* ══════════════════════════════════════════════════════════════
   Bloc EditorJS : crmTeam — grille de personnes
   ══════════════════════════════════════════════════════════════ */

/* Team : grille propre, sans card, juste photo + nom + rôle.
   Mêmes principes que timeline : pas de bordures, air généreux. */
.tiptap-crm-team {
    margin: var(--spacing-3xl) 0;
}

/* Double-classe pour battre .prose-content h3 (spécificité 0,1,1) */
.tiptap-crm-team .tiptap-crm-team__title {
    font-size: var(--font-size-xl);
    font-weight: 700;
    margin: 0 0 var(--spacing-xl);
    padding: 0 0 var(--spacing-sm);
    border-bottom: 1px solid var(--color-border);
    color: var(--color-text);
}

.tiptap-crm-team__list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    gap: var(--spacing-2xl) var(--spacing-lg);
    grid-template-columns: 1fr;
}

@media (min-width: 30em) {
    .tiptap-crm-team--grid .tiptap-crm-team__list {
        grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    }
}

/* Chaque fiche porte deja un filet de separation et sa propre respiration
   interne : un grand ecart en plus etirait la liste sans rien clarifier. */
.tiptap-crm-team--list .tiptap-crm-team__list {
    grid-template-columns: 1fr;
    gap: var(--spacing-sm);
}

.tiptap-crm-team__card {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--spacing-sm);
    padding: 0;
    background: transparent;
    border: none;
    transition: transform var(--transition-fast);
}

/* Mode « resume » : portrait a gauche, identite puis biographie a droite.
   `center`, et non `flex-start` : le portrait fait desormais la hauteur du
   bloc de texte type (8rem contre ~130px). Cale en haut, il ne s'aligne donc
   avec le texte que sur la fiche la plus longue — partout ailleurs il
   deborde par le bas, et la liste parait decalee d'une ligne a l'autre.
   Centre, la fiche reste equilibree quelle que soit la longueur du resume.
   (Le raisonnement inverse, tenu en livrant le mode liste, valait quand le
   portrait ne faisait que 4rem.) */
.tiptap-crm-team--list .tiptap-crm-team__card {
    flex-direction: row;
    text-align: left;
    align-items: center;
    gap: var(--spacing-lg);
    padding-bottom: var(--spacing-md);
    border-bottom: 1px solid var(--color-border);
}

.tiptap-crm-team--list .tiptap-crm-team__card:last-child {
    padding-bottom: 0;
    border-bottom: none;
}

/* Pas de soulevement au survol en mode liste : la carte occupe toute la
   largeur, la faire bouger deplacerait tout le paragraphe sous le curseur. */
.tiptap-crm-team--list .tiptap-crm-team__card:hover {
    transform: none;
}

.tiptap-crm-team__card:hover {
    transform: translateY(-2px);
}

/* Double-classe OBLIGATOIRE pour battre `.prose-content img` (0,1,1), qui
   arrondit toutes les images de contenu a `--radius-md`. Sans elle, le
   portrait sort en carre a coins arrondis alors que la regle demande un
   cercle — et le defaut ne se voit QUE sur une vraie photo : le repli en
   initiales est un `<div>`, que ce selecteur n'atteint pas. Un jeu de test
   sans image donne donc des cercles parfaits et un faux sentiment de
   conformite. Meme motif que le titre du bloc et que le lien « Lire la
   biographie ». */
.tiptap-crm-team .tiptap-crm-team__photo {
    width: 6.5rem;
    height: 6.5rem;
    border-radius: 50%;
    object-fit: cover;
    background: var(--color-bg-light);
    border: none;
    flex-shrink: 0;
    transition: box-shadow var(--transition-fast);
}

.tiptap-crm-team__card:hover .tiptap-crm-team__photo {
    box-shadow: 0 6px 20px rgba(12, 21, 32, 0.12);
}

/* Meme grammaire d'avatar que le trombinoscope `/portraits` et que la fiche :
   cercle detache du fond par un lisere blanc.

   Taille calee sur la hauteur du bloc de texte type — nom, biographie resumee
   sur deux lignes, lien vers la fiche, soit environ 8rem. Mesure prise sur la
   page gouvernance : 104px de texte sans le lien, ~130px avec. Un portrait
   nettement plus petit que sa colonne de texte donne une rangee desequilibree,
   ce que faisaient les 4rem d'origine comme les 5rem qui ont suivi. */
.tiptap-crm-team--list .tiptap-crm-team__photo {
    width: 8rem;
    height: 8rem;
    box-shadow: 0 0 0 3px #fff, 0 6px 16px rgba(15, 23, 42, 0.12);
}

/* Sous 30em, un portrait de 8rem mangerait la moitie de la largeur : la
   biographie se retrouverait dans une colonne de quelques mots. */
@media (max-width: 29.9375em) {
    .tiptap-crm-team--list .tiptap-crm-team__photo {
        width: 5rem;
        height: 5rem;
    }
}

.tiptap-crm-team__photo--placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--font-size-xl);
    font-weight: 700;
    color: var(--color-text-light);
    letter-spacing: 0.05em;
}

.tiptap-crm-team__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1;
}

.tiptap-crm-team__name {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
    color: var(--color-text);
    line-height: var(--line-height-tight);
}

.tiptap-crm-team__role {
    margin: 0;
    font-size: var(--font-size-sm);
    font-weight: 500;
    color: var(--color-primary);
}

.tiptap-crm-team__org {
    margin: 0;
    font-size: var(--font-size-xs);
    color: var(--color-text-light);
}

.tiptap-crm-team__bio {
    margin: var(--spacing-xs) 0 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-light);
    line-height: 1.55;
}

/* Biographie resumee : conteneur de blocs rendus (role editorial `teaser`),
   contrairement a la biographie complete qui tient dans un seul <p> de texte
   brut. Les marges internes sont neutralisees pour que les deux variantes
   occupent le meme rythme vertical dans la carte. */
.tiptap-crm-team__bio--resume > :first-child {
    margin-top: 0;
}

.tiptap-crm-team__bio--resume > :last-child {
    margin-bottom: 0;
}

.tiptap-crm-team__bio--resume p {
    margin: 0 0 var(--spacing-xs);
}

.tiptap-crm-team__bio--resume a {
    color: inherit;
    text-decoration: underline;
}

/* Lien vers la fiche complete. Rendu seulement quand la fiche existe
   vraiment (consentement `public_biography`, cf. le gabarit). */
.tiptap-crm-team__more {
    margin: var(--spacing-sm) 0 0;
    font-size: var(--font-size-sm);
}

/* Double-classe pour battre `.prose-content a` (0,1,1), qui souligne tous les
   liens de contenu : ici le souligné permanent alourdit une liste de fiches
   qui en compte un par personne. Même motif que le titre du bloc. */
.tiptap-crm-team .tiptap-crm-team__more-link {
    display: inline-flex;
    align-items: center;
    gap: 0.3125rem;
    color: var(--color-primary);
    font-weight: 600;
    text-decoration: none;
}

.tiptap-crm-team .tiptap-crm-team__more-link:hover,
.tiptap-crm-team .tiptap-crm-team__more-link:focus-visible {
    text-decoration: underline;
}

/* La fleche avance au survol : elle signale un depart vers une autre page,
   pas un depliement sur place. */
.tiptap-crm-team__more-link span[aria-hidden] {
    transition: transform 0.15s ease;
}

.tiptap-crm-team__more-link:hover span[aria-hidden] {
    transform: translateX(2px);
}

/* ══════════════════════════════════════════════════════════════
   Bloc EditorJS : timeline — frise chronologique
   Layout 3 colonnes : année | axe (dot) | contenu
   Pas de bordure sur le contenu — juste un rythme vertical propre.
   ══════════════════════════════════════════════════════════════ */

.tiptap-timeline {
    margin: var(--spacing-3xl) 0;
    max-width: 52rem;
}

.tiptap-timeline__title {
    font-size: var(--font-size-xl);
    font-weight: 700;
    margin: 0 0 var(--spacing-lg);
    padding-bottom: var(--spacing-sm);
    border-bottom: 1px solid var(--color-border);
    color: var(--color-text);
}

.tiptap-timeline__list {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2xl);
    margin: 0;
    padding: 0;
}

.tiptap-timeline__item {
    display: grid;
    /* Colonne de date ELASTIQUE et bornee. Elle etait figee a 5 rem avec
       `white-space: nowrap` : un libelle plus long que « 2012 » — et une frise
       editoriale en porte souvent (« Printemps 2020 », « 2001-2005 ») —
       debordait par-dessus la pastille, qui se retrouvait au milieu du texte.
       La borne haute empeche a l'inverse un libelle a rallonge de manger la
       colonne de contenu. */
    grid-template-columns: minmax(5rem, 9rem) 1.5rem 1fr;
    gap: var(--spacing-lg);
    align-items: start;
}

/* Colonne année à gauche, alignée à droite pour "coller" visuellement au dot.
   Même typographie que le titre pour un alignement vertical parfait. */
.tiptap-timeline__year {
    align-self: start;
    font-size: 1rem;
    font-weight: 700;
    line-height: var(--line-height-tight);
    color: var(--color-primary);
    text-align: right;
    letter-spacing: 0.02em;
    /* Un libelle long passe a la ligne plutot que de deborder. */
    overflow-wrap: break-word;
}

/* Colonne axe : ligne verticale continue + dot en haut de chaque item */
.tiptap-timeline__marker {
    position: relative;
    align-self: stretch;
    display: flex;
    justify-content: center;
    min-height: 2rem;
}

.tiptap-timeline__marker::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: calc(-1 * var(--spacing-2xl));
    left: 50%;
    transform: translateX(-50%);
    width: 2px;
    background: var(--color-border);
}

.tiptap-timeline__item:last-child .tiptap-timeline__marker::before {
    bottom: auto;
    height: 0.625rem;
}

.tiptap-timeline__dot {
    position: relative;
    z-index: 1;
    width: 0.875rem;
    height: 0.875rem;
    margin-top: 0.25rem;
    border-radius: 50%;
    background: var(--color-primary);
    box-shadow: 0 0 0 4px #fff, 0 0 0 6px var(--color-primary-light);
}

/* Colonne contenu : pas de card, juste du texte bien hiérarchisé */
.tiptap-timeline__content {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-xs);
}

/* LE TITRE D'UN JALON N'A PAS DE CLASSE : le contenu d'un `timelineItem` est du
   HTML editorial libre, `<h4>` compris. La regle precedente visait
   `.tiptap-timeline__item-title`, que personne n'emet — elle ne matchait donc
   jamais, et son commentaire decrivait pourtant exactement le defaut qui
   subsistait : `.prose-content h4` posait 24 px de marge haute et le titre
   tombait 49 px sous son annee.

   Une regle morte assortie d'un commentaire qui affirme corriger le bug est
   pire qu'une absence de regle : elle fait croire le probleme traite. On vise
   donc le PREMIER ENFANT du contenu, quel qu'il soit — titre, paragraphe,
   liste — avec assez de specificite pour battre `.prose-content h4` (0,1,1). */
.prose-content .tiptap-timeline__content > :first-child {
    margin-top: 0;
}

.tiptap-timeline .tiptap-timeline__content > :is(h3, h4, h5) {
    margin-bottom: 0;
    font-size: 1rem;
    font-weight: 700;
    color: var(--color-text);
    line-height: var(--line-height-tight);
}

/* Responsive : sur mobile étroit, année au-dessus, axe + contenu en dessous */
@media (max-width: 29.9375em) {
    .tiptap-timeline__item {
        grid-template-columns: 1.5rem 1fr;
        grid-template-areas:
            "year year"
            "marker content";
    }

    .tiptap-timeline__year {
        grid-area: year;
        text-align: left;
        padding-top: 0;
    }

    .tiptap-timeline__marker {
        grid-area: marker;
    }

    .tiptap-timeline__content {
        grid-area: content;
    }
}

.tiptap-timeline__image {
    max-width: 100%;
    height: auto;
    border-radius: var(--radius-md);
    margin: var(--spacing-xs) 0;
}

.tiptap-timeline__text {
    font-size: var(--font-size-base);
    color: var(--color-text-light);
    line-height: 1.6;
    margin: 0;
}

.tiptap-timeline__text p { margin: 0 0 var(--spacing-xs); }
.tiptap-timeline__text p:last-child { margin-bottom: 0; }
.tiptap-timeline__text a { color: var(--color-primary); text-decoration: underline; }
.tiptap-timeline__text a:hover { color: var(--color-primary-dark); }
.tiptap-timeline__text strong { font-weight: 700; color: var(--color-text); }

.tiptap-timeline__link {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-xs);
    margin-top: var(--spacing-xs);
    align-self: flex-start;
    padding: var(--spacing-xs) var(--spacing-sm);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-sm);
    font-weight: 600;
    color: var(--color-navy);
    text-decoration: none;
    transition: color var(--transition-fast), transform var(--transition-fast);
}

.tiptap-timeline__link:hover {
    color: var(--color-primary);
    transform: translateX(2px);
}


/* Precision sous un message « aucun resultat » : elle propose une suite,
   elle n'annonce rien. Un cran sous le corps de texte. */
.content-list__empty-hint {
    font-size: var(--font-size-sm);
}

/* ── Regroupement en PUCES ──
   Ce que la maquette v2 pose a la place d'une liste deroulante quand la liste
   n'a que deux ou trois axes : un menu cache derriere un clic un choix qui tient
   en trois mots, et il ne montre pas les axes disponibles tant qu'on ne l'ouvre
   pas.

   Meme grammaire que les pastilles de facette du rail — c'est le meme geste
   (choisir une valeur parmi peu), il doit avoir la meme forme.

   LA MISE EN LIGNE N'EST PAS ICI : elle vient de `content-list__field--inline`,
   la grammaire partagee d'une etiquette posee A COTE de ses controles. La
   redeclarer aurait recree la divergence qu'elle existe pour empecher. */
.content-list__group-pill {
    display: inline-flex;
    align-items: center;
    height: 1.75rem;
    padding: 0 var(--spacing-ms);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    background: var(--surface-2);
    font-size: var(--font-size-xs);
    font-weight: 600;
    /* Meme raison que dans les pastilles de facette : une hauteur de ligne
       heritee laisse le texte flotter dans sa boite, et le centrage de la boite
       ne rattrape pas le decalage de la ligne. */
    line-height: 1;
    color: var(--color-text);
    white-space: nowrap;
}

.content-list__group-pill:hover {
    border-color: var(--color-primary);
    color: var(--color-primary-dark);
    text-decoration: none;
}

/* L'etat est le REMPLISSAGE, comme pour les facettes : dans une grappe de trois,
   une puce pleine se lit d'un coup d'oeil la ou un soulignement se cherche. */
.content-list__group-pill--on {
    border-color: var(--color-primary);
    background: var(--color-primary);
    color: var(--color-on-primary);
}

/* UNE PASTILLE ACTIVE GARDE SON ENCRE AU SURVOL.
   `:hover` compte DEUX selecteurs (classe + pseudo-classe) contre UN pour
   `--on` : il l'emportait donc, et repeignait l'encre en navy fonce PAR-DESSUS
   le fond bleu. Mesure : #1b2e5a sur #2a4d92, soit un contraste d'environ
   1,6:1 — ce n'est pas une maladresse d'aspect, c'est un texte illisible.

   Le survol d'un etat DEJA choisi n'a d'ailleurs rien a annoncer : le seul
   retour utile est que la cible reste cliquable, et le curseur le dit. */
.content-list__group-pill--on:hover,
.content-list__group-pill--on:focus-visible {
    color: var(--color-on-primary);
}

/* ── Pagination EN CARTE ──
   Ce que la maquette v2 pose au pied d'une liste dont la barre est deja une
   carte : la plage a gauche, les numeros a droite, dans une surface blanche.
   Sans elle, la pagination flottait sous la grille comme un reste.

   `ui-card` est emise par le gabarit et porte surface, bordure et rayon. Ne
   restent ici que les corrections propres a l'usage : la colonne centree
   redevient une rangee, et le filet superieur disparait — la carte separe deja.

   Variante opt-in : les six autres listes gardent le bandeau centre. */
.pagination--card {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-ms);
    flex-wrap: wrap;
    margin-top: 0;
    padding: var(--spacing-ms) var(--spacing-md);
    border-top: 0;
}

/* Chasse fixe, comme tous les reperes chiffres du site : la plage change a
   chaque page, et une police proportionnelle la fait sauter d'une largeur a
   l'autre sous les yeux. */
.pagination--card .pagination__info {
    font-family: var(--font-data);
    font-size: var(--font-size-xs);
}

/* Les numeros se rangent a droite, et cessent de se centrer : ils ne sont plus
   seuls sur leur ligne. */
.pagination--card .pagination__list {
    justify-content: flex-end;
    margin-left: auto;
}

/* Sous 48 em, la carte de pagination s'EMPILE plutot que de s'enrouler.

   `space-between` + `flex-wrap` la faisait passer a deux lignes des que la place
   manquait — mais une seconde ligne obtenue par enroulement se range a DROITE,
   sous une premiere ligne qui occupe toute la largeur. On lit un debordement,
   pas une mise en page.

   EN FIN DE BLOC, et ce n'est pas un rangement : a specificite egale c'est
   l'ORDRE qui tranche. Posee plus haut, cette media query etait reecrite par le
   `justify-content: flex-end` de la regle de base — la pagination restait calee
   a droite sous le compteur, centre a 265 pour une carte centree a 188. Le piege
   est nomme dans `design-system.md`, et je viens de le repayer. */
@media (width < 48em) {
    .pagination--card {
        flex-direction: column;
        align-items: center;
        gap: var(--spacing-sm);
    }

    .pagination--card .pagination__list {
        justify-content: center;
        margin-left: 0;
    }
}

/* ── CHIFFRES-CLES D'EN-TETE DE LISTE ─────────────────────────────────────────
   Le composant de chiffre de la maquette « Pages de rubrique » : un filet
   court, la valeur en Barlow, l'intitule en dessous. La maquette les range en
   RANGEE sous le hero, et en COLONNE dans sa section marine — c'est la seconde
   forme, parce qu'ici ils occupent la colonne droite de l'en-tete, celle ou une
   photographie irait si la page en avait une.

   Rendu ici et non dans `content-header.css` : c'est une composition de PAGE
   posee dans la fente `aside`, pas une piece de la brique. Une regle partagee
   se paie sur les sept pages de liste ; celle-ci n'en sert qu'une, et la feuille
   qui la porte est deja chargee par toutes.

   La colonne ne s'ETIRE PAS : `--split > .content-header__aside` porte
   `align-self: flex-start`, et c'est deliberer — etiree, elle prendrait la
   hauteur du titre plus le chapo plus la ligne de service, et l'ecart entre les
   chiffres dependrait de la longueur du chapo. Le `gap` fixe ci-dessous est ce
   qui les tient a distance constante. */
.list-figures {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    /* ECART DE RANGEE RESSERRE depuis que la photographie occupe une cellule.
       La grille est passee de deux rangees a trois : a 24 px d'ecart et 16 px de
       rembourrage, la colonne montait a 325 px quand celle de `/actualites` en
       fait 277, et c'est ELLE qui donnait alors sa hauteur a l'en-tete — la
       colonne de gauche n'en fait que 266. Mesure du 2026-08-29 : en-tete a
       413 px contre 365. A 16 px d'ecart et 12 de rembourrage, les quatre
       chiffres et la photographie tiennent dans la meme hauteur qu'une mosaique
       de trois photos. */
    gap: var(--spacing-md);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* LA CELLULE PHOTOGRAPHIE, quand l'agenda en porte une.
   Elle ENJAMBE DEUX RANGEES dans la premiere colonne : c'est le decoupage de la
   mosaique du hero, « un grand a gauche sur deux rangees, deux petits empiles a
   droite ». Posee au-dessus de la grille au lieu d'y entrer, elle ajoutait
   312 px et l'en-tete montait a 625 contre 359 pour `/actualites`.

   Meme arrondi et meme ecretage que la cellule de mosaique : c'est le meme
   objet, une photographie dans un cadre. `cover`, parce que c'est une
   PHOTOGRAPHIE et non une affiche — le `contain` des cartes d'agenda existe
   pour ne pas mutiler un visuel compose avec son texte, ce qui n'est pas le
   cas ici. */
.list-figures__photo {
    min-width: 0;
}

/* LA PHOTOGRAPHIE EN BAS A DROITE, sur deux rangees. Le placement est EXPLICITE
   par zones, et non laisse au placement automatique : en flux, une cellule qui
   enjambe deux rangees a partir du milieu entre en collision avec le chiffre
   qui occupe deja sa case, et la grille ouvre une rangee de plus.

   Elle est aussi la DERNIERE du balisage. Elle est decorative — alternative
   vide, l'information est dans les chiffres — et la lire en premier ferait
   annoncer une image avant les quatre nombres qu'elle accompagne.
   L'ordre visuel vient des zones, l'ordre de lecture du balisage : les deux
   n'ont pas a coincider ici. */
.list-figures--photo {
    grid-template-areas:
        "f1 f2"
        "f3 ph"
        "f4 ph";
}

.list-figures--photo .list-figures__item:nth-child(1) { grid-area: f1; }
.list-figures--photo .list-figures__item:nth-child(2) { grid-area: f2; }
.list-figures--photo .list-figures__item:nth-child(3) { grid-area: f3; }
.list-figures--photo .list-figures__item:nth-child(4) { grid-area: f4; }
.list-figures--photo .list-figures__photo { grid-area: ph; }

/* ── MOINS DE TROIS CHIFFRES : LA PHOTO PASSE PLEINE LARGEUR ──

   Les zones ci-dessus sont dessinees pour QUATRE chiffres et une photo, la
   composition de /ressources. Le centre d'aide n'en a qu'un ou deux : `f3` et
   `f4` restaient vides, la photo occupait la colonne de droite des rangees 2
   et 3, et l'en-tete rendait une photographie petite, decalee vers le bas et
   posee par-dessus la forme decorative, avec un grand vide a sa gauche.

   Le selecteur compte les CHIFFRES, pas les enfants : avec deux chiffres, le
   troisieme enfant est la photo elle-meme, qui ne porte pas
   `.list-figures__item`. La regle s'applique donc a un et a deux chiffres, et
   jamais a quatre.

   Un seul chiffre : il prend aussi toute la largeur. Une carte a demi-largeur
   suivie d'un trou est pire que deux blocs pleins. */
.list-figures--photo:not(:has(.list-figures__item:nth-child(3))) {
    grid-template-areas:
        "f1 f2"
        "ph ph";
}

.list-figures--photo:not(:has(.list-figures__item:nth-child(2))) {
    grid-template-areas:
        "f1 f1"
        "ph ph";
}

/* ── UN CHIFFRE SEUL, SOUS LE PALIER, PREND TOUTE LA LARGEUR ──
   La grille est a deux colonnes a toutes les tailles : une rubrique qui n'a
   qu'un chiffre rendait au telephone une carte a demi-largeur suivie d'un
   trou. Sur grand ecran la demi-largeur est juste — la colonne fait 560 px et
   la carte y garde une taille de carte. */
@media (width < 64em) {
    .list-figures:not(.list-figures--photo):not(:has(.list-figures__item:nth-child(2))) .list-figures__item {
        grid-column: 1 / -1;
    }
}

/* La photo pleine largeur a besoin d'une PROPORTION : sans elle, la cellule
   prend la hauteur de son contenu, et l'image s'etirait sur toute la hauteur
   disponible. 16/7, la meme que la couverture d'une fiche. */
.list-figures--photo:not(:has(.list-figures__item:nth-child(3))) .list-figures__figure {
    aspect-ratio: 16 / 7;
    height: auto;
}

.list-figures__figure {
    position: relative;
    height: 100%;
    margin: 0;
    overflow: hidden;
    border-radius: var(--radius-md);
}

.list-figures__image {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* CARTES DE NIVEAU 3, pas des cartes pleines. La grammaire des fonds interdit
   de meler deux niveaux dans une meme vue, et l'en-tete n'a AUCUNE surface
   (`--bare`) : quatre `ui-card` y pesaient plus que le titre, et les chiffres
   auraient eu l'air plus importants que la page. Le niveau 3 est decrit pour
   exactement cet emploi — « blanc translucide sur le plateau, sans bordure,
   presentes jamais concurrentes » — et c'est ce que la maquette emploie pour
   les cartes de sa colonne d'appui. On obtient le rythme sans l'inversion de
   hierarchie.

   NI BORDURE NI OMBRE : ce sont les trois marques de premier plan de la carte
   du systeme, et c'est precisement ce qu'on ne veut pas ici. Meme raisonnement,
   et meme jeton, que la carte « prochain rendez-vous ». */
.list-figures__item {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2xs);
    min-width: 0;
    padding: var(--spacing-ms);
    border-radius: var(--radius-md);
    background: var(--surface-3);
}

.list-figures__value {
    font-family: var(--font-title);
    font-size: var(--font-size-3xl);
    font-weight: 700;
    line-height: 1;
    color: var(--color-primary-dark);
}

.list-figures__label {
    font-size: var(--font-size-sm);
    line-height: 1.45;
    color: var(--color-text-light);
    /* Un intitule de deux mots ne doit pas casser au milieu d'un mot dans une
       colonne de 200 px. */
    text-wrap: pretty;
}

/* ── LA RANGEE D'ACTIONS D'UNE TETE DE LISTE ──
   Maquette « Cards decorees ANCESU », tour 4c : un bouton primaire qui MENE
   quelque part, et le partage a cote, en second rang.

   ELLE REMPLACE LA LIGNE DE SERVICE, elle ne s'y ajoute pas. La maquette pose
   le reproche en toutes lettres : « le seul bouton est le moins utile » —
   « Partager » etait l'unique action d'une page de rubrique, quand rien ne
   menait au dossier le plus recent. Le partage reste, il descend d'un rang.

   Les deux controles sont des BRIQUES : `ui.button` et `_share_buttons`. La
   rangee les met en ligne, et elle decide du RANG du second. */
.hero-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-ms);
    margin-top: var(--spacing-sm);
}

/* ══ LES DEUX CONTROLES SUR UNE MEME LIGNE ══════════════════════════════════
   A partir de 30em, le bouton garde sa largeur intrinseque et le partage tient
   a cote. C'est LA que le second doit se distinguer du premier, et c'est donc
   la seule portee ou les regles qui suivent ont un sens. */
@media (width >= 30em) {

    /* ── LE PARTAGE PASSE EN LIEN, SANS CADRE ──

       La maquette le pose ainsi et elle a une raison : deux controles encadres
       COTE A COTE se lisent comme deux choix equivalents, alors que l'un MENE au
       dernier dossier et que l'autre est un service. Le cadre est ce qui dit
       « bouton » ; le retirer suffit a dire « second rang ».

       La regle est portee par la RANGEE et non par la brique de partage :
       ailleurs sur le site, le declencheur encadre reste juste — dans une ligne
       de service, il n'a pas de bouton primaire a cote de qui se demarquer.
       C'est le contexte qui decide, donc c'est le contexte qui l'ecrit.

       ET ELLE NE VAUT QUE TANT QU'ILS PARTAGENT UNE LIGNE. Sous 30em le partage
       passe dessous : il n'a plus de voisin dont se distinguer, et un libelle nu
       centre sous un bouton plein n'a plus aucune forme. Il reprend alors son
       cadre, cf. plus bas. */
    .hero-actions .share-dropdown__summary {
        padding-inline: var(--spacing-md);
        border-color: transparent;
        border-radius: var(--radius-md);
        background: transparent;
        color: var(--color-navy);
        font-weight: 600;
    }

    .hero-actions .share-dropdown__summary:hover,
    .hero-actions .share-dropdown__summary:focus-visible {
        border-color: transparent;
        background: var(--surface-3);
    }

    /* LA HAUTEUR N'EST PAS UN NOMBRE, c'est celle du bouton — mais il faut la
       TRANSMETTRE, et c'est la que la premiere version se trompait.

       `align-self: stretch` avait ete pose sur le `summary`, qui n'est PAS
       l'enfant direct de la rangee : le declencheur vit dans
       `.share-dropdown-group > details > summary`. La regle ne s'appliquait donc
       a rien, et le commentaire qui la justifiait affirmait le contraire de ce
       qui se passait — mesure a 1440 px, bouton 44 px, declencheur 30. L'ecart
       ne se voit pas : sans cadre ni fond, seule la ZONE CLIQUABLE retrecit, de
       32 %.

       La hauteur descend donc la chaine entiere, maillon par maillon. Le
       `align-items: stretch` du groupe est EXPLICITE : il porte `center` dans sa
       propre feuille, et un maillon qui centre interrompt la chaine aussi
       surement qu'un maillon absent. */
    .hero-actions > .share-dropdown-group {
        align-self: stretch;
        display: flex;
        align-items: stretch;
    }

    .hero-actions .share-dropdown {
        display: flex;
    }

    .hero-actions .share-dropdown__summary {
        align-self: stretch;
    }
}

/* ══ SUR TELEPHONE : UNE PILE, ET DEUX FORMES DISTINCTES ════════════════════

   A 375 px, les deux controles cote a cote ne tiennent pas — il faudrait 339 px
   pour 309 disponibles. Le bouton prend donc la largeur et le partage passe
   dessous.

   ET IL SE CENTRE, ce qui est le point. Aligne a gauche, son pictogramme
   s'assoit au bord de la rangee pendant que le libelle du bouton, lui, est
   centre : deux axes de lecture a douze pixels d'ecart, qu'on lit comme un
   defaut d'alignement et non comme deux rangs. Centre, l'ensemble forme une
   pile coherente.

   L'ECART PASSE DE 12 A 16 px. Serre a douze sous un bouton pleine largeur, le
   lien se lit comme la suite du bouton plutot que comme un second rang. */
@media (width < 30em) {
    .hero-actions {
        justify-content: center;
        gap: var(--spacing-md);
    }

    .hero-actions > .btn {
        width: 100%;
    }

    /* SEUL SUR SA LIGNE, LE PARTAGE NE PEUT PLUS S'ETIRER. `align-self: stretch`
       remplit une LIGNE de flex : quand le declencheur passe a la ligne, il est
       seul dessus et cette ligne fait sa propre hauteur — 30 px mesures, la ou
       la rangee lui en donnait 44 quand il partageait la ligne du bouton.

       C'est exactement la ou une hauteur minimale se justifie, et elle n'est pas
       un nombre choisi : `--touch-target-min` est le plancher de zone tactile de
       la charte. Sur telephone, ou le doigt remplace la souris, un declencheur
       de 30 px est le seul endroit de cette tete qu'on rate. */
    .hero-actions .share-dropdown__summary {
        min-height: var(--touch-target-min);
    }
}


/* DEUX COLONNES A TOUTES LES LARGEURS, et pas d'`auto-fit`.
   `auto-fit` ouvrait jusqu'a CINQ pistes des que l'en-tete s'empile et que la
   colonne prend la largeur de la page : les quatre chiffres passaient sur une
   seule rangee, en cartes de 110 px, ou « formats de rendez-vous » tient sur
   quatre lignes. Mesure du 2026-08-29 : 5 pistes a 900 px, 4 a 768, 3 a 640.

   Ils ne descendent pas non plus a une colonne : quatre lignes de chiffres
   avant le premier resultat repousseraient la liste hors de l'ecran. Deux, aux
   deux bouts de l'echelle. */

/* ── EN-TETE DE L'AGENDA ─────────────────────────────────────────────────────
   Deux reglages propres a cette page. Ils passent DEVANT `content-header.css`
   par la specificite et non par l'ordre : cette feuille est chargee AVANT elle,
   donc a specificite egale c'est la brique qui gagnerait. */

/* LES QUATRE CHIFFRES SE DECALENT EN MOSAIQUE.
   Quatre cartes egales alignees sur deux rangees droites forment une grille, et
   une grille se lit comme un tableau. Le decalage leur rend le rythme de la
   mosaique du hero, qui tient le sien du DECOUPAGE et non d'une rotation — la
   maquette est explicite la-dessus : « trois cadres penches dans une grille se
   lisent comme un defaut d'alignement ».

   PAR `transform` ET NON PAR UNE MARGE. Une marge haute sur la colonne de
   droite grandirait la premiere rangee de la grille, donc le bloc entier, et le
   centrage pose juste au-dessus serait fausse d'autant. Un `transform` ne
   touche pas a la mise en page : la boite reste celle que le centrage a
   calculee.

   ET EN SENS OPPOSES, une demie chacun : la colonne de gauche monte de 16 px,
   celle de droite descend d'autant. Le centre visuel du bloc ne bouge donc pas
   — decaler une seule colonne vers le bas aurait fait descendre l'ensemble de
   huit pixels et rouvert la question du centrage.

   BORNE AU MEME PALIER que le centrage : le decalage n'a de sens qu'a DEUX
   colonnes. Sur une colonne unique, ce n'est plus une mosaique, c'est un
   defaut d'alignement. */
@media (min-width: 64em) {
    .content-header--agenda .list-figures {
        --figures-decalage: 2rem;
    }

    .content-header--agenda .list-figures:not(.list-figures--photo) .list-figures__item:nth-child(odd) {
        transform: translateY(calc(var(--figures-decalage) / -2));
    }

    .content-header--agenda .list-figures:not(.list-figures--photo) .list-figures__item:nth-child(even) {
        transform: translateY(calc(var(--figures-decalage) / 2));
    }
}

/* LES CHIFFRES SE CENTRENT SUR LA COLONNE DE GAUCHE. La brique pose
   `align-self: flex-start` sur l'aside, et c'est juste pour une mosaique :
   etiree, elle repartirait la hauteur du titre plus le chapo plus la ligne de
   service sur ses rangees, et la proportion des photos dependrait de la
   longueur du chapo. Une colonne de chiffres n'a pas ce probleme — elle garde
   sa hauteur propre — et cales en haut, ses 209 px laissaient 25 px de vide
   sous eux quand la colonne de gauche en fait 234.

   `center` et NON `stretch` : rien n'est etire, donc le defaut ci-dessus ne
   peut pas revenir par ici.

   BORNE AU PALIER 64em, celui ou la brique passe le corps en rangee. En
   dessous il est en colonne, `align-self` y gouverne l'HORIZONTALE, et centrer
   retrecirait le bloc a la largeur de son contenu. */
@media (min-width: 64em) {
    .content-header--agenda .content-header__body--split > .content-header__aside {
        align-self: center;
    }
}

/* ── LA LIGNE DE DATE D'UNE CARTE D'AGENDA ───────────────────────────────────
   Elle a d'abord ete une pastille posee SUR l'affiche, puis un cartouche en
   chasse fixe. Les deux ont ete ecartes a l'ecran, et pour trois raisons qui se
   cumulaient : la pastille couvrait l'oeuvre, elle se lisait mal sur une
   affiche chargee, et sa fleche ecrivait deux fois le mois pour dire deux jours
   consecutifs.

   C'est donc une LIGNE, et elle est mise en valeur par ce qui compte : elle
   vient AVANT le type et le titre, elle porte son pictogramme, et elle est la
   seule donnee de la carte en couleur de marque. Sur un agenda, la date est ce
   que l'on cherche en premier.

   `order: -1` PARCE QUE LA SEULE FENTE DISPONIBLE TOMBE APRES LE CHAPO. Le bloc
   `media_card_content` de la brique est place la ; le corps etant une colonne
   flex, l'ordre visuel se corrige sans toucher au composant partage. L'ordre de
   LECTURE reste celui du balisage, et il est le bon : un lecteur d'ecran
   annonce le titre avant la date. */
.agenda-card__date {
    order: -1;
    display: flex;
    align-items: center;
    gap: var(--spacing-xs);
    margin: 0;
    font-family: var(--font-data);
    font-size: var(--font-size-xs);
    font-weight: 600;
    line-height: 1.2;
    color: var(--color-primary);
}

.agenda-card__date svg {
    flex: none;
    opacity: 0.75;
}

/* ── LE CADRE D'UNE AFFICHE D'EVENEMENT ──────────────────────────────────────
   « Affiche de l'edition, fond blanc, jamais recadree » : c'est la regle de la
   maquette, au composant 46, et elle vaut partout ou une affiche est montree.
   Le fond blanc est deja celui de la brique (`--fit-contain` -> `--surface-2`,
   qui vaut #ffffff), donc les bandes d'un `contain` ne se voient pas : les
   affiches sont elles-memes sur blanc.

   CE QUI MANQUAIT EST LA FORME DU CADRE. Les visuels d'evenement sont des
   BANDEAUX — mesure du 2026-08-29 sur les treize : ratios de 1,76 a 6,00,
   neuf au-dessus de 2, mediane a 2,81. Dans une boite 16/9, une affiche a 2,81
   n'occupe que la largeur et laisse 37 % de hauteur vide ; elle flotte au lieu
   de remplir. A 2,8, elle occupe son cadre entier.

   LA MEDIANE ET NON LA MOYENNE : deux valeurs extremes (6,00 et 4,09) tirent la
   moyenne vers le haut et videraient les onze autres. A 2,8, le gachis moyen
   tombe de 31 % a 18 %.

   BORNE A L'ECHELLE VERTICALE. La vedette pose son visuel a GAUCHE en 4/3, la
   ou la hauteur vient du texte a cote : une bande y serait un filet. Et la
   regle « un seul ratio par contexte » est tenue — toutes les cartes de la
   grille ont le meme. */
.media-card--agenda.media-card--vertical .media-card__media {
    aspect-ratio: 2.8 / 1;
}

/* LA VEDETTE PREND LA MEME FORME, et pas le 4/3 de l'echelle. Son visuel est une
   colonne de gauche dont la hauteur vient du texte a cote : une affiche a 2,81
   y laissait 53 % de blanc et flottait au milieu d'un cadre deux fois trop
   haut. Cale en haut et a la bonne proportion, elle remplit sa largeur.

   `align-self: start` : sans lui, la colonne s'etire sur la hauteur du texte et
   le rapport impose ne s'applique plus. */
.media-card--agenda.media-card--feature .media-card__media {
    align-self: start;
    aspect-ratio: 2.8 / 1;
}
