/* Reset & base */
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; -webkit-font-smoothing: antialiased; }
img { max-width: 100%; display: block; }
p { text-wrap: pretty; }

/* Visually hidden but readable by screen readers — standard WP utility class,
 * not shipped by block themes by default. Used by the planning table's empty
 * corner header cell (patterns/planning-entrainements.php). */
.screen-reader-text {
    border: 0;
    clip: rect(1px, 1px, 1px, 1px);
    clip-path: inset(50%);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;
    word-wrap: normal !important;
}

/* Focus visibility (accessibility) */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: 2px solid var(--wp--preset--color--accent);
    outline-offset: 2px;
}

/* Section padding scale: 100px desktop -> 64px tablet -> 48px mobile.
 * Both .wp-block-group and .wp-block-columns carry .gjpm-section: the alt rows
 * and pricing cards are columns blocks, so a group-only selector left them with
 * no vertical rhythm at all. */
.wp-block-group.gjpm-section,
.wp-block-columns.gjpm-section,
.gjpm-cta-band {
    padding-top: var(--wp--preset--spacing--70);
    padding-bottom: var(--wp--preset--spacing--70);
}
@media (max-width: 1100px) {
    .wp-block-group.gjpm-section,
    .wp-block-columns.gjpm-section { padding-top: 64px; padding-bottom: 64px; }
}
@media (max-width: 700px) {
    .wp-block-group.gjpm-section,
    .wp-block-columns.gjpm-section { padding-top: 48px; padding-bottom: 48px; }
}

/* Secondary button variants */
.gjpm-btn-secondary .wp-block-button__link {
    background: rgba(0, 0, 0, 0.05);
    color: var(--wp--preset--color--foreground);
}
.gjpm-btn-secondary.is-on-photo .wp-block-button__link {
    background: rgba(255, 255, 255, 0.92);
    color: var(--wp--preset--color--foreground);
}

/* Form fields */
.gjpm-form input[type="text"],
.gjpm-form input[type="email"],
.gjpm-form select,
.gjpm-form textarea {
    width: 100%;
    padding: 12px 14px;
    border: 1px solid rgba(0, 0, 0, 0.12);
    border-radius: 10px;
    font-size: 16px;
    font-family: inherit;
}
.gjpm-form label {
    display: block;
    font-size: 13px;
    font-weight: 600;
    margin-bottom: 6px;
}
.gjpm-form .gjpm-field {
    margin-bottom: 16px;
}
.gjpm-form textarea {
    resize: vertical;
}
.gjpm-form button[type="submit"] {
    width: 100%;
    padding: 14px;
    background: var(--wp--preset--color--sand);
    color: var(--wp--preset--color--foreground);
    border: none;
    border-radius: 980px;
    font-size: 16px;
    font-weight: 500;
    cursor: pointer;
}
.gjpm-form button[type="submit"]:hover {
    background: var(--wp--preset--color--sand-dark);
}
.gjpm-form .gjpm-form-error {
    color: #b3261e;
    font-size: 14px;
    margin-top: -10px;
    margin-bottom: 16px;
}

/* Social icons (nav + footer) */
.gjpm-social-links { gap: 16px; align-items: center; }
.gjpm-social-link {
    display: inline-flex;
    color: var(--wp--preset--color--foreground);
    transition: color 0.15s ease;
}
.gjpm-social-link:hover { color: var(--wp--preset--color--accent); }
.gjpm-site-footer .gjpm-social-link { color: var(--wp--preset--color--muted); }
.gjpm-site-footer .gjpm-social-link:hover { color: var(--wp--preset--color--foreground); }
@media (max-width: 1300px) {
    /* Same treatment as .gjpm-nav-links/.gjpm-nav-cta just below: the
     * hamburger overlay only ever rebuilds itself from .gjpm-nav-links (see
     * nav.js), so these icons would otherwise sit stranded next to it. They
     * stay reachable through the footer once the hamburger takes over. */
    .gjpm-nav .gjpm-nav-social { display: none; }
}

/*
 * Site logo (header + footer). core/site-logo's stored block style
 * ("style":{"border":{"radius":"50%"}}) in header.html/footer.html isn't
 * actually rendered by this WP version — the block outputs a bare <img>
 * with no inline style at all — so the circular crop is applied here
 * instead.
 * Targets .wp-block-site-logo (the wrapper), not .custom-logo/img directly:
 * core's own block-library CSS has ".wp-block-site-logo a, .wp-block-site-
 * logo img { border-radius: inherit; }", specificity (0,1,1) — a bare
 * ".custom-logo" class selector, (0,1,0), loses to that regardless of
 * source order and silently resolves to 0. Setting the radius on the
 * wrapper instead works *with* that inherit rule rather than fighting its
 * specificity, and rounds the link's own hit/focus area along with the
 * image.
 * This also happens to hide a real problem in the current source file:
 * logo-gjpm.svg has a leftover checkerboard "transparency" pattern baked
 * into its four corners as opaque vector shapes (an artifact from the
 * vectorizer tool tracing a screenshot rather than a properly transparent
 * source). The crop lands exactly on the badge's own circle, which is
 * inscribed edge-to-edge in the square canvas, so the checkerboard corners
 * are cropped away entirely along with it — replace this file with a
 * cleanly-exported transparent SVG if that ever needs fixing at the source
 * instead.
 */
