/* ==========================================================================
   Movember Almaviva Santé
   Couche de design posée par-dessus Bootstrap 5.3.
   Charte : bleu Almaviva dominant, orange Almaviva en accent, blanc respirant.
   ========================================================================== */

@font-face {
    font-family: 'Anton';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/anton-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                   U+02DC, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}

:root {
    /* Bleus Almaviva */
    --mo-blue-900: #001a3d;
    --mo-blue-800: #002754;
    --mo-blue-700: #003c87;   /* bleu du logo */
    --mo-blue-600: #0a4fa8;
    --mo-blue-400: #2e7bd6;
    --mo-blue-100: #d9e6f7;

    /* Orange Almaviva */
    --mo-orange: #ef7d00;
    --mo-orange-2: #ff9e38;

    /* Neutres */
    --mo-paper: #ffffff;
    --mo-cream: #f3f7fc;
    --mo-text: #14233c;
    --mo-muted: #5b6a84;
    --mo-line: rgba(255, 255, 255, .13);
    --mo-line-dark: rgba(0, 60, 135, .12);

    --mo-font-display: 'Anton', 'Arial Black', Impact, sans-serif;
    --mo-font-body: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;

    --mo-radius: 18px;
    --mo-shadow: 0 18px 45px -22px rgba(0, 26, 61, .45);
}

/* --- Base ---------------------------------------------------------------- */

html {
    scroll-behavior: smooth;
    scroll-padding-top: 84px;
    /* Sur <body> seul, le débordement horizontal reste scrollable via <html> :
       il faut la règle sur les deux pour supprimer la barre du bas. */
    overflow-x: hidden;
}

body {
    font-family: var(--mo-font-body);
    color: var(--mo-text);
    background: var(--mo-cream);
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}

/* « hidden » fait de <body> une boîte de défilement à lui seul, et
   position:sticky se cale alors sur cette boîte — qui ne défile jamais. La
   barre de navigation ne collait donc pas. « clip » coupe le débordement
   exactement pareil, mais sans créer de boîte de défilement : sticky retrouve
   la fenêtre pour repère. Les rubans continuent d'être rognés, la barre du bas
   ne revient pas, et « hidden » reste le repli pour les navigateurs qui ne
   connaissent pas encore « clip ». */
@supports (overflow: clip) {
    html,
    body {
        overflow-x: clip;
    }
}

::selection {
    background: var(--mo-orange);
    color: #fff;
}

:focus-visible {
    outline: 3px solid var(--mo-orange);
    outline-offset: 3px;
    border-radius: 4px;
}

.display-font {
    font-family: var(--mo-font-display);
    font-weight: 400;
    letter-spacing: .01em;
    line-height: .95;
    text-transform: uppercase;
}

.eyebrow {
    display: inline-flex;
    align-items: center;
    gap: .6rem;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--mo-orange);
    margin-bottom: 1rem;
}

.eyebrow::before {
    content: '';
    flex: none;
    width: 30px;
    height: 3px;
    border-radius: 3px;
    background: var(--mo-orange);
}

/* Le trait devient une petite moustache. On se sert du PNG du héros comme
   masque : la couleur reste celle du libellé et l'image est déjà en cache.
   Les navigateurs sans mask-image gardent le trait. */
@supports ((mask-image: url('')) or (-webkit-mask-image: url(''))) {
    .eyebrow::before {
        /* 962 × 250 dans le fichier, soit un rapport de 3,85. */
        width: 42px;
        height: 11px;
        border-radius: 0;
        background: currentColor;
        -webkit-mask: url('../../img/moustache-orange.png') no-repeat center / contain;
        mask: url('../../img/moustache-orange.png') no-repeat center / contain;
    }
}

.section {
    padding: clamp(3.5rem, 8vw, 7rem) 0;
    position: relative;
}

/* Sections « profondes » : bleu Almaviva, jamais du noir. */
.section--dark {
    background: linear-gradient(180deg, var(--mo-blue-900), var(--mo-blue-800));
    color: #fff;
}

.section--paper {
    background: var(--mo-paper);
}

.section-title {
    font-size: clamp(2rem, 5.2vw, 3.5rem);
    /* Anton est très serré : sans cet écart, les accents des capitales
       (É de « ÉTABLISSEMENT ») viennent toucher la ligne précédente. */
    line-height: 1.06;
    color: var(--mo-blue-700);
}

.section--dark .section-title {
    color: #fff;
}

.lead-muted {
    color: var(--mo-muted);
    font-size: 1.06rem;
     
}

.section--dark .lead-muted {
    color: rgba(255, 255, 255, .72);
}

/* --- Boutons ------------------------------------------------------------- */

.btn-mo {
    --bs-btn-color: #fff;
    --bs-btn-bg: var(--mo-orange);
    --bs-btn-border-color: var(--mo-orange);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: #d96f00;
    --bs-btn-hover-border-color: #d96f00;
    --bs-btn-active-bg: #c46400;
    --bs-btn-active-border-color: #c46400;
    --bs-btn-disabled-bg: var(--mo-orange);
    --bs-btn-disabled-border-color: var(--mo-orange);
    font-weight: 650;
    letter-spacing: .01em;
    border-radius: 100px;
    padding: .78rem 1.6rem;
    box-shadow: 0 12px 28px -14px rgba(239, 125, 0, .95);
    transition: transform .18s ease, box-shadow .18s ease, background-color .18s ease;
}

.btn-mo:hover {
    transform: translateY(-2px);
    box-shadow: 0 18px 34px -14px rgba(239, 125, 0, .95);
}

.btn-blue {
    --bs-btn-color: #fff;
    --bs-btn-bg: var(--mo-blue-700);
    --bs-btn-border-color: var(--mo-blue-700);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--mo-blue-600);
    --bs-btn-hover-border-color: var(--mo-blue-600);
    font-weight: 640;
    border-radius: 100px;
    padding: .78rem 1.6rem;
    transition: transform .18s ease;
}

.btn-blue:hover {
    transform: translateY(-2px);
}

/* Bouton fantôme, posé sur les fonds bleus profonds. */
.btn-ghost {
    --bs-btn-color: #fff;
    --bs-btn-border-color: rgba(255, 255, 255, .38);
    --bs-btn-hover-color: var(--mo-blue-700);
    --bs-btn-hover-bg: #fff;
    --bs-btn-hover-border-color: #fff;
    --bs-btn-active-color: var(--mo-blue-700);
    --bs-btn-active-bg: #fff;
    font-weight: 620;
    border-radius: 100px;
    padding: .78rem 1.6rem;
    transition: transform .18s ease;
}

.btn-ghost:hover {
    transform: translateY(-2px);
}

/* Bouton discret sur fond clair. */
.btn-outline-ink {
    --bs-btn-color: var(--mo-blue-700);
    --bs-btn-border-color: rgba(0, 60, 135, .28);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--mo-blue-700);
    --bs-btn-hover-border-color: var(--mo-blue-700);
    border-radius: 100px;
    font-weight: 620;
    padding: .7rem 1.4rem;
}

/* --- Signature de marque -------------------------------------------------- */

.mo-brand {
    display: inline-flex;
    align-items: center;
    gap: .85rem;
    text-decoration: none;
}

.mo-brand img {
    height: 36px;
    width: auto;
    display: block;
}

/* ---------------------------------------------------------------------------
   Le mot « Movember »

   Movember est une marque déposée de la Movember Foundation : le mot se reprend
   tel quel, d'un seul tenant et en noir. Il ne se recolorise pas et ne se coupe
   pas en deux couleurs — d'où le <span> intérieur ramené à la même encre que le
   reste. Sur les fonds sombres (pied de page, admin), la marque ne devient pas
   blanche : elle se pose sur une plaque claire, comme un logo appliqué sur un
   support foncé.

   Avant le 2026-09-09, la signature était bicolore : « Mo » en
   var(--mo-blue-700), « vember » en var(--mo-orange), et blanche en variante
   claire. Une copie des fichiers d'origine est dans
   .backup/2026-09-09_movember-noir/ si l'on veut revenir en arrière.
   --------------------------------------------------------------------------- */

.mo-brand-text {
    font-family: var(--mo-font-display);
    font-size: 1.4rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    line-height: 1;
    color: #000;
    padding-left: .85rem;
    border-left: 1px solid var(--mo-line-dark);
}

.mo-brand-text span {
    color: inherit;
}

/* Variante posée sur les fonds bleus profonds (pied de page, admin) : la marque
   reste noire, c'est le fond qui s'éclaircit sous elle. La barre de séparation
   n'a plus lieu d'être, la plaque fait déjà la coupure. */
.mo-brand--light .mo-brand-text {
    background: #fff;
    padding: .45rem .8rem;
    border-left: 0;
    border-radius: 8px;
}

/* --- Navigation ---------------------------------------------------------- */

.mo-nav {
    background: rgba(255, 255, 255, .93);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--mo-line-dark);
    transition: background .25s ease, box-shadow .25s ease, padding-block .25s ease;
    padding-block: .5rem;
}

/* ---------------------------------------------------------------------------
   La barre qui se pose

   En haut de page, la barre fait partie du décor : haute, aérée, sans ombre.
   Passé le premier écran, elle se resserre et prend son ombre, puis ne bouge
   plus. Le mouvement est une transition, pas une arrivée par le haut : la
   barre est déjà collée quand le seuil est franchi, la faire sortir de l'écran
   pour l'y ramener se voyait comme un clignotement.

   Le seuil de sortie (60 px) est plus bas que celui d'entrée (140 px) : sans
   cet écart, une molette qui hésite autour du seuil ferait battre la barre à
   chaque cran.
   --------------------------------------------------------------------------- */

.mo-nav.is-pinned {
    background: rgba(255, 255, 255, .98);
    box-shadow: 0 14px 34px -22px rgba(0, 26, 61, .6);
    padding-block: .38rem;
}

/* Le logo et le nom se resserrent avec elle. */
.mo-nav .mo-brand img,
.mo-nav .mo-brand-text {
    transition: height .25s ease, font-size .25s ease;
}

/* ---------------------------------------------------------------------------
   L'appel à l'action suit le même mouvement : il perd de la hauteur en même
   temps que la barre. C'est lui l'élément le plus haut de la barre — s'il
   gardait sa taille pleine, la barre posée se réduirait à un liseré de part et
   d'autre du bouton. En le resserrant plus que la barre, on garde la hauteur
   totale gagnée au défilement tout en lui rendant de l'air.
   Les dimensions vivent ici et non en classes utilitaires : une transition ne
   peut pas animer un px-3 qui ne bouge pas.
   --------------------------------------------------------------------------- */

.mo-nav__cta {
    padding: .55rem 1.15rem;
    font-size: .92rem;
    white-space: nowrap;
    transition: padding .25s ease, font-size .25s ease,
                transform .18s ease, box-shadow .18s ease, background-color .18s ease;
}

.mo-nav.is-pinned .mo-nav__cta {
    padding: .3rem .95rem;
    font-size: .84rem;
    box-shadow: 0 9px 22px -14px rgba(239, 125, 0, .95);
}

/* Page ouverte déjà défilée (une ancre, un retour arrière) : la barre est
   posée d'emblée, sans jouer la transition — on n'anime pas un changement
   d'état que personne n'a vu se produire. */
.mo-nav.is-instant,
.mo-nav.is-instant .mo-brand img,
.mo-nav.is-instant .mo-brand-text,
.mo-nav.is-instant .mo-nav__cta {
    transition: none;
}

.mo-nav.is-pinned .mo-brand img {
    height: 30px;
}

.mo-nav.is-pinned .mo-brand-text {
    font-size: 1.2rem;
}

.mo-nav .nav-link {
    display: flex;
    align-items: center;
    gap: .45rem;
    color: var(--mo-blue-800);
    font-weight: 560;
    font-size: .95rem;
    padding: .5rem .95rem;
    border-radius: 100px;
    transition: color .16s ease, background .16s ease;
}

/* L'icône reste en retrait du libellé, et prend la couleur d'accent au
   survol : elle guide l'œil sans concurrencer le texte. */
.mo-nav .nav-link > .bi {
    font-size: 1rem;
    line-height: 1;
    color: var(--mo-blue-400);
    transition: color .16s ease;
}

