/**
 * Gutenberg New Gen - Bloc « Cartes services V2 ».
 *
 * Portage de assets/css/ws-widget-services-cards.css (WS Booster) vers
 * Gutenberg. Regles reprises telles quelles, prefixe ws-sc -> gng-sc.
 *
 * - Cartes en grille avec hauteurs decalees
 * - Image plein cadre avec parallaxe subtil (translateY -2% au repos, 0 au hover)
 * - Titre en haut + Description + bouton circulaire en bas
 * - Bouton circulaire qui se DEPLOIE horizontalement au hover pour reveler le texte
 * 100% CSS, zero JS.
 */

.gng-sc__grid {
    display: grid;
    /* v4.9.73 : minmax(0, 1fr) au lieu de 1fr pur. Defensif contre les cards
       dont TOUS les enfants sont position:absolute (donc 0 intrinsic content).
       Sans minmax(0, ...), si le parent contexte est non-stretch (ex: flex
       align-items:flex-start dans le builder), 1fr peut resoudre a 0px. Cf
       Bible Partie 9.x : pattern "grid avec items absolute". */
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
    align-items: end; /* important : permet aux cards de hauteurs differentes de s'aligner en bas */
    /* v4.9.73 : force la largeur a 100% du parent pour empecher le shrink-to-fit
       dans le builder Elementor (qui parfois enveloppe en flex non-stretch). */
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
    /* v4.9.42 : variable consommee par les formats uniforme / portrait / paysage */
    --gng-sc-uniform-h: 440px;
    /* v4.9.46 : variables animation (defauts override par les controles) */
    --gng-sc-anim-dur: 0.7s;
    --gng-sc-anim-stagger: 0.12s;
    --gng-sc-anim-dist: 40px;
    --gng-sc-anim-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ============ ANIMATION D'APPARITION (v4.9.46) ============
   L'observateur de gng-service-cards.js detecte l'arrivee a l'ecran puis
   pose .is-visible sur la grille. Le decalage se calcule via
   --gng-sc-card-idx (pose en ligne par le PHP) * --gng-sc-anim-stagger.
   Dans l'editeur, le script pose is-visible tout de suite : on n'y defile pas. */

/* === Easing presets === */
.gng-sc-anim-ease-smooth .gng-sc__grid { --gng-sc-anim-ease: cubic-bezier(0.22, 1, 0.36, 1); }
.gng-sc-anim-ease-spring .gng-sc__grid { --gng-sc-anim-ease: cubic-bezier(0.34, 1.4, 0.64, 1); }
.gng-sc-anim-ease-snappy .gng-sc__grid { --gng-sc-anim-ease: cubic-bezier(0.4, 0, 0.2, 1); }
.gng-sc-anim-ease-bounce .gng-sc__grid { --gng-sc-anim-ease: cubic-bezier(0.68, -0.55, 0.27, 1.55); }
.gng-sc-anim-ease-linear .gng-sc__grid { --gng-sc-anim-ease: linear; }

/* === ANIMATION D'APPARITION - PATTERN MANIFEST 6569 (FAQ Avancee) ===
   v4.9.61 REFACTOR : abandon des transitions au profit de CSS animations
   avec `animation-fill-mode: backwards`. Avantages :
   - Zero race condition entre is-init et is-visible (l'anim ne demarre
     que quand le JS pose explicitement is-visible).
   - `backwards` : pendant le delay l'item est a l'etat FROM, apres l'anim
     il revient a son CSS normal -> hover FX preserves.
   - Replay propre en editeur a chaque re-render (l'animation re-joue).
   - Fail-safe : sans JS / .is-init absent -> cartes visibles, pas
     d'animation parasite. */

/* Etat cache : actif uniquement si JS a marque le grid avec is-init
   ET que is-visible n'est pas encore present. Sans .is-init -> cartes
   visibles (fail-safe).
   v4.9.71 : la regle est restreinte au FRONT uniquement
   (body:not(.elementor-editor-active)). En editeur, les cards restent
   TOUJOURS visibles meme si le JS poste is-init avant is-visible
   (race condition MutationObserver vs double RAF). L'animation joue
   quand meme via le keyframe + backwards. */
body:not(.elementor-editor-active) .gng-sc-anim-yes .gng-sc__grid.is-init:not(.is-visible) .gng-sc__card {
    opacity: 0;
}

/* L'animation joue quand .is-visible est ajoute. animation-fill-mode:
   backwards = le from est applique des le declenchement (meme pendant
   le delay) -> garantie d'un etat de depart propre. */
.gng-sc-anim-yes .gng-sc__grid.is-init.is-visible .gng-sc__card {
    animation: gng-sc-card-fadeup var(--gng-sc-anim-dur, 0.7s) var(--gng-sc-anim-ease, cubic-bezier(0.22, 1, 0.36, 1)) backwards;
    animation-delay: calc(var(--gng-sc-card-idx, 0) * var(--gng-sc-anim-stagger, 0.12s));
}

/* Keyframes par type. Defaut = fade-up (utilise par la regle generique
   gng-sc-card-fadeup). Les autres types overrident l'animation-name. */
@keyframes gng-sc-card-fadeup {
    from { opacity: 0; transform: translateY(var(--gng-sc-anim-dist, 40px)); }
    to   { opacity: 1; transform: none; }
}
@keyframes gng-sc-card-fadedown {
    from { opacity: 0; transform: translateY(calc(var(--gng-sc-anim-dist, 40px) * -1)); }
    to   { opacity: 1; transform: none; }
}
@keyframes gng-sc-card-fadeleft {
    from { opacity: 0; transform: translateX(calc(var(--gng-sc-anim-dist, 40px) * -1)); }
    to   { opacity: 1; transform: none; }
}
@keyframes gng-sc-card-faderight {
    from { opacity: 0; transform: translateX(var(--gng-sc-anim-dist, 40px)); }
    to   { opacity: 1; transform: none; }
}
@keyframes gng-sc-card-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@keyframes gng-sc-card-scaleup {
    from { opacity: 0; transform: scale(0.85); }
    to   { opacity: 1; transform: none; }
}
@keyframes gng-sc-card-scaledown {
    from { opacity: 0; transform: scale(1.15); }
    to   { opacity: 1; transform: none; }
}
@keyframes gng-sc-card-flip {
    from { opacity: 0; transform: perspective(800px) rotateX(45deg); transform-origin: center bottom; }
    to   { opacity: 1; transform: none; }
}
@keyframes gng-sc-card-tilt {
    from { opacity: 0; transform: translate(calc(var(--gng-sc-anim-dist, 40px) * -0.5), var(--gng-sc-anim-dist, 40px)) rotate(-3deg); }
    to   { opacity: 1; transform: none; }
}

/* Mapping type -> keyframe (override de animation-name). La generique au-dessus
   utilise -fadeup, les autres types redirigent vers leur keyframe. */
.gng-sc-anim-yes.gng-sc-anim-type-fade-up    .gng-sc__grid.is-init.is-visible .gng-sc__card { animation-name: gng-sc-card-fadeup; }
.gng-sc-anim-yes.gng-sc-anim-type-fade-down  .gng-sc__grid.is-init.is-visible .gng-sc__card { animation-name: gng-sc-card-fadedown; }
.gng-sc-anim-yes.gng-sc-anim-type-fade-left  .gng-sc__grid.is-init.is-visible .gng-sc__card { animation-name: gng-sc-card-fadeleft; }
.gng-sc-anim-yes.gng-sc-anim-type-fade-right .gng-sc__grid.is-init.is-visible .gng-sc__card { animation-name: gng-sc-card-faderight; }
.gng-sc-anim-yes.gng-sc-anim-type-fade       .gng-sc__grid.is-init.is-visible .gng-sc__card { animation-name: gng-sc-card-fade; }
.gng-sc-anim-yes.gng-sc-anim-type-scale-up   .gng-sc__grid.is-init.is-visible .gng-sc__card { animation-name: gng-sc-card-scaleup; }
.gng-sc-anim-yes.gng-sc-anim-type-scale-down .gng-sc__grid.is-init.is-visible .gng-sc__card { animation-name: gng-sc-card-scaledown; }
.gng-sc-anim-yes.gng-sc-anim-type-flip       .gng-sc__grid.is-init.is-visible .gng-sc__card { animation-name: gng-sc-card-flip; }
.gng-sc-anim-yes.gng-sc-anim-type-tilt       .gng-sc__grid.is-init.is-visible .gng-sc__card { animation-name: gng-sc-card-tilt; }

/* === Respect prefers-reduced-motion === */
@media (prefers-reduced-motion: reduce) {
    .gng-sc-anim-yes .gng-sc__card {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
        animation: none !important; /* v4.9.61 : kill aussi le keyframe */
    }
}

/* ============ FORMATS (v4.9.42) ============ */

/* Format "Tous a la meme taille" : override les hauteurs individuelles inline */
.gng-sc-format-uniforme .gng-sc__grid {
    align-items: stretch; /* tout en haut, pas decales */
}
.gng-sc-format-uniforme .gng-sc__card {
    height: var(--gng-sc-uniform-h, 440px) !important;
}

/* Format Portrait : aspect-ratio 3/4. Width-determined (depend du nombre de colonnes).
   La hauteur du slider sert de MIN-HEIGHT (utile en mobile 1 colonne pour cap). */
.gng-sc-format-portrait .gng-sc__grid {
    align-items: stretch;
}
.gng-sc-format-portrait .gng-sc__card {
    height: auto !important;
    aspect-ratio: 3 / 4;
    min-height: var(--gng-sc-uniform-h, 0);
}

/* Format Paysage : aspect-ratio 4/3 (plus large que haut). */
.gng-sc-format-paysage .gng-sc__grid {
    align-items: stretch;
}
.gng-sc-format-paysage .gng-sc__card {
    height: auto !important;
    aspect-ratio: 4 / 3;
    min-height: var(--gng-sc-uniform-h, 0);
}

/* Format Pyramide (v4.9.43) : centre plus grand, bords plus petits.
   --gng-sc-rel-dist est pose par PHP sur chaque .gng-sc__card (0 = centre, 1 = bord).
   --gng-sc-shrink est pose par le slider "Intensite" (0-0.7).
   --gng-sc-uniform-h est pose par le slider "Hauteur des cartes" (responsive). */
.gng-sc-format-pyramide .gng-sc__grid {
    --gng-sc-shrink: 0.4; /* fallback si le slider n'est pas regle */
    align-items: end; /* defaut : aligne en bas pour effet pyramide haute */
}
.gng-sc-format-pyramide .gng-sc__card {
    height: calc(var(--gng-sc-uniform-h, 440px) * (1 - var(--gng-sc-shrink, 0.4) * var(--gng-sc-rel-dist, 0))) !important;
}

/* Sur mobile (1 colonne typiquement), la pyramide horizontale n'a plus de sens
   visuellement (les cartes sont empilees). On force toutes les cartes a la hauteur
   du slider mobile -> comportement identique au mode uniforme. */
@media (max-width: 767px) {
    .gng-sc-format-pyramide .gng-sc__card {
        height: var(--gng-sc-uniform-h, 320px) !important;
    }
}

/* ============ MODE CARROUSEL MOBILE (v4.9.45) ============
   Sur mobile, basculer la grille en scroll horizontal avec snap.
   Peu importe le format desktop (uniforme/portrait/paysage/pyramide).
   La largeur des cartes est controlee par --gng-sc-mobile-card-w (defaut 85vw). */
@media (max-width: 767px) {
    .gng-sc-mobile-carrousel .gng-sc__grid {
        /* Override grid -> flex horizontal scroll */
        display: flex !important;
        flex-direction: row;
        flex-wrap: nowrap;
        grid-template-columns: none !important;
        overflow-x: auto;
        overflow-y: hidden;
        scroll-snap-type: x mandatory;
        -webkit-overflow-scrolling: touch;
        scroll-padding-left: 16px;
        scroll-padding-right: 16px;
        /* Padding lateral pour permettre un look "centre" du premier/dernier item */
        padding-left: 16px;
        padding-right: 16px;
        margin-left: -16px; /* compense le padding pour ne pas decaler le widget */
        margin-right: -16px;
    }

    .gng-sc-mobile-carrousel .gng-sc__card {
        flex: 0 0 auto;
        width: var(--gng-sc-mobile-card-w, 85vw);
        max-width: var(--gng-sc-mobile-card-w, 85vw);
        scroll-snap-align: start;
        /* Annule l'effet pyramide / aspect-ratio en mobile carrousel : uniforme */
        height: var(--gng-sc-uniform-h, 320px) !important;
        aspect-ratio: auto !important;
        min-height: 0;
    }

    /* Hide scrollbar par defaut. Quand .gng-sc-mobile-scrollbar-yes : on l'affiche. */
    .gng-sc-mobile-carrousel:not(.gng-sc-mobile-scrollbar-yes) .gng-sc__grid {
        scrollbar-width: none; /* Firefox */
        -ms-overflow-style: none; /* IE 10+ */
        padding-bottom: 0;
    }
    .gng-sc-mobile-carrousel:not(.gng-sc-mobile-scrollbar-yes) .gng-sc__grid::-webkit-scrollbar {
        display: none; /* Chrome / Safari / Opera */
    }

    /* v4.9.57 : scrollbar visible -> dimensions safe + padding pour ne pas
       deborder du widget. Fix du probleme "se met pas bien dans le cadre". */
    .gng-sc-mobile-carrousel.gng-sc-mobile-scrollbar-yes .gng-sc__grid {
        padding-bottom: 12px;
        scrollbar-width: thin;
        scrollbar-color: rgba(0, 0, 0, 0.3) transparent;
    }
    .gng-sc-mobile-carrousel.gng-sc-mobile-scrollbar-yes .gng-sc__grid::-webkit-scrollbar {
        height: 6px;
    }
    .gng-sc-mobile-carrousel.gng-sc-mobile-scrollbar-yes .gng-sc__grid::-webkit-scrollbar-track {
        background: transparent;
        margin: 0 16px;
    }
    .gng-sc-mobile-carrousel.gng-sc-mobile-scrollbar-yes .gng-sc__grid::-webkit-scrollbar-thumb {
        background: rgba(0, 0, 0, 0.35);
        border-radius: 6px;
    }
    .gng-sc-mobile-carrousel.gng-sc-mobile-scrollbar-yes .gng-sc__grid::-webkit-scrollbar-thumb:hover {
        background: rgba(0, 0, 0, 0.55);
    }
}

/* ============ NAVIGATION CARROUSEL (v4.9.57) ============
   .gng-sc wrapper contient .gng-sc__grid + .gng-sc__arrows + .gng-sc__dots
   Tout est cache sauf en mode mobile carrousel.
   v4.9.73 : width 100% explicite pour empecher que le wrapper se contracte
   dans le builder Elementor (sympt : grid columns "0px 0px 0px 0px" alors
   que .elementor-widget-container fait 1112px). */
.gng-sc {
    position: relative;
    display: block;
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
}

/* Cacher arrows + dots par defaut (desktop + mode stack) */
.gng-sc__arrows,
.gng-sc__dots {
    display: none;
}

@media (max-width: 767px) {
    /* En mode carrousel mobile : afficher si les options sont activees */
    .gng-sc-mobile-carrousel.gng-sc-mobile-arrows-yes .gng-sc__arrows { display: block; }
    .gng-sc-mobile-carrousel.gng-sc-mobile-dots-yes .gng-sc__dots   { display: flex; }

    /* === ARROWS === */
    .gng-sc__arrows {
        pointer-events: none; /* tout passe sauf les boutons */
    }
    .gng-sc__arrow {
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        width: 40px;
        height: 40px;
        border: none;
        border-radius: 50%;
        background-color: rgba(0, 0, 0, 0.55);
        color: #fff;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        pointer-events: auto;
        z-index: 5;
        transition: background-color 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
        -webkit-tap-highlight-color: transparent;
    }
    .gng-sc__arrow:hover,
    .gng-sc__arrow:focus-visible {
        transform: translateY(-50%) scale(1.08);
        outline: none;
    }
    .gng-sc__arrow:disabled,
    .gng-sc__arrow[aria-disabled="true"] {
        opacity: 0.3;
        cursor: default;
    }
    /* Position INSIDE : sur les bords du carrousel */
    .gng-sc-mobile-arrows-pos-inside .gng-sc__arrow--prev { left: 12px; }
    .gng-sc-mobile-arrows-pos-inside .gng-sc__arrow--next { right: 12px; }

    /* Position OUTSIDE : sous les cartes, centrees */
    .gng-sc-mobile-arrows-pos-outside .gng-sc__arrows {
        position: relative;
        margin-top: 16px;
        display: flex !important;
        justify-content: center;
        gap: 12px;
        pointer-events: auto;
    }
    .gng-sc-mobile-arrows-pos-outside .gng-sc__arrow {
        position: relative;
        top: auto;
        left: auto !important;
        right: auto !important;
        transform: none;
    }
    .gng-sc-mobile-arrows-pos-outside .gng-sc__arrow:hover,
    .gng-sc-mobile-arrows-pos-outside .gng-sc__arrow:focus-visible {
        transform: scale(1.08);
    }

    /* === DOTS === */
    .gng-sc__dots {
        flex-wrap: wrap;
        justify-content: center;
        gap: 8px;
        margin-top: 16px;
        padding: 0 16px;
    }
    .gng-sc__dot {
        width: 8px;
        height: 8px;
        border-radius: 50%;
        border: none;
        background-color: rgba(0, 0, 0, 0.25);
        cursor: pointer;
        padding: 0;
        transition: background-color 0.2s ease, transform 0.2s ease, width 0.2s ease;
        -webkit-tap-highlight-color: transparent;
    }
    .gng-sc__dot.is-active {
        background-color: #0f172a;
        width: 24px; /* pill style pour le dot actif */
        border-radius: 4px;
    }
}

/* ============================================================
   v4.9.155 : CARROUSEL DESKTOP (>= 1024px)
   Pattern identique au mobile mais sur grand viewport. Variables :
   --gng-sc-desktop-spv = slides per view (defaut 3)
   --gng-sc-desktop-gap = espacement entre cartes (utilise la var globale 'gap')
   Active uniquement si l'user a explicitement choisi desktop_mode=carrousel.
   ============================================================ */
@media (min-width: 1024px) {
    .gng-sc-desktop-carrousel .gng-sc__grid {
        display: flex !important;
        flex-direction: row;
        flex-wrap: nowrap;
        grid-template-columns: none !important;
        overflow-x: auto;
        overflow-y: hidden;
        scroll-snap-type: x mandatory;
        -webkit-overflow-scrolling: touch;
        scroll-padding-left: 24px;
        scroll-padding-right: 24px;
        scroll-behavior: smooth;
        scrollbar-width: none;
        -ms-overflow-style: none;
    }
    .gng-sc-desktop-carrousel .gng-sc__grid::-webkit-scrollbar {
        display: none;
    }
    .gng-sc-desktop-carrousel .gng-sc__card {
        flex: 0 0 auto;
        /* width = (100% - gap * (spv - 1)) / spv */
        width: calc(
            (100% - var(--gng-sc-gap, 16px) * (var(--gng-sc-desktop-spv, 3) - 1))
            / var(--gng-sc-desktop-spv, 3)
        );
        max-width: 100%;
        scroll-snap-align: start;
        height: var(--gng-sc-uniform-h, 440px) !important;
        aspect-ratio: auto !important;
        min-height: 0;
    }

    /* Afficher arrows + dots selon les switchs */
    .gng-sc-desktop-carrousel.gng-sc-desktop-arrows-yes .gng-sc__arrows { display: block; }
    .gng-sc-desktop-carrousel.gng-sc-desktop-dots-yes   .gng-sc__dots   { display: flex; }

    /* === ARROWS desktop === */
    .gng-sc-desktop-carrousel .gng-sc__arrows {
        pointer-events: none;
    }
    .gng-sc-desktop-carrousel .gng-sc__arrow {
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        width: 48px;
        height: 48px;
        border: none;
        border-radius: 50%;
        background-color: rgba(0, 0, 0, 0.55);
        color: #fff;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        pointer-events: auto;
        z-index: 5;
        transition: background-color 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
    }
    .gng-sc-desktop-carrousel .gng-sc__arrow:hover,
    .gng-sc-desktop-carrousel .gng-sc__arrow:focus-visible {
        transform: translateY(-50%) scale(1.08);
        outline: none;
    }
    .gng-sc-desktop-carrousel .gng-sc__arrow:disabled,
    .gng-sc-desktop-carrousel .gng-sc__arrow[aria-disabled="true"] {
        opacity: 0.3;
        cursor: default;
    }
    .gng-sc-desktop-arrows-pos-inside .gng-sc__arrow--prev { left: 16px; }
    .gng-sc-desktop-arrows-pos-inside .gng-sc__arrow--next { right: 16px; }
    .gng-sc-desktop-arrows-pos-outside .gng-sc__arrows {
        position: relative;
        margin-top: 20px;
        display: flex !important;
        justify-content: center;
        gap: 16px;
        pointer-events: auto;
    }
    .gng-sc-desktop-arrows-pos-outside .gng-sc__arrow {
        position: relative;
        top: auto;
        left: auto !important;
        right: auto !important;
        transform: none;
    }
    .gng-sc-desktop-arrows-pos-outside .gng-sc__arrow:hover,
    .gng-sc-desktop-arrows-pos-outside .gng-sc__arrow:focus-visible {
        transform: scale(1.08);
    }

    /* === DOTS desktop === */
    .gng-sc-desktop-carrousel .gng-sc__dots {
        flex-wrap: wrap;
        justify-content: center;
        gap: 10px;
        margin-top: 20px;
        padding: 0 24px;
    }
    .gng-sc-desktop-carrousel .gng-sc__dot {
        width: 10px;
        height: 10px;
        border-radius: 50%;
        border: none;
        background-color: rgba(0, 0, 0, 0.25);
        cursor: pointer;
        padding: 0;
        transition: background-color 0.2s ease, transform 0.2s ease, width 0.2s ease;
    }
    .gng-sc-desktop-carrousel .gng-sc__dot.is-active {
        background-color: #0f172a;
        width: 28px;
        border-radius: 4px;
    }
}

/* ============ CARD ============ */
/* v4.9.48 : la hauteur est maintenant TOUJOURS controlee par --gng-sc-uniform-h
   (le slider responsive "Hauteur des cartes" dans Style > Image). Plus de hauteur
   inline par carte (card_height retire). Les formats portrait/paysage/pyramide
   overrident ce comportement avec leurs propres regles. */
.gng-sc__card {
    position: relative;
    display: block;
    width: 100%;
    /* v4.9.73 : min-width: 0 indispensable pour que les grid items puissent
       prendre leur 1fr meme quand leur contenu est position:absolute. Sans
       cette regle, le min-content de la card peut "bloquer" le shrink/grow
       du track en flex/grid parent non-stretch. */
    min-width: 0;
    height: var(--gng-sc-uniform-h, 440px);
    overflow: hidden;
    border-radius: 16px;
    text-decoration: none;
    isolation: isolate;
    background: #1a1a1a;
    transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Image full bleed : epouse exactement la forme de la carte (inset 0).
   !important sur width/height/max-* obligatoire pour override le theme WP
   (img { max-width:100%; height:auto }) qui sinon ecrase la taille et laisse
   l'image paysage petite en haut de la carte. Cf BIBLE Partie 9.13.
   object-fit / object-position SANS !important : les controles Elementor
   "Adaptation" + "Position" injectent .elementor-element-XXX .gng-sc__img
   (specificite 0,2,0) qui doit pouvoir overrider ces defauts (0,1,0). */
.gng-sc__img {
    position: absolute !important;
    top: 0 !important;
    left: 0 !important;
    width: 100% !important;
    height: 100% !important;
    max-width: none !important;
    max-height: none !important;
    object-fit: cover;
    object-position: center center;
    transition: transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
    z-index: 0;
}

/* v4.9.68 retire en v4.9.72 (revert : la regle defensive WebP picture
   wrap n'etait pas la cause du bug et possiblement contributrice. On
   revient a l'etat qui fonctionnait avant). */

/* Zoom hover (active via classe wrapper) */
.gng-sc-zoom-yes .gng-sc__card:hover .gng-sc__img {
    transform: scale(1.06);
}

/* Voile sombre en gradient bottom-up pour assurer la lisibilite du texte */
.gng-sc__card::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(0,0,0,0.45) 0%, transparent 60%);
    pointer-events: none;
    z-index: 1;
}