.wp-block-site-logo { border-radius: 50%; }

/* Nav */
.gjpm-nav {
    position: fixed;
    top: 0; left: 0; right: 0;
    height: 84px;
    z-index: 100;
    padding: 0 32px;
    background: rgba(251, 251, 253, 0.86);
    backdrop-filter: blur(14px);
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
    align-items: center;
    transition: background-color 0.25s ease, border-color 0.25s ease;
}
main { padding-top: 84px; }

/*
 * When an admin is logged in, WordPress adds body.admin-bar and its own fixed
 * toolbar at top:0 — the same slot as .gjpm-nav, so the toolbar covered the
 * header. Push the header below the toolbar (32px, 46px under 782px per core)
 * and move the mobile overlay down by the same amount.
 * main's padding-top stays 60px: core also sets html{margin-top} for the
 * toolbar, so the document already starts below it.
 */
body.admin-bar .gjpm-nav { top: 32px; }
body.admin-bar .gjpm-nav-overlay { top: 116px; }
@media screen and (max-width: 782px) {
    body.admin-bar .gjpm-nav { top: 46px; }
    body.admin-bar .gjpm-nav-overlay { top: 130px; }
}
.gjpm-nav-links a {
    position: relative;
    display: inline-block;
    margin-right: 28px;
    padding-bottom: 4px;
    font-weight: 500;
    color: var(--wp--preset--color--foreground);
    transition: color 0.2s ease;
}
.gjpm-nav-links a[aria-current="page"] { color: var(--wp--preset--color--accent); font-weight: 600; }
/* Sand underline on hover, sliding in from the left rather than just
 * appearing — a scaleX transform on a full-width ::after is cheaper to
 * animate than a width transition and doesn't reflow neighbouring links. */
.gjpm-nav-links a::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: var(--wp--preset--color--sand);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.2s ease;
}
.gjpm-nav-links a:hover::after { transform: scaleX(1); }
.gjpm-nav-toggle { display: none; flex-direction: column; gap: 4px; background: none; border: none; cursor: pointer; padding: 8px; }
.gjpm-nav-toggle span { width: 22px; height: 2px; background: var(--wp--preset--color--foreground); transition: background-color 0.2s ease; }
.wp-block-site-title a { transition: color 0.2s ease; }

@media (max-width: 1300px) {
    /*
     * Core prints .wp-block-navigation.is-layout-flex{display:flex} and the
     * equivalent for .wp-block-buttons, both (0,2,0). A bare .gjpm-nav-links
     * (0,1,0) loses to them, which left the desktop nav and CTA on screen
     * below this breakpoint next to our own toggle — two hamburgers in the
     * header. These selectors are (0,3,0) so they win regardless of source
     * order.
     * Breakpoint: .gjpm-nav lays the logo, 5 nav links, 3 social icons and
     * the CTA button out in one flexWrap:nowrap row (see header.html). With
     * that much content, the row itself stops fitting well before a phone
     * width — measured (via a same-origin iframe at various widths, in lieu
     * of a real viewport-resize tool) wrapping to a broken 2-line header
     * from 1265px down to the old 860px cutoff, first rendering cleanly on
     * one line at 1270px. 1300px keeps a small safety margin above that
     * measured value for font-rendering variance across browsers/OSes —
     * i.e. this single breakpoint now covers both tablet *and* phone
     * widths, not just phones.
     */
    .gjpm-nav .gjpm-nav-links.wp-block-navigation,
    .gjpm-nav .gjpm-nav-cta.wp-block-buttons { display: none; }
    .gjpm-nav-toggle { display: flex; }
    .gjpm-nav-overlay {
        position: fixed; inset: 0; top: 84px; z-index: 99;
        background: var(--wp--preset--color--base);
        display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 24px;
    }
    .gjpm-nav-overlay.is-open { display: flex; }
    .gjpm-nav-overlay:not(.is-open) { display: none; }
    .gjpm-nav-overlay a { font-size: 20px; color: var(--wp--preset--color--foreground); }
}