.mo-nav .nav-link:hover,
.mo-nav .nav-link:focus,
.mo-nav .nav-link.active {
    color: var(--mo-blue-700);
    background: rgba(0, 60, 135, .07);
}

.mo-nav .nav-link:hover > .bi,
.mo-nav .nav-link:focus > .bi,
.mo-nav .nav-link.active > .bi {
    color: var(--mo-orange);
}

.mo-nav .navbar-toggler {
    border-color: var(--mo-line-dark);
    color: var(--mo-blue-700);
    padding: .4rem .6rem;
}

.mo-nav .navbar-toggler:focus {
    box-shadow: none;
}

@media (max-width: 991.98px) {
    .mo-nav .navbar-collapse {
        border-top: 1px solid var(--mo-line-dark);
        margin-top: .6rem;
        padding-top: .6rem;
    }
}

/* --- Héros --------------------------------------------------------------- */

.mo-hero {
    position: relative;
    background: linear-gradient(165deg, var(--mo-blue-800) 0%, var(--mo-blue-900) 55%, #00132e 100%);
    color: #fff;
    padding: clamp(3rem, 9vw, 6rem) 0 clamp(3rem, 7vw, 5rem);
    overflow: hidden;
    isolation: isolate;
}

/* ---------------------------------------------------------------------------
   Ruban de sensibilisation
   Motif récurrent du site : posé en filigrane sur le héros, le bandeau de
   chiffres, l'encart d'aide et le pied de page. Toujours décoratif, donc
   aria-hidden côté balisage et pointer-events désactivés ici.
   --------------------------------------------------------------------------- */

.mo-hero__ribbon,
.gallery-hero__ribbon,
.has-ribbon::before,
.help-band::after,
.mo-footer::before {
    background: url('../../img/ruban.webp') no-repeat center / contain;
    pointer-events: none;
}

/* ---------------------------------------------------------------------------
   Le ruban respire

   Même geste que la moustache du héros (.mo-stache) : le ruban monte un peu et
   s'incline, sans fin. Chaque exemplaire garde sa pose d'origine, d'où le
   passage par des variables — la rotation de base fait partie de la même
   propriété transform que l'animation, elle ne peut pas rester dans une règle
   à part.

   Les durées diffèrent d'un ruban à l'autre, et les délais sont négatifs :
   deux rubans visibles en même temps ne partent donc pas du même point du
   cycle et ne battent jamais ensemble.
   --------------------------------------------------------------------------- */

.mo-hero__ribbon,
.gallery-hero__ribbon,
.has-ribbon::before,
.help-band::after,
.mo-footer::before,
.causes-ribbon,
.slideshow__ribbon {
    --mo-ribbon-rot: 0deg;    /* pose d'origine */
    --mo-ribbon-flip: 1;      /* -1 pour un ruban retourné */
    --mo-ribbon-lift: -16px;  /* hauteur du souffle */
    --mo-ribbon-sway: 1.3deg; /* inclinaison ajoutée au sommet */
    transform: rotate(var(--mo-ribbon-rot)) scaleX(var(--mo-ribbon-flip));
    animation: mo-ribbon-drift var(--mo-ribbon-time, 14s) ease-in-out infinite;
}

@keyframes mo-ribbon-drift {
    0%, 100% {
        transform: translate3d(0, 0, 0)
                   rotate(var(--mo-ribbon-rot))
                   scaleX(var(--mo-ribbon-flip));
    }
    50% {
        transform: translate3d(0, var(--mo-ribbon-lift), 0)
                   rotate(calc(var(--mo-ribbon-rot) + var(--mo-ribbon-sway)))
                   scaleX(var(--mo-ribbon-flip));
    }
}

.mo-hero__ribbon {
    position: absolute;
    z-index: -1;
    top: -10%;
    right: -2%;
    width: min(44vw, 560px);
    height: 120%;
    opacity: .17;
    --mo-ribbon-rot: 9deg;
    --mo-ribbon-time: 13s;
    animation-delay: -2s;
}

@media (max-width: 991.98px) {
    .mo-hero__ribbon {
        right: -26%;
        width: 86vw;
        opacity: .1;
    }
}

/* Sur fond clair, le ruban n'est plus un filigrane : il est affiché en plein,
   à côté du titre de la section « Les causes ». Comme on le voit vraiment, son
   souffle est plus court que celui des filigranes. */
.causes-ribbon {
    width: auto;
    height: clamp(190px, 21vw, 300px);
    filter: drop-shadow(0 18px 28px rgba(0, 60, 135, .2));
    --mo-ribbon-rot: 7deg;
    --mo-ribbon-lift: -11px;
    --mo-ribbon-sway: 1.1deg;
    --mo-ribbon-time: 9s;
}

.has-ribbon {
    position: relative;
    overflow: hidden;
}

.has-ribbon::before {
    content: '';
    position: absolute;
    left: -34px;
    top: -45%;
    width: 210px;
    height: 190%;
    opacity: .09;
    --mo-ribbon-rot: -13deg;
    --mo-ribbon-time: 17s;
    animation-delay: -6s;
}

.mo-hero__glow {
    position: absolute;
    inset: -30% -10% auto -10%;
    height: 130%;
    z-index: -3;
    background:
        radial-gradient(46% 40% at 20% 16%, rgba(239, 125, 0, .34), transparent 68%),
        radial-gradient(44% 42% at 84% 26%, rgba(46, 123, 214, .55), transparent 70%),
        radial-gradient(62% 52% at 50% 102%, rgba(255, 158, 56, .16), transparent 70%);
    pointer-events: none;
}

.mo-hero__grid {
    position: absolute;
    inset: 0;
    z-index: -2;
    background-image:
        linear-gradient(rgba(255, 255, 255, .05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, .05) 1px, transparent 1px);
    background-size: 64px 64px;
    mask-image: radial-gradient(70% 60% at 50% 40%, #000 30%, transparent 100%);
    -webkit-mask-image: radial-gradient(70% 60% at 50% 40%, #000 30%, transparent 100%);
    pointer-events: none;
}

.mo-badge {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .42rem 1rem .42rem .55rem;
    border: 1px solid var(--mo-line);
    background: rgba(255, 255, 255, .07);
    border-radius: 100px;
    font-size: .82rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .88);
}

.mo-badge .dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--mo-orange);
    box-shadow: 0 0 0 4px rgba(239, 125, 0, .22);
    animation: mo-pulse 2.4s ease-in-out infinite;
}

@keyframes mo-pulse {
    0%, 100% { box-shadow: 0 0 0 3px rgba(239, 125, 0, .28); }
    50%      { box-shadow: 0 0 0 8px rgba(239, 125, 0, 0); }
}

.mo-hero__title {
    font-size: clamp(3.4rem, 15vw, 10.5rem);
    line-height: .82;
    margin: 1.4rem 0 0;
    background: linear-gradient(180deg, #fff 28%, #b9d3f2 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.mo-hero__year {
    font-family: var(--mo-font-display);
    font-size: clamp(1rem, 2.4vw, 1.6rem);
    color: var(--mo-orange-2);
    letter-spacing: .5em;
    text-transform: uppercase;
    margin-top: .9rem;
}

.mo-hero__tagline {
    font-size: clamp(1.05rem, 2.2vw, 1.35rem);
    color: rgba(255, 255, 255, .8);
    max-width: 46ch;
}

.mo-stache {
    /* Les boucles des extrémités ont besoin de place : en dessous d'environ
       240 px de large, les ajours se referment visuellement. */
    width: clamp(250px, 48vw, 540px);
    height: auto;
    display: block;
    filter: drop-shadow(0 10px 18px rgba(239, 125, 0, .3));
    animation: mo-float 6s ease-in-out infinite;
}

@keyframes mo-float {
    0%, 100% { transform: translateY(0) rotate(0deg); }
    50%      { transform: translateY(-10px) rotate(-1.2deg); }
}

/* --- Compte à rebours ---------------------------------------------------- */

.mo-countdown {
    display: flex;
    gap: .6rem;
    flex-wrap: wrap;
}

.mo-count-box {
    background: rgba(255, 255, 255, .07);
    border: 1px solid var(--mo-line);
    border-radius: 14px;
    padding: .7rem 1rem;
    min-width: 78px;
    text-align: center;
}

.mo-count-box b {
    display: block;
    font-family: var(--mo-font-display);
    font-size: 1.9rem;
    line-height: 1;
    color: #fff;
    font-variant-numeric: tabular-nums;
}

.mo-count-box span {
    font-size: .68rem;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .55);
}

/* --- Bandeau défilant ---------------------------------------------------- */

.mo-marquee {
    background: var(--mo-orange);
    color: #fff;
    padding: .85rem 0;
    overflow: hidden;
}

/* La piste est un multiple exact du motif : l'animation la décale de 50 %,
   donc d'un nombre entier de groupes, et la boucle est invisible. Aucun
   padding ici, il fausserait ce calcul et ferait apparaître un décalage. */
.mo-marquee__track {
    display: flex;
    width: max-content;
    animation: mo-scroll var(--mo-marquee-duration, 34s) linear infinite;
    will-change: transform;
}

.mo-marquee__group {
    display: flex;
    align-items: center;
    gap: 3rem;
    padding-right: 3rem;
    flex: 0 0 auto;
}

.mo-marquee__group span {
    font-family: var(--mo-font-display);
    font-size: 1.1rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    white-space: nowrap;
}

@keyframes mo-scroll {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

/* --- Mention légale de la campagne --------------------------------------- */

/* Une ligne de service, pas une section : elle se lit sans arrêter l'œil, juste
   sous le bandeau orange et avant que la page ne commence vraiment. */
.mo-legal {
    background: var(--mo-paper);
    border-bottom: 1px solid var(--mo-line-dark);
    padding: 1.1rem 0;
}

.mo-legal__text {
    max-width: 78ch;
    margin-inline: auto;
    text-align: center;
    font-size: .92rem;
    line-height: 1.55;
    color: var(--mo-muted);
}

/* --- Chiffres clés ------------------------------------------------------- */

.mo-fact {
    padding: 1.6rem 1.2rem;
    border-left: 1px solid var(--mo-line);
    height: 100%;
}

.mo-fact b {
    display: block;
    font-family: var(--mo-font-display);
    font-size: clamp(2.4rem, 6vw, 3.6rem);
    line-height: 1;
    color: var(--mo-orange-2);
    font-variant-numeric: tabular-nums;
}

.mo-fact span {
    display: block;
    margin-top: .55rem;
    color: rgba(255, 255, 255, .7);
    font-size: .95rem;
    max-width: 24ch;
}

/* --- Cartes « causes » --------------------------------------------------- */

.cause-card {
    background: var(--mo-paper);
    border: 1px solid var(--mo-line-dark);
    border-radius: var(--mo-radius);
    padding: 1.9rem 1.6rem;
    height: 100%;
    position: relative;
    overflow: hidden;
    transition: transform .22s ease, box-shadow .22s ease, border-color .22s ease;
}

.cause-card::after {
    content: '';
    position: absolute;
    inset: auto -40% -60% auto;
    width: 220px;
    height: 220px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(0, 60, 135, .12), transparent 70%);
    opacity: 0;
    transition: opacity .3s ease;
}

.cause-card:hover {
    transform: translateY(-6px);
    box-shadow: var(--mo-shadow);
    border-color: rgba(0, 60, 135, .35);
}

.cause-card:hover::after {
    opacity: 1;
}

.cause-card__icon {
    width: 54px;
    height: 54px;
    border-radius: 16px;
    display: grid;
    place-items: center;
    font-size: 1.5rem;
    color: #fff;
    background: linear-gradient(135deg, var(--mo-blue-700), var(--mo-blue-400));
    margin-bottom: 1.1rem;
    box-shadow: 0 12px 22px -12px rgba(0, 60, 135, .9);
}

.cause-card h3 {
    font-size: 1.18rem;
    font-weight: 700;
    margin-bottom: .55rem;
    color: var(--mo-blue-800);
}

.cause-card p {
    color: var(--mo-muted);
    font-size: .95rem;
    margin: 0;
}

.cause-card__tag {
    position: absolute;
    top: 1.4rem;
    right: 1.4rem;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: #a35400;
    background: rgba(239, 125, 0, .14);
    border-radius: 100px;
    padding: .28rem .7rem;
}