/* ============ CONTENT ============ */
/* v4.9.48 : flex column avec title en haut + desc en bas (TOUJOURS en bas,
   meme si pas de titre). C'etait `justify-content: space-between` mais
   quand le titre est absent, la desc remontait en haut. Fix : marge auto
   sur les 2 elements pour forcer leurs positions. */
.gng-sc__content {
    position: absolute;
    inset: 0;
    z-index: 2;
    padding: 24px;
    display: flex;
    flex-direction: column;
    pointer-events: none; /* le link parent gere le click */
}

.gng-sc__title {
    margin: 0 0 auto 0; /* push tout ce qui suit vers le bas */
    color: #ffffff;
    font-size: 22px;
    font-weight: 600;
    /* INTERLETTRE ET INTERLIGNE NORMALES (2026-08-30). Le titre etait
       resserre d'office (-0.02em) et l'interligne fixee : deux choix
       imposes qu'on ne pouvait defaire qu'en les redecouvrant. Le reglage
       de Typographie du panneau passe par-dessus des qu'on y touche. */
    line-height: normal;
    letter-spacing: normal;
    max-width: 90%;
}

.gng-sc__desc {
    margin: auto var(--gng-sc-btn-reserve, 60px) 0 0; /* margin-top:auto => reste TOUJOURS en bas, meme sans titre.
                              60px a droite pour laisser la place au bouton circulaire. */
    color: #ffffff;
    font-size: 14px;
    line-height: normal;
    letter-spacing: normal;
    opacity: 0.92;
}

