/* ===== Thème général (inspiré EA Sports FC / Bungie Fireteams) ===== */

:root {
    --bg: #101312;
    --bg-rgb: 18, 23, 28; /* = #12171C en RGB, pour rgba() (ex. dégradé du hero) — garder synchro avec --bg */
    --bg-elevated: #00000052;
    /*--bg-card: #1a1f26;*/
    --border: #2a3038;
    --text: #eef1f4;
    --text-muted: #98a2ad;
    --green: #34d399;
    --green-strong: #10b981;
    --green-rgb:52, 211, 153;
    --accent-2: #3a86ff;
    --danger: #FF0000;
    --warning: #ffd166;
    --gold: #FFB300;
    --gold2: #ded295;
    --gold2-strong: #C2B67A;
    --btngold-rgba: 255, 179, 0, 0.3;
    --gold-strong: #c78e2c;
    --radius: 12px;
    --radius-sm: 8px;
    --max-width: 1180px;
    --noradius: 0px;

    /* Bannière "façon Bungie" des lignes de club (.match-member-row.is-filled, listing.php —
       voir club_banner_style() dans includes/helpers.php) : dégradé de la couleur vive du club
       (extraite du blason, clubs.vibrant_color) vers un noir saturé de cette même teinte, +
       blason en grand, transparent, mélangé et légèrement grainé sur la droite. Réglages
       centralisés ici pour être faciles à ajuster sans toucher au reste du fichier —
       --member-color-rgb/--member-color-dark-rgb/--member-crest-url sont posées par ligne
       (inline, PHP/JS), le reste est un réglage global. */
    --member-banner-crest-opacity: 0.3;
    --member-banner-crest-size: 40%;
    --member-banner-crest-angle: -8deg;
    --member-banner-crest-blend-mode: screen; /* essaie aussi : screen, overlay, soft-light, normal */
    --member-banner-grain-opacity: 0.3;

    /* Réglages du dégradé de couleur lui-même (restauré le 2026-07-22 après être passé gris uni
       par erreur — voir .match-member-row.is-filled plus bas). --member-banner-vivid-mix pilote
       "saturation/opacité" façon curseur : 100% = couleur du club pleine, 0% = gris neutre uni
       (#282D31, même gris que .match-history-row) — désature/adoucit progressivement plutôt que
       tout ou rien. --member-banner-gradient-angle et les points d'arrêt sont aussi ajustables. */
    --member-banner-vivid-mix: 100%;
    --member-banner-gradient-angle: 120deg;
    --member-banner-gradient-stop-start: 20%;
    --member-banner-gradient-stop-end: 100%;

    /* Indicateur de chargement temporaire (.section-loading/.loading-spinner, voir plus bas) —
       réutilisé par toute section chargée en différé (manage-club.php pour l'instant, d'autres
       pages pourront reprendre les deux mêmes classes plus tard). Couleur et vitesse réglables
       ici sans toucher à .loading-spinner ; pour changer complètement l'animation (autre chose
       qu'une rotation), redéfinir le bloc @keyframes loading-spin juste après .loading-spinner. */
    --loading-spinner-color: var(--green);
    --loading-spinner-duration: 0.8s;

    /* Piste de grille FIXE réservée à la flèche ">" du nouveau classement "jury" (voir
       .leaderboard-jury-filters/.leaderboard-jury-score plus bas) — définie globalement (pas
       seulement sur .leaderboard-jury) car .leaderboard-jury-filters vit dans .heading-section,
       un conteneur FRÈRE de .leaderboard-jury, pas un descendant : une variable custom posée sur
       .leaderboard-jury ne lui serait pas héritée. */
    --jury-arrow-slot: 32px;
    /* Largeur FIXE partagée par .leaderboard-jury-title-spacer ET .leaderboard-jury-info : la
       condition qui garantit que la grille de filtres et chaque grille de valeurs démarrent
       exactement à la même position X (voir commentaire complet plus bas, section "jury"). */
    --jury-label-col: 220px;
}

* { box-sizing: border-box; }

/* L'attribut HTML [hidden] doit TOUJOURS cacher l'élément, quelle que soit sa classe. Sans ça,
   n'importe quelle règle d'auteur posant un `display` (ex. .section-loading{display:flex},
   .roster-breakdown{display:flex}, .opt-select{display:inline-block}) ÉCRASE le `display:none` par
   défaut du navigateur pour [hidden] (spécificité de classe > spécificité de l'attribut dans la
   feuille du navigateur) — le spinner de chargement restait alors affiché (76px de haut) même après
   element.hidden = true en JS, d'où un "chargement qui tourne à l'infini" alors que la donnée était
   bien arrivée (bug vécu, 2026-07-23). Le !important garantit que la sémantique de [hidden] gagne
   partout, une bonne fois pour toutes. */
[hidden] { display: none !important; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--text);
    font-family: "Figtree", "Segoe UI", Roboto, Arial, sans-serif;
    font-optical-sizing: auto;
    line-height: 1.45;
}

/* Space Mono (chargée via Google Fonts, voir includes/header.php) : dispo au besoin pour des
   éléments façon "terminal/score" (ex. décompte, stats) — pas appliquée par défaut. */
.space-mono-regular {
    font-family: "Space Mono", monospace;
    font-weight: 400;
    font-style: normal;
}

.space-mono-bold {
    font-family: "Space Mono", monospace;
    font-weight: 700;
    font-style: normal;
}

.space-mono-regular-italic {
    font-family: "Space Mono", monospace;
    font-weight: 400;
    font-style: italic;
}

.space-mono-bold-italic {
    font-family: "Space Mono", monospace;
    font-weight: 700;
    font-style: italic;
}

a { color: inherit; text-decoration: none; }

.container {
    max-width: var(--max-width);
    margin: 2vh auto;
    padding: 0 20px;
}

.containeur {
    max-width: var(--max-width);
    margin: 0vh auto;
    /*padding: 0 20px;*/
}

/* ----- Header / navigation ----- */

.site-header {
    background: rgba(10, 12, 15, 0.85);
    /*border: 1px solid var(--border);*/
    backdrop-filter: blur(10px);
    top: 0;
    position: sticky;
    z-index: 10;
    /*max-width: var(--max-width);*/
    margin: 0vh auto;
    padding-top: 1vh;
}

/* flex-wrap volontairement absent (pas "wrap") : le passage en menu burger est piloté par JS
   (assets/js/header-nav.js, classe .site-header.is-compact plus bas) qui mesure une VRAIE collision
   entre le logo et le menu et bascule AVANT que ça déborde — un flex-wrap ici aurait provoqué un
   retour à la ligne "entre deux" moche (juste le menu qui redescend, sans passer proprement en
   burger) pendant la zone grise entre "tout tient" et le seuil fixe qu'on utilisait avant. */
.site-header .containeur {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-top: 0px;
    padding-bottom: 0px;
    gap: 12px;
}

/* Mode compact : basculé par assets/js/header-nav.js selon une largeur réellement mesurée (logo +
   menu, tels qu'ils sont VRAIMENT — pas un seuil de media query figé qui casserait si le menu
   change). S'adapte donc automatiquement, quel que soit le nombre de liens dans .main-nav. */
.site-header.is-compact .containeur { flex-direction: column; align-items: stretch; }
.site-header.is-compact .site-header-top { width: 100%; }
.site-header.is-compact .nav-burger { display: inline-flex; }
.site-header.is-compact .main-nav {
    display: none;
    width: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
}
.site-header.is-compact .main-nav.is-open { display: flex; }

.logo {
    font-weight: 800;
    font-size: 1.2rem;
    letter-spacing: 1px;
    text-transform: uppercase;
    display: inline-flex;
    align-items: center;
    padding: 15px 0 15px 0;
}

.logo span { color: var(--green); }

/* Pas de fichier ? dépose ton logo dans assets/images/LFG-FC-clubs-logo.png (même nom, plus
   SEO-friendly que "logo.png" générique) — en son absence,
   le nom du site s'affiche à la place (voir l'attribut onerror dans includes/header.php). */
.logo-img { height: 30px; max-width: 220px; object-fit: contain; }

.site-header-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

/* Bouton burger : masqué par défaut (desktop), affiché uniquement en mode compact — piloté par JS
   (assets/js/header-nav.js, classe .site-header.is-compact plus haut), pas par une media query. */
.nav-burger {
    display: none;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-sm);
    border: none;
    background: transparent;
    color: var(--text);
    cursor: pointer;
    flex-shrink: 0;
}

.nav-burger:active { color: var(--green); }
.nav-burger svg { width: 22px; height: 22px; }

.main-nav {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
    align-items: center;
}

.main-nav a {
    padding: 8px 14px;
    border-radius: var(--noradius);
    font-size: 0.82rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    border-bottom: 2px solid transparent;
}

.main-nav a:active { color: var(--text); }

.main-nav a.primary {
    background: rgba(255,255,255,0.1);
    color: #ffffff;
    border-radius: 0px;
    padding: 8px 18px;
}

.main-nav a.primary:active { filter: brightness(1.08); }

.nav-account {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px 6px 6px;
    border-radius: 0;
    font-weight: 600;
    /*background: #FFFFFF;*/
}

.nav-account a{
    font-family: "Bebas Neue", sans-serif;
    font-size: 1.2rem;
    font-weight: 800;
    text-transform: uppercase;
}

.nav-account:active { background: var(--bg-card); }

@media (hover: hover) {
    .nav-burger:hover { color: var(--green); }
    .main-nav a:hover { color: var(--text); }
    .main-nav a.primary:hover { filter: brightness(1.08); }
    .nav-account:hover { background: var(--bg); }
}

/* ----- Bandeau "hero" en tête de page ----- */

.hero {
    position: relative;
    padding: 7vh 0 6vh;
    background:
        linear-gradient(180deg, rgba(var(--bg-rgb), 0.35) 0%, rgba(var(--bg-rgb), 0.95) 100%),
        radial-gradient(ellipse at 20% 0%, rgba(52, 211, 153, 0.16), transparent 55%),
        radial-gradient(ellipse at 80% 10%, rgba(58, 134, 255, 0.14), transparent 55%),
        url("../images/hero.jpg");
    background-size: cover;
    background-position: top;
    border-bottom: 0px solid var(--border);
}

/* Pas d'image ? place la tienne dans assets/images/hero.jpg (même nom, ce dégradé sert de repli). */