/* --- Listes de conseils --------------------------------------------------- */

.checks {
    list-style: none;
    padding: 0;
    margin: 1.1rem 0 0;
}

.checks li {
    display: flex;
    gap: .55rem;
    align-items: flex-start;
    font-size: .89rem;
    line-height: 1.5;
    color: var(--mo-muted);
    margin-bottom: .5rem;
}

.checks li:last-child {
    margin-bottom: 0;
}

.checks i {
    color: var(--mo-orange);
    font-size: .95rem;
    line-height: 1.5;
    flex: 0 0 auto;
}

/* Encart d'aide : une touche de bleu au milieu d'une section blanche. */
.help-band {
    position: relative;
    overflow: hidden;
    margin-top: 3rem;
    background: linear-gradient(120deg, var(--mo-blue-800), var(--mo-blue-700));
    color: #fff;
    border-radius: var(--mo-radius);
    padding: 1.6rem 1.8rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.5rem;
    flex-wrap: wrap;
}

.help-band::after {
    content: '';
    position: absolute;
    right: 12%;
    top: -60%;
    width: 120px;
    height: 240%;
    opacity: .2;
    --mo-ribbon-rot: 12deg;
    --mo-ribbon-time: 11s;
    animation-delay: -4s;
}

.help-band > * {
    position: relative;
    z-index: 1;
}

.help-band strong {
    display: block;
    font-size: 1.05rem;
    margin-bottom: .3rem;
}

.help-band span {
    color: rgba(255, 255, 255, .74);
    font-size: .94rem;
    max-width: 62ch;
    display: block;
}

/* --- Programme (timeline) ------------------------------------------------ */

.timeline {
    position: relative;
    margin-top: 2.5rem;
}

.timeline__item {
    position: relative;
    padding-left: 76px;
    padding-bottom: 2.1rem;
}

/* Le trait est découpé en segments d'une pastille à la suivante : il démarre
   sous l'icône et s'arrête avant la suivante, plutôt que de les traverser.
   --i (rang de l'étape) et --n (nb d'étapes - 1) viennent du gabarit et
   reproduisent le dégradé d'origine, de l'orange plein au presque effacé. */
.timeline__item::before {
    content: '';
    position: absolute;
    left: 27px;
    top: 66px;
    bottom: 10px;
    width: 2px;
    background: var(--mo-orange);
    opacity: calc(1 - .8 * var(--i, 0) / var(--n, 1));
}

.timeline__item:last-child {
    padding-bottom: 0;
}

.timeline__item:last-child::before {
    display: none;
}

.timeline__dot {
    position: absolute;
    left: 0;
    top: 0;
    z-index: 1;
    width: 56px;
    height: 56px;
    border-radius: 18px;
    display: grid;
    place-items: center;
    font-size: 1.35rem;
    color: var(--mo-orange-2);
    background: rgba(255, 255, 255, .06);
    border: 1px solid var(--mo-line);
}

.timeline__date {
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--mo-orange-2);
}

.timeline__item h3 {
    font-size: 1.15rem;
    font-weight: 700;
    margin: .35rem 0 .4rem;
    color: #fff;
}

.timeline__item p {
    color: rgba(255, 255, 255, .68);
    margin: 0;
    max-width: 58ch;
    font-size: .96rem;
}

/* --- Étapes « participer » ----------------------------------------------- */

.step {
    display: flex;
    gap: 1rem;
    align-items: flex-start;
}

.step__num {
    flex: 0 0 auto;
    width: 42px;
    height: 42px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-family: var(--mo-font-display);
    font-size: 1.15rem;
    color: #fff;
    background: var(--mo-blue-700);
}

.step h4 {
    font-size: 1.02rem;
    font-weight: 700;
    margin-bottom: .25rem;
    color: var(--mo-blue-800);
}

.step p {
    color: var(--mo-muted);
    font-size: .93rem;
    margin: 0;
}

/* --- bootstrap-select : socle commun ------------------------------------- */

/* Sa feuille masque le <select> d'origine dès qu'elle est chargée
   (select.selectpicker { display: none !important }). Sans JS pour poser le
   menu, il faut le remettre à l'écran : mieux vaut la liste native que pas
   de liste du tout. */
html:not(.js) select.selectpicker {
    display: block !important;
}

/* bootstrap-select recopie les classes du <select> sur sa div conteneur :
   sans ça, .form-select y dessinerait une seconde bordure et un second
   chevron autour du bouton. La largeur, elle, est reprise par data-width :
   la feuille de bootstrap-select impose 220 px avec un sélecteur à quatre
   classes, inutile de surenchérir. */
.bootstrap-select.form-select {
    display: block;
    height: auto;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
}

/* Le menu est en position absolue : sans largeur imposée, il se dimensionne
   sur l'entrée la plus longue et déborde de l'écran sur mobile. */
.bootstrap-select > .dropdown-menu {
    width: 100%;
}

/* Sa feuille impose son propre halo de focus en !important
   (outline: 5px auto -webkit-focus-ring-color), qui jure avec le reste : à la
   souris on lui substitue l'anneau des autres champs, au clavier on garde un
   contour net. */
.bootstrap-select > .dropdown-toggle:focus:not(:focus-visible) {
    outline: none !important;
}

.bootstrap-select > .dropdown-toggle:focus-visible {
    outline: 2px solid var(--mo-orange) !important;
    outline-offset: 2px;
}

/* Le <select> masqué porte toujours la contrainte « required » : c'est donc
   au bouton de virer au rouge quand la validation Bootstrap s'affiche. */
.was-validated .bootstrap-select:has(> select:invalid) > .dropdown-toggle {
    border-color: var(--bs-form-invalid-border-color, #dc3545);
}

.was-validated .bootstrap-select:has(> select:invalid) > .dropdown-toggle:focus {
    box-shadow: 0 0 0 .22rem rgba(220, 53, 69, .25);
}

/* --- Galerie ------------------------------------------------------------- */

/* En-tête de la galerie : il chapeaute les deux concours, on le traite donc
   comme un second héros — centré, halo discret, appel à l'action et compteurs
   sous le texte — plutôt qu'en titre de section aligné à gauche. */
.gallery-hero {
    position: relative;
    isolation: isolate;
    max-width: 62rem;
    margin: 0 auto clamp(3rem, 6vw, 4.5rem);
    text-align: center;
}

.gallery-hero::before {
    content: '';
    position: absolute;
    z-index: -1;
    inset: -40% -12% auto -12%;
    height: 180%;
    background:
        radial-gradient(40% 44% at 50% 32%, rgba(239, 125, 0, .20), transparent 70%),
        radial-gradient(54% 50% at 50% 42%, rgba(46, 123, 214, .26), transparent 72%);
    pointer-events: none;
}

/* Le ruban en filigrane, à gauche du titre des concours. Il déborde du bloc de
   texte (qui plafonne à 62rem) pour aller chercher le bord de la section ;
   le débordement horizontal est absorbé par l'overflow-x:hidden de <body>.
   Retourné et penché, pour ne pas répéter à l'identique celui du héros. */
.gallery-hero__ribbon {
    position: absolute;
    z-index: -1;
    top: -12%;
    left: -22%;
    width: min(30vw, 380px);
    /* Assez haut pour respirer, assez court pour ne pas franchir le filet qui
       sépare l'en-tête du premier concours. */
    height: 124%;
    opacity: .11;
    --mo-ribbon-rot: -12deg;
    --mo-ribbon-flip: -1;
    --mo-ribbon-time: 15s;
    animation-delay: -7s;
}

@media (max-width: 991.98px) {
    /* Le bloc de texte occupe alors toute la largeur : le ruban n'a plus de
       marge où se poser, on le recule et on l'efface. */
    .gallery-hero__ribbon {
        left: -34%;
        width: 62vw;
        opacity: .08;
    }
}

.gallery-hero__title {
    font-size: clamp(2.3rem, 6vw, 4.2rem);
    margin-bottom: 1.4rem;
}

/* .lead-muted est calé sur 62ch et aligné à gauche : ici on le recentre. */
.gallery-hero__lead {
    max-width: 58ch;
    margin-left: auto;
    margin-right: auto;
}

/* Le **gras** saisi dans les textes du site (admin/textes.php) : en blanc
   sur le fond sombre de la galerie, comme les deux concours qu'il désigne. */
.gallery-hero__lead strong {
    color: #fff;
}

.gallery-hero__cta {
    margin-top: 2rem;
}

.gallery-hero__stats {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .6rem .75rem;
    list-style: none;
    margin: 1.75rem 0 0;
    padding: 0;
}

.gallery-hero__stats li {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .48rem 1.05rem;
    border: 1px solid var(--mo-line);
    border-radius: 100px;
    background: rgba(255, 255, 255, .06);
    font-size: .9rem;
    color: rgba(255, 255, 255, .6);
}

.gallery-hero__stats b {
    font-size: 1.1rem;
    font-weight: 700;
    color: #fff;
}

.gallery-hero__stats .bi {
    color: var(--mo-orange);
    font-size: .92rem;
}

/* La bulle reprend le bleu qu'elle a sur les tuiles : d'un coup d'œil, on
   relie le compteur à ce qu'il compte. */
.gallery-hero__stats-chat {
    color: var(--mo-blue-400) !important;
}

/* Les deux concours partagent la même section bleue : un filet les sépare,
   chacun garde son en-tête, son podium, son filtre et sa grille. */
.contest  {
    margin-top: clamp(3rem, 6vw, 5rem);
    padding-top: clamp(2.5rem, 5vw, 4rem);
    border-top: 1px solid var(--mo-line);
}

.contest__head {
    margin-bottom: 2rem;
}

.contest__eyebrows {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem 1.1rem;
    margin-bottom: .9rem;
}

/* Concours réservé au réseau du groupe : le cadenas le dit sans en rajouter. */
.contest__lock {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .26rem .72rem;
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: 100px;
    background: rgba(255, 255, 255, .06);
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .72);
}

/* Le rappel adressé au modérateur qui regarde le site depuis une IP hors du
   groupe : ce qu'il voit, un visiteur ordinaire ne le verrait pas. */
.contest__lock--mod {
    border-color: rgba(255, 158, 56, .55);
    background: rgba(239, 125, 0, .14);
    color: var(--mo-orange-2);
}

.contest__title {
    display: flex;
    align-items: center;
    gap: .7rem;
    font-size: clamp(1.55rem, 3.4vw, 2.4rem);
    line-height: 1.1;
    color: #fff;
    margin: 0 0 .9rem;
}

.contest__title .bi {
    font-size: .78em;
    color: var(--mo-orange);
}

.contest__intro {
    margin-bottom: .7rem;
}

.contest__count {
    margin: 0;
    font-size: .92rem;
    color: rgba(255, 255, 255, .55);
}

.contest__count strong {
    color: #fff;
}

/* Sur mobile, le podium passe avant le filtre : c'est ce qu'on veut voir en
   premier quand la galerie se resserre. */
.gallery-head {
    display: flex;
    flex-direction: column;
}

@media (max-width: 767.98px) {
    .gallery-head .podium {
        order: -1;
    }
}

.gallery-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem .9rem;
    margin-bottom: 2rem;
}

.gallery-filters__label {
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--mo-orange-2);
}

/* Le QR code de l'établissement filtré : posé à côté du menu, il n'apparaît
   qu'une fois un établissement choisi (le JS retire l'attribut « hidden »). */
.gallery-filters__qr {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .5rem .9rem;
    border: 1px solid var(--mo-line);
    border-radius: 100px;
    background: rgba(255, 255, 255, .06);
    color: rgba(255, 255, 255, .82);
    font-size: .82rem;
    font-weight: 600;
    line-height: 1;
    transition: background-color .16s ease, border-color .16s ease, transform .16s ease;
}

.gallery-filters__qr[hidden] {
    display: none;
}

.gallery-filters__qr:hover {
    background: rgba(255, 255, 255, .12);
    border-color: rgba(255, 158, 56, .65);
    transform: translateY(-1px);
}

.gallery-filters__qr i {
    font-size: 1.05rem;
    color: var(--mo-orange-2);
}

/* Le temps que l'adresse soit copiée, le bouton passe au vert : la
   confirmation ne repose pas sur la seule infobulle. */
.gallery-filters__qr.is-copied,
.gallery-filters__qr.is-copied:hover {
    background: rgba(25, 135, 84, .85);
    border-color: rgba(25, 135, 84, .95);
    color: #fff;
}

.gallery-filters__qr.is-copied i {
    color: #fff;
}

/* Filtre qui ne laisse rien : le mot qui remplace la grille vide. */
.gallery-none {
    margin: 0;
    padding: 2.5rem 1rem;
    text-align: center;
    color: rgba(255, 255, 255, .62);
}

.gallery-none[hidden] {
    display: none;
}

.gallery-none i {
    display: block;
    font-size: 2rem;
    margin-bottom: .7rem;
    color: rgba(255, 255, 255, .28);
}

.gallery-none a {
    color: var(--mo-orange-2);
}

@media (max-width: 575.98px) {
    .gallery-filters__qr span {
        display: none;   /* l'icône suffit quand la place manque */
    }
}

select.gallery-filters__select,
.gallery-filters .bootstrap-select {
    flex: 0 1 32rem;
    min-width: 0;
    max-width: 100%;
}

/* Pastille commune au <select> natif (repli sans JS) et au bouton posé par
   bootstrap-select : les deux doivent être indiscernables à l'œil.
   Attention : bootstrap-select recopie les classes du <select> sur sa div
   conteneur, d'où le sélecteur d'élément qui lui évite la même pastille. */
select.gallery-filters__select,
.gallery-filters .bootstrap-select > .btn {
    width: 100%;
    appearance: none;
    -webkit-appearance: none;
    border: 1px solid rgba(255, 255, 255, .2);
    background-color: rgba(255, 255, 255, .06);
    color: #fff;
    border-radius: 100px;
    padding: .52rem 2.6rem .52rem 1.1rem;
    font-family: inherit;
    font-size: .92rem;
    font-weight: 560;
    line-height: 1.5;
    cursor: pointer;
    /* Chevron dessiné en SVG inline : aucune requête réseau, net à tout zoom. */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ff9e38'%3E%3Cpath d='M3.2 5.7a.9.9 0 0 1 1.3 0L8 9.2l3.5-3.5a.9.9 0 1 1 1.3 1.3l-4.1 4.1a.9.9 0 0 1-1.3 0L3.2 7a.9.9 0 0 1 0-1.3z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right .95rem center;
    background-size: 1rem;
    transition: border-color .16s ease, background-color .16s ease;
}

/* Repli sans JS : color-scheme demande au navigateur de peindre sa propre
   liste en sombre — c'est tout ce qu'il accepte de nous. */
select.gallery-filters__select {
    color-scheme: dark;
    text-overflow: ellipsis;
}

select.gallery-filters__select option {
    background: var(--mo-blue-900);
    color: #fff;
}

select.gallery-filters__select:hover,
.gallery-filters .bootstrap-select > .btn:hover,
.gallery-filters .bootstrap-select > .btn:focus {
    border-color: rgba(255, 255, 255, .45);
    background-color: rgba(255, 255, 255, .1);
    color: #fff;
}

select.gallery-filters__select:focus-visible {
    outline: 2px solid var(--mo-orange);
    outline-offset: 2px;
}

/* --- bootstrap-select, habillé aux couleurs Movember --------------------- */

.gallery-filters .bootstrap-select > .btn {
    text-align: left;
}

/* Le caret de Bootstrap ferait doublon avec le chevron ci-dessus. */
.gallery-filters .bootstrap-select > .btn::after,
.gallery-filters .bootstrap-select > .btn .caret {
    display: none;
}

.gallery-filters .bootstrap-select.show > .btn {
    border-color: var(--mo-orange);
    background-color: rgba(239, 125, 0, .16);
}

.gallery-filters .bootstrap-select .filter-option-inner-inner {
    overflow: hidden;
}

/* Le contenu d'une entrée : nom à gauche, compteur en pastille à droite.
   Le même balisage sert dans le bouton (bootstrap-select y recopie le
   data-content de l'option choisie). */
.mo-opt {
    display: flex;
    align-items: center;
    gap: .6rem;
}

.mo-opt__name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mo-opt__count {
    flex: none;
    font-size: .7rem;
    font-weight: 700;
    line-height: 1;
    padding: .3rem .48rem;
    border-radius: 100px;
    background: rgba(255, 255, 255, .12);
    color: rgba(255, 255, 255, .72);
    font-variant-numeric: tabular-nums;
}

.gallery-filters .bootstrap-select > .btn .mo-opt__count {
    background: rgba(255, 255, 255, .16);
    color: #fff;
}

.gallery-filters .bootstrap-select .dropdown-menu {
    --bs-dropdown-bg: rgba(0, 26, 61, .96);
    --bs-dropdown-border-color: rgba(255, 255, 255, .16);
    --bs-dropdown-border-radius: 18px;
    --bs-dropdown-padding-x: .35rem;
    --bs-dropdown-padding-y: .35rem;
    --bs-dropdown-item-padding-x: .6rem;
    --bs-dropdown-item-padding-y: .48rem;
    --bs-dropdown-font-size: .9rem;
    --bs-dropdown-link-color: rgba(255, 255, 255, .84);
    --bs-dropdown-link-hover-color: #fff;
    --bs-dropdown-link-hover-bg: rgba(255, 255, 255, .1);
    --bs-dropdown-link-active-color: #fff;
    --bs-dropdown-link-active-bg: rgba(255, 255, 255, .1);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    box-shadow: 0 26px 55px -18px rgba(0, 0, 0, .75);
}

/* Le menu intérieur hérite déjà du fond : pas de second cadre. */
.gallery-filters .bootstrap-select .dropdown-menu.inner {
    --bs-dropdown-bg: transparent;
}

/* L'intitulé de région. Le gris par défaut de Bootstrap s'efface sur ce fond
   bleu nuit ; on reprend l'orange clair des étiquettes de filtre, et le filet
   sépare les régions sans ajouter de trait à la première. */
.gallery-filters .bootstrap-select .dropdown-header {
    padding: .7rem .6rem .3rem;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mo-orange-2);
}

.gallery-filters .bootstrap-select .dropdown-header:not(:first-child) {
    margin-top: .35rem;
    border-top: 1px solid rgba(255, 255, 255, .1);
}

.gallery-filters .bootstrap-select .dropdown-item {
    border-radius: 12px;
    line-height: 1.3;
}

.gallery-filters .bootstrap-select .dropdown-item .text {
    display: block;
}

.gallery-filters .bootstrap-select .dropdown-item .mo-opt__name {
    white-space: normal;
    overflow: visible;
}

.gallery-filters .bootstrap-select .dropdown-item:active {
    background-color: rgba(255, 255, 255, .14);
}

/* .selected = le choix courant, .active = l'entrée survolée ou pointée au
   clavier : les deux peuvent tomber sur des entrées différentes. */
.gallery-filters .bootstrap-select .dropdown-item.selected {
    background-color: rgba(239, 125, 0, .18);
    color: #fff;
    font-weight: 600;
}

.gallery-filters .bootstrap-select .dropdown-item.selected.active {
    background-color: rgba(239, 125, 0, .26);
}

.gallery-filters .bootstrap-select .dropdown-item.selected .mo-opt__count {
    background: rgba(239, 125, 0, .34);
    color: #fff;
}

.gallery-filters .bootstrap-select .check-mark {
    color: var(--mo-orange-2);
}

/* Champ de recherche du menu. */
.gallery-filters .bootstrap-select .bs-searchbox {
    padding: .3rem .3rem .45rem;
}

.gallery-filters .bootstrap-select .bs-searchbox .form-control {
    /* Le champ est un <input type="search"> : color-scheme fait peindre sa
       croix d'effacement native en clair plutôt qu'en noir. */
    color-scheme: dark;
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: 100px;
    background: rgba(255, 255, 255, .07);
    color: #fff;
    font-size: .88rem;
    padding: .42rem .95rem;
}

.gallery-filters .bootstrap-select .bs-searchbox .form-control::placeholder {
    color: rgba(255, 255, 255, .45);
}

.gallery-filters .bootstrap-select .bs-searchbox .form-control:focus {
    border-color: var(--mo-orange);
    background: rgba(255, 255, 255, .1);
    box-shadow: 0 0 0 .18rem rgba(239, 125, 0, .22);
}

.gallery-filters .bootstrap-select .no-results {
    margin: 0;
    padding: .5rem .6rem;
    border-radius: 12px;
    background: rgba(255, 255, 255, .06);
    color: rgba(255, 255, 255, .62);
    font-size: .86rem;
}

/* Ascenseur discret quand la liste dépasse la hauteur affichée. */
.gallery-filters .bootstrap-select .inner {
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, .28) transparent;
    overscroll-behavior: contain;
}

.gallery-filters .bootstrap-select .inner::-webkit-scrollbar {
    width: 11px;
}

.gallery-filters .bootstrap-select .inner::-webkit-scrollbar-thumb {
    border: 3px solid transparent;
    border-radius: 100px;
    background-color: rgba(255, 255, 255, .26);
    background-clip: padding-box;
}

.gallery-filters .bootstrap-select .inner::-webkit-scrollbar-thumb:hover {
    background-color: rgba(255, 255, 255, .45);
}

/* Deux colonnes dès le mobile : on voit plus de moustaches d'un coup, quitte à
   resserrer les gouttières et la pastille de vote sur les petits écrans. */
.gallery {
    column-gap: 1rem;
    columns: 2;
}

@media (min-width: 768px)  { .gallery { columns: 3; } }
@media (min-width: 1200px) { .gallery { columns: 4; } }
/* Au-delà, .container plafonne à 1320px : c'est la largeur utile maximale,
   donc le dernier palier. */
@media (min-width: 1400px) { .gallery { columns: 5; } }

@media (max-width: 575.98px) {
    .gallery {
        column-gap: .55rem;
    }

    .gallery__item {
        margin-bottom: .55rem;
        border-radius: 10px;
    }

    .gallery__actions {
        top: .35rem;
        right: .35rem;
        gap: .25rem;
    }

    .gallery__like,
    .gallery__comment {
        gap: .25rem;
        padding: .24rem .45rem;
        font-size: .74rem;
    }

    .gallery__like i,
    .gallery__comment i {
        font-size: .82rem;
    }

    .gallery__meta {
        padding: 1.8rem .55rem .55rem;
    }

    .gallery__meta strong {
        font-size: .82rem;
    }

    .gallery__meta small {
        font-size: .72rem;
    }
}

.gallery__item {
    break-inside: avoid;
    margin-bottom: 1rem;
    position: relative;
    border-radius: 14px;
    overflow: hidden;
    background: rgba(255, 255, 255, .06);
    border: 1px solid var(--mo-line);
    display: block;
    width: 100%;
    transition: transform .22s ease, border-color .22s ease;
}

/* La photo agrandit, le cœur vote : deux boutons voisins plutôt qu'un bouton
   dans un bouton, que le HTML interdit. */
.gallery__open {
    display: block;
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    text-align: left;
}

/* Bootstrap pose « cursor: pointer » sur tout bouton actif, avec une
   spécificité (0,1,1) qu'une simple classe ne bat pas. Le :not(:disabled) la
   rattrape : sans lui, la loupe d'agrandissement ne s'affiche jamais. */
.gallery__open:not(:disabled),
.podium__item:not(:disabled) {
    cursor: zoom-in;
}

.gallery__item:hover {
    transform: translateY(-4px);
    border-color: rgba(255, 158, 56, .65);
}

.gallery__item img {
    width: 100%;
    height: auto;
    display: block;
    transition: transform .5s ease;
}

.gallery__item:hover img {
    transform: scale(1.04);
}

.gallery__meta {
    position: absolute;
    inset: auto 0 0 0;
    padding: 2.6rem .9rem .8rem;
    background: linear-gradient(180deg, transparent, rgba(0, 19, 46, .92));
    color: #fff;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity .22s ease, transform .22s ease;
}

.gallery__item:hover .gallery__meta,
.gallery__open:focus-visible .gallery__meta {
    opacity: 1;
    transform: none;
}

.gallery__meta strong {
    display: block;
    font-size: .95rem;
    line-height: 1.25;
}

.gallery__meta small {
    color: rgba(255, 255, 255, .72);
    font-size: .8rem;
}