/* === POSITION DU BLOC TITRE + DESC (controle title_position, v4.9.147) ===
   - Haut (default historique) : titre en haut, desc en bas (effet "spread"
     via margin:auto sur les deux).
   - Milieu / Bas : titre + desc collent ensemble, le bloc se place via
     justify-content. On neutralise les margins auto pour que les 2 textes
     soient solidaires. Padding-bottom etoffe en mode "Bas" pour eviter le
     chevauchement avec le bouton circulaire (right:24px; bottom:24px).
*/
.gng-sc-titlepos-middle .gng-sc__content { justify-content: center; }
.gng-sc-titlepos-bottom .gng-sc__content {
    justify-content: flex-end;
    padding-bottom: var(--gng-sc-btn-reserve-bas, 64px); /* reserve la place du bouton bas-droit */
}

.gng-sc-titlepos-middle .gng-sc__title,
.gng-sc-titlepos-bottom .gng-sc__title {
    margin: 0 0 10px 0; /* annule margin-bottom:auto -> titre colle a desc */
}

.gng-sc-titlepos-middle .gng-sc__desc,
.gng-sc-titlepos-bottom .gng-sc__desc {
    margin: 0 var(--gng-sc-btn-reserve, 60px) 0 0; /* annule margin-top:auto -> desc colle au titre */
}