/*
 * nav.js appends the mobile overlay to <body> on every page. Its styling lives
 * in the mobile media query, so without this base rule the overlay renders as a
 * plain block of links at the bottom of the page on wider viewports.
 */
.gjpm-nav-overlay { display: none; }

/*
 * Transparent header over the hero photo, homepage only. .gjpm-nav above
 * stays solid everywhere by default — these rules only punch a hole in that
 * while the hero is still visible under the fixed nav. nav.js watches the
 * hero with an IntersectionObserver and toggles .is-scrolled the moment its
 * bottom edge scrolls out from under the nav, so the header turns solid
 * again exactly when it stops overlapping the photo.
 * Text/icon colors reuse the same foreground-inverse / accent-pale tokens
 * the hero copy itself uses (see patterns/hero-photo.php), so contrast
 * stays consistent between the header and the banner beneath it.
 */
body.home .gjpm-nav:not(.is-scrolled) {
    background: transparent;
    backdrop-filter: none;
    border-bottom-color: transparent;
}
body.home .gjpm-nav:not(.is-scrolled) .wp-block-site-title a,
body.home .gjpm-nav:not(.is-scrolled) .gjpm-nav-links a,
body.home .gjpm-nav:not(.is-scrolled) .gjpm-social-link {
    color: var(--wp--preset--color--foreground-inverse);
}
body.home .gjpm-nav:not(.is-scrolled) .gjpm-nav-links a[aria-current="page"],
body.home .gjpm-nav:not(.is-scrolled) .gjpm-social-link:hover {
    color: var(--wp--preset--color--accent-pale);
}
body.home .gjpm-nav:not(.is-scrolled) .gjpm-nav-toggle span {
    background: var(--wp--preset--color--foreground-inverse);
}

/* Footer */
.gjpm-site-footer {
    border-top: 1px solid rgba(0, 0, 0, 0.08);
    background: var(--wp--preset--color--base);
    padding: 40px 24px;
}
/* The flex row (social links / logo+copyright / nav) used to be laid out by
 * .gjpm-site-footer itself; it's now nested one level down so the club-crests
 * band (.gjpm-footer-clubs) can stack above it instead of becoming a 4th flex
 * item competing for the same row. Both rows are plain flex children of
 * .gjpm-site-footer (no "constrained" layout on it, deliberately) so they
 * share the exact same full-width box instead of the crests row being
 * recentered on a narrower content width than the row below. */
.gjpm-footer-row {
    gap: 16px;
    width: 100%;
}
.gjpm-footer-clubs {
    width: 100%;
    gap: 32px;
    margin-bottom: 32px;
}
.gjpm-footer-club-logo img { height: 48px; width: auto; }
/* Same big-badge-above-crests treatment as the contact page
 * (.gjpm-contact-logo), but centering needs one more thing here: <footer>
 * itself is a vertical flex container (.gjpm-site-footer, "orientation":
 * "vertical"), so this figure is a flex item, not a plain block in normal
 * flow — align-items:stretch (flex's default) stretches it to the full
 * container width, which defeats "aligncenter"'s margin:auto/display:table
 * centering trick (that trick only centers a shrink-to-content block, and
 * stretch never lets it shrink). align-self:center opts this one item out
 * of stretching so it hugs its own (120px) width and centers on the cross
 * axis instead. The contact-page logo doesn't need this: a wp:column's own
 * children flow normally (only the outer wp:columns is flex), so plain
 * "aligncenter" was enough there. */
.gjpm-footer-logo { align-self: center; margin-bottom: 20px; }
/* Same sand-underline hover as .gjpm-nav-links a above. The footer nav is a
 * plain core wp:navigation block with no className of its own, so it's
 * scoped through .gjpm-site-footer instead. */
.gjpm-site-footer nav.wp-block-navigation a {
    position: relative;
    display: inline-block;
    padding-bottom: 4px;
}
.gjpm-site-footer nav.wp-block-navigation a::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: var(--wp--preset--color--sand);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.2s ease;
}
.gjpm-site-footer nav.wp-block-navigation a:hover::after { transform: scaleX(1); }