/* --- Le cœur (vote) et la bulle (commentaires) ---------------------------- */

/* Les deux pastilles voyagent ensemble, posées sur le coin de la photo. Le
   conteneur porte la position, les boutons ne portent que leur allure : le même
   couple se retrouve tel quel dans la visionneuse (.gallery__actions--lg). */
.gallery__actions {
    position: absolute;
    top: .6rem;
    right: .6rem;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: .35rem;
}

.gallery__like,
.gallery__comment,
.gallery__share {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    border: 1px solid rgba(255, 255, 255, .22);
    background: rgba(0, 19, 46, .58);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    color: #fff;
    border-radius: 100px;
    padding: .3rem .62rem;
    font-size: .82rem;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    transition: background-color .16s ease, border-color .16s ease, transform .16s ease;
}

.gallery__like:hover,
.gallery__comment:hover,
.gallery__share:hover {
    transform: scale(1.06);
    border-color: rgba(255, 158, 56, .7);
}

.gallery__like i,
.gallery__comment i,
.gallery__share i {
    font-size: .95rem;
    color: rgba(255, 255, 255, .8);
    transition: color .16s ease;
}

/* Le partage : une pastille ronde, sans compteur à afficher. */
.gallery__share {
    padding: .3rem .45rem;
}

/* Le temps que l'adresse soit copiée, la pastille passe au vert : la
   confirmation ne dépend pas seulement de l'infobulle. */
.gallery__share.is-copied {
    background: rgba(25, 135, 84, .85);
    border-color: rgba(25, 135, 84, .95);
}

.gallery__share.is-copied i {
    color: #fff;
}

.gallery__like.is-liked {
    background: var(--mo-orange);
    border-color: var(--mo-orange);
}

.gallery__like.is-liked i {
    color: #fff;
}

/* La bulle s'allume en bleu dès qu'un commentaire a été publié : d'un coup
   d'œil, on voit quelles photos font parler. */
.gallery__comment.has-comments {
    background: rgba(46, 123, 214, .82);
    border-color: rgba(46, 123, 214, .9);
}

.gallery__comment.has-comments i {
    color: #fff;
}

/* Petit battement au moment du clic. */
.gallery__like.is-pop i {
    animation: mo-heartbeat .42s ease;
}

@keyframes mo-heartbeat {
    0%   { transform: scale(1); }
    35%  { transform: scale(1.45); }
    60%  { transform: scale(.92); }
    100% { transform: scale(1); }
}

/* --- Podium du concours --------------------------------------------------- */

.podium {
    border: 1px solid var(--mo-line);
    border-radius: var(--mo-radius);
    background: rgba(255, 255, 255, .05);
    padding: 1.1rem 1.2rem 1.3rem;
    margin-bottom: 1.8rem;
}

.podium__head {
    display: flex;
    align-items: center;
    gap: .55rem;
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--mo-orange-2);
    margin-bottom: 1rem;
}

.podium__list {
    display: grid;
    gap: .8rem;
    grid-template-columns: 1fr;
}

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

/* La marche est un <button> : on repart des réglages du navigateur (police,
   alignement, largeur) avant de la dessiner. */
.podium__item {
    display: flex;
    align-items: center;
    gap: .8rem;
    /* Sans ce min-width, la colonne de grille se dimensionne sur le nom
       d'établissement, qui ne se coupe pas : les cartes débordent à droite au
       lieu de partager la largeur en trois. */
    min-width: 0;
    width: 100%;
    overflow: hidden;
    padding: .55rem .8rem .55rem .55rem;
    border: 1px solid var(--mo-line);
    border-radius: 14px;
    background: rgba(255, 255, 255, .04);
    font: inherit;
    text-align: left;
    transition: transform .18s ease, border-color .18s ease, background-color .18s ease;
}

.podium__item:hover,
.podium__item:focus-visible {
    transform: translateY(-2px);
    border-color: rgba(255, 158, 56, .6);
    background: rgba(255, 255, 255, .08);
}

.podium__item:hover img {
    transform: scale(1.06);
}

.podium__rank {
    flex: none;
    width: 1.7rem;
    height: 1.7rem;
    display: grid;
    place-items: center;
    border-radius: 100px;
    background: var(--mo-orange);
    color: #fff;
    font-family: var(--mo-font-display);
    font-size: 1rem;
    line-height: 1;
}

/* Argent et bronze pour les deux suivants : le podium se lit d'un coup d'œil. */
.podium__item:nth-child(2) .podium__rank { background: #b9c6d8; color: var(--mo-blue-900); }
.podium__item:nth-child(3) .podium__rank { background: #b07d4b; }

.podium__item img {
    flex: none;
    width: 64px;
    height: 48px;
    object-fit: cover;
    border-radius: 8px;
    transition: transform .3s ease;
}

.podium__meta {
    flex: 1 1 auto;
    min-width: 0;
    color: #fff;
}

/* Les noms d'établissement sont longs et la commune, entre parenthèses, est
   la partie utile : deux lignes plutôt qu'une coupe nette au premier tiers. */
.podium__meta strong {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    font-size: .88rem;
    line-height: 1.25;
    overflow: hidden;
}

.podium__meta small {
    color: rgba(255, 255, 255, .6);
    font-size: .78rem;
}

.podium__score {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    color: var(--mo-orange-2);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.gallery-empty {
    border: 1px dashed rgba(255, 255, 255, .22);
    border-radius: var(--mo-radius);
    padding: 3.5rem 1.5rem;
    text-align: center;
    color: rgba(255, 255, 255, .68);
}

/* --- Visionneuse --------------------------------------------------------- */

/* Le site passe en flou derrière la photo agrandie, plutôt qu'un simple voile
   sombre. L'opacité du voile reste à 1 et la transparence est portée par la
   couleur de fond : sur un élément semi-opaque, le résultat de backdrop-filter
   est recomposé avec l'image nette du dessous et le flou paraît délavé. */
.modal-backdrop {
    --bs-backdrop-bg: rgba(0, 15, 35, .6);
    --bs-backdrop-opacity: 1;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

/* Navigateurs sans backdrop-filter : on assombrit davantage pour garder le
   contraste entre la photo et la page. */
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
    .modal-backdrop {
        --bs-backdrop-bg: rgba(0, 15, 35, .85);
    }
}

.lightbox .modal-content {
    background: transparent;
    border: 0;
}

/* En plein écran, la fenêtre couvre tout : il lui faut son propre fond, sinon
   la page défile derrière la bande de commentaires et se voit par-dessous.
   Le voile reste légèrement translucide, pour garder le flou du fond.
   (La visionneuse de l'espace modérateur, elle, n'est pas en plein écran et
   garde son fond transparent.) */
.lightbox .modal-fullscreen .modal-content {
    background: rgba(0, 15, 35, .96);
}

/* --- Visionneuse : la scène et la bande de commentaires -------------------

   Plein écran. Sur grand écran, deux colonnes : la photo prend la place qui
   reste, les commentaires tiennent une bande fixe à droite qui défile pour son
   propre compte. Sous 992 px la bande passe sous la photo et c'est la colonne
   entière qui défile : on descend pour lire, comme sur un fil.               */

.lightbox__layout {
    display: flex;
    height: 100%;
    min-height: 0;
}

.lightbox__main {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: clamp(1rem, 3vw, 2.4rem);
}

/* La bande de droite : en-tête figé, liste qui défile, formulaire posé en bas. */
.lightbox__side {
    flex: 0 0 clamp(320px, 26vw, 400px);
    width: clamp(320px, 26vw, 400px);
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: rgba(0, 20, 46, .94);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    border-left: 1px solid var(--mo-line);
    color: #fff;
}

/* La croix de fermeture est posée sur le coin de la fenêtre, donc juste
   au-dessus de cet en-tête : on lui laisse la place plutôt que de la voir
   recouvrir le compteur. */
.lb-side__head {
    flex: 0 0 auto;
    padding: 1.15rem 4rem .9rem 1.25rem;
    border-bottom: 1px solid var(--mo-line);
}

.lb-side__title {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: .01em;
}

.lb-side__title i {
    color: var(--mo-orange-2);
}

.lb-side__count {
    margin-left: auto;
    background: rgba(255, 255, 255, .12);
    border-radius: 100px;
    padding: .12rem .55rem;
    font-size: .82rem;
    font-variant-numeric: tabular-nums;
}

.lb-side__hint {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin: .5rem 0 0;
    font-size: .76rem;
    color: rgba(255, 255, 255, .6);
}

.lb-side__body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 1rem 1.25rem;
    display: flex;
    flex-direction: column;
    gap: .95rem;
}

/* --- Un commentaire ------------------------------------------------------- */

.mo-comment {
    display: flex;
    gap: .65rem;
    align-items: flex-start;
}

.mo-comment__avatar {
    flex: 0 0 34px;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-size: .78rem;
    font-weight: 700;
    color: #fff;
    background: var(--mo-blue-600);
    text-transform: uppercase;
}

.mo-comment__bubble {
    flex: 1 1 auto;
    min-width: 0;
    background: rgba(255, 255, 255, .08);
    border: 1px solid rgba(255, 255, 255, .08);
    border-radius: 4px 16px 16px 16px;
    padding: .55rem .8rem .6rem;
}

.mo-comment__author {
    display: block;
    font-size: .84rem;
    font-weight: 700;
    color: #fff;
}

.mo-comment__body {
    margin: .18rem 0 0;
    font-size: .88rem;
    line-height: 1.45;
    color: rgba(255, 255, 255, .88);
    /* Un mot très long (une URL collée) ne doit pas élargir la bande. */
    overflow-wrap: anywhere;
    white-space: pre-line;
}

.mo-comment__time {
    display: block;
    margin-top: .3rem;
    font-size: .72rem;
    color: rgba(255, 255, 255, .45);
}

/* Le commentaire que son auteur vient de déposer : visible de lui seul, tant
   que la modération ne l'a pas publié. */
.mo-comment.is-pending .mo-comment__bubble {
    background: rgba(255, 158, 56, .12);
    border-color: rgba(255, 158, 56, .38);
    border-style: dashed;
}

.mo-comment__badge {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    margin-top: .35rem;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--mo-orange-2);
}

.lb-side__empty {
    margin: auto 0;
    text-align: center;
    color: rgba(255, 255, 255, .55);
    font-size: .88rem;
    padding: 1.5rem 0;
}

.lb-side__empty i {
    display: block;
    font-size: 1.9rem;
    margin-bottom: .6rem;
    color: rgba(255, 255, 255, .25);
}

/* --- Écrire un commentaire ------------------------------------------------ */

.lb-side__form {
    flex: 0 0 auto;
    padding: .9rem 1.25rem 1.1rem;
    border-top: 1px solid var(--mo-line);
    background: rgba(0, 14, 34, .6);
}

/* Le leurre anti-robot : hors de l'écran plutôt que display:none, que certains
   robots savent repérer. */
.lb-side__decoy {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.lb-side__name,
.lb-side__text {
    width: 100%;
    border: 1px solid rgba(255, 255, 255, .16);
    background: rgba(255, 255, 255, .07);
    color: #fff;
    border-radius: 12px;
    padding: .5rem .75rem;
    font-size: .86rem;
    font-family: inherit;
}

.lb-side__name::placeholder,
.lb-side__text::placeholder {
    color: rgba(255, 255, 255, .45);
}

.lb-side__name:focus,
.lb-side__text:focus {
    outline: none;
    border-color: rgba(255, 158, 56, .75);
    background: rgba(255, 255, 255, .11);
}

.lb-side__name {
    margin-bottom: .5rem;
}

.lb-side__compose {
    display: flex;
    align-items: flex-end;
    gap: .5rem;
}

.lb-side__text {
    resize: none;
    max-height: 8.5rem;
    line-height: 1.4;
}

.lb-side__send {
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    border: 0;
    border-radius: 50%;
    background: var(--mo-orange);
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 1rem;
    transition: transform .16s ease, background-color .16s ease, opacity .16s ease;
}

.lb-side__send:hover:not(:disabled) {
    background: #d96f00;
    transform: scale(1.06);
}

.lb-side__send:disabled {
    opacity: .45;
    cursor: not-allowed;
}

.lb-side__feedback {
    margin: .6rem 0 0;
    font-size: .78rem;
    line-height: 1.4;
    color: var(--mo-orange-2);
}

.lb-side__feedback.is-error {
    color: #ff8b8b;
}

/* --- Sous 992 px : une colonne, un seul défilement ------------------------ */

@media (max-width: 991.98px) {
    .lightbox__layout {
        flex-direction: column;
        overflow-y: auto;
        overscroll-behavior: contain;
        -webkit-overflow-scrolling: touch;
    }

    .lightbox--talk .lightbox__main {
        flex: 0 0 auto;
        /* La photo tient dans l'écran sans le remplir tout à fait : le haut de
           la bande de commentaires dépasse, et l'on comprend qu'il y a à lire
           en dessous. */
        min-height: 68vh;
        padding: 1rem .75rem .5rem;
    }

    .lightbox--talk .lightbox img {
        max-height: 62vh;
    }

    .lightbox__side {
        flex: 0 0 auto;
        width: auto;
        border-left: 0;
        border-top: 1px solid var(--mo-line);
        border-radius: 20px 20px 0 0;
        background: rgba(0, 20, 46, .98);
    }

    /* Plus de défilement interne : c'est la colonne entière qui défile. */
    .lb-side__body {
        overflow: visible;
        min-height: 4rem;
    }

    /* Le champ reste sous le pouce pendant qu'on remonte le fil. */
    .lb-side__form {
        position: sticky;
        bottom: 0;
        background: rgba(0, 16, 38, .97);
        -webkit-backdrop-filter: blur(10px);
        backdrop-filter: blur(10px);
        padding-bottom: max(1.1rem, env(safe-area-inset-bottom));
    }

    .lb-side__head {
        position: sticky;
        top: 0;
        z-index: 2;
        background: rgba(0, 20, 46, .98);
        border-radius: 20px 20px 0 0;
    }
}

.lightbox__close {
    position: absolute;
    top: .75rem;
    right: .75rem;
    z-index: 6;
    width: 46px;
    height: 46px;
    border: 0;
    border-radius: 50%;
    background: var(--mo-orange);
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 1.15rem;
    box-shadow: 0 10px 26px -10px rgba(0, 0, 0, .7);
    transition: transform .16s ease, background-color .16s ease;
}

.lightbox__close:hover,
.lightbox__close:focus-visible {
    background: #d96f00;
    transform: scale(1.07);
}

/* Le couple cœur / bulle de la visionneuse : les mêmes boutons que sur les
   tuiles, en plus grands, posés à gauche pour ne pas gêner la croix. */
.gallery__actions--lg {
    top: .75rem;
    left: .75rem;
    right: auto;
    z-index: 6;
    gap: .5rem;
}

.gallery__like--lg,
.gallery__comment--lg,
.gallery__share--lg {
    gap: .5rem;
    padding: .55rem 1rem;
    font-size: 1rem;
    background: rgba(0, 19, 46, .72);
    box-shadow: 0 10px 26px -12px rgba(0, 0, 0, .7);
}

.gallery__share--lg {
    padding: .55rem .75rem;
}

.gallery__like--lg i,
.gallery__comment--lg i,
.gallery__share--lg i {
    font-size: 1.35rem;
}

/* Le glissement d'une photo à l'autre. La sortante part du côté du geste en
   s'effaçant, la suivante arrive de l'autre côté : la classe « from » pose le
   point de départ sans transition, on la retire à la image d'après et le retour
   à zéro se fait, lui, en glissant. */
.lightbox__stage {
    transition: transform .26s cubic-bezier(.22, .8, .3, 1), opacity .22s ease;
    will-change: transform, opacity;
}

.lightbox__stage.is-sliding-out-left {
    transform: translateX(-14%);
    opacity: 0;
}

.lightbox__stage.is-sliding-out-right {
    transform: translateX(14%);
    opacity: 0;
}

.lightbox__stage.is-sliding-from-right,
.lightbox__stage.is-sliding-from-left {
    transition: none;
    opacity: 0;
}

.lightbox__stage.is-sliding-from-right { transform: translateX(14%); }
.lightbox__stage.is-sliding-from-left { transform: translateX(-14%); }

/* Le cadre se réduit à la photo (inline-block + line-height nulle) : les deux
   boutons se calent donc sur ses bords, jamais sur ceux de la fenêtre modale
   qui, elle, garde la largeur du dialogue quelle que soit la photo. */
.lightbox__frame {
    position: relative;
    display: inline-block;
    max-width: 100%;
    line-height: 0;
}

.lightbox img {
    max-width: 100%;
    max-height: 76vh;
    width: auto;
    display: block;
    border-radius: 12px;
    box-shadow: 0 30px 70px -25px rgba(0, 19, 46, .95);
    /* Le geste de balayage sur mobile ne doit pas être avalé par le navigateur
       comme un défilement horizontal. */
    touch-action: pan-y;
}

/* En plein écran, la hauteur disponible est celle de la fenêtre moins la
   respiration de la colonne et la légende : la photo se cale dessus plutôt que
   sur une fraction fixe, sinon la légende sort de l'écran sur un portable. */
@media (min-width: 992px) {
    .lightbox img {
        max-height: calc(100vh - 11rem);
    }
}

.lightbox__caption {
    color: rgba(255, 255, 255, .9);
    text-align: center;
    margin-top: 1rem;
}

.lightbox__nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 46px;
    height: 46px;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, .28);
    background: rgba(0, 19, 46, .55);
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 1.3rem;
    z-index: 5;
}