.hero-title {
    font-size: 2.1rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    margin: 0 0 6px;
}

.hero-subtitle { color: var(--text-muted); margin: 0 0 22px; max-width: 560px; }

.hero-actions {
    display: flex;
    align-items: center;
    gap: 18px;
    flex-wrap: wrap;
}

.hero-status {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--text-muted);
    font-size: 0.85rem;
    font-weight: 600;
}

.status-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--text-muted);
    flex-shrink: 0;
}

.status-dot.is-active {
    background: var(--green);
    box-shadow: 0 0 8px rgba(52, 211, 153, 0.6);
}

/* ----- Layout général ----- */

main { position: relative; padding-bottom: 60px; }

/* Image de fond optionnelle, en dégradé vers la couleur de fond du site, sur une bonne hauteur
   de page (listing.php) — dépose une image dans assets/images/listing-bg.jpg pour l'activer,
   même principe de repli que .hero (dégradé uni tant que le fichier est absent).
   z-index: -1 (pas 0) : un élément positionné avec z-index:0 se peint en réalité AU-DESSUS du
   contenu normal non positionné (.listing-header-row, .match-members-head, #match-cta...), même
   avec pointer-events:none — piège CSS classique qui rendait ces blocs invisibles (bug trouvé et
   confirmé le 2026-07-21 : ils réapparaissaient dès que ce fond était désactivé). z-index:-1 se
   peint bien derrière tout contenu non positionné du même contexte d'empilement, comme attendu
   pour un simple fond décoratif. */
.page-bg-fade {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 520px;
    z-index: -1;
    pointer-events: none;
    background:
        linear-gradient(180deg, rgba(var(--bg-rgb), 0.6) 0%, rgba(var(--bg-rgb), 1) 100%),
        url("../images/listing-bg.jpg");
    background-size: cover;
    background-position: center top;
}

h1, h2, h3 { margin-top: 0; }

.page-title { font-size: 1.6rem; margin-bottom: 0}
.page-subtitle { color: var(--text-muted); margin-bottom: 1vh; margin-top: 0;}

/* Titre de page + actions sur la même ligne, actions en haut à droite (manage-club.php). */
/* Le bloc texte (titre+sous-titre) rétrécit en premier (jusqu'à 300px, en dessous le sous-titre
   deviendrait dur à lire) pour garder les boutons sur la même ligne le plus longtemps possible —
   .page-header-actions ne rétrécit jamais (flex-shrink:0). Une fois que même 300px + les boutons
   ne tiennent plus, flex-wrap fait passer les boutons à la ligne, et le texte (seul sur sa ligne)
   reprend naturellement sa pleine largeur (flex-grow:1) — comportement natif, pas de media query. */
.page-header-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.page-header-text { flex: 1 1 300px; min-width: 300px; }
.page-header-actions { display: flex; gap: 10px; flex-wrap: wrap; flex-shrink: 0; }

.page-body { padding-top: 0px; }

/* ----- Boutons -----
   UN SEUL système pour TOUS les .btn du site (inspiré de bray.tech) : contour en box-shadow
   "inset" plutôt qu'une vraie bordure, coins carrés (border-radius:0), anneau ::after qui
   s'agrandit et s'allume au survol/clic (:hover et :active produisent le même résultat visuel —
   :hover enveloppé dans @media (hover:hover) pour éviter l'effet "collé" sur écran tactile).
   Fusionné le 2026-07-25 : il existait deux systèmes en parallèle (un ".btn" historique avec des
   classes de couleur toutes faites — .btn-primary/.btn-gold/.btn-danger/.btn-ready/
   .btn-outline-accent, chacune avec ses propres règles :hover/:active — et un système "duo" plus
   récent piloté par une seule variable --duo-rgb + des modificateurs .btn-duo-hover-fill/
   -hover-invert). Le ".btn{}" historique était devenu une coquille commentée (donc morte), tandis
   que le markup utilisait encore "btn-duo" comme classe de base — qui elle-même N'AVAIT JAMAIS EU
   de règle définissant padding/fond/police/anneau : ces boutons ("Voir les matchs", "Déconnexion"
   sur manage-club.php et create-listing.php) s'affichaient donc comme de simples liens sans aucun
   style. Fusion : "btn-duo" → "btn" (récupère enfin le bloc de base ci-dessous, jamais perdu, juste
   mal relié), "btn-duo-hover-fill/-invert" → "btn-hover-fill/-invert". Les classes de couleur
   historiques (.btn-primary, .btn-gold, .btn-danger, .btn-ready, .btn-outline-accent) et leurs
   valeurs, y compris celles qui peuvent sembler incohérentes au premier regard (ex.
   .btn-primary:hover qui vire au doré) sont volontaires et conservées à l'identique. */
.btn {
    display: inline-block;
    position: relative;
    padding: 10px 20px;
    border-radius: 0;
    border: none;
    background: rgba(255, 255, 255, 0.08);
    color: var(--text);
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
    transition: color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
    text-transform: uppercase;
    margin-top: 1vh;
    font-family: "Geologica", sans-serif;
}

/* Anneau : discret et légèrement plus grand que le bouton au repos, se resserre et s'allume
   (reprend `currentColor`, donc s'adapte à la couleur de chaque variante sans la répéter) au
   survol/clic — même mécanique que bray.tech (scale(1.02) -> scale(1) + box-shadow qui apparaît). */
.btn::after {
    content: "";
    position: absolute;
    inset: -3px;
    box-shadow: 0 0 0 0 transparent;
    transform: scale(1.02);
    pointer-events: none;
    transition: box-shadow 0.2s ease, transform 0.2s ease;
}

.btn:active { background: rgba(255, 255, 255, 0.22); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.5); }
.btn:active::after { box-shadow: 0 0 0 2px currentColor; transform: scale(1); }