/* Hero */
.gjpm-hero {
    position: relative;
    /* The nav (.gjpm-nav) is position:fixed — it overlays the page rather
     * than pushing it down, so it doesn't actually reserve any of the
     * viewport for layout purposes; the hero's own top edge just happens to
     * render behind it. Pinning the hero to the full 100vh (not 100vh minus
     * the nav's 84px) is therefore what makes its *bottom* edge land exactly
     * on the bottom of the viewport.
     * !important: the cover block's own minHeight attribute (720px) is
     * rendered as an inline style, which otherwise always beats a class rule
     * regardless of specificity.
     * height (not just min-height) pins the banner to exactly one screen: the
     * copy + stats must be visible on arrival with no scroll, and scrolling
     * once should land straight on the next section — a min-height alone lets
     * the box grow past the viewport whenever the content needs more room. */
    height: 100vh !important;
    min-height: 100vh !important;
    /* The theme's global blockGap (theme.json) puts a 24px margin-top on
     * every block that follows another one, hero included — which would
     * otherwise push its bottom edge 24px past the viewport. The fixed nav
     * already covers the top of the photo, so this margin serves no visual
     * purpose here anyway. */
    margin-top: 0 !important;
    /* Safety net for short windows: if the copy + stats ever need more room
     * than the pinned height allows, clip rather than push the box (and the
     * rest of the page) taller than one screen. */
    overflow: hidden;
    /* Grid, not flex: the background span, the photo and the inner-container
     * all get stacked in the same single cell (grid-area rule below) instead
     * of core's absolute positioning. Firefox won't resolve a percentage
     * height (the photo's width:100%/height:100%, needed for object-fit) against
     * a container whose own height comes only from min-height — it silently
     * falls back to the photo's intrinsic pixel size, leaving a plain gap
     * below it once the banner grows past that. A grid *track*, unlike a plain
     * box's auto height, is always a definite size once laid out, so a
     * percentage height on a grid item resolves reliably in every browser. */
    display: grid;
    /* Without this, the implicit row sizes itself to fit its tallest item's
     * content (the copy + stats, via the inner-container) instead of the
     * container's own pinned height — so the row can grow past 100vh even
     * though .gjpm-hero itself can't, and align-self:end then anchors the
     * copy to the bottom of that oversized row instead of the visible
     * banner. minmax(0, …) additionally stops the row's automatic minimum
     * size from re-introducing the same blowout.
     * The same applies sideways: without an explicit column, the implicit
     * one auto-sizes to its widest item's max-content — here, the copy's own
     * text — instead of the container's full width, leaving the photo (a
     * grid item now, sized off that same track) narrower than the banner
     * with the dark gradient's edges exposed as plain gaps on both sides. */
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    /* Core gives every cover block a default 16px padding. The old
     * absolutely-positioned photo ignored it (abs-pos fills the full padding
     * box regardless); as a normal grid item now, it would inherit that gap
     * on all four edges without this override. The copy's own inset comes
     * from the inner-container's padding instead (below). */
    padding: 0;
}
.gjpm-hero > * { grid-area: 1 / 1; }
.gjpm-hero .wp-block-cover__background,
.gjpm-hero .wp-block-cover__image-background {
    /* Out of the grid item's own default position:absolute (set by core) and
     * back to a normal, in-flow grid item — position:absolute is what
     * reintroduces the very percentage-height ambiguity the grid is here to
     * avoid (see comment above). */
    position: static;
    width: 100%;
    height: 100%;
}
.gjpm-hero .wp-block-cover__image-background {
    object-fit: cover;
    /* The dark overlay span (customOverlayColor, #0a1524) sits in the same
     * grid cell behind the photo, so the fade reveals it from a dark screen
     * rather than a flash of blank white — a deliberate arrival moment
     * instead of a hard image pop-in on load.
     * The opacity ramp itself is already uniform across the whole banner
     * (it's a single CSS property on one element covering the full 100vh
     * cell) — but the bottom of the photo sits under the heaviest part of
     * the gradient/scrim below (::after, ::before), so the brightness
     * *change* there is much less visible than at the top, which reads as
     * "only the top fades". The scale nudges the whole frame perceptibly
     * throughout the reveal so it doesn't lean on brightness contrast
     * alone to be seen. */
    animation: gjpm-hero-fade-in 2.6s ease-out both;
    transform-origin: center;
}
@keyframes gjpm-hero-fade-in {
    from { opacity: 0; transform: scale(1.05); }
    to { opacity: 1; transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
    .gjpm-hero .wp-block-cover__image-background { animation: none; }
}
.gjpm-hero::after {
    content: "";
    position: absolute;
    inset: 0;
    /* Gradient stops per wordpress-spec.md. On its own this thins to 0.15 right
     * where the copy sits, which measured 1.05:1 on the eyebrow — the local
     * scrim below carries the contrast instead, so the photo stays bright. */
    background: linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0.15) 40%, rgba(0,0,0,0.55) 100%);
    pointer-events: none;
}
.gjpm-hero .wp-block-cover__inner-container {
    position: relative;
    z-index: 1;
    /* Anchor the copy + stats to the bottom of the banner instead of the
     * vertical middle. The padding below (moved here from .gjpm-hero itself,
     * which must stay padding-free so the photo covers it edge to edge —
     * see the grid comment above) is what keeps the copy off the bottom
     * edge; top is mostly moot since the content is bottom-anchored. */
    align-self: end;
    justify-self: center;
    padding-top: var(--wp--preset--spacing--70);
    padding-bottom: var(--wp--preset--spacing--70);
    width: 100%;
}
/*
 * Local scrim behind the hero copy. The inner container is a stacking context
 * (z-index 1), so a z-index:-1 pseudo-element paints above the full-bleed
 * gradient yet below the text.
 * A centred ellipse was tried first and measured 2.51:1 on the eyebrow: the copy
 * is left-aligned in its column, so its glyphs land where a centred ellipse has
 * already faded out. A horizontal band with soft top and bottom edges covers the
 * whole text column evenly and leaves the photo untouched above and below it.
 */