.lightbox__nav:hover {
    background: var(--mo-orange);
    border-color: var(--mo-orange);
}

/* Les flèches se calent sur les bords de la colonne « photo », pas sur ceux de
   l'écran : sur grand écran elles ne passent donc jamais sous la bande. */
.lightbox__nav--prev { left: .35rem; }
.lightbox__nav--next { right: .35rem; }

@media (min-width: 992px) {
    .lightbox__nav--prev { left: 1.25rem; }
    .lightbox__nav--next { right: 1.25rem; }
}

/* --- Formulaire de dépôt ------------------------------------------------- */

.upload-card {
    background: var(--mo-paper);
    border-radius: 22px;
    box-shadow: 0 30px 60px -35px rgba(0, 26, 61, .4);
    border: 1px solid var(--mo-line-dark);
    padding: clamp(1.4rem, 4vw, 2.6rem);
}

.form-label {
    font-weight: 620;
    font-size: .92rem;
    margin-bottom: .35rem;
    color: var(--mo-blue-800);
}

.form-control,
.form-select {
    border-radius: 12px;
    border-color: rgba(0, 60, 135, .2);
    padding: .7rem .9rem;
}

.form-control:focus,
.form-select:focus {
    border-color: var(--mo-blue-400);
    box-shadow: 0 0 0 .22rem rgba(46, 123, 214, .2);
}

/* --- bootstrap-select du formulaire (fond clair) ------------------------- */

/* Le bouton reçoit l'habillage .form-select (data-style), donc la bordure,
   le rayon et le chevron des autres champs. */
.mo-select-light > .dropdown-toggle {
    cursor: pointer;
    text-align: left;
    /* La règle .form-select ci-dessus écrase le padding-right de Bootstrap :
       sans ça, un nom long passerait sous le chevron. */
    padding-right: 2.4rem;
}

.mo-select-light > .dropdown-toggle::after {
    display: none;
}

.mo-select-light .filter-option-inner-inner {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* « Choisir… » doit se lire comme un texte de substitution, pas comme un
   choix déjà fait. */
.mo-select-light > .dropdown-toggle.bs-placeholder {
    color: var(--mo-muted);
}

.mo-select-light .dropdown-menu {
    --bs-dropdown-border-color: var(--mo-line-dark);
    --bs-dropdown-border-radius: 14px;
    --bs-dropdown-padding-x: .35rem;
    --bs-dropdown-padding-y: .35rem;
    --bs-dropdown-item-padding-x: .6rem;
    --bs-dropdown-item-padding-y: .42rem;
    --bs-dropdown-font-size: .92rem;
    --bs-dropdown-link-color: var(--mo-text);
    --bs-dropdown-link-hover-bg: rgba(0, 60, 135, .07);
    --bs-dropdown-link-hover-color: var(--mo-blue-700);
    --bs-dropdown-link-active-bg: rgba(0, 60, 135, .07);
    --bs-dropdown-link-active-color: var(--mo-blue-700);
    box-shadow: 0 22px 48px -22px rgba(0, 26, 61, .55);
}

.mo-select-light .dropdown-item {
    border-radius: 10px;
    line-height: 1.3;
}

.mo-select-light .dropdown-item.selected {
    background-color: rgba(0, 60, 135, .09);
    color: var(--mo-blue-700);
    font-weight: 600;
}

.mo-select-light .check-mark {
    color: var(--mo-orange);
}

/* Les régions (optgroup) deviennent des en-têtes de groupe. */
/* L'icône du concours, dans le bouton comme dans la liste. */
.mo-opt__icon {
    margin-right: .55rem;
    color: var(--mo-orange);
}

.mo-select-light .dropdown-header {
    padding: .7rem .6rem .3rem;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mo-orange);
}

.mo-select-light .bs-searchbox {
    padding: .3rem .3rem .45rem;
}

.mo-select-light .bs-searchbox .form-control {
    border-radius: 100px;
    padding: .45rem .95rem;
    font-size: .9rem;
}

.mo-select-light .no-results {
    margin: 0;
    padding: .5rem .6rem;
    border-radius: 10px;
    background: var(--mo-cream);
    color: var(--mo-muted);
    font-size: .88rem;
}

.form-check-input:checked {
    background-color: var(--mo-blue-700);
    border-color: var(--mo-blue-700);
}

.dropzone {
    border: 2px dashed rgba(0, 60, 135, .28);
    border-radius: 16px;
    background: #f7fafd;
    padding: 2.2rem 1.2rem;
    text-align: center;
    cursor: pointer;
    transition: border-color .18s ease, background .18s ease;
}

.dropzone:hover,
.dropzone.is-dragover {
    border-color: var(--mo-orange);
    background: rgba(239, 125, 0, .07);
}

.dropzone__icon {
    font-size: 2rem;
    color: var(--mo-blue-700);
}

.preview-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
    gap: .6rem;
    margin-top: 1rem;
}

.preview-grid figure {
    position: relative;
    margin: 0;
    border-radius: 10px;
    overflow: hidden;
    aspect-ratio: 1;
    background: var(--mo-blue-100);
}

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