.btn-primary { background: rgba(255,255,255,0.1); color: #ffffff; }
.btn-primary:active { background: rgba(255,255,255,0.3); box-shadow: inset 0 0 0 1px #ffffff; }

.btn-gold { background: rgba(255,179,0,0.3); color: #ffffff; font-weight: 600; box-shadow: inset 0 0 0 1px var(--gold); }
.btn-gold:active { filter: brightness(1.1); background: rgba(255,179,0,0.5); box-shadow: inset 0 0 0 1px var(--gold); }

.btn-outline-accent { color: var(--accent-2); background: rgba(58, 134, 255, 0.15); box-shadow: inset 0 0 0 1px rgba(58, 134, 255, 0.5); }
.btn-outline-accent:active { background: var(--accent-2); color: #fff; box-shadow: inset 0 0 0 1px var(--accent-2); }

/*.btn-green { background: rgba(var(--green-rgb), 0.16); box-shadow: inset 0 0 0 1px rgba(var(--green-rgb), 0.5); color: rgb(var(--green-rgb)); }
.btn-green:active { rgba(var(--green-rgb), 1); box-shadow: inset 0 0 0 1px rgba(var(--green-rgb), 0.5); color: rgb(var(--green-rgb)); border: 0px;}*/

/* .btn-danger-outline : utilisée sur listing.php (suppressions) mais jamais définie nulle part —
   n'a donc jamais eu de style. Complétée sur le même principe que .btn-outline-accent ci-dessus
   (fond très translucide + liseré au repos, plein au survol/clic) avec la couleur danger. */
.btn-danger-outline { color: var(--danger); background: rgba(255, 0, 0, 0.15); box-shadow: inset 0 0 0 1px rgba(255, 0, 0, 0.5); }
.btn-danger-outline:active { background: var(--danger); color: #fff; box-shadow: inset 0 0 0 1px var(--danger); }

.btn-danger { background: rgba(255, 0, 0, 0.3); box-shadow: inset 0 0 0 1px var(--danger); color: #FFFFFF; }
.btn-danger:active { background: rgba(255, 0, 0, 1); box-shadow: inset 0 0 0 1px var(--danger); }

/* Bouton "Prêt" (listing.php) : gris, utilisé pour ACCEPTER (créateur, cliquable) et pour les
   bandeaux "C'est parti !" une fois les deux clubs prêts (affichage seul, voir
   .match-cta-static) — même fond neutre dans les deux cas. */
.btn-ready { background-color: rgba(255,255,255,0.3); color: #ffffff; box-shadow: inset 0 0 0 1px var(--green); }
.btn-ready:active { filter: brightness(1.2); background-color: rgba(255,255,255,0.45); color: #ffffff; box-shadow: inset 0 0 0 1px var(--green); }

.btn-green{ background-color: rgba(52, 211, 153,0.16); color: var(--green); box-shadow: inset 0 0 0 1px #ffffff; }
.btn-green:active { filter: brightness(1.2); rgba(52, 211, 153,0.5); color: var(--green); box-shadow: inset 0 0 0 1px #ffffff; }

/* ----- Variante "duo" — recette bicolore réutilisable, pour les boutons qui n'ont pas besoin
   d'une classe de couleur toute faite -----
   Une seule couleur à définir (--duo-rgb, via une classe .btn-<preset> ou un style inline), le
   second "ton" est calculé automatiquement (fond très translucide vs. la couleur pleine). Deux
   comportements de survol/clic au choix, à ajouter EN PLUS de .btn :
   - .btn-hover-fill    : le fond se remplit davantage de la couleur (garde le texte clair).
   - .btn-hover-invert  : la couleur devient pleine, le texte passe en sombre (contraste inversé).
   Exemple pour une nouvelle couleur : class="btn btn-hover-fill" style="--duo-rgb: 58,134,255;"
   — ou un des préréglages ci-dessous (.btn-accent/.btn-muted). */
.btn-accent { --duo-rgb: 52, 211, 153; }
.btn-muted  { --duo-rgb: 152, 162, 173; }
.btn-green  { --duo-rgb: 52, 211, 153; } 

.btn-hover-fill:active { background: rgba(var(--duo-rgb), 0.32); box-shadow: inset 0 0 0 1px rgba(var(--duo-rgb), 0.85); }
@media (hover: hover) {
    .btn-hover-fill:hover { background: rgba(var(--duo-rgb), 0.32); box-shadow: inset 0 0 0 1px rgba(var(--duo-rgb), 0.85); }
}

.btn-hover-invert:active { background: rgb(var(--duo-rgb)); color: #10131a; box-shadow: inset 0 0 0 1px rgb(var(--duo-rgb)); }
@media (hover: hover) {
    .btn-hover-invert:hover { background: rgb(var(--duo-rgb)); color: #10131a; box-shadow: inset 0 0 0 1px rgb(var(--duo-rgb)); }
}

.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; }
.btn:disabled::after, .btn[aria-disabled="true"]::after { display: none; }

/* Survol desktop uniquement : @media (hover:hover) exclut les écrans tactiles (un tap y déclenche
   :hover sans le relâcher tant qu'on n'a pas touché ailleurs — jamais souhaitable). Chaque règle
   ici est le miroir exact de son équivalent :active ci-dessus. */
@media (hover: hover) {
    .btn:hover { background: rgba(255, 255, 255, 0.22); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.5); }
    .btn:hover::after { box-shadow: 0 0 0 2px currentColor; transform: scale(1); }
    .btn-primary:hover { background: rgba(255,179,0,0.45); box-shadow: inset 0 0 0 1px rgba(255,179,0,0.85); }
    .btn-gold:hover { filter: brightness(1.1); background: rgba(255,179,0,0.5); box-shadow: inset 0 0 0 1px var(--gold); }
    .btn-outline-accent:hover { background: var(--accent-2); color: #fff; box-shadow: inset 0 0 0 1px var(--accent-2); }
    .btn-danger-outline:hover { background: var(--danger); color: #fff; box-shadow: inset 0 0 0 1px var(--danger); }
    .btn-danger:hover { background: var(--danger); color: #fff; box-shadow: inset 0 0 0 1px var(--danger); }
    .btn-ready:hover { filter: brightness(1.2); background-color: rgba(255,255,255,0.45); color: #ffffff; box-shadow: inset 0 0 0 1px #ffffff; }
    .btn:disabled:hover, .btn[aria-disabled="true"]:hover { background: rgba(255, 255, 255, 0.08); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18); }
}

/* Décompte à 0 : le bandeau "C'est parti" devient inerte/grisé pour tout le monde — le match est
   sur le point d'être désactivé, ce n'est plus vraiment actionnable. */
.extend-indicator.is-expired {
    background: var(--bg-elevated);
    color: var(--text-muted);
    pointer-events: none;
}
.extend-indicator.is-expired:hover { background: var(--bg-elevated); color: var(--text-muted); }

.btn-block { display: block; width: 100%; text-align: center;}

/* ----- Cartes / boîtes ----- */

.card {
    background: var(--bg-card);
    border: 0px solid var(--border);
    border-radius: 0;
    padding: 0px;
    max-width: 100%;
}

/* ----- Badge de club (initiales + couleur générée) ----- */
/* Pas d'image de blason officielle disponible publiquement chez EA (voir includes/ea_api.php) */

.club-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    font-weight: 800;
    font-size: 0.95rem;
    color: #ffffff;
    flex-shrink: 0;
    object-fit: cover; /* utile quand le badge est une vraie image de blason EA */
    background: var(--bg-elevated); /* le temps qu'une image charge */
}

/* Taille par contexte (sélecteur descendant scopé au conteneur), PAS une classe de taille partagée
   entre plusieurs endroits sans rapport — "sm"/"lg"/"manage" posées par render_club_badge()
   couplaient par exemple la pastille de nav, l'aperçu de connexion et les stats comparées : changer
   l'une cassait les autres (vécu le 2026-07-23, .sm passé à 60px avait tout cassé d'un coup).
   Modifier la taille d'un badge à un seul endroit ne peut plus en affecter un autre. */
.match-member-row.is-club-summary .club-badge { width: 72px; height: 72px; font-size: 1.4rem; } /* manage-club.php, résumé du club */
.club-result-row .club-badge { width: 30px; height: 30px; font-size: 0.72rem; } /* login.php, résultats de recherche */
.nav-account .club-badge { width: 30px; height: 30px; font-size: 0.72rem; } /* header.php, pastille compte */
.match-history-row .club-badge { width: 40px; height: 40px; font-size: 0.72rem; } /* historique de matchs, manage-club.php */
.stat-box-legend .club-badge { width: 30px; height: 30px; font-size: 0.72rem; } /* comparaison de stats, listing.php */

.division-badge-img { width: 60px; height: 60px; object-fit: contain; flex-shrink: 0; }

/* ----- Badge de division (généré, coloré par palier — pas d'icône EA officielle disponible) ----- */

.division-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 7px;
    font-weight: 800;
    font-size: 0.78rem;
    flex-shrink: 0;
    transform: rotate(45deg);
}

.division-badge span { transform: rotate(-45deg); }

.div-tier-elite { background: linear-gradient(180deg, #ffe08a, var(--gold-strong)); color: #241704; }
.div-tier-high   { background: linear-gradient(180deg, #d9c2ff, #8338ec); color: #f4edff; }
.div-tier-mid    { background: linear-gradient(180deg, #9fc4ff, var(--accent-2)); color: #061226; }
.div-tier-low    { background: linear-gradient(180deg, #aeb8c2, #5c6773); color: #0c0f12; }
.div-tier-unknown{ background: var(--bg-elevated); border: 1px solid var(--border); color: var(--text-muted); }

/* ----- Étiquettes (mood tag, division, statut) ----- */

.tags {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
}

.pill-division { color: var(--accent-2); border-color: var(--accent-2); }
.pill-muted { color: var(--text-muted); }

/* ----- Filtres page principale ----- */

.filters-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 24px;
    flex-wrap: wrap;
}

.filters-row .filters { margin-bottom: 0; }

/* "refresh-state" — barre fine qui rétrécit et s'estompe jusqu'au prochain rafraîchissement
   automatique (inspirée de bray.tech, page Activité : élément .refresh-state/.ttr/.bar), pour
   montrer visuellement que le site s'auto-actualise plutôt qu'une icône qui tourne. Le point de
   variable --duration (posé en JS, assets/js/home.js et listing.js) doit correspondre à
   l'intervalle réel de sondage de la page. Cliquable : redéclenche un rafraîchissement immédiat
   ET relance la barre à zéro (voir resetRefreshState() dans le JS). */
.refresh-state {
    display: block;
    width: 100%;
    max-width: 160px;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
}

.refresh-state .ttr { width: 100%; height: 2px; background: rgba(255, 255, 255, 0.1); position: relative; overflow: hidden; }
.refresh-state .bar { position: absolute; inset: 0; background: var(--text); animation: refresh-ttr var(--duration, 20s) linear forwards; }

@keyframes refresh-ttr {
    0%   { opacity: 0.6; width: 100%; }
    80%  { opacity: 0.4; }
    90%  { opacity: 0.3; }
    100% { opacity: 0; width: 0%; }
}

.filters {
    display: flex;
    gap: 10px;
    margin-bottom: 24px;
    flex-wrap: wrap;
}

.filters button {
    padding: 8px 16px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--bg-card);
    color: var(--text-muted);
    font-size: 0.9rem;
    cursor: pointer;
}

.filters button.active { border: none; color: #fff; text-decoration: underline; text-underline-offset: 4px; }
.filters button:disabled { background: none; border: none; border-radius: 0; opacity: 0.4; cursor: not-allowed; }

/* ----- Sélecteur de tags d'ambiance (création d'un match, choix multiple) ----- */
/* Case à cocher masquée + <label> stylée en chip : coche/décoche au clic sur le texte,
   sans JS, et l'état ":checked" pilote l'apparence via le sélecteur adjacent ci-dessous. */

.tag-picker {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

.tag-checkbox {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

/* Même langage que .btn (voir plus haut, "Boutons" : anneau ::after, hover===active, coins
   carrés) — pas de variante dorée ici, juste la case cochée/sélectionnée en accent. */
.tag-chip {
    position: relative;
    display: inline-flex;
    padding: 15px 25px;
    border-radius: 0;
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-muted);
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    user-select: none;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
    transition: color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
}

.tag-chip::after {
    content: "";
    position: absolute;
    inset: -3px;
    box-shadow: 0 0 0 0 transparent;
    transform: scale(1.02);
    pointer-events: none;
    transition: box-shadow 0.2s ease, transform 0.2s ease;
}

.tag-chip:active { background: rgba(255, 255, 255, 0.22); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.5); }
.tag-chip:active::after { box-shadow: 0 0 0 2px currentColor; transform: scale(1); }
@media (hover: hover) {
    .tag-chip:hover { background: rgba(255, 255, 255, 0.22); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.5); }
    .tag-chip:hover::after { box-shadow: 0 0 0 2px currentColor; transform: scale(1); }
}

.positions{
    color: var(--text);
    padding: 10px 16px;
    border-radius: 0px;
    font-size: 0.85rem;
    font-weight: 600;
}

.tag-checkbox:checked + .tag-chip { background: var(--gold2); color: var(--bg); box-shadow: inset 0 0 0 1px var(--gold2-strong); }
.tag-checkbox:checked + .tag-chip:active { filter: brightness(1.15); }
@media (hover: hover) {
    .tag-checkbox:checked + .tag-chip:hover { filter: brightness(1.15); }
}
.tag-checkbox:focus-visible + .tag-chip { outline: 2px solid var(--gold2); outline-offset: 2px; }

/* ----- Liste de matchs (une carte pleine largeur par match) ----- */

.listing-grid {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.listing-card {
    display: block;
    border-radius: var(--radius);
    overflow: hidden;
    border: 1px solid var(--border);
    transition: border-color 0.15s ease, transform 0.15s ease;
}

.listing-card:active { border-color: var(--green); }

@media (hover: hover) {
    .listing-card:hover { border-color: var(--green); transform: translateY(-2px); }
}

/* Annonce apparue au rafraîchissement automatique (assets/js/home.js) : petit effet de
   "poussée" (glisse depuis le haut + fondu + léger flash doré) pour se faire remarquer. */
.listing-card.is-new-entry { animation: listing-card-push-in 0.6s ease; }

@keyframes listing-card-push-in {
    0%   { transform: translateY(-18px); opacity: 0; box-shadow: 0 0 0 2px var(--gold); }
    60%  { opacity: 1; }
    100% { transform: translateY(0); opacity: 1; box-shadow: 0 0 0 0 transparent; }
}

/* Match complet/terminé : gardé visible (preuve d'activité du site) mais visuellement en retrait
   plutôt que supprimé — voir cleanup_expired_listings() dans includes/repo.php. */
.listing-card.is-inactive { opacity: 0.55; filter: grayscale(0.5); }
.listing-card.is-inactive:active { border-color: var(--border); }

/* Annonce créée ou rejointe par le club connecté, tant qu'elle n'est pas "closed" — remontée en
   tête de liste (voir fetch_home_listings() dans includes/repo.php) et mise en évidence en doré. */
.listing-card.is-mine { border-color: var(--gold); }
.listing-card.is-mine:active { border-color: var(--gold); }
.listing-card.is-mine .listing-card-body { background: rgba(217, 164, 65, 0.14); }

@media (hover: hover) {
    .listing-card.is-inactive:hover { border-color: var(--border); transform: none; }
    .listing-card.is-mine:hover { border-color: var(--gold); }
}

.listing-card-topbar {
    display: flex;
    align-items: stretch;
}

.listing-card-topbar-label {
    background: #292828;
    color: var(--text);
    padding: 14px 20px;
    flex: 1;
    font-weight: 600;
}

.listing-card-topbar-time {
    background: #525151;
    color: var(--text);
    padding: 14px 20px;
    font-weight: 700;
    white-space: nowrap;
    display: flex;
    align-items: center;
}

/* Passé LISTING_STALE_WARNING_MINUTES (40 min) sans être rejoint, un match approche de la
   suppression automatique (LISTING_ABANDONED_TIMEOUT_MINUTES, 60 min) — signalé en rouge léger. */
.listing-card-topbar-time.is-stale { background: #5c3438; }

.listing-card-body {
    background: rgba(245, 245, 245, 0.1);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 16px 20px;
    flex-wrap: wrap;
}

.listing-card-chips {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.chip {
    background: #525659;
    color: var(--text);
    padding: 8px 16px;
    border-radius: 0px;
    font-size: 0.85rem;
    font-weight: 600;
}

.listing-card-images {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
}

.listing-card-images .club-badge,
.listing-card-images .division-badge,
.listing-card-images .division-badge-img {
    width: 48px;
    height: 48px;
}

.empty-state {
    text-align: center;
    color: var(--text-muted);
    padding: 60px 20px;
}

/* ----- Formulaires ----- */

.form-group { margin-bottom: 3vh; }
.titresouli{ margin-bottom: 1vh; border-bottom: 1px solid #282b2a; font-size: 0.8rem;}

label { display: block; margin-bottom: 6px; font-weight: 600; font-size: 0.9rem; }

input[type="text"], input[type="password"], input[type="search"], input[type="time"], select {
    width: 100%;
    padding: 11px 14px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text);
    font-size: 0.95rem;
}

input:focus, select:focus { outline: none; border-color: var(--green); }

.form-hint { font-size: 0.8rem; color: var(--text-muted); margin-top: 6px; }
.form-error { font-size: 0.85rem; color: var(--danger); margin-top: 6px; }

.form-row { display: flex; gap: 12px; flex-wrap: wrap; }
.form-row > * { flex: 1; min-width: 180px; }

/* ----- Page de connexion (login.php) : carte centrée + fond plein écran ---------------------- */

/* Occupe l'espace restant sous le header (et au-dessus du footer) pour centrer .auth-card
   verticalement, desktop comme mobile — pas juste centré horizontalement comme avant. */
.auth-page-wrap {
    min-height: 75vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 30px 0;
}

.auth-card { max-width: 480px; margin: 0 auto; width: 100%; }

/* Fond plein écran optionnel de la page de connexion — dépose ton image dans
   assets/images/login-bg.jpg (même nom) pour l'activer, même principe de repli que .hero/
   .page-bg-fade (dégradé uni tant que le fichier est absent). position:fixed (pas absolute) :
   couvre tout le viewport même si la page est plus courte, pas besoin de connaître sa hauteur.
   z-index:-1 (pas 0, voir le piège documenté sur .page-bg-fade plus haut) pour rester derrière
   tout le contenu normal. */
.auth-page-bg {
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background:
        linear-gradient(180deg, rgba(var(--bg-rgb), 0.55) 0%, rgba(var(--bg-rgb), 0.95) 100%),
        url("../images/login-bg.jpg");
    background-size: cover;
    background-position: center;
}

/* ----- Résultats de recherche de club (inscription) ----- */

.club-results { margin-top: 14px; display: flex; flex-direction: column; gap: 8px;
}

.club-result-row {
    position: relative;
    isolation: isolate; /* même confinement du blason géant que .match-member-row, voir plus bas */
    overflow: hidden;
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    max-height: 80px;
    padding: 10px 12px;
    border: 2px solid var(--border);
    border-radius: var(--noradius);
    background: var(--bg-elevated);
    color: var(--text);
    cursor: pointer;
    text-align: left;
    font-size: 0.95rem;
    transition: opacity 0.15s ease, max-height 0.15s ease, padding 0.15s ease, margin 0.15s ease, border-width 0.15s ease;
}

.club-result-row:active { border-color: var(--gold); }
.club-result-row.selected { border-color: var(--gold); }

@media (hover: hover) {
    .club-result-row:hover { border-color: var(--gold); }
}

/* Autres résultats une fois un club sélectionné (selectClub() dans signup.js) : repliés en
   douceur plutôt que supprimés d'un coup, pour éviter le "saut" visuel signalé par l'utilisateur
   (la ligne sélectionnée, elle, reste exactement à sa place — plus de bloc séparé qui apparaît
   ailleurs, voir l'ancien #club-selected-box/.selected-club-box, retiré). */
.club-result-row.is-removing {
    opacity: 0;
    max-height: 0;
    padding-top: 0;
    padding-bottom: 0;
    margin-top: 0;
    margin-bottom: 0;
    border-width: 0;
}

.club-result-row .club-name { font-weight: 700; flex: 1; }

/* Sélecteur de joueur (create-listing.php, "recherche_club") : simple ancre position:relative pour
   que #player-picker-panel (.opt-select-panel réutilisé tel quel — même design que
   #leaderboard-sort-panel sur manage-club.php) flotte juste sous le champ de recherche. */
.player-picker-wrap { position: relative; }

/* ----- Page "Gérer club" ----- */
/* Le résumé du club réutilise directement .match-member-row.is-filled (listing.php) — voir
   manage-club.php — plus besoin d'une classe .club-summary-header séparée. */

/* Pastille "verre/glossy" (plateforme, club-summary-header) : fond translucide + flou +
   liseré clair en haut façon reflet — plutôt qu'un simple fond uni comme .pill-muted seule. */
.pill-glass {
    background: rgba(0, 0, 0, 0.3);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(15px);
    border: 1px solid rgba(255, 255, 255, 0.25);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 2px 8px rgba(0, 0, 0, 0.15);
}

.roster-breakdown { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 5vh;}
.roster-breakdown-label { font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); margin-right: auto; }

/* Indicateur temporaire pendant le chargement différé de l'historique de matchs/classement (voir
   assets/js/manage-club.js, ajax/manage-club-data.php) — placeholder simple en attendant mieux. */
.section-loading { display: flex; justify-content: center; padding: 24px 0; }
.loading-spinner {
    width: 28px;
    height: 28px;
    border: 3px solid rgba(255, 255, 255, 0.15);
    border-top-color: var(--loading-spinner-color);
    border-radius: 50%;
    animation: loading-spin var(--loading-spinner-duration) linear infinite;
}
@keyframes loading-spin {
    to { transform: rotate(360deg); }
}

/* Historique des derniers matchs (manage-club.php) — barre d'accent colorée sur le bord gauche de
   chaque ligne, inspirée de la liste "reports" de bray.tech (voir debug/PROJECT.md) : victoire en
   vert AVEC la même lumière que leur effet "flawless" (double box-shadow), défaite en rouge sobre
   (pas de lumière), nul en gris clair sans lumière (distinct du fond très sombre de la ligne, mais
   sans halo pour rester "neutre") — voir .match-history-row.is-win/.is-loss/.is-draw plus bas. */
.match-history { display: flex; flex-direction: column; gap: 2px; margin: 5vh 0; }
.match-history-heading { font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); padding-bottom: 10px;}

/* Classement : titre + menu de tri (.opt-select) sur la même ligne, trigger à droite — voir
   manage-club.php. .opt-select garde sa marge basse propre (14px), pas besoin de celle du titre. */
.match-history-heading-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 1vh; }
.match-history-heading-row .match-history-heading { margin-bottom: 0; }

/* Grid à colonnes FIXES (pas basées sur le contenu) plutôt qu'un flex : garantit que chaque
   colonne (temps, adversaire, type, MOM, score) tombe exactement au même endroit d'une ligne à
   l'autre, même quand un nom d'adversaire ou de MOM change de longueur — "lecture fluide" demandée.
   Groupes voulus par l'utilisateur : [blason+adversaire+temps+type] serrés à gauche (colonnes 1-4,
   gap normal — la colonne adversaire utilise fit-content(130px), PAS minmax(0,130px) : ces deux
   bornes étant des longueurs fixes (pas "auto"/content-based), minmax() se faisait maximiser à
   130px par l'algo de grid dès qu'il restait de la place ailleurs, même pour un nom court — ce qui
   écartait le chip de type du nom au lieu de rester collés. fit-content(130px) épouse vraiment la
   largeur du nom, plafonnée à 130px avec overflow hidden/ellipsis au-delà) -- [1fr, grand espace
   vide] -- [MOM ... petit espace fixe ... score] à droite (colonnes 6-8, "pas trop proche mais
   ensemble" : gap plus large que la colonne 7 le permet). */
.match-history-row {
    position: relative;
    display: grid;
    grid-template-columns: 40px fit-content(130px) auto auto 1fr auto 20px auto;
    align-items: center;
    column-gap: 15px;
    padding: 10px 14px 10px 18px;
    background: #171a19;
    font-size: 0.9rem;
    margin-bottom: 5px;
}

.match-history-row::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    width: 4px;
}

.match-history-row.is-win::before { background: var(--green); box-shadow: 0 0 10px 0 var(--green), 0 0 10px 0 var(--green); }
.match-history-row.is-loss::before { background: var(--danger); }
.match-history-row.is-draw::before { background: #ffffff; }

.match-history-row .club-badge { grid-column: 1; }
.match-history-opponent { grid-column: 2; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.match-history-time { grid-column: 3; color: var(--text-muted); font-size: 0.78rem; }
.match-history-type { grid-column: 4; font-size: 0.7rem; padding: 3px 10px; }
.match-history-mom { grid-column: 6; font-size: 0.78rem; color: var(--gold); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 160px; }
.match-history-score { grid-column: 8; justify-self: end; font-weight: 800; font-variant-numeric: tabular-nums; font-size: 1.3rem;}

.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
    gap: 10px;
}

.stat-box {
    background: #171a19;
    border-radius: var(--noradius);
    padding: 14px;
    text-align: center;
}

.stat-box .value { font-size: 1.4rem; font-weight: 800; }
.stat-box .label { font-size: 0.78rem; color: var(--text-muted); text-transform: uppercase; }

/* Panneau stats fusionné (listing.php, une fois les deux clubs prêts) : chaque stat-box affiche
   ma valeur puis, en dessous du libellé, celle de l'adversaire (teintée de sa couleur, posée
   inline par render_club_stat_grid()) — un peu plus espacé que la version à une seule valeur. */
.stat-grid-dual .stat-box { display: flex; flex-direction: column; gap: 6px; padding: 16px 14px; }
.stat-box .value-opponent { font-size: 1.2rem; font-weight: 700; }

/* Stat-box "légende" (logos des deux clubs) : première case de la grille fusionnée, même
   structure value/label/value-opponent que les autres pour qu'on comprenne à qui appartient
   chaque colonne de chiffres. */
.stat-box-legend .value,
.stat-box-legend .value-opponent { display: flex; justify-content: center; }

/* ----- Page détail d'un match (listing.php) ----- */

.live-info {
    font-size: 0.82rem;
    color: var(--text-muted);
    margin-top: 8px;
}

.listing-header-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 3vh;
    margin-top: 3vh;
}

.listing-header-badges {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

.pill-info {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    border-radius: 999px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    color: var(--text-muted);
    font-size: 0.82rem;
    font-weight: 600;
}


.listing-layout {
    display: grid;
    grid-template-columns: 1.6fr 1fr;
    align-items: start;
    gap: 20px;
}

.listing-side {
    display: flex;
    flex-direction: column;
    gap: 20px;
    z-index: 1;
}

.match-members-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12px;
}

.match-members-title { font-size: 1rem; margin: 0; }
.match-members-count { font-weight: 800; color: var(--text-muted); }

.match-members {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.match-member-row {
    position: relative;
    isolation: isolate; /* garde le blason géant (::before, z-index négatif) contenu à cette ligne */
    overflow: hidden; /* rogne le blason qui déborde à droite/en haut/en bas */
    display: flex;
    align-items: center;
    gap: 20px;
    background: rgba(255, 255, 255, 0.2);
    border: 2px solid transparent;
    padding: 16px 20px;
}

/* Occupée par un club : dégradé teinté de sa couleur (--member-color-rgb, posée inline par
   club_banner_style() en PHP ou son équivalent JS, voir listing.js) par-dessus le fond translucide
   habituel, + le blason du club en grand et très transparent sur la droite (::before, en dessous
   du texte grâce au z-index négatif + .isolation ci-dessus). Sans club (lignes vides), aucune de
   ces variables n'est posée : le fond reste le simple translucide de base. */
/* Dégradé plein (pas de fondu vers transparent) : couleur vive du club à gauche, noir saturé de
   cette même teinte à droite — là où le blason (::before) est affiché. Même traitement réutilisé
   sur .club-result-row (résultats de recherche, login.php — voir bannerStyle() dans signup.js et
   club_banner_style() côté PHP) et .match-member-row (résumé de club, manage-club.php — même
   classe réutilisée directement, pas une classe séparée). Les cartes joueur (.player-card, plus
   bas) n'utilisent PAS ce système : dégradé radial différent, posé directement en style inline
   par carte (voir cardGradient() dans leaderboard.js).
   RESTAURÉ le 2026-07-22 : était passé à un gris uni (#282D31) par erreur, la couleur extraite du
   blason (--member-color-rgb/--member-color-dark-rgb, posées par ligne) n'était plus utilisée du
   tout. color-mix() vers ce même gris via --member-banner-vivid-mix (:root) permet de désature/
   adoucir la couleur progressivement (curseur 0-100%) plutôt que de choisir entre "coloré" et
   "gris" — voir le commentaire complet dans :root. */
.match-member-row.is-filled,
.club-result-row.is-filled {
    background: linear-gradient(var(--member-banner-gradient-angle),
        color-mix(in srgb, rgb(var(--member-color-rgb, 42, 48, 56)) var(--member-banner-vivid-mix), #282D31) var(--member-banner-gradient-stop-start),
        color-mix(in srgb, rgb(var(--member-color-dark-rgb, 18, 23, 28)) var(--member-banner-vivid-mix), #282D31) var(--member-banner-gradient-stop-end));
}

.match-member-row.is-filled::before,
.club-result-row.is-filled::before {
    content: "";
    position: absolute;
    top: 50%;
    right: -10%;
    width: var(--member-banner-crest-size);
    aspect-ratio: 1;
    z-index: -1;
    transform: translateY(-50%) rotate(var(--member-banner-crest-angle));
    background-image: var(--member-crest-url, none);
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
    opacity: var(--member-banner-crest-opacity);
    mix-blend-mode: var(--member-banner-crest-blend-mode);
    pointer-events: none;
}

/* Grain léger par-dessus tout (dégradé + blason) — texture SVG générée, pas de fichier à fournir.
   --member-banner-grain-opacity dans :root pour l'intensité. */
.match-member-row.is-filled::after,
.club-result-row.is-filled::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 180 180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
    background-repeat: repeat;
    opacity: var(--member-banner-grain-opacity);
    mix-blend-mode: overlay;
    pointer-events: none;
}

/* ----- Cartes du classement des joueurs (manage-club.php, assets/js/leaderboard.js) -----
   Grille de cartes (3 par ligne desktop, s'adapte au mobile) — v2 (2026-07-21) : fond neutre uni
   (le dégradé coloré par joueur de la v1 a été jugé "pas bien du tout"), reprend la disposition
   de la carte de référence fournie par l'utilisateur : métrique triée + poste + blason du club
   empilés en haut à gauche, silhouette générique en haut à droite (toujours pas de vraie photo
   joueur, l'API EA n'en fournit pas), nom + pseudo EA au centre, 6 statistiques fixes en grille
   en bas. */
.leaderboard-cards {
    display: grid;
    /* minmax(0, 1fr) et pas juste "1fr" : sans le "0", la taille minimale d'une colonne de grille
       est "auto" (= la largeur du contenu le plus large qu'elle contient), donc une carte avec un
       contenu large (long nom de joueur, etc.) pousse toute la grille hors de .container au lieu
       d'être contenue/tronquée par sa propre carte (voir overflow: hidden sur .player-card-name). */
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 14px;
}

.player-card {
    position: relative;
    background: #171a19;
    border: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 14px;
    cursor: pointer;
    transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;
}

/* Fond distinct une fois les stats ouvertes (voir assets/js/leaderboard.js) — demande explicite. */
.player-card:not(.is-collapsed) { background: #282D31; }

/* Photo de fond par poste (assets/js/player-card-backgrounds.js) — appliquée uniquement quand une
   image a réellement été tirée pour la carte (classe .has-bg + variable --player-card-bg-url
   posées côté JS). Dégradé haut (0.2 d'opacité) -> bas (0.80) pour garder les stats lisibles une
   fois la carte dépliée, sans cacher complètement la photo en haut. Le contenu (::before est en
   z-index 0) doit rester au-dessus de la photo, d'où le z-index 1 sur les enfants directs.
   background-size: cover (demande explicite : l'image doit TOUJOURS couvrir toute la hauteur ET
   largeur de la carte, sans déformation — un souci vu sur mobile où "100% auto" laissait des zones
   non couvertes en bas de carte quand la photo n'était pas assez haute une fois la largeur mobile
   appliquée). Contrepartie assumée : ".player-card" étant un conteneur flex dont la hauteur
   s'agrandit progressivement à l'ouverture (transition max-height de .player-card-stats), le
   cadrage peut légèrement se recalculer pendant cette transition — accepté au profit d'une
   couverture garantie en toutes circonstances. */
.player-card.has-bg {
    background-image: var(--player-card-bg-url);
    background-size: cover;
    background-position: top center;
}
.player-card.has-bg::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background: linear-gradient(to bottom, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.8));
}
.player-card.has-bg > * { position: relative; z-index: 1; }

.player-card:active { transform: translateY(-3px); border-color: var(--green); box-shadow: 0 10px 24px rgba(0, 0, 0, 0.35); }
@media (hover: hover) {
    .player-card:hover { transform: translateY(-3px); border-color: #ded295; box-shadow: 0 10px 24px rgba(0, 0, 0, 0.35); }
}

/* Chevron discret indiquant que la carte est cliquable/dépliable — même mécanique que le chevron
   de .opt-select-trigger (rotation 180deg à l'ouverture), pour une cohérence de langage visuel. */
.player-card-toggle-icon { text-align: center; color: var(--text-muted); font-size: 1.5rem; line-height: 1; transition: transform 0.2s ease; }
.player-card:not(.is-collapsed) .player-card-toggle-icon { transform: rotate(180deg); }

/* v4 : métrique + explication de la métrique triée à gauche ; blason du club + silhouette groupés
   en haut à droite, avec nom + pseudo EA + poste empilés EN DESSOUS (aligné à droite) — remplace le
   poste qui était sous la métrique (n'expliquait pas ce que "133" représente) par le libellé de la
   métrique triée elle-même (même fonction metricLabel() que le menu de tri). */
.player-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.player-card-headleft { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.player-card-headright { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; flex-shrink: 0; }
.player-card-headright-icons { display: flex; align-items: center; gap: 8px; }
.player-card-metric { font-size: 3.5rem; font-weight: 800; line-height: 1.1; }
/* Partie décimale (séparateur "." ou "," + chiffres + suffixe "%" éventuel, voir
   formatMetricHtml() dans assets/js/leaderboard.js) affichée plus petite que la partie entière —
   même principe visuel qu'un prix ("19€99" en plus petit après l'entier). */
.player-card-metric-decimal { font-size: 1.5rem; }
.player-card-metric-label,
.player-card-position { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); }
.player-card-club-logo { width: 32px; height: 32px; object-fit: contain; }

.player-card-silhouette { width: 34px; height: 34px; fill: var(--text-muted); opacity: 0.6; flex-shrink: 0; }

.player-card-identity { text-align: right; max-width: 150px; }
.player-card-name { display: block; font-size: 1rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.02em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.player-card-username { display: block; font-size: 0.72rem; color: var(--text-muted); }

.player-card-metric-detail{
    font-size: 0.8rem;
}

.player-card-stats {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px 14px;
    margin-top: auto;
    padding-top: 10px;
    border-top: 1px solid var(--border);
    max-height: 200px;
    opacity: 1;
    overflow: hidden;
    transition: max-height 0.25s ease, opacity 0.2s ease, padding-top 0.25s ease, border-color 0.25s ease;
}

/* TOUTES les cartes démarrent repliées (pas seulement au-delà des 8 premières) — les stats ne
   s'affichent qu'au clic sur la carte (écouteur délégué sur cardsEl, assets/js/leaderboard.js),
   avec un effet "grandissant" (max-height animé) plutôt qu'un affichage/masquage instantané —
   demande explicite de l'utilisateur, "fie-toi à l'image" pour l'état replié par défaut. */
.player-card.is-collapsed .player-card-stats {
    max-height: 0;
    opacity: 0;
    padding-top: 0;
    border-top-color: transparent;
}

.leaderboard-load-more { margin-top: 14px; }
.player-card-stat { display: flex; flex-direction: column; }
.player-card-stat-value { font-size: 0.95rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.player-card-stat-label { font-size: 0.65rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }

/* ----- Nouveau classement "jury" (manage-club.php, assets/js/leaderboard-jury.js) -----
   Inspiré de la page de vote des jurés d'awwwards.com/sites/just-phil ("user_votes") : REMPLACE
   VISUELLEMENT .leaderboard-cards ci-dessus (conservées, désactivées) — ligne de filtres façon
   leur "grid-score--titles", une colonne de valeurs par filtre visible, alignée sous son libellé,
   coloration de la colonne active au clic.

   ALIGNEMENT tableau (v2, corrige une régression) : le titre (retiré, voir plus bas) ET
   .leaderboard-jury-info ont la MÊME largeur FIXE (--jury-label-col) — condition nécessaire pour
   que .leaderboard-jury-filters et chaque .leaderboard-jury-score démarrent exactement à la même
   position X : ancrer seulement le bord DROIT (ex. justify-content:space-between) ne suffit pas,
   deux grilles de largeurs totales différentes n'ont pas les mêmes pistes 1fr même en partageant
   ce bord droit. Avec la même largeur de colonne fixe à gauche partout, la grille de droite a
   TOUJOURS exactement la même largeur totale d'une ligne à l'autre, donc les mêmes pistes.
   --jury-label-col est définie dans :root tout en haut du fichier. */

/* .heading-section/.mb-0 : wrapper emprunté à awwwards pour la ligne filtres (séparateur pointillé
   en bas, comme chez eux) — volontairement DISTINCT de .match-history-heading-row pour ne pas
   rattacher visuellement ce bloc au reste de "Gérer club" (demande explicite). Le titre lui-même a
   été retiré (jugé trop proche de la ligne de filtres) SANS élargir .leaderboard-jury-filters à sa
   place : l'espace qu'il occupait reste vide via .leaderboard-jury-title-spacer, qui garde la même
   largeur que .leaderboard-jury-info (nécessaire à l'alignement ci-dessus). */
.heading-section {
    display: flex;
    align-items: stretch;
    padding-bottom: 12px;
    margin-bottom: 14px;
    background-image: linear-gradient(to right, var(--border) 0 6px, transparent 6px);
    background-position: bottom;
    background-size: 10px 1px;
    background-repeat: repeat-x;
    margin-top: 5vh;
}
.heading-section.mb-0 { margin-bottom: 0; }
.leaderboard-jury-title-spacer { width: var(--jury-label-col); flex-shrink: 0; }

/* flex:1 + min-width:0 : cette grille prend TOUT l'espace restant à droite de la colonne fixe —
   sans min-width:0 un enfant flex ne peut jamais rétrécir sous sa taille de contenu naturelle, ce
   qui empêcherait la grille de se comprimer sur mobile. column-gap:0 + cellules bord à bord
   (demande explicite) : pas d'espace visible entre colonnes, la ligne se lit comme un vrai tableau
   plutôt que des puces séparées. */
.leaderboard-jury-filters {
    display: grid;
    grid-template-columns: repeat(var(--jury-cols, 1), minmax(0, 1fr)) var(--jury-arrow-slot);
    column-gap: 0;
    align-items: stretch;
    flex: 1 1 auto;
    min-width: 0;
}

.leaderboard-jury-filter {
    font-family: "Figtree", sans-serif;
    background: none;
    border: none;
    padding: 8px 4px;
    color: var(--text-muted);
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    text-align: center;
    line-height: 1.25;
    cursor: pointer;
    transition: color 0.2s ease, background-color 0.2s ease;
}
.leaderboard-jury-filter.is-active { color: #ffffff; background: #222526; }
.leaderboard-jury-filter:active { color: var(--text); background: rgba(255, 255, 255, 0.08); }
@media (hover: hover) {
    .leaderboard-jury-filter:hover { color: var(--text); background: rgba(255, 255, 255, 0.08); }
}

/* La flèche ">" occupe la piste de grille FIXE réservée (--jury-arrow-slot) — jamais dans les N
   colonnes de filtres elles-mêmes, ne disparaît donc jamais, même à la largeur mobile la plus
   étroite (demande explicite). Reprend TEL QUEL le design déjà établi de .opt-select-trigger/
   -panel/-option (anneau ::after, bg-elevated + blur, scrollbar redéfinie) plutôt qu'un style
   maison — seule la largeur change (icône compacte au lieu d'un trigger texte de 250px). */
.leaderboard-jury-more { position: relative; display: flex; }
.leaderboard-jury-more-trigger {
    position: relative;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.06);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
    color: var(--text);
    border: none;
    font-size: 0.9rem;
    cursor: pointer;
    transition: background-color 0.2s ease, box-shadow 0.2s ease;
}
.leaderboard-jury-more-trigger::after {
    content: "";
    position: absolute;
    inset: -3px;
    box-shadow: 0 0 0 0 transparent;
    transform: scale(1.02);
    pointer-events: none;
    transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.leaderboard-jury-more-trigger:active { background: rgba(255, 255, 255, 0.12); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.32); }
.leaderboard-jury-more-trigger:active::after { box-shadow: 0 0 0 2px currentColor; transform: scale(1); }
@media (hover: hover) {
    .leaderboard-jury-more-trigger:hover { background: rgba(255, 255, 255, 0.3); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.32); }
    .leaderboard-jury-more-trigger:hover::after { box-shadow: 0 0 0 2px currentColor; transform: scale(1); }
}

.leaderboard-jury-more-panel {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    z-index: 5;
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 4px;
    min-width: 220px;
    max-height: 260px;
    overflow-y: auto;
    background: #171a19;
    backdrop-filter: blur(20px);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18), 0 10px 24px rgba(0, 0, 0, 0.4);
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.25) transparent;
}
.leaderboard-jury-more-panel::-webkit-scrollbar { width: 6px; }
.leaderboard-jury-more-panel::-webkit-scrollbar-track { background: transparent; }
.leaderboard-jury-more-panel::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.25); border-radius: 3px; }
.leaderboard-jury-more-panel::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.4); }

.leaderboard-jury-more-option {
    position: relative;
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    color: var(--text-muted);
    padding: 12px 12px;
    font-size: 0.8rem;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease;
}
.leaderboard-jury-more-option::after {
    content: "";
    position: absolute;
    inset: -1px;
    box-shadow: 0 0 0 0 transparent;
    transform: scale(1.02);
    pointer-events: none;
    transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.leaderboard-jury-more-option:active { background: rgba(255, 255, 255, 0.08); color: var(--text); }
.leaderboard-jury-more-option:active::after { box-shadow: 0 0 0 2px currentColor; transform: scale(1); }
@media (hover: hover) {
    .leaderboard-jury-more-option:hover { background: rgba(255, 255, 255, 0.08); color: var(--text); }
    .leaderboard-jury-more-option:hover::after { box-shadow: 0 0 0 2px currentColor; transform: scale(1); }
}

.leaderboard-jury-list { display: flex; flex-direction: column; margin: 0; padding: 0; list-style: none; }

.leaderboard-jury-item {
    position: relative;
    display: flex;
    align-items: stretch;
    border-bottom: 1px solid var(--border);
}
.leaderboard-jury-item:last-child { border-bottom: none; }
.leaderboard-jury-item:nth-child(odd) { background: rgba(255, 255, 255, 0.02); }

/* Pas de <figure>/photo (demande explicite — l'API EA n'en fournit pas de toute façon) : juste
   nom+pseudo sur une ligne, poste sur la ligne du dessous. Réutilise TEL QUEL le typographisme
   déjà établi par .player-card-name/-username/-position (leaderboard.js) plutôt que d'en
   redéfinir un nouveau — ces 3 classes ne sont scopées à aucun parent précis.
   width fixe (--jury-label-col, même valeur que .leaderboard-jury-title-spacer) + le padding
   vertical PORTE la hauteur de la ligne (voir .leaderboard-jury-cell plus bas, qui n'a plus de
   padding du tout : la hauteur se compense ICI plutôt que d'être perdue). */
.leaderboard-jury-info {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 2px;
    width: var(--jury-label-col);
    flex-shrink: 0;
    min-width: 0;
    padding: 14px 8px;
}
.leaderboard-jury-info-line1 { display: flex; align-items: baseline; gap: 6px; }
.leaderboard-jury-info .player-card-name { max-width: 150px; }

.leaderboard-jury-score {
    display: grid;
    grid-template-columns: repeat(var(--jury-cols, 1), minmax(0, 1fr)) var(--jury-arrow-slot);
    column-gap: 0;
    flex: 1 1 auto;
    min-width: 0;
}
/* Couleur de colonne au clic sur un filtre (demande explicite) : la colonne du filtre ACTIF passe
   à #222526, toutes les autres restent à #1c1e1f — même logique de fond que .leaderboard-jury-
   filter.is-active ci-dessus. AUCUN padding ici (demande explicite, "pas de carré visible") : la
   cellule remplit sa piste de grille bord à bord (largeur ET hauteur, .leaderboard-jury-item étant
   en align-items:stretch) — le texte reste lisible seul grâce au centrage flex, sans avoir besoin
   de marge interne vu que les valeurs affichées sont toujours courtes (nombres/pourcentages). */
.leaderboard-jury-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
    color: var(--text-muted);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-align: center;
    /*font-family: "Space Mono", monospace;*/
}
.leaderboard-jury-cell.is-active { background: var(--gold2); color: var(--bg); font-size: 1.5rem;}

.leaderboard-jury-loadmore { margin-top: 14px; }
.leaderboard-jury-footer { margin-top: 10px; }
.leaderboard-jury-count { font-size: 0.78rem; color: var(--text-muted); }

/* ----- Menu compact "sélection actuelle" (remplace un <select> natif) -----
   Vérifié en direct sur bray.tech/settings (2026-07-22, ".select"/".option.button.selected") : leur
   "select" est un vrai <select> personnalisé où chaque option EST un ".button" à part entière — il
   hérite donc automatiquement du même anneau ::after qui s'agrandit au survol/clic que nos .btn
   (même mécanique, déjà portée fidèlement ici depuis bray.tech, voir plus haut). Le repli précédent
   (fond/contour plats, sans anneau) n'avait pas cet anneau ; ajouté ici pour le trigger ET chaque
   option du panneau. Le panneau lui-même reprend gap+padding de leur ".select.expanded .options"
   (les options ont besoin de cet espace pour que l'anneau de chacune ne chevauche pas sa voisine). */
.opt-select { position: relative; display: inline-block; width: 250px; }

.opt-select-trigger {
    position: relative;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    background: rgba(255, 255, 255, 0.06);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
    color: var(--text);
    border: none;
    padding: 16px 12px;
    font-size: 0.8rem;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
    transition: background-color 0.2s ease, box-shadow 0.2s ease;
}
/* Anneau sur ::before (::after est déjà pris par le chevron ▾ ci-dessous) — même mécanique que
   .btn::after : discret et légèrement plus grand au repos, se resserre et s'allume au survol/clic. */
.opt-select-trigger::before {
    content: "";
    position: absolute;
    inset: -3px;
    box-shadow: 0 0 0 0 transparent;
    transform: scale(1.02);
    pointer-events: none;
    transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.opt-select-trigger::after { content: "▾"; font-size: 0.65rem; color: var(--text-muted); flex-shrink: 0; transition: transform 0.2s ease; }
.opt-select.is-open .opt-select-trigger::after { transform: rotate(180deg); }
.opt-select-hint { color: var(--text-muted); font-weight: 400; margin-right: 4px; }

.opt-select-trigger:active { background: rgba(255, 255, 255, 0.12); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.32); }
.opt-select-trigger:active::before { box-shadow: 0 0 0 2px currentColor; transform: scale(1); }
@media (hover: hover) {
    .opt-select-trigger:hover { background: rgba(255, 255, 255, 0.3); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.32); }
    .opt-select-trigger:hover::before { box-shadow: 0 0 0 2px currentColor; transform: scale(1); }
}

.opt-select-panel {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 5;
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 4px;
    background: var(--bg-elevated);
    backdrop-filter: blur(20px);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18), 0 10px 24px rgba(0, 0, 0, 0.4);
    max-height: 260px;
    overflow-y: auto;
    /* Sans ça, le survol de la barre de défilement retombe sur le style NATIF du navigateur
       (fin/translucide au repos -> large et opaque au survol sur Chrome/Edge Windows), très
       différent visuellement de son état au repos. On la redéfinit entièrement pour un rendu
       identique posé/survolé, cohérent avec le reste du site. */
    scrollbar-width: thin; /* Firefox */
    scrollbar-color: rgba(255, 255, 255, 0.25) transparent; /* Firefox */
}
.opt-select-panel::-webkit-scrollbar { width: 6px; }
.opt-select-panel::-webkit-scrollbar-track { background: transparent; }
.opt-select-panel::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.25); border-radius: 3px; }
.opt-select-panel::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.4); }

.opt-select-option {
    position: relative;
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    color: var(--text-muted);
    padding: 16px 12px;
    font-size: 0.8rem;
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease;
}
.opt-select-option::after {
    content: "";
    position: absolute;
    inset: -1px;
    box-shadow: 0 0 0 0 transparent;
    transform: scale(1.02);
    pointer-events: none;
    transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.opt-select-option.is-selected { color: #ffffff; background: rgba(var(--btngold-rgba)); }
.opt-select-option:active { background: rgba(255, 255, 255, 0.08); color: var(--text); }
.opt-select-option:active::after { box-shadow: 0 0 0 2px currentColor; transform: scale(1); }
@media (hover: hover) {
    .opt-select-option:hover { background: rgba(255, 255, 255, 0.08); color: var(--text); }
    .opt-select-option:hover::after { box-shadow: 0 0 0 2px currentColor; transform: scale(1); }
}


/* Bordure verte une fois prêt — le seul indicateur de statut porté par la ligne elle-même,
   la pastille .ready-badge (coin haut-droit) reste l'indicateur "Pas prêt" en attendant. */
.match-member-row.is-ready { border-color: var(--green); }

.match-member-row .club-badge { flex-shrink: 0; }

.match-member-info { flex: 1; min-width: 0;}
.match-member-info strong { display: block; letter-spacing: 1px; font-size: 1.2rem; margin-bottom: 8px; font-weight: 800;}

.match-member-chips { display: flex; gap: 8px; flex-wrap: wrap; }
.match-member-chips .chip { padding: 6px 12px; font-size: 0.78rem; }

.match-member-row .division-badge,
.match-member-row .division-badge-img { flex-shrink: 0; }

/* Stats du joueur sélectionné (create-listing.php, "recherche_club") intégrées DANS la bannière —
   3e bloc flex de .match-member-row, après le blason et .match-member-info. Classes DÉDIÉES à ce
   cas (pas de réutilisation de .player-card-stats/.player-card-stat : cette classe est pensée pour
   la carte VERTICALE du classement — grille figée 2 colonnes, cellules empilées à gauche — et ne
   rendait pas bien une fois embarquée dans une bannière horizontale). Simple grille 2 lignes × 3
   colonnes alignée à droite, demande explicite. */
.player-picker-stats {
    display: grid;
    grid-template-columns: repeat(3, auto);
    gap: 8px 70px;
    flex-shrink: 0;
}
.player-picker-stat { display: flex; flex-direction: column; align-items: flex-start; }
.player-picker-stat-value { font-size: 1rem; font-weight: 700; font-variant-numeric: tabular-nums; text-align: right; color: #ffffff;}
.player-picker-stat-label { font-size: 0.7rem; color: var(--text); text-transform: uppercase; letter-spacing: 0.04em; text-align: right; }

/* Sans ça, badge + nom + 6 valeurs de stats sur une seule ligne nowrap écrasaient le nom du joueur
   à quelques pixels de large dans le cadre étroit de create-listing.php (.card, max-width:520px).
   :has() cible PRÉCISÉMENT les .match-member-row qui contiennent cette grille de stats embarquée
   (uniquement le joueur sélectionné du sélecteur "recherche_club") — les bannières club classiques
   ailleurs sur le site (listing.php, manage-club.php) restent en nowrap comme avant. */
.match-member-row:has(.player-picker-stats) { flex-wrap: wrap; row-gap: 10px; }
.match-member-row:has(.player-picker-stats) .player-picker-stats { justify-content: flex-end; }

/* Place vide pas encore rejointe, vue par un club qui n'a pas encore rejoint (pas le créateur) :
   le survol indique que c'est cliquable, le clic révèle le formulaire d'effectif juste en
   dessous (voir .match-join-prompt / .match-join-form et assets/js/listing.js). */
.match-member-row.is-joinable { cursor: pointer; transition: border-color 0.15s ease, background 0.15s ease;}
.match-member-row.is-joinable:active { border-color: #AAAAAA; background: rgba(52, 211, 153, 0.06); }

@media (hover: hover) {
    .match-member-row.is-joinable:hover { border-color: #AAAAAA; background: rgba(52, 211, 153, 0.06); }
}

.match-join-prompt {
    display: flex;
    align-items: center;
    gap: 16px;
    width: 100%;
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.match-join-form { display: none; width: 100%; }
.match-member-row.is-revealed .match-join-form { display: block; }
.match-member-row.is-revealed .match-join-prompt { display: none; }

.match-join-form-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.match-join-form-row label { margin: 0; white-space: nowrap; }
.match-join-form-row select { width: auto; flex: 1; min-width: 90px; }
.match-join-form-row .btn { flex-shrink: 0; }

/* Pastille "Prêt"/"Pas prêt" en haut à droite de chaque ligne membre — visible réciproquement
   dès que les deux places sont occupées, avant même la révélation des noms. "Pas prêt" ne se
   produit en pratique que sur la ligne du créateur (le joiner est toujours déjà prêt dès qu'il
   rejoint, effectif+prêt étant atomiques côté serveur — voir "Flux Prêt" dans PROJECT.md) : ce
   style rouge, plus appuyé qu'un badge neutre, est une invite adressée au créateur à cliquer
   plus bas, pas un simple statut passif.  */
/* Ruban de coin, plaqué contre le coin haut-droit de la ligne (comme un tag "SALE") plutôt
   qu'une pastille flottante — angle extérieur arrondi comme la carte, angle intérieur en pointe. */
.ready-badge {
    position: absolute;
    top: 0;
    right: 0;
    padding: 6px 20px;
    font-size: 0.7rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    background: #282D31;
    border-top: 0;
    border-right: 0;
    color: #ffffff;
}

.ready-badge.is-ready { background: var(--green); border-color: var(--green); color: #06231a; }

/* Bandeau d'action sous les membres (#match-cta) : ACCEPTER (créateur, cliquable) ou "C'est
   parti !" une fois les deux prêts (affichage seul, voir .match-cta-static — la prolongation
   manuelle est en pause, voir PROJECT.md) — les deux réutilisent .btn.btn-ready.btn-block. */
#match-cta:empty { display: none; }
/* Calque de composition dédié : les lignes .match-member-row juste au-dessus utilisent
   mix-blend-mode + isolation + un ::before en z-index négatif (blason en fond) — combinaison qui
   pouvait faire "oublier" à Chromium de repeindre #match-cta après une reconstruction JS
   (renderMatchCta()) tant qu'aucun repaint n'était forcé par ailleurs (ex: survol d'une ligne
   au-dessus) : le bouton ACCEPTER/bandeau restait invisible bien que présent et correct dans le
   DOM (display/opacity/z-index tous corrects à l'inspection). */
#match-cta { isolation: isolate; transform: translateZ(0); margin-top: 20px;}
.match-cta-static { cursor: default; pointer-events: none; background-color: rgba(255,255,255,0.3); border: 2px #ffffff; border-radius: 0;}

/* ----- Colonne stats (listing.php) : "Statistique de mon club" / "Statistiques équipes
   adverse", réutilise .card + .stat-grid (voir render_club_stat_panel() dans helpers.php) ----- */

.stat-panel-title { font-size: 1rem; margin-bottom: 14px; }

.stat-panel-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 4px;
}

.stat-panel-head-opponent { margin-top: 10px; }

.stat-panel-head strong { flex: 1; font-size: 1rem; }
.stat-panel-head .division-badge,
.stat-panel-head .division-badge-img { flex-shrink: 0; }

/* ----- Bandeau messages flash ----- */

.flash {
    padding: 12px 16px;
    border-radius: var(--radius-sm);
    margin-bottom: 20px;
    font-size: 0.92rem;
}

.flash-success { background: rgba(52, 211, 153, 0.12); border: 1px solid var(--green); color: var(--green); }
.flash-error { background: rgba(239, 71, 111, 0.12); border: 1px solid var(--danger); color: var(--danger); }
.flash-info { background: rgba(58, 134, 255, 0.12); border: 1px solid var(--accent-2); color: var(--accent-2); }

/* ----- Créateur de statistiques du pro (builder.php) -----
   Inspiré du design de bray.tech (page personnage/équipement + clubsbuilder.com, analysés en
   direct le 2026-07-21, voir debug/PROJECT.md) : sidebar sticky des archétypes groupés par poste
   (façon clubsbuilder.com), blocs ".b-section" façon "bucket" (titre + trait de séparation, même
   schéma partout — voir _section_d8fat_1 chez bray.tech), liste de stats façon "Puissance" (nom +
   barre dégradée + valeur + delta coloré). Boutons +/- dans le même langage visuel que .btn
   (anneau au survol/clic) mais en version compacte. */

.builder {
    display: grid;
    grid-template-columns: 240px 1fr;
    gap: 24px;
    align-items: start;
}

.builder-main { display: flex; flex-direction: column; gap: 4vh; }

.b-section {
    background: var(--bg-elevated);
    border: 0px solid var(--border);
}

.b-section h3 {
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    margin: 0 0 14px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--border);
}

/* Sections pas encore développées (PlayStyles/Spécialisations/Facilities) : même habillage
   "bucket", contenu centré en attendant les règles/données réelles. */
.b-bucket-empty .form-hint { text-align: center; margin: 4px 0 0; }

/* Sidebar sticky des archétypes (clubsbuilder.com : tout visible d'un coup, groupé par poste —
   un seul clic fixe poste + archétype ensemble, plus besoin d'un premier choix de poste séparé). */
.b-sidebar {
    position: sticky;
    top: 20px;
    display: flex;
    flex-direction: column;
    gap: 20px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    padding: 18px 16px;
    max-height: calc(100vh - 40px);
    overflow-y: auto;
}

.b-sidebar-group-title {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    margin: 0 0 8px;
}

.b-arch-btn {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    background: rgba(255, 255, 255, 0.05);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
    color: var(--text-muted);
    border: none;
    padding: 8px 10px;
    margin-bottom: 4px;
    font-size: 0.8rem;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
    transition: color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
}

.b-arch-icon { width: 22px; height: 22px; flex-shrink: 0; opacity: 0.8; }

.b-arch-btn:active { color: var(--text); background: rgba(255, 255, 255, 0.09); }
.b-arch-btn.is-active { color: var(--green); background: rgba(52, 211, 153, 0.14); box-shadow: inset 0 0 0 1px var(--green); }
.b-arch-btn.is-active .b-arch-icon { opacity: 1; }

@media (hover: hover) {
    .b-arch-btn:hover { color: var(--text); background: rgba(255, 255, 255, 0.09); }
}

/* Niveau + points à répartir + note globale sur une même ligne, en haut de page (demande
   explicite de l'utilisateur : "Body en haut, AP restant aussi, lvl aussi"). */
.b-level-row { display: flex; align-items: flex-end; gap: 20px; flex-wrap: wrap; }

.b-ap-box { text-align: center; }
.b-ap-box-label { display: block; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); margin-bottom: 4px; }
.b-ap-box-value { font-size: 1.3rem; font-weight: 800; }
.b-overall { color: var(--gold); }

.b-sliders { display: flex; flex-direction: column; gap: 16px; }
.b-slider-row { display: flex; flex-direction: column; gap: 8px; }
.b-slider-label { display: flex; justify-content: space-between; font-size: 0.85rem; color: var(--text-muted); }
.b-slider-label strong { color: var(--text); }

.b-slider-row input[type="range"] {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 4px;
    background: rgba(255, 255, 255, 0.12);
    cursor: pointer;
}
.b-slider-row input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--green);
    cursor: pointer;
}
.b-slider-row input[type="range"]::-moz-range-thumb {
    width: 14px;
    height: 14px;
    border: none;
    border-radius: 50%;
    background: var(--green);
    cursor: pointer;
}

.b-stat-list { display: flex; flex-direction: column; gap: 10px; }

.b-stat-row {
    display: grid;
    grid-template-columns: 140px 1fr 32px 44px auto;
    align-items: center;
    gap: 12px;
    font-size: 0.85rem;
}

.b-stat-name { color: var(--text-muted); }

.b-stat-bar { height: 6px; background: rgba(255, 255, 255, 0.08); position: relative; }
/* Dégradé (repéré chez bray.tech, section "Puissance") plutôt qu'un aplat uni. */
.b-stat-bar-fill { position: absolute; inset: 0; background: linear-gradient(90deg, var(--green-strong), var(--green)); }

/* "Vitesse" (pace) : titre en travers sur le côté droit plutôt qu'au-dessus — repéré chez
   bray.tech (_header_d8fat_7) pour les catégories secondaires à peu de stats. */
.b-section-rotated { display: flex; align-items: stretch; gap: 16px; }
.b-section-rotated .b-stat-list { flex: 1; }
.b-rotated-title {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    white-space: nowrap;
    margin: 0;
    padding: 0 0 0 14px;
    border-bottom: none;
    border-left: 1px solid var(--border);
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}

.b-stat-value { font-weight: 700; text-align: right; }

.b-stat-delta { font-size: 0.75rem; font-weight: 700; text-align: right; color: var(--text-muted); }
.b-stat-delta.is-positive { color: var(--green); }
.b-stat-delta.is-negative { color: var(--danger); }

.b-stat-controls { display: flex; gap: 4px; }

.b-stat-btn {
    width: 22px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.06);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
    color: var(--text);
    border: none;
    font-size: 0.9rem;
    line-height: 1;
    cursor: pointer;
    transition: color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
}
.b-stat-btn:active:not(:disabled) { background: rgba(255, 255, 255, 0.14); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4); }
.b-stat-btn:disabled { opacity: 0.3; cursor: not-allowed; }

@media (hover: hover) {
    .b-stat-btn:hover:not(:disabled) { background: rgba(255, 255, 255, 0.14); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4); }
}

/* ----- Responsive mobile ----- */

/* En dessous de ~1024px de large d'écran, 4 colonnes rendent chaque carte trop étroite pour son
   .player-card-head (métrique + nom/poste côte à côte) : le contenu se superpose au lieu de
   déborder proprement (observé autour de 975px). On réduit à 3 colonnes AVANT le palier 900px
   (qui, lui, passe carrément à 2) pour donner à chaque carte plus de place avant que ça arrive. */
@media (max-width: 1024px) {
    .leaderboard-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
    .listing-layout { grid-template-columns: 1fr; }
    .builder { grid-template-columns: 1fr; }
    .b-sidebar { position: static; max-height: none; }
    .leaderboard-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 640px) {
    /* Le passage menu <-> burger est maintenant piloté par .site-header.is-compact (mesure JS
       réelle, voir assets/js/header-nav.js et .site-header .containeur plus haut), plus par ce
       seuil fixe — seul l'espacement propre à ce gabarit reste ici. */
    .site-header.is-compact .containeur { margin-top: 2vh; }
    .hero { padding: 40px 0 28px; }
    .hero-title { font-size: 1.5rem; }
    .match-member-row { flex-wrap: wrap; }
    .filters-row { margin-top: 1vh; }
    /* Seul MOM disparaît en mobile (demande explicite) — le reste de la ligne (adversaire, temps,
       type, score) reste visible, voir .match-history-row dans le bloc "Gérer club" plus haut. */
    .match-history-mom { display: none; }
    .leaderboard-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
    .player-card { padding: 10px; }
    .player-card-metric { font-size: 1.3rem; }
    .player-card-metric-decimal { font-size: 0.85rem; }
    /* Le nombre de colonnes de filtres/valeurs s'adapte déjà dynamiquement à la largeur réelle
       (mesure JS, voir assets/js/leaderboard-jury.js). --jury-label-col resserrée ICI (variable
       partagée, voir :root) suffit à réduire À LA FOIS .leaderboard-jury-title-spacer ET
       .leaderboard-jury-info sans jamais les désynchroniser (l'alignement des colonnes en dépend). */
    :root { --jury-label-col: 130px; }
    .leaderboard-jury-info { padding: 10px 6px; }
    .leaderboard-jury-info .player-card-name { max-width: 110px; }
    .leaderboard-jury-cell { font-size: 0.75rem; }
    .b-stat-row { grid-template-columns: 90px 1fr 28px 36px auto; gap: 8px; font-size: 0.78rem; }
    /* Texte pivoté peu lisible sur petit écran : repli sur le même schéma titre-au-dessus que les
       autres catégories. */
    .b-section-rotated { flex-direction: column; }
    .b-rotated-title { writing-mode: horizontal-tb; transform: none; border-left: none; border-bottom: 1px solid var(--border); padding: 0 0 12px; margin-bottom: 14px; order: -1; }
    .match-member-row.is-club-summary .club-badge { display: none; }
    .division-badge-img{width: 50px;height: 50px;}
}