.gjpm-hero .wp-block-cover__inner-container::before {
    content: "";
    position: absolute;
    inset: -80px 0;
    z-index: -1;
    /* Fade lengths are in px, not %, so the ramp stays clear of the copy
     * whatever the block's height: percentage stops put the 14% ramp right on
     * the eyebrow's own baseline and measured 4.09:1 there. */
    background: linear-gradient(180deg,
        rgba(0,0,0,0) 0,
        rgba(0,0,0,0.68) 64px,
        rgba(0,0,0,0.68) calc(100% - 64px),
        rgba(0,0,0,0) 100%);
    pointer-events: none;
}
@media (max-width: 700px) {
    /* Below this width the copy + 5 stats no longer fit in one screen — let
     * the banner grow with its content again instead of clipping it. */
    .gjpm-hero { height: auto !important; min-height: 560px; overflow: visible; }
    .gjpm-hero .wp-block-cover__inner-container { padding-left: 24px; padding-right: 24px; }
}

/* Hero stats row */
/* Same trick as .gjpm-card-grid: force the columns block to grid so the 5
 * stats wrap in fixed-size rows instead of core's !important mobile stacking
 * (which only ever collapses to a single column). */
.gjpm-hero-stats { margin-top: var(--wp--preset--spacing--70); }
.gjpm-hero-stats .wp-block-columns.is-layout-flex {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
}
.gjpm-hero-stats .wp-block-column { text-align: center; }
.gjpm-stat-number {
    font-size: clamp(28px, 4vw, 40px);
    font-weight: 700;
    font-style: italic;
    line-height: 1;
    letter-spacing: -0.01em;
    margin: 0 0 6px;
}
.gjpm-stat-label {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    margin: 0;
}
@media (max-width: 900px) {
    .gjpm-hero-stats .wp-block-columns.is-layout-flex { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
    .gjpm-hero-stats .wp-block-columns.is-layout-flex { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .gjpm-hero-stats { margin-top: var(--wp--preset--spacing--60); }
}

/* Card grid */
/* Grille de cartes : 3 colonnes qui se replient sur plusieurs rangées.
 * Le wp:columns de core répartit à parts égales sans jamais passer à la ligne
 * au-dessus de 1100px — avec les 9 catégories, les cartes tomberaient à ~108px
 * de large. Le sélecteur cible .is-layout-flex pour passer devant le
 * display:flex de core, qui a la même spécificité (0,2,0) que
 * `.gjpm-card-grid .wp-block-columns` seul. */
.gjpm-card-grid .wp-block-columns.is-layout-flex {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 24px;
    max-width: 1200px;
    margin: 0 auto;
}
.gjpm-card-grid .gjpm-card {
    border-radius: 18px;
    overflow: hidden;
}
.gjpm-card-grid:not(.is-dark) .gjpm-card {
    background: var(--wp--preset--color--surface);
    border: 1px solid rgba(0, 0, 0, 0.08);
}
.gjpm-card-grid.is-dark .gjpm-card {
    background: rgba(255, 255, 255, 0.04);
    border: none;
}
/* The card image and body are real blocks now, so core's flow-layout block gap
 * (a 24px margin-block-start on following siblings) would push the body away from
 * the image; the design wants them flush. */
.gjpm-card-grid .gjpm-card { gap: 0; }
.gjpm-card-grid .gjpm-card > * + * { margin-block-start: 0; }
.gjpm-card-grid .gjpm-card img { height: 220px; object-fit: cover; }
.gjpm-card-grid .gjpm-card-body { padding: 22px 24px; }
.gjpm-card-grid .gjpm-header-block { max-width: 640px; margin: 0 auto 64px; text-align: center; }
@media (max-width: 1100px) { .gjpm-card-grid .wp-block-columns.is-layout-flex { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 700px) { .gjpm-card-grid .wp-block-columns.is-layout-flex { grid-template-columns: minmax(0, 1fr); } }

/* Team cards (Nos Équipes) */
/* Reuses .gjpm-card-grid/.gjpm-card (see "Card grid" above) but the photo is a
 * small circular avatar rather than a full-bleed rectangle, and everything —
 * photo included — lives inside .gjpm-card-body so the fields can flow under
 * it. The extra .gjpm-card class on the selector below outweighs the generic
 * `.gjpm-card-grid .gjpm-card img` rule that would otherwise force a 220px
 * rectangular crop onto the avatar. */
.gjpm-card-grid .gjpm-card.gjpm-team-card .gjpm-team-photo img {
    border-radius: 50%;
    height: 104px;
    object-fit: cover;
    margin: 0 0 18px;
}
.gjpm-team-card--lead {
    background: var(--wp--preset--color--sand-dark) !important;
}

/* Multi-coach trial (u10-u11, u12-u13 in inc/categories.php): several
 * avatars + first names side by side, grouped together on the left (same
 * edge as the rest of the card's text) instead of the single 104px photo.
 * First tried `justify-content: space-between` to spread them across the
 * card's full width — looked fine with 3, but with only 2 coaches it put
 * one avatar hard against each edge with a big empty gap between, which
 * read as broken rather than intentional. Plain `flex-start` + a fixed gap
 * groups them naturally regardless of count. Selector below chains onto the
 * same `.gjpm-card-grid .gjpm-card.gjpm-team-card .gjpm-team-photo img`
 * prefix as the generic rule above plus one more class
 * (.gjpm-team-photo-multi), so it's strictly more specific and wins
 * regardless of source order — same technique as .gjpm-team-grid overrides
 * documented below. */
.gjpm-team-photo-multi {
    justify-content: flex-start;
    gap: 28px;
    margin: 0 0 18px;
}
.gjpm-card-grid .gjpm-card.gjpm-team-card .gjpm-team-photo-multi .gjpm-team-photo img {
    height: 88px;
    margin: 0 0 8px;
}
.gjpm-team-photo-multi__item {
    align-items: center;
    gap: 0;
    flex: 0 0 auto;
}
.gjpm-team-photo-multi__item p {
    text-align: center;
}

/* .gjpm-team-grid: page-specific spacing for Nos Équipes only (not the shared
 * .gjpm-card-grid rules above, which the news/évènements card grids also
 * use). Loosely modeled on https://xvcorsaire.fr/categories/ (very generous
 * section padding-block and card padding there) but sized to this theme's own
 * scale rather than copied. Each override selector chains an extra class onto
 * the generic .gjpm-card-grid rule it replaces, so it wins on specificity
 * regardless of source order. 2 columns instead of the generic 3: with 10
 * cards, 3 columns stranded the last card alone on its row — 2 columns fills
 * 5 full rows and gives each card more room, which is the point of the
 * request. */
.gjpm-card-grid.gjpm-team-grid.gjpm-section { padding-top: 120px; padding-bottom: 120px; }
.gjpm-card-grid.gjpm-team-grid .wp-block-columns.is-layout-flex {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 32px;
    /* Capped and centered so the 2 cards stay a readable width even though
     * the dark band around them (below) now runs edge to edge — without
     * this they'd stretch to match the full viewport, which reads as
     * oversized/awkward for a two-field-per-row card. */
    max-width: 1680px;
    width: 100%;
    margin-left: auto;
    margin-right: auto;
}
.gjpm-card-grid.gjpm-team-grid .gjpm-card-body { padding: 40px 40px; }

/* The group block's own "constrained" layout clamps ITS width to the theme's
 * global content size (1000px — same var as every other section on the
 * site), which read as two wide blank margins either side of the dark band:
 * the "bandes blanches" the user asked to remove. `max-width: none` lets the
 * band run the full viewport width; `.gjpm-card-grid.gjpm-team-grid` (0,2,0)
 * simply outweighs the ancestor's `.is-layout-constrained > :where(...)`
 * clamp — :where() carries zero specificity by spec — so this wins without
 * touching the block's own align attribute. The cards themselves stay a
 * sane width via the inner columns rule above, which now carries its own cap
 * instead of inheriting one from this element. */
.gjpm-card-grid.gjpm-team-grid {
    max-width: none;
    padding-left: 48px;
    padding-right: 48px;
}
@media (max-width: 1100px) {
    .gjpm-card-grid.gjpm-team-grid.gjpm-section { padding-top: 80px; padding-bottom: 80px; }
    .gjpm-card-grid.gjpm-team-grid { padding-left: 32px; padding-right: 32px; }
}
@media (max-width: 700px) {
    .gjpm-card-grid.gjpm-team-grid.gjpm-section { padding-top: 56px; padding-bottom: 56px; }
    .gjpm-card-grid.gjpm-team-grid { padding-left: 20px; padding-right: 20px; }
    .gjpm-card-grid.gjpm-team-grid .wp-block-columns.is-layout-flex { grid-template-columns: minmax(0, 1fr); gap: 20px; }
    .gjpm-card-grid.gjpm-team-grid .gjpm-card-body { padding: 32px 28px; }
}

/* Org chart (Nos Équipes) */
/* Images already carry their own name/role banner baked in (see
 * patterns/organigramme-educateurs.php) — light section, no card background,
 * just gentle rounding/shadow on the photos themselves and a bit of vertical
 * rhythm between the three rows. `.wp-block-columns + .wp-block-columns`
 * rather than relying on the theme's global blockGap: the header block above
 * the first row already provides its own bottom margin, so only the two
 * row-to-row gaps need this. */
.gjpm-org-photos { padding-top: 100px; padding-bottom: 100px; }
.gjpm-org-photo img {
    border-radius: 14px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12);
}
.gjpm-org-photos .wp-block-columns + .wp-block-columns { margin-top: 32px; }
@media (max-width: 1100px) {
    .gjpm-org-photos { padding-top: 72px; padding-bottom: 72px; }
}
@media (max-width: 700px) {
    .gjpm-org-photos { padding-top: 48px; padding-bottom: 48px; }
}

/* Values row */
.gjpm-values-row.wp-block-columns,
.gjpm-values-row .wp-block-columns { max-width: 1000px; margin: 0 auto; gap: 48px; text-align: center; padding-left: 24px; padding-right: 24px; }
.gjpm-values-row.gjpm-section { padding-top: var(--wp--preset--spacing--70); padding-bottom: var(--wp--preset--spacing--70); }

/* CTA band */
.gjpm-cta-band {
    position: relative;
    /* Kept in sync with the inline min-height on the cover block itself
     * (patterns/bande-cta.php) — the inline style is what actually wins
     * (higher specificity than this class), this is just a fallback/doc so
     * the two don't silently drift apart. Raised 480 -> 600 -> 660 -> 850: at
     * 480 the cover's object-fit:cover cropped the standing players' heads
     * off (very short/wide box vs. the photo's own ~16:9 ratio); at 600 the
     * tallest player's head was still clipped; once object-position (below)
     * fixed the top framing, 660 was still cropping the seated row's feet
     * off the bottom — 850 keeps that same top framing and reveals the
     * whole seated row too. */
    min-height: 850px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.gjpm-cta-band .wp-block-cover__image-background {
    /* Default object-position (50% 50%) crops equally top/bottom — with a
     * box this much wider than the photo's own ratio, that still ate into
     * the tallest standing player's head even at 660px. Biasing the crop
     * window toward the top keeps every head fully in frame and only trims
     * a bit more grass at the bottom instead. */
    object-position: 50% 15%;
}
.gjpm-cta-band::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(0,0,0,0.05), rgba(0,0,0,0.55));
    pointer-events: none;
}
.gjpm-cta-band .wp-block-cover__inner-container {
    /* align-self: stretch (instead of the parent's align-items: center) gives
     * this box the band's full min-height, so the "gap" percentage below has
     * an actual height to resolve against — a percentage row-gap in a column
     * flex is relative to the flex item's own height. justify-content:
     * flex-start + padding-top (rather than centering) pulls the heading/
     * button block up to sit around the standing players' jersey height —
     * centering it in the full 660px band put the button low enough to
     * land right on a seated player's face. */
    position: relative;
    z-index: 1;
    align-self: stretch;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    padding-top: 14%;
    gap: 8%;
    text-align: center;
}
.gjpm-cta-band .wp-block-cover__inner-container .wp-block-buttons { pointer-events: auto; justify-content: center; }

/* Pricing cards */
.gjpm-pricing-cards.wp-block-columns,
.gjpm-pricing-cards .wp-block-columns { max-width: 1100px; margin: 0 auto; gap: 24px; }
.gjpm-pricing-cards .wp-block-column {
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 18px;
    padding: 32px 28px;
}
.gjpm-pricing-cards ul { list-style: none; padding: 0; margin: 16px 0 0; display: flex; flex-direction: column; gap: 10px; font-size: 14px; }
.gjpm-pricing-cards ul li::before { content: "— "; }

/* Image styling that used to sit in inline style attributes. Those attributes made
 * the wp:image blocks fail editor validation, since core/image's save() only
 * emits aspect-ratio, object-fit and width there. */
.gjpm-club-banner img { height: 420px; width: 100%; object-fit: cover; }
.gjpm-contact-columns { max-width: 1100px; margin: 0 auto; }
/* Stand-in for the map photo (not available yet, per the owner): big GJPM
 * badge + the 4 founding clubs' crests underneath, same assets as the footer
 * band (parts/footer.html / .gjpm-footer-club-logo) at a smaller size to fit
 * a half-width column. Swap templates/page-contact.html back to a real
 * map/venue photo (a wp:image on .gjpm-contact-map, still styled by nothing
 * now that this replaced it) once one exists. */
/* Centering itself now comes from the block's own "aligncenter" class
 * (margin:auto — the standard/reliable way core centers a single fixed-width
 * image), not from text-align here; a plain figure is a full-width block box
 * by default, so text-align on it wouldn't reliably center a same-width
 * child the way it visually appeared to in an ad hoc preview. */
.gjpm-contact-logo { margin-bottom: 20px; }
.gjpm-contact-clubs { gap: 20px; margin-bottom: 32px; }
.gjpm-contact-club-logo img { height: 40px; width: auto; }

/* Partners row (homepage) */
.gjpm-partners { text-align: center; }
.gjpm-partners-row {
    max-width: 1000px;
    margin: 40px auto 0;
    gap: 40px 56px;
}
/* Height-based rather than width-based: these are real sponsor logos with
 * very different native proportions (wide wordmarks vs a near-square badge),
 * so a shared width made some tiny and others tall/cramped — a shared height
 * keeps them visually even instead. Full color, no grayscale/opacity (owner's
 * call, reversed from an initial "keep it discreet" instruction).
 */
.gjpm-partner-logo img {
    height: 40px;
    width: auto;
}

/* Sponsors by club (homepage, dark section below the premium sponsors) */
.gjpm-sponsors-clubs { text-align: center; }
/* Same grid trick as .gjpm-card-grid / .gjpm-hero-stats: force the columns
 * block into a real 4-column grid so it wraps in fixed-size rows instead of
 * core's flex distribution. */
.gjpm-sponsor-club-columns.is-layout-flex {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    max-width: 1200px;
    margin: 40px auto 0;
}
.gjpm-sponsor-club-logos {
    max-width: 240px;
    margin: 20px auto 0;
    gap: 16px;
}
.gjpm-sponsor-club-logo img {
    width: 90px;
    height: auto;
    filter: grayscale(1);
    /* Higher than .gjpm-partner-logo's 0.7 — the light placeholder boxes need
     * a bit more contrast to read clearly against the dark background. */
    opacity: 0.85;
}
@media (max-width: 900px) {
    .gjpm-sponsor-club-columns.is-layout-flex { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px; }
}
@media (max-width: 560px) {
    .gjpm-sponsor-club-columns.is-layout-flex { grid-template-columns: minmax(0, 1fr); }
}
/* Hide the sponsors club for now */
.gjpm-sponsors-clubs {
    display: none;
}

/* Planning général des entraînements (page Nos Évènements) —
 * patterns/planning-entrainements.php. Pas de .gjpm-section sur le wrapper
 * (voir le commentaire dans le pattern) : la marge basse ci-dessous fait
 * office d'espacement avant la grille d'évènements qui suit. */
.gjpm-planning { margin-bottom: var(--wp--preset--spacing--70); }
.gjpm-planning .gjpm-header-block { max-width: 640px; margin: 0 auto 40px; text-align: center; }
.gjpm-planning-table-wrap {
    overflow-x: auto;
    /* Gutter so the focus ring / shadow on edge cells isn't clipped by the
     * scroll container. */
    padding: 2px;
}
.gjpm-planning-table {
    width: 100%;
    min-width: 720px;
    border-collapse: collapse;
}
.gjpm-planning-table th,
.gjpm-planning-table td {
    border: 1px solid #e5e5ea;
    padding: 12px 14px;
    text-align: left;
    vertical-align: top;
}
.gjpm-planning-table thead th {
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--wp--preset--color--muted);
    border-bottom: 2px solid var(--wp--preset--color--foreground);
    white-space: nowrap;
}
.gjpm-planning-table__corner { border-top: none; border-left: none; }
.gjpm-planning-table tbody th {
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
    background: var(--wp--preset--color--base);
}
.gjpm-planning-session {
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding: 6px 10px;
    border-radius: 8px;
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.35;
}
.gjpm-planning-session + .gjpm-planning-session { margin-top: 6px; }
.gjpm-planning-session__venue { font-weight: 500; opacity: 0.9; }
.gjpm-planning-session__note {
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    font-size: 11px;
    opacity: 0.75;
}
.gjpm-planning-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px 24px;
    margin: 24px 0 0;
    padding: 0;
    list-style: none;
    font-size: 14px;
    color: var(--wp--preset--color--muted);
}
.gjpm-planning-legend li { display: flex; align-items: center; gap: 8px; }
.gjpm-venue-dot { width: 11px; height: 11px; border-radius: 50%; flex: none; }
@media (max-width: 700px) {
    .gjpm-planning-table th,
    .gjpm-planning-table td { padding: 10px; }
}