.preview-grid figcaption {
    position: absolute;
    inset: auto 0 0 0;
    background: rgba(0, 19, 46, .78);
    color: #fff;
    font-size: .68rem;
    padding: .2rem .35rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* --- Pied de page -------------------------------------------------------- */

.mo-footer {
    position: relative;
    overflow: hidden;
    background: linear-gradient(180deg, var(--mo-blue-900), #00132e);
    color: rgba(255, 255, 255, .68);
    padding: 3.5rem 0 2rem;
    border-top: 3px solid var(--mo-orange);
}

.mo-footer::before {
    content: '';
    position: absolute;
    right: -30px;
    top: -70px;
    width: 260px;
    height: 420px;
    opacity: .08;
    --mo-ribbon-rot: -11deg;
    --mo-ribbon-time: 19s;
    animation-delay: -9s;
}

.mo-footer > .container {
    position: relative;
    z-index: 1;
}

.mo-footer a {
    color: rgba(255, 255, 255, .82);
    text-decoration: none;
}

.mo-footer a:hover {
    color: var(--mo-orange-2);
}

.mo-footer h5 {
    color: #fff;
    font-size: .82rem;
    letter-spacing: .16em;
    text-transform: uppercase;
    margin-bottom: 1rem;
}

/* La ligne des documents légaux : soulignée et en pleine opacité, à la
   différence des autres liens du pied. Ce sont eux qu'un contrôle vient
   chercher, et c'est par là que passe une demande de retrait de photo. */
.mo-footer__legal a {
    color: #fff;
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* --- Classement des établissements ---------------------------------------- */

.clinic-top {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    color: #fff;
}

/* Le titre et le chapô sont réglés pour les sections claires : sur ce fond de
   photo assombri, il faut leur rendre la couleur des sections sombres. */
.clinic-top .section-title {
    color: #fff;
}

.clinic-top .lead-muted {
    color: rgba(255, 255, 255, .74);
}

/* Le fond ne bouge pas : la section glisse par-dessus comme une fenêtre sur
   une image restée en place.

   C'est « background-attachment: fixed » qui le fait, et non du JavaScript.
   Repositionner un calque depuis l'évènement « scroll » donnait un résultat
   saccadé : le défilement est composité hors du fil principal, et le calque
   arrivait toujours avec une image de retard — imperceptible sur un fond qui
   glisse lentement, très visible sur un fond censé être immobile.

   iOS ignore cette valeur et retombe sur un fond normal : l'image est là,
   elle ne reste simplement pas fixe. C'est le seul compromis, et il vaut mieux
   que le tremblement. */
.clinic-top {
    background-attachment: fixed;
    background-position: center;
    background-repeat: no-repeat;
    background-size: cover;
}

/* Sans lui, le texte passerait sur une photo claire. Le dégradé garde en plus
   les raccords nets avec les sections voisines, qui sont du même bleu. */
.clinic-top__veil {
    position: absolute;
    inset: 0;
    z-index: -1;
    background:
        linear-gradient(180deg, var(--mo-blue-900) 0%, rgba(0, 26, 61, .82) 22%,
                        rgba(0, 26, 61, .82) 78%, var(--mo-blue-900) 100%),
        radial-gradient(60% 60% at 50% 40%, rgba(239, 125, 0, .16), transparent 70%);
}

.clinic-top__head {
    text-align: center;
    margin-bottom: clamp(2rem, 5vw, 3rem);
}

.clinic-top__lead {
    max-width: 56ch;
    margin-left: auto;
    margin-right: auto;
}

.clinic-rank {
    display: grid;
    gap: 1rem;
    grid-template-columns: 1fr;
    list-style: none;
    margin: 0;
    padding: 0;
    counter-reset: none;
}

@media (min-width: 992px) {
    .clinic-rank {
        grid-template-columns: repeat(3, 1fr);
        /* Les noms font une ou deux lignes : les cartes s'alignent sur la plus
           haute plutôt que de danser d'un cran. */
        align-items: stretch;
    }
}

.clinic-rank__item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1.1rem 1.2rem;
    border: 1px solid var(--mo-line);
    border-radius: var(--mo-radius);
    background: rgba(0, 19, 46, .62);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
}

/* Le premier se distingue sans casser la grille : même largeur, plus de
   présence. */
.clinic-rank__item--first {
    border-color: rgba(255, 158, 56, .5);
    background: rgba(0, 19, 46, .74);
    box-shadow: 0 22px 48px -26px rgba(0, 0, 0, .9);
}

.clinic-rank__place {
    flex: none;
    width: 2.2rem;
    height: 2.2rem;
    display: grid;
    place-items: center;
    border-radius: 100px;
    background: #b9c6d8;
    color: var(--mo-blue-900);
    font-family: var(--mo-font-display);
    font-size: 1.25rem;
    line-height: 1;
}

.clinic-rank__item--first .clinic-rank__place {
    background: var(--mo-orange);
    color: #fff;
}

.clinic-rank__item:nth-child(3) .clinic-rank__place {
    background: #b07d4b;
    color: #fff;
}

.clinic-rank__photo {
    flex: none;
    width: 62px;
    height: 62px;
    object-fit: cover;
    border-radius: 12px;
    border: 1px solid var(--mo-line);
}

/* Le site n'a pas encore de photo de lieu : un pictogramme tient la place, et
   la carte garde exactement la même géométrie que les autres. */
.clinic-rank__photo--none {
    display: grid;
    place-items: center;
    background: rgba(255, 255, 255, .05);
    color: rgba(255, 255, 255, .34);
    font-size: 1.5rem;
}

.clinic-rank__body {
    flex: 1 1 auto;
    min-width: 0;
}

.clinic-rank__name {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: .95rem;
    line-height: 1.25;
}

.clinic-rank__stats {
    display: flex;
    flex-wrap: wrap;
    gap: .15rem .8rem;
    list-style: none;
    margin: .35rem 0 0;
    padding: 0;
    font-size: .78rem;
    color: rgba(255, 255, 255, .62);
}

.clinic-rank__stats li {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
}

.clinic-rank__stats b {
    color: #fff;
    font-variant-numeric: tabular-nums;
}

.clinic-rank__stats i {
    color: var(--mo-orange-2);
    font-size: .82rem;
}

/* --- Mobilisation du groupe ------------------------------------------------
   La galerie sait dire « 21 établissements représentés » : un constat. Rapporté
   aux 35 du groupe, c'est un appel — et les manquants sont nommés, chacun étant
   un lien vers le dépôt déjà rempli. */

.mobilise {
    max-width: 62rem;
    margin: 0 auto;
    text-align: center;
}

.mobilise__title {
    margin-bottom: 1.2rem;
}

/* Le compteur animé : chiffres à chasse fixe, sinon la largeur du titre saute
   à chaque dizaine pendant le décompte. */
.mobilise__title b {
    color: var(--mo-orange);
    font-weight: inherit;
    font-variant-numeric: tabular-nums;
}

.mobilise__lead {
    max-width: 56ch;
    margin: 0 auto;
}

.mobilise__gauge {
    display: flex;
    align-items: center;
    gap: 1rem;
    max-width: 44rem;
    margin: 2.2rem auto 0;
}

.mobilise__track {
    flex: 1 1 auto;
    height: 14px;
    border-radius: 100px;
    background: rgba(0, 60, 135, .12);
    overflow: hidden;
}

.mobilise__fill {
    display: block;
    width: 0;
    height: 100%;
    border-radius: 100px;
    background: linear-gradient(90deg, var(--mo-orange), var(--mo-orange-2));
    /* La jauge se remplit quand la section entre à l'écran, en même temps que
       le compteur du titre (data-count, 1,4 s lui aussi) : les deux disent la
       même chose, ils doivent arriver ensemble. */
    transition: width 1.4s cubic-bezier(.22, .8, .3, 1);
}

.reveal.is-visible .mobilise__fill {
    width: var(--mo-fill, 0%);
}

.mobilise__ratio {
    flex: none;
    font-size: 1.05rem;
    color: var(--mo-muted);
    font-variant-numeric: tabular-nums;
}

.mobilise__ratio b {
    font-size: 1.5rem;
    color: var(--mo-blue-700);
}

/* --- Diaporama plein écran ------------------------------------------------ */

/* Destiné à tourner seul sur un écran de hall : rien à cliquer, tout en grand,
   et la marque présente à chaque image. */
.slideshow {
    position: fixed;
    inset: 0;
    z-index: 2300;
    background: var(--mo-blue-900);
    overflow: hidden;
    cursor: none;              /* pas de curseur qui traîne sur un écran mural */
}

.slideshow[hidden] {
    display: none;
}

/* Le curseur revient dès qu'on bouge la souris : c'est ce qui découvre aussi
   le bouton de sortie. */
.slideshow.is-awake {
    cursor: default;
}

/* Deux cadres superposés : le sortant et l'entrant. Chacun porte sa photo deux
   fois — en fond flouté qui remplit l'écran, et en entier par-dessus. Un écran
   de hall est en 16/9, les photos rarement : sans ce fond, il resterait deux
   bandes noires à chaque image.

   Le cadre n'est plus qu'un conteneur : ce sont ses deux calques qui jouent,
   et jamais au même rythme (voir le balisage). */
.slideshow__frame {
    position: absolute;
    inset: 0;
}

/* La toile : fondu lent et lent rapprochement, pendant toute la durée de la
   photo. C'est ce qui empêche l'écran de se figer entre deux transitions. */
.slideshow__back {
    position: absolute;
    inset: 0;
    opacity: 0;
    background-position: center;
    background-size: cover;
    will-change: transform, opacity;
}

.slideshow__back::before {
    content: '';
    position: absolute;
    inset: 0;
    /* Le fond n'est qu'une toile : on l'assombrit fortement pour que la photo
       posée dessus se détache. */
    background: rgba(0, 19, 46, .78);
    -webkit-backdrop-filter: blur(28px);
    backdrop-filter: blur(28px);
}

/* Le plateau : il porte l'entrée et la sortie du tirage. Le tirage garde son
   propre transform pour l'inclinaison et le flottement — deux calques, deux
   mouvements, aucune propriété disputée. Le centrage passe par la grille et
   non par un translate(-50%) : le transform du tirage appartient entièrement
   à l'animation. */
.slideshow__stage {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    opacity: 0;
    will-change: transform, opacity;
}

/* La photo est posée au centre comme un tirage : marge blanche, coins
   arrondis, ombre portée, et une légère inclinaison tirée au sort à chaque
   passage. */
.slideshow__card {
    margin: 0;
    padding: clamp(9px, 1vw, 18px);
    background: #fff;
    border-radius: clamp(10px, 1vw, 18px);
    box-shadow:
        0 42px 90px -28px rgba(0, 0, 0, .78),
        0 8px 24px -10px rgba(0, 0, 0, .45);
    line-height: 0;
    will-change: transform;
}

.slideshow__card img {
    display: block;
    /* La carte épouse la photo : c'est l'image qui porte les limites, donc le
       cadre blanc reste d'épaisseur constante quelle que soit l'orientation.

       On prend le plus de place possible, à trois réserves près :
        - la hauteur s'arrête à 72 %, et jamais à moins de 270 px du haut et du
          bas réunis : le ruban, le logo, « Movember 2026 » et la légende
          occupent une hauteur à peu près fixe, qui pèse bien plus lourd sur un
          écran court. Un pourcentage seul suffisait en 1080p et recouvrait la
          légende en 768p ;
        - la largeur à 80 %, parce qu'une carte penchée de trois degrés déborde
          de sa propre largeur, et qu'il faut en plus de l'air autour : sans
          marge, le balancement ne se voit pas — il n'a plus de bord auquel se
          comparer ;
        - aucun plafond en pixels : il bridait les grands écrans, là où
          justement ce diaporama est fait pour être vu.

       Pourquoi une largeur calculée plutôt que max-width / max-height :

        - « max-width » ne fait que **réduire**. Une photo plus petite que la
          place disponible restait petite, et les deux tiers du fonds le sont ;
        - « width » seul agrandit bien, mais couplé à « max-height » le
          navigateur écrase l'image au lieu de recalculer la largeur — mesuré :
          un rapport de 1,333 rendu en 1,906.

       On calcule donc la largeur soi-même, à partir du rapport réel de la
       photo (--mo-ratio, posé par le JavaScript qui la précharge). La hauteur
       reste « auto » : elle suit le rapport, qui ne peut donc pas être trahi.

       Le troisième terme borne l'agrandissement à une fois et demie la taille
       réelle du fichier : au-delà, sur un grand écran, la photo devient molle.
       Les photos déposées en novembre feront 1800 px, la borne ne jouera que
       pour les plus petites. */
    width: min(
        80vw,
        calc(min(72vh, 100vh - 270px) * var(--mo-ratio, 1.5)),
        calc(var(--mo-natural, 1800) * 1.5px)
    );
    height: auto;
    border-radius: 4px;
}

/* --- Le repli, quand GSAP n'est pas là ------------------------------------
   Le moteur d'animation est chargé à la demande, au lancement du diaporama.
   S'il manque à l'appel, un simple fondu croisé prend le relais : un écran de
   hall ne doit jamais rester noir. La transition CSS est réservée à ce cas —
   posée en permanence, elle lisserait chaque image écrite par GSAP et rendrait
   toutes ses animations poisseuses. */
.slideshow.is-css .slideshow__back,
.slideshow.is-css .slideshow__stage {
    transition: opacity 1s ease;
}

.slideshow.is-css .slideshow__frame.is-active .slideshow__back,
.slideshow.is-css .slideshow__frame.is-active .slideshow__stage {
    opacity: 1;
}

.slideshow.is-css .slideshow__frame.is-active .slideshow__card {
    animation: mo-slidefloat 7s ease-in-out infinite alternate;
}

@keyframes mo-slidefloat {
    from { transform: rotate(-1.6deg) translate3d(-1%, 1%, 0) scale(.985); }
    to   { transform: rotate(-1.6deg) translate3d(1%, -1%, 0) scale(1.015); }
}

/* --- La marque, à chaque image --------------------------------------------
   Elle se tient au-dessus des cadres en toutes circonstances. Le rappel est
   nécessaire : pendant une transition, les deux cadres reçoivent un z-index
   explicite (l'entrant doit se poser sur le sortant, voir la pile), et un
   z-index passe devant un frère qui n'en a pas, quel que soit l'ordre du
   balisage. Sans cette règle, le ruban et la légende disparaîtraient sous la
   photo à chaque changement. */
.slideshow__ribbon,
.slideshow__logo,
.slideshow__wordmark,
.slideshow__caption {
    z-index: 3;
}

.slideshow__ribbon {
    position: absolute;
    top: clamp(1.2rem, 3vh, 2.4rem);
    left: clamp(1.2rem, 3vw, 2.6rem);
    width: auto;
    height: clamp(70px, 11vh, 130px);
    filter: drop-shadow(0 8px 22px rgba(0, 0, 0, .6));
    /* Le diaporama tourne des heures sur un écran de hall : le souffle du ruban
       y est le seul mouvement entre deux photos, on le garde très lent. */
    --mo-ribbon-lift: -9px;
    --mo-ribbon-sway: 1.4deg;
    --mo-ribbon-time: 12s;
}

.slideshow__logo {
    position: absolute;
    top: clamp(1.2rem, 3vh, 2.4rem);
    right: clamp(1.2rem, 3vw, 2.6rem);
    width: clamp(120px, 13vw, 220px);
    height: auto;
    filter: drop-shadow(0 8px 22px rgba(0, 0, 0, .6));
}

/* « Movember 2026 » en bas à gauche, dans la typographie du héros. */
.slideshow__wordmark {
    position: absolute;
    left: clamp(1.2rem, 3vw, 2.6rem);
    bottom: clamp(1.2rem, 3vh, 2.4rem);
    display: flex;
    align-items: baseline;
    gap: .6rem;
    color: #fff;
    text-shadow: 0 6px 24px rgba(0, 0, 0, .7);
}

.slideshow__wordmark .display-font {
    font-size: clamp(1.8rem, 4.4vw, 3.4rem);
    line-height: 1;
}

.slideshow__wordmark b {
    font-family: var(--mo-font-display);
    font-weight: 400;
    font-size: clamp(1.8rem, 4.4vw, 3.4rem);
    line-height: 1;
    color: var(--mo-orange);
}

/* L'établissement et l'auteur, en face du bloc de marque. */
.slideshow__caption {
    position: absolute;
    right: clamp(1.2rem, 3vw, 2.6rem);
    bottom: clamp(1.4rem, 3.4vh, 2.8rem);
    max-width: min(52ch, 52vw);
    text-align: right;
    color: #fff;
    font-size: clamp(.95rem, 1.5vw, 1.35rem);
    line-height: 1.35;
    text-shadow: 0 4px 20px rgba(0, 0, 0, .8);
    opacity: 0;
    transition: opacity .5s ease;
}

.slideshow__caption.is-shown {
    opacity: 1;
}

.slideshow__caption b {
    display: block;
    font-weight: 700;
}

.slideshow__caption span {
    color: rgba(255, 255, 255, .74);
    font-size: .84em;
}

/* La sortie ne se montre qu'au mouvement de la souris : sur un écran mural,
   elle n'a rien à faire à l'image. */
.slideshow__close {
    position: absolute;
    top: clamp(1.2rem, 3vh, 2.4rem);
    right: clamp(1.2rem, 3vw, 2.6rem);
    z-index: 4;   /* au-dessus de la marque, dont elle prend la place */
    width: 46px;
    height: 46px;
    border: 0;
    border-radius: 50%;
    background: rgba(0, 19, 46, .72);
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 1.1rem;
    opacity: 0;
    pointer-events: none;
    transition: opacity .25s ease, background-color .16s ease;
}

.slideshow.is-awake .slideshow__close {
    opacity: 1;
    pointer-events: auto;
}

.slideshow__close:hover {
    background: var(--mo-orange);
}

/* Quand la sortie apparaît, le logo lui cède la place. */
.slideshow.is-awake .slideshow__logo {
    transform: translateX(-58px);
    transition: transform .25s ease;
}

/* Mouvement réduit : le diaporama garde son fondu — il faut bien passer d'une
   photo à l'autre — mais perd tout déplacement. Le JavaScript le sait aussi et
   n'y joue qu'un fondu (voir slideCalm dans site.js). */
@media (prefers-reduced-motion: reduce) {
    .slideshow.is-css .slideshow__back,
    .slideshow.is-css .slideshow__stage,
    .slideshow__caption,
    .slideshow__logo {
        transition-duration: .4s;
    }

    .slideshow.is-css .slideshow__frame.is-active .slideshow__card {
        animation: none;
    }
}

/* --- Le QR code du site, dans le pied de page ----------------------------- */

.footer-qr {
    display: flex;
    align-items: center;
    gap: .9rem;
    margin-top: 1.6rem;
    padding-top: 1.4rem;
    border-top: 1px solid var(--mo-line);
}

/* Le code est en bleu nuit sur blanc : il lui faut son fond, le pied de page
   étant lui-même sombre. */
.footer-qr__thumb {
    flex: none;
    padding: 5px;
    border: 1px solid var(--mo-line);
    border-radius: 12px;
    background: #fff;
    line-height: 0;
    cursor: zoom-in;
    transition: transform .16s ease, border-color .16s ease;
}

.footer-qr__thumb:hover,
.footer-qr__thumb:focus-visible {
    transform: scale(1.04);
    border-color: rgba(255, 158, 56, .7);
}

.footer-qr__thumb img {
    width: 76px;
    height: 76px;
    display: block;
    border-radius: 6px;
}

.footer-qr__text {
    display: flex;
    flex-direction: column;
    gap: .2rem;
    font-size: .82rem;
    line-height: 1.4;
    color: rgba(255, 255, 255, .58);
}

.footer-qr__text strong {
    color: #fff;
    font-size: .88rem;
}

/* --- Le QR code d'une photo ----------------------------------------------- */

/* Posé par-dessus tout, visionneuse et infobulles comprises : un calque à part
   plutôt qu'une seconde fenêtre Bootstrap empilée sur la première. */
.qr-pop {
    position: fixed;
    inset: 0;
    z-index: 2200;
    display: grid;
    place-items: center;
    padding: 1rem;
}

/* [hidden] vaut display:none, mais display:grid ci-dessus le supplante : il
   faut le redire, sinon le calque reste visible. */
.qr-pop[hidden] {
    display: none;
}

.qr-pop__veil {
    position: absolute;
    inset: 0;
    background: rgba(0, 10, 26, .74);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    opacity: 0;
    transition: opacity .2s ease;
}

.qr-pop__card {
    position: relative;
    width: min(400px, 100%);
    background: var(--mo-paper);
    color: var(--mo-text);
    border-radius: 22px;
    padding: 1.7rem 1.6rem 1.5rem;
    text-align: center;
    box-shadow: 0 40px 80px -30px rgba(0, 10, 26, .8);
    opacity: 0;
    transform: translateY(14px) scale(.97);
    transition: opacity .22s ease, transform .22s cubic-bezier(.22, .9, .3, 1.02);
}

.qr-pop.is-open .qr-pop__veil {
    opacity: 1;
}

.qr-pop.is-open .qr-pop__card {
    opacity: 1;
    transform: none;
}

.qr-pop__close {
    position: absolute;
    top: .7rem;
    right: .7rem;
    width: 34px;
    height: 34px;
    border: 0;
    border-radius: 50%;
    background: rgba(0, 60, 135, .08);
    color: var(--mo-blue-700);
    display: grid;
    place-items: center;
    transition: background-color .16s ease;
}

.qr-pop__close:hover {
    background: rgba(0, 60, 135, .16);
}

.qr-pop__title {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    margin: 0 0 .2rem;
    font-size: 1.05rem;
    font-weight: 700;
}

.qr-pop__title i {
    color: var(--mo-orange);
}

.qr-pop__sub {
    margin: 0 0 1.1rem;
    font-size: .88rem;
    color: var(--mo-muted);
    /* Un nom d'établissement long ne doit pas étirer la carte. */
    overflow-wrap: anywhere;
}

/* Le cadre garde sa place pendant le chargement : sans hauteur réservée, la
   carte sauterait au moment où l'image arrive. */
.qr-pop__frame {
    position: relative;
    aspect-ratio: 1;
    display: grid;
    place-items: center;
    border: 1px solid var(--mo-line-dark);
    border-radius: 16px;
    overflow: hidden;
    background: #fff;
}

.qr-pop__frame img {
    width: 100%;
    height: auto;
    display: block;
    transition: opacity .2s ease;
}

.qr-pop__frame.is-loading img {
    opacity: 0;
}

.qr-pop__spinner {
    position: absolute;
    width: 30px;
    height: 30px;
    border: 3px solid rgba(0, 60, 135, .18);
    border-top-color: var(--mo-orange);
    border-radius: 50%;
    animation: mo-spin .7s linear infinite;
    opacity: 0;
}

.qr-pop__frame.is-loading .qr-pop__spinner {
    opacity: 1;
}

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

.qr-pop__hint {
    margin: .9rem 0 1rem;
    font-size: .8rem;
    line-height: 1.45;
    color: var(--mo-muted);
}

.qr-pop__download {
    width: 100%;
}

/* --- Infobulles (Tippy) --------------------------------------------------- */

/* Tippy injecte lui-même son habillage de base (fond gris, flèche) ; ce thème
   ne fait que l'habiller aux couleurs de la maison. La classe est posée par
   assets/js/tooltips.js via l'option « theme ». */
.tippy-tooltip.movember-theme {
    background-color: var(--mo-blue-900);
    color: #fff;
    border-radius: 10px;
    font-size: .8rem;
    font-weight: 500;
    line-height: 1.35;
    letter-spacing: .01em;
    box-shadow: 0 14px 32px -14px rgba(0, 12, 30, .85);
}

.tippy-tooltip.movember-theme .tippy-content {
    padding: .42rem .7rem;
}

/* La flèche de Tippy 5 est un triangle de bordures : sa couleur se pose côté
   par côté, celui qui pointe vers l'élément. */
.tippy-tooltip.movember-theme[data-placement^=top] > .tippy-arrow    { border-top-color: var(--mo-blue-900); }
.tippy-tooltip.movember-theme[data-placement^=bottom] > .tippy-arrow { border-bottom-color: var(--mo-blue-900); }
.tippy-tooltip.movember-theme[data-placement^=left] > .tippy-arrow   { border-left-color: var(--mo-blue-900); }
.tippy-tooltip.movember-theme[data-placement^=right] > .tippy-arrow  { border-right-color: var(--mo-blue-900); }

/* La visionneuse est en plein écran (z-index Bootstrap 1055) : les bulles sont
   rendues dans <body>, il leur faut passer par-dessus. */
.tippy-popper {
    z-index: 2000;
}

/* --- Apparitions au défilement ------------------------------------------- */

/* L'état masqué n'est appliqué que si JavaScript est actif : sans lui, le
   contenu reste visible au lieu de disparaître définitivement. */
.js .reveal {
    opacity: 0;
    transform: translateY(26px);
    transition: opacity .7s cubic-bezier(.22, .8, .3, 1), transform .7s cubic-bezier(.22, .8, .3, 1);
}

.js .reveal.is-visible {
    opacity: 1;
    transform: none;
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }

    .js .reveal {
        opacity: 1;
        transform: none;
        transition: none;
    }

    .lightbox__stage {
        transition: none;
    }

    .mo-stache,
    .mo-marquee__track,
    .gallery__like.is-pop i,
    .mo-badge .dot,
    .mo-hero__ribbon,
    .gallery-hero__ribbon,
    .has-ribbon::before,
    .help-band::after,
    .mo-footer::before,
    .causes-ribbon,
    .slideshow__ribbon {
        animation: none;
    }

    /* La barre change encore d'allure en se posant, mais d'un coup : c'est le
       mouvement qu'on retire, pas l'information. */
    .mo-nav,
    .mo-nav .mo-brand img,
    .mo-nav .mo-brand-text,
    .mo-nav__cta {
        transition: none;
    }

    .gallery__item img,
    .cause-card,
    .btn-mo,
    .btn-ghost,
    .mobilise__fill {
        transition: none;
    }
}