/* ============ BOUTON CIRCULAIRE EXPANSIBLE ============
   Pattern eprouve (circle-to-pill) du codepen itsmikemoran/yOqNGB :
   - Au repos : largeur fixe = hauteur (cercle), label invisible (display:none impossible
     car ca tue la transition, donc width:0 + opacity:0 + position absolute)
   - Au hover : largeur auto, padding s'ouvre, label apparait avec un delay
*/
/* v4.9.47 : Bouton simplifie en cercle pur (plus de pillule expand).
   Garde une legere rotation de la fleche au hover de la card pour effet subtil. */
.gng-sc__btn {
    position: absolute;
    right: 24px;
    bottom: 24px;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background-color: #ffffff;
    color: #0f172a;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
    z-index: 3;
    transition: background-color 0.3s ease, color 0.3s ease, transform 0.3s ease;
}

.gng-sc__btn-arrow {
    width: 100%;
    height: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    line-height: 1;
    transform: rotate(0deg);
    transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

/* === HOVER : leger zoom du cercle + petite rotation de la fleche === */
.gng-sc__card:hover .gng-sc__btn {
    transform: scale(1.08);
}

.gng-sc__card:hover .gng-sc__btn-arrow {
    transform: rotate(45deg);
}

/* Plus de label, mais le selecteur est conserve pour compat retro si une page
   ancienne le contient encore dans son HTML (will simply hide if found). */

/* ============ RESPONSIVE ============
   v4.9.48 : on ne force PLUS de hauteur fixe en CSS media queries.
   La hauteur est entierement geree par le slider responsive
   "Hauteur des cartes" (Desktop/Tablette/Mobile) qui ecrit --gng-sc-uniform-h.
   Les colonnes sont aussi controlees par le slider Colonnes responsive.
   Le seul fallback ici est le titre plus petit sur petit ecran. */
@media (max-width: 600px) {
    .gng-sc__title {
        font-size: 20px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .gng-sc__img,
    .gng-sc__btn,
    .gng-sc__btn-arrow,
        .gng-sc__card {
        transition: none !important;
    }
}

/* ===== IMAGE ENVELOPPEE PAR UN PLUGIN WEBP =====
   Les plugins de conversion WebP remplacent <img class="..."> par
   <picture class="..."><source><img></picture> : NOTRE classe se retrouve sur
   le <picture>, et l'image reelle, a l'interieur, se retrouve sans rien - ni
   dimension, ni cadrage. Or `object-fit` n'existe pas sur un <picture> : tout
   le cadrage tombe dans le vide, et le front cesse de ressembler au
   constructeur, qui lui recoit l'<img> d'origine.

   `inherit` reprend explicitement la valeur calculee du parent : l'image
   interne recupere le cadrage pose sur le <picture>. Sans plugin de conversion,
   cette regle ne rencontre jamais son selecteur et ne coute rien. */
picture[class*="gng-"] {
    display: block;
}

picture[class*="gng-"] > img {
    width: 100% !important;
    height: 100% !important;
    max-width: none !important;
    max-height: none !important;
    object-fit: inherit;
    object-position: inherit;
    border-radius: inherit;
    display: block;
}


/* ====================================================================
   BOUTON MASQUE (reglage « Afficher le bouton »)
   Les deux reserves de place n'ont plus lieu d'etre : le texte reprend
   toute la largeur, et le grand vide sous le texte en position « Bas »
   disparait. C'etait la cause de l'espace qu'on ne pouvait pas retirer.
   ==================================================================== */
.gng-sc-btn-no {
    --gng-sc-btn-reserve: 0px;
    --gng-sc-btn-reserve-bas: 0px;
}
.gng-sc-btn-no .gng-sc__btn { display: none; }

/* ====================================================================
   EFFET 3D AU SURVOL
   La carte s'incline vers le curseur. Le script ne pose que deux nombres
   (--gng-sc-mx / --gng-sc-my, entre -1 et 1) ; tout le reste est calcule
   ici. Aucune bibliotheque d'animation : une inclinaison n'est qu'un
   `transform`, compose par la carte graphique.
   ==================================================================== */
.gng-sc-tilt-yes .gng-sc__card {
    transform-style: preserve-3d;
    transition: transform var(--gng-sc-tilt-speed, .3s) ease-out;
}
.gng-sc-tilt-yes .gng-sc__card:hover {
    transform:
        rotateY(calc(var(--gng-sc-mx, 0) * var(--gng-sc-tilt-deg, 12) * 1deg))
        rotateX(calc(var(--gng-sc-my, 0) * var(--gng-sc-tilt-deg, 12) * -1deg))
        scale(var(--gng-sc-tilt-scale, 1.04));
}
/* Direction inversee : la carte fuit le curseur au lieu de le suivre. */
.gng-sc-tilt-yes.gng-sc-tiltrev-yes .gng-sc__card:hover {
    transform:
        rotateY(calc(var(--gng-sc-mx, 0) * var(--gng-sc-tilt-deg, 12) * -1deg))
        rotateX(calc(var(--gng-sc-my, 0) * var(--gng-sc-tilt-deg, 12) * 1deg))
        scale(var(--gng-sc-tilt-scale, 1.04));
}
/* Mouvement reduit demande : la carte ne s'incline plus. */
@media (prefers-reduced-motion: reduce) {
    .gng-sc-tilt-yes .gng-sc__card,
    .gng-sc-tilt-yes .gng-sc__card:hover { transform: none; transition: none; }
}