/* =====================================================================
   Magelan Billetterie — feuille de style unique (public + backoffice).
   Bleu Magelan #0b4f9e. Mobile d'abord : la majorité des billets se
   prennent au téléphone, souvent dans les minutes qui suivent l'ouverture
   des ventes.
   ===================================================================== */

/* ── Palette ──────────────────────────────────────────────────────────────────
   Deux familles à ne pas confondre, c'est ce qui rend le thème sombre possible :

   • les couleurs de REMPLISSAGE (--bleu, --rouge…) portent du texte blanc :
     bandeau, bouton principal, jauge. Elles restent soutenues dans les deux thèmes.
   • les couleurs d'ACCENT (--bleu-accent…) sont du TEXTE posé sur un aplat teinté
     (--bleu-clair…) : étiquettes, alertes, liens, plan du stade. En thème sombre,
     l'aplat devient foncé et l'accent doit donc s'ÉCLAIRCIR.

   Confondre les deux donnerait, en sombre, soit des boutons bleu pâle à texte
   blanc, soit des liens bleu marine sur fond nuit — illisibles dans les deux cas. */
:root {
    color-scheme: light;

    /* Remplissages (texte blanc par-dessus) */
    --bleu: #0b4f9e;
    --bleu-fonce: #083a75;

    /* Accents : texte/trait sur aplat teinté */
    --bleu-accent: #0b4f9e;
    --vert: #15803d;
    --rouge: #b91c1c;
    --orange: #b45309;

    /* Aplats teintés */
    --bleu-clair: #e8f0fa;
    --vert-clair: #dcfce7;
    --rouge-clair: #fee2e2;
    --orange-clair: #fef3c7;

    /* Neutres */
    --texte: #1f2937;
    --gris: #6b7280;
    --gris-clair: #f3f4f6;
    --bordure: #e5e7eb;
    --bordure-forte: #d1d5db;

    /* Surfaces */
    --fond: #f8fafc;
    --surface: #fff;
    --surface-alt: var(--gris-clair);
    --topbar: var(--bleu);
    --topbar-admin: #1f2937;
    --ombre-lien: rgba(11, 79, 158, .08);

    /* Terrain du plan du stade */
    --pelouse: #e7f3ea;
    --pelouse-trait: #b9d8c2;
    --but: #94b8a1;
    --horsvente: #fafafa;
    --horsvente-texte: #9ca3af;

    /* ⚠️ Plaque BLANCHE sous les écussons et les QR. Transparente en thème clair (invisible sur
       une carte blanche), elle devient un vrai fond blanc en sombre — voir le bloc de fin. */
    --plaque: transparent;

    --rayon: 10px;
}

* { box-sizing: border-box; }

/* ⚠️ La couleur de fond est portée par `html`, PAS par `body`. Le filigrane du club est un calque
   fixe posé en `body::before` avec `z-index: -1` : si `body` avait lui-même un fond, ce calque
   passerait DERRIÈRE et resterait invisible — sans erreur, sans message, juste rien à l'écran.
   Cf. le bloc « filigrane » en fin de fichier. */
html { background: var(--fond); }

body {
    margin: 0;
    font-family: "Segoe UI", Roboto, Arial, sans-serif;
    color: var(--texte);
    background: transparent;
    line-height: 1.5;
}

a { color: var(--bleu-accent); }

/* ── En-tête ── */

.topbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 20px;
    background: var(--topbar);
    color: #fff;
}

.topbar-admin { background: var(--topbar-admin); }

.marque {
    display: flex;
    align-items: center;
    gap: 10px;
    color: #fff;
    text-decoration: none;
}

.marque-pastille {
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    border-radius: 9px;
    background: rgba(255, 255, 255, .15);
    font-size: 19px;
}

.marque b { display: block; font-size: 16px; }
.marque small { display: block; font-size: 12px; opacity: .8; }

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

.nav a { color: #fff; text-decoration: none; font-size: 15px; }
.nav a:hover { text-decoration: underline; }
.nav .agent { font-size: 13px; opacity: .8; }
/* Sélecteur de langue (FR · NL · EN · RO) : la langue affichée en gras, les autres en liens. */
.lang { display: inline-flex; align-items: center; gap: 2px; font-size: 13px; letter-spacing: .03em; }
.lang a, .lang span { padding: 3px 6px; border-radius: 4px; color: #fff; text-decoration: none; opacity: .7; }
.lang a:hover { opacity: 1; text-decoration: underline; }
.lang .on { opacity: 1; font-weight: 700; background: rgba(255, 255, 255, .16); }
.enligne { display: inline; margin: 0; }

/* ── Structure ── */

.page {
    max-width: 880px;
    margin: 0 auto;
    padding: 26px 18px 60px;
}

.page-large { max-width: 1200px; }

.pied {
    padding: 22px;
    text-align: center;
    color: var(--gris);
    font-size: 13px;
    border-top: 1px solid var(--bordure);
}

h1 { font-size: 26px; margin: 0 0 6px; }
h2 { font-size: 19px; margin: 30px 0 12px; }
h3 { font-size: 16px; margin: 20px 0 8px; }
.sous-titre { color: var(--gris); margin: 0 0 24px; }

/* ── Cartes ── */

.carte {
    background: var(--surface);
    border: 1px solid var(--bordure);
    border-radius: var(--rayon);
    padding: 18px;
    margin-bottom: 14px;
}

.carte-lien { text-decoration: none; color: inherit; display: block; }
.carte-lien:hover { border-color: var(--bleu-accent); box-shadow: 0 2px 10px var(--ombre-lien); }

.grille { display: grid; gap: 14px; }
.grille-2 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.grille-3 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

/* ── Rencontre ── */

.rencontre-entete { display: flex; flex-wrap: wrap; gap: 14px; align-items: baseline; justify-content: space-between; }
.rencontre-titre { font-size: 20px; font-weight: 700; margin: 0; }

/* ── Plan du stade ───────────────────────────────────────────────────────────
   Le SVG porte un viewBox et aucune dimension fixe : il occupe la largeur
   disponible et se met à l'échelle seul, du téléphone au grand écran. */
.plan-stade { margin: 0 0 18px; }
.plan-svg { width: 100%; height: auto; display: block; }

.plan-terrain { fill: var(--pelouse); stroke: var(--pelouse-trait); stroke-width: 2; }
.plan-ligne { stroke: var(--pelouse-trait); stroke-width: 2; fill: none; }
/* Les buts, aux deux bouts du terrain : ils disent l'orientation du jeu, donc
   quelle tribune est derrière un but et lesquelles bordent la touche. */
.plan-but { fill: var(--but); }

.plan-bloc :is(rect, polygon) { stroke-width: 2; transition: filter .12s ease; }
/* Tailles calées sur le TÉLÉPHONE, pas sur l'écran large. Le SVG se met à
   l'échelle du viewBox (920 de large) : sur un écran de 390 px, la carte laisse
   ~342 px utiles, soit un facteur 0,37. Du texte à 22 px y arriverait à 8 px, et
   le libellé des Business seats à 6 px — illisible là où se prennent la plupart
   des billets. Ces valeurs paraissent grosses au repos ; elles sont justes une
   fois réduites. */
.plan-bloc text {
    text-anchor: middle; dominant-baseline: central;
    font-size: 30px; font-weight: 700; pointer-events: none;
}
/* Libellés longs (BUSINESS SEATS, VISITEURS) : plus petits que les codes de
   bloc, mais pas au point de disparaître au téléphone. */
.plan-libelle-long text { font-size: 22px; }

.plan-dispo :is(rect, polygon) { fill: var(--bleu-clair); stroke: var(--bleu-accent); }
.plan-dispo text { fill: var(--bleu-accent); }
.plan-complet :is(rect, polygon) { fill: var(--surface-alt); stroke: var(--bordure-forte); }
.plan-complet text { fill: var(--gris); }
.plan-visiteur :is(rect, polygon) { fill: var(--orange-clair); stroke: var(--orange); }
.plan-visiteur text { fill: var(--orange); }
.plan-horsvente :is(rect, polygon) { fill: var(--horsvente); stroke: var(--bordure); }
.plan-horsvente text { fill: var(--horsvente-texte); }

/* Retour visuel au survol ET au focus clavier : le plan est une vraie voie de
   navigation, pas une image décorative. */
a.plan-bloc { cursor: pointer; }
a.plan-bloc:hover :is(rect, polygon) { filter: brightness(.94); }
a.plan-bloc:focus-visible :is(rect, polygon) { outline: 3px solid var(--bleu-accent); outline-offset: 2px; }

.plan-tribune { text-anchor: middle; font-size: 19px; font-weight: 700; fill: var(--gris); letter-spacing: .08em; }
/* Téléphone : le plan est réduit à l'écran, et d'autant plus que le stade a de tribunes — un plan à
   quatre tribunes (repère de 1100) tombe à ×0,31 sur 375 px, et les noms à 5,9 px : illisibles.
   24 unités donnent ~7,4 px à quatre tribunes, ~8,9 px sur le plan du 00001.
   ⚠️ PAS 28 : essayé et REGARDÉ sur téléphone — le nom du BAS est posé à y 494, ses lettres montaient
   au-dessus de y 470 et touchaient la ligne de fond du terrain (même cas sur le plan du 00001). À 24,
   le haut des lettres reste sous le terrain. */
@media (max-width: 620px) {
    .plan-tribune { font-size: 24px; }
}

.plan-legende { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; margin: 10px 0 0; font-size: 13px; color: var(--gris); }
.plan-cle { width: 14px; height: 14px; border-radius: 3px; display: inline-block; border: 2px solid; vertical-align: -2px; }
.plan-legende .plan-dispo { background: var(--bleu-clair); border-color: var(--bleu-accent); }
.plan-legende .plan-complet { background: var(--surface-alt); border-color: var(--bordure-forte); }
.plan-legende .plan-visiteur { background: var(--orange-clair); border-color: var(--orange); }
.plan-legende .plan-horsvente { background: var(--horsvente); border-color: var(--bordure); }

/* ── Choix des sièges d'un bloc numéroté (Pages/Shared/_ChoixSieges) ──
   Trois états seulement, lisibles sans la couleur : libre = contour, choisi = plein,
   occupé = grisé sans contour. Le PMR se distingue par un contour en pointillés. */
.sieges-outils { display: flex; flex-wrap: wrap; align-items: end; gap: 10px 16px; margin-bottom: 8px; }
.sieges-nombre { display: flex; align-items: center; gap: 8px; margin: 0; }
.sieges-nombre select { width: auto; margin: 0; }
.sieges-legende { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; margin: 6px 0 10px; font-size: 13px; color: var(--gris); }
.siege-cle { width: 16px; height: 16px; border-radius: 4px; display: inline-block; border: 2px solid; vertical-align: -3px; }
.siege-cle.siege-libre { background: var(--surface); border-color: var(--bleu-accent); }
.siege-cle.siege-choisi { background: var(--bleu); border-color: var(--bleu); }
.siege-cle.siege-pris { background: var(--surface-alt); border-color: var(--surface-alt); }
.siege-cle.siege-pmr { border-style: dashed; }

.sieges-defil { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* Une largeur plancher PAR SIÈGE : au-dessous, le plan défile dans sa carte plutôt que de
   rétrécir. 18 px tiennent un secteur de 40 sièges dans la colonne de 880 px du site ; au
   téléphone on monte à 24 px, la taille d'un doigt, et le plan défile. */
#plan-sieges { width: 100%; height: auto; display: block; min-width: calc(var(--sieges-colonnes, 20) * 18px + 50px); }
@media (max-width: 620px) {
    #plan-sieges { min-width: calc(var(--sieges-colonnes, 20) * 24px + 60px); }
}
.sieges-terrain { fill: var(--pelouse); stroke: var(--pelouse-trait); stroke-width: 2; }
.sieges-terrain-txt { text-anchor: middle; dominant-baseline: central; font-size: 16px; font-weight: 700; letter-spacing: .3em; fill: var(--pelouse-texte, var(--gris)); }
.sieges-rang { text-anchor: middle; dominant-baseline: central; font-size: 12px; font-weight: 700; fill: var(--gris); }

.siege rect { stroke-width: 2; }
.siege text { text-anchor: middle; dominant-baseline: central; font-size: 10px; font-weight: 600; pointer-events: none; }
.siege-libre { cursor: pointer; }
.siege-libre rect { fill: var(--surface); stroke: var(--bleu-accent); }
.siege-libre text { fill: var(--bleu-accent); }
.siege-libre:hover rect { fill: var(--bleu-clair); }
.siege-libre:focus-visible { outline: none; }
.siege-libre:focus-visible rect { stroke-width: 4; }
.siege-pmr rect { stroke-dasharray: 4 3; }
.siege.siege-choisi rect { fill: var(--bleu); stroke: var(--bleu); }
.siege.siege-choisi text { fill: #fff; }
.siege-pris rect { fill: var(--surface-alt); stroke: none; }
.siege-pris text { fill: var(--bordure-forte); }

.place-siege { align-items: end; }
.place-siege + .place-siege { border-top: 1px solid var(--bordure); margin-top: 14px; padding-top: 6px; }
.place-siege-libelle { display: flex; align-items: center; gap: 8px; min-height: 38px; }
.place-siege-retirer { flex: 0 0 auto; }
.sieges-total { margin-right: auto; font-size: 16px; }

/* Bloc « logos + intitulé » d'une rencontre. Les logos sont alignés sur le CENTRE et non sur la
   ligne de base : un écusson n'a pas de ligne de base, s'y accrocher le décale vers le haut. */
.rencontre-ident { display: flex; align-items: center; gap: 12px; }
/* Un CADRE, jamais une taille imposée : les logos des clubs vont du carré au format bannière.
   object-fit évite l'étirement, et la hauteur fixe garde les cartes alignées entre elles. */
/* ⚠️ Plaque sous l'écusson. Les logos de la fédération sont des JPEG à FOND BLANC, sans
   transparence : posés tels quels sur une carte sombre, ils affichent un carré blanc qui a l'air
   d'une image cassée. La plaque (transparente en clair, blanche en sombre) transforme ce défaut en
   parti pris — même raisonnement que sur le billet PDF. */
.logo-club {
    width: 48px; height: 48px; object-fit: contain; flex: 0 0 auto;
    background: var(--plaque); border-radius: 6px; padding: 2px;
}
@media (max-width: 480px) { .logo-club { width: 36px; height: 36px; } }
.rencontre-date { color: var(--gris); font-size: 14px; }
.rencontre-compet { font-size: 12px; text-transform: uppercase; letter-spacing: .04em; color: var(--gris); }

/* ── Blocs ── */

.bloc-ligne {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
    justify-content: space-between;
    padding: 14px 0;
    border-bottom: 1px solid var(--bordure);
}

.bloc-ligne:last-child { border-bottom: 0; }

.bloc-code {
    display: inline-grid;
    place-items: center;
    min-width: 48px;
    height: 48px;
    padding: 0 8px;
    border-radius: 9px;
    background: var(--bleu-clair);
    color: var(--bleu-accent);
    font-size: 19px;
    font-weight: 700;
}

.bloc-complet .bloc-code { background: var(--gris-clair); color: var(--gris); }
.bloc-nom { font-weight: 600; }
.bloc-info { color: var(--gris); font-size: 13px; }

/* ── Étiquettes ── */

.etiq {
    display: inline-block;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    background: var(--gris-clair);
    color: var(--gris);
}

.etiq-vert { background: var(--vert-clair); color: var(--vert); }
.etiq-rouge { background: var(--rouge-clair); color: var(--rouge); }
.etiq-orange { background: var(--orange-clair); color: var(--orange); }
.etiq-bleu { background: var(--bleu-clair); color: var(--bleu-accent); }

/* ── Formulaires ── */

label { display: block; font-size: 14px; font-weight: 600; margin: 14px 0 5px; }
.aide { font-weight: 400; color: var(--gris); font-size: 13px; }

/* ⚠️⚠️ LA LISTE DOIT COUVRIR TOUS LES TYPES EMPLOYES DANS LES PAGES. Un type absent d'ici ne
   « perd » pas un peu de style : il retombe entierement sur le rendu par defaut du navigateur —
   largeur d'une vingtaine de caracteres, bordure creusee, police du systeme. Il ne ressemble alors
   a AUCUN autre champ de la page, et cela se voit immediatement.
   ⭐ `tel` et `url` manquaient. Le telephone de la CREATION DE COMPTE et celui du PROFIL etaient
   donc mal rendus depuis le premier jour ; c'est le formulaire d'inscription au repas qui l'a
   rendu visible, en le posant a cote de deux champs corrects.
   ⚠️ `file` reste volontairement dehors : son widget est fourni par le navigateur et ne se
   restyle pas de cette facon. */
input[type=text], input[type=email], input[type=password], input[type=date],
input[type=number], input[type=datetime-local], input[type=tel], input[type=url],
select, textarea {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--bordure);
    border-radius: 8px;
    font: inherit;
    background: var(--surface);
    color: inherit;
}

input:focus, select:focus, textarea:focus { outline: 2px solid var(--bleu-accent); outline-offset: -1px; }

.champ-etroit { max-width: 200px; }
.ligne-champs { display: grid; gap: 0 14px; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

.case { display: flex; align-items: center; gap: 8px; font-weight: 400; margin: 12px 0; }
.case input { width: auto; }

/* ── Boutons ── */

.btn {
    display: inline-block;
    padding: 10px 18px;
    border: 1px solid transparent;
    border-radius: 8px;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    background: var(--gris-clair);
    color: var(--texte);
}

.btn:hover { filter: brightness(.97); }
.btn-principal { background: var(--bleu); color: #fff; }
.btn-danger { background: var(--rouge-clair); color: var(--rouge); }
.btn-fantome { background: transparent; color: #fff; border-color: rgba(255, 255, 255, .4); }
.btn-petit { padding: 6px 12px; font-size: 13px; }
.btn[disabled] { opacity: .5; cursor: not-allowed; }
.barre-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 22px; align-items: center; }

/* Marqueur de version au pied du backoffice : présent, discret, jamais au milieu du chemin. */
.pied-version { display: block; margin-top: 4px; font-size: 12px; opacity: .75; }

/* ── Liste « À faire » du tableau de bord ──
   Chaque ligne porte le lien vers l'écran qui la règle : une liste de reproches sans chemin pour les
   lever finit par ne plus être lue. Le lien est poussé à DROITE pour que les boutons s'alignent en
   colonne — l'œil les trouve alors sans relire les phrases. */
.liste-afaire { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.liste-afaire li { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
/* ⚠️ Le bouton est posé sur l'aplat AMBRE de l'alerte : son fond gris par défaut y disparaîtrait à
   moitié. On lui donne un fond opaque et un bord, dans les deux thèmes. */
.liste-afaire .btn {
    background: var(--surface);
    color: var(--texte);
    border-color: var(--bordure-forte);
    white-space: nowrap;
}

/* ── Alertes ── */

.alerte {
    padding: 12px 16px;
    border-radius: 8px;
    margin-bottom: 18px;
    font-size: 15px;
}

.alerte-ok { background: var(--vert-clair); color: var(--vert); }
.alerte-ko { background: var(--rouge-clair); color: var(--rouge); }
.alerte-info { background: var(--bleu-clair); color: var(--bleu-accent); }
.alerte-attention { background: var(--orange-clair); color: var(--orange); }

/* ── Tableaux ── */

.tableau-boite { overflow-x: auto; }

table.tableau {
    width: 100%;
    border-collapse: collapse;
    background: var(--surface);
    font-size: 14px;
}

table.tableau th, table.tableau td {
    padding: 10px 12px;
    border-bottom: 1px solid var(--bordure);
    text-align: left;
    vertical-align: middle;
}

table.tableau th { background: var(--gris-clair); font-size: 13px; }
table.tableau td.nombre, table.tableau th.nombre { text-align: right; }
/* Un montant en second rang dans une colonne chiffrée ne doit PAS se couper : « 492,00 » d'un côté
   et « € » de l'autre se lit comme deux valeurs. */
table.tableau td.nombre .bloc-info { white-space: nowrap; }
table.tableau tr.inactif td { opacity: .55; }

/* ── Jauge de remplissage ── */

.jauge { height: 8px; border-radius: 999px; background: var(--gris-clair); overflow: hidden; min-width: 90px; }
.jauge span { display: block; height: 100%; background: var(--bleu); }
.jauge-pleine span { background: var(--rouge); }

/* ── Billets ── */

.billet {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    align-items: center;
    justify-content: space-between;
    border: 1px solid var(--bordure);
    border-left: 5px solid var(--bleu-accent);
    border-radius: var(--rayon);
    background: var(--surface);
    padding: 16px;
    margin-bottom: 12px;
}

/* ⚠️ Le QR reste NOIR SUR BLANC, dans les deux thèmes. Un QR inversé ou posé sur un fond sombre
   se scanne mal, et c'est le seul élément du billet qui doit fonctionner à coup sûr, un soir de
   match, sous la pluie, sur un téléphone à luminosité réduite. La plaque blanche est donc TOUJOURS
   présente ici — pas de var(--plaque). */
.billet-qr {
    width: 104px; height: 104px;
    background: #fff; border-radius: 8px; padding: 5px;
}
.billet-numero { font-family: Consolas, monospace; font-size: 12px; color: var(--gris); }

/* ── Divers ── */

.vide { text-align: center; color: var(--gris); padding: 40px 20px; }
.total { font-size: 20px; font-weight: 700; }
.compte-a-rebours { font-weight: 600; }

/* =====================================================================
   THÈME SOMBRE
   =====================================================================
   Trois déclencheurs, dans cet ordre de priorité :

   1. `@media (prefers-color-scheme: dark)` — le réglage du système. C'est le
      défaut : un visiteur qui a mis son téléphone en sombre obtient un site
      sombre sans rien demander.
   2. `[data-theme="sombre"]` — le choix explicite du visiteur, mémorisé dans le
      navigateur. Il DOIT gagner sur le système.
   3. `[data-theme="clair"]` — le choix inverse, qui doit lui aussi gagner : sans
      cette troisième règle, quelqu'un dont le système est en sombre ne pourrait
      JAMAIS revenir en clair. C'est l'oubli classique.

   Les valeurs vivent dans un seul jeu de variables, appliqué par les trois
   sélecteurs — aucune règle de mise en page n'est dupliquée ici.
   ===================================================================== */

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="clair"]) {
        color-scheme: dark;

        /* Remplissages : le bleu reste soutenu (il porte du texte blanc), mais on
           descend d'un cran — le bleu vif d'un bandeau plein écran éblouit la nuit. */
        --bleu: #1c5fb0;
        --bleu-fonce: #0d3f80;

        /* Accents : ÉCLAIRCIS. #0b4f9e sur fond nuit tomberait sous le seuil de lisibilité. */
        --bleu-accent: #7fb2f0;
        --vert: #6ee7a0;
        --rouge: #fca5a5;
        --orange: #fcd34d;

        /* Aplats teintés : la même teinte, mais assombrie au point de servir de fond. */
        --bleu-clair: #12294a;
        --vert-clair: #10291c;
        --rouge-clair: #3a1a1a;
        --orange-clair: #392c0e;

        --texte: #e5e7eb;
        --gris: #98a2b3;
        --gris-clair: #1e293b;
        --bordure: #2b3648;
        --bordure-forte: #3d4b63;

        --fond: #0f172a;
        --surface: #172033;
        --surface-alt: var(--gris-clair);
        --topbar: #0c2d55;
        --topbar-admin: #111827;
        --ombre-lien: rgba(0, 0, 0, .5);

        /* La pelouse reste VERTE — c'est ce qui rend le plan lisible d'un coup d'œil.
           Assombrie, pas désaturée : un terrain gris ne se reconnaît plus. */
        --pelouse: #15301f;
        --pelouse-trait: #2f5b3c;
        --but: #3f7a52;
        --horsvente: #141c2b;
        --horsvente-texte: #5b6478;

        --plaque: #fff;
    }

    /* Le survol du plan éclaircissait le bloc (brightness < 1) : sur fond sombre il faut
       l'inverse, sinon le retour visuel disparaît au moment où on en a besoin. */
    :root:not([data-theme="clair"]) a.plan-bloc:hover :is(rect, polygon) { filter: brightness(1.35); }
    :root:not([data-theme="clair"]) .btn:hover { filter: brightness(1.18); }
}

/* Choix explicite « sombre » — mêmes valeurs, priorité sur le système. */
:root[data-theme="sombre"] {
    color-scheme: dark;
    --bleu: #1c5fb0;
    --bleu-fonce: #0d3f80;
    --bleu-accent: #7fb2f0;
    --vert: #6ee7a0;
    --rouge: #fca5a5;
    --orange: #fcd34d;
    --bleu-clair: #12294a;
    --vert-clair: #10291c;
    --rouge-clair: #3a1a1a;
    --orange-clair: #392c0e;
    --texte: #e5e7eb;
    --gris: #98a2b3;
    --gris-clair: #1e293b;
    --bordure: #2b3648;
    --bordure-forte: #3d4b63;
    --fond: #0f172a;
    --surface: #172033;
    --surface-alt: var(--gris-clair);
    --topbar: #0c2d55;
    --topbar-admin: #111827;
    --ombre-lien: rgba(0, 0, 0, .5);
    --pelouse: #15301f;
    --pelouse-trait: #2f5b3c;
    --but: #3f7a52;
    --horsvente: #141c2b;
    --horsvente-texte: #5b6478;
    --plaque: #fff;
}

:root[data-theme="sombre"] a.plan-bloc:hover :is(rect, polygon) { filter: brightness(1.35); }
:root[data-theme="sombre"] .btn:hover { filter: brightness(1.18); }

/* ── Bouton de bascule ──────────────────────────────────────────────────────── */
.bascule-theme {
    display: inline-grid; place-items: center;
    width: 34px; height: 34px; padding: 0;
    border: 1px solid rgba(255, 255, 255, .35);
    border-radius: 9px;
    background: rgba(255, 255, 255, .12);
    color: #fff; font-size: 16px; line-height: 1; cursor: pointer;
}
.bascule-theme:hover { background: rgba(255, 255, 255, .22); }
/* Chaque thème ne montre QUE l'icône de la destination : on affiche où l'on va, pas où l'on est. */
.bascule-theme .vers-sombre { display: inline; }
.bascule-theme .vers-clair { display: none; }
:root[data-theme="sombre"] .bascule-theme .vers-sombre { display: none; }
:root[data-theme="sombre"] .bascule-theme .vers-clair { display: inline; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="clair"]) .bascule-theme .vers-sombre { display: none; }
    :root:not([data-theme="clair"]) .bascule-theme .vers-clair { display: inline; }
}

/* =====================================================================
   IDENTITÉ DU CLUB — bandeau et bannière d'accueil
   =====================================================================
   Le visuel est un PARAMÈTRE (`club.visuel`), pas un fichier codé en dur : la
   billetterie est prévue pour d'autres clubs, et un club sans image doit garder
   le site exactement tel qu'il est. Les règles ci-dessous ne s'appliquent donc
   qu'aux éléments que la vue n'écrit QUE si le paramètre est renseigné.

   ⚠️ Le visuel est un PNG/WebP à FOND TRANSPARENT (50,7 % des pixels du fichier
   d'origine). C'est ce qui lui permet de fonctionner dans les deux thèmes sans
   traitement séparé : la page se voit à travers, au lieu d'un pavé blanc posé sur
   un fond nuit.
   ===================================================================== */

/* ── Bandeau : le drapeau en TEXTURE, pas en image ────────────────────────────
   La barre fait ~62 px de haut. Une photo y serait un fragment illisible ; à
   faible opacité et ancrée à droite, elle donne une matière qui se remarque sans
   se regarder. Le texte du bandeau garde son contraste de 8:1 : le drapeau est
   posé DERRIÈRE la couleur, pas devant. */
.topbar {
    position: relative;
    isolation: isolate;      /* borne le z-index aux enfants du bandeau */
    overflow: hidden;
}

.topbar-visuel::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background-image: var(--visuel);
    background-repeat: no-repeat;
    background-position: right -30px center;
    background-size: auto 260%;
    opacity: .18;
    /* Fondu vers la gauche : le drapeau s'efface avant d'atteindre le nom du club,
       qui doit rester lisible sur l'aplat plein. */
    -webkit-mask-image: linear-gradient(to right, transparent 35%, #000 85%);
            mask-image: linear-gradient(to right, transparent 35%, #000 85%);
    pointer-events: none;
}

/* ── Bannière d'accueil ───────────────────────────────────────────────────────
   La composition du fichier tombe juste : zone vide à gauche, blason à droite.
   C'est littéralement une mise en page de bannière — le texte va donc à gauche,
   là où le visuel ne dessine rien, et rien ne se superpose. */
.banniere {
    position: relative;
    display: flex;
    align-items: center;
    min-height: 190px;
    margin: 0 0 26px;
    padding: 26px 30px;
    border-radius: var(--rayon);
    overflow: hidden;
    /* Fond SOMBRE dans les deux thèmes : c'est l'identité du club (noir et blanc),
       et cela garantit le contraste du texte blanc sans dépendre du thème actif. */
    background:
        linear-gradient(100deg, #0d1117 0%, #0d1117 42%, rgba(13, 17, 23, .72) 62%, rgba(13, 17, 23, .35) 100%),
        var(--visuel) right center / auto 118% no-repeat,
        #0d1117;
    color: #fff;
}

.banniere-texte { max-width: 62%; }
.banniere-sur {
    margin: 0 0 4px;
    font-size: 12px; letter-spacing: .12em; text-transform: uppercase;
    color: #ffd54a;                       /* le jaune du blason */
}
.banniere h1 { margin: 0; font-size: 30px; line-height: 1.15; }
.banniere-sous { margin: 8px 0 0; font-size: 15px; color: rgba(255, 255, 255, .82); }

.titre-calendrier { margin-top: 0; }

/* Téléphone : le drapeau passe en filigrane derrière le texte plutôt que de lui
   disputer une largeur qui n'existe pas. Sans cela, « Royal Olympic Club
   Charleroi » se casse en quatre lignes contre le blason. */
@media (max-width: 620px) {
    .banniere {
        min-height: 150px;
        padding: 20px;
        background:
            linear-gradient(180deg, rgba(13, 17, 23, .90) 0%, rgba(13, 17, 23, .78) 100%),
            var(--visuel-petit, var(--visuel)) right center / auto 130% no-repeat,
            #0d1117;
    }
    .banniere-texte { max-width: 100%; }
    .banniere h1 { font-size: 23px; }
}

/* ── Filigrane du blason ──────────────────────────────────────────────────────
   Le « fond » demandé : le blason du club, très effacé, FIXE (il ne défile pas
   avec la page — un filigrane qui glisse attire l'œil, c'est l'inverse du but).

   Trois précautions qui font la différence entre un filigrane et une gêne :

   • `z-index: -1` + fond de page porté par `html` (cf. plus haut). Sans ce
     déplacement, le calque serait masqué par le fond du `body`.
   • `pointer-events: none` : le calque couvre tout l'écran ; sans cela il
     intercepterait chaque clic de la page.
   • Ancré EN BAS À DROITE et débordant volontairement : sur écran large il
     occupe la marge vide à droite de la colonne de contenu (880 px centrés), là
     où il n'y a rien à lire. Il n'est jamais sous un prix ni sous le plan du stade.

   L'opacité diffère par thème : sur fond clair on perçoit le DESSIN sombre du
   blason, sur fond sombre ce sont ses aplats CLAIRS qui ressortent. La même image
   sert aux deux, il n'y a qu'à doser. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-image: var(--filigrane);
    background-repeat: no-repeat;
    background-position: right -4vw bottom -6vh;
    background-size: min(56vw, 520px) auto;
    opacity: var(--filigrane-opacite, .05);
}

/* Sans visuel déclaré, aucune règle ne s'applique : `var(--filigrane)` est vide,
   `background-image` reste `none`, et le calque ne coûte rien. */

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="clair"]) { --filigrane-opacite: .07; }
}
:root[data-theme="sombre"] { --filigrane-opacite: .07; }
:root[data-theme="clair"]  { --filigrane-opacite: .05; }

/* Téléphone : plus petit et remonté dans le coin, pour ne pas se retrouver
   derrière la barre de boutons du bas de page. */
@media (max-width: 620px) {
    body::before {
        background-position: right -12vw bottom -2vh;
        background-size: 78vw auto;
    }
}

/* Impression : aucun filigrane. Une page imprimée sert à être lue ou classée, et
   l'encre d'un aplat de 520 px n'y apporte rien. */
@media print {
    body::before { display: none; }
}

/* Code de corrélation de la page d'erreur : lisible et sélectionnable d'un double-clic, sans crier.
   `user-select: all` évite la faute de recopie — un caractère de travers renvoie vers rien. */
.code-erreur { margin-top: 14px; font-size: 14px; color: var(--gris); }
.code-erreur b {
    font-family: Consolas, "Courier New", monospace;
    font-size: 17px; letter-spacing: .12em; color: var(--texte);
    user-select: all; padding: 2px 8px; border-radius: 6px;
    background: var(--gris-clair); border: 1px solid var(--bordure-forte);
}

/* ── Encart du club en tête des abonnements ──
   Message libre tenu au back-office (paramètre « abonnement.message »). Un ENCART, pas une alerte :
   ce n'est ni une erreur ni un avertissement, c'est le club qui parle à ses supporters. Le filet
   bleu à gauche le distingue du corps de la page sans crier.
   ⚠️ Uniquement des variables de couleur : la page a un thème clair ET un thème sombre, une
      couleur écrite en dur y deviendrait illisible dans l'un des deux. */
.encart-abo {
    background: var(--surface-alt);
    border-left: 4px solid var(--bleu-accent);
    border-radius: 8px;
    padding: 14px 18px;
    margin: 0 0 20px;
    font-size: 15px;
    line-height: 1.55;
}

.encart-abo p { margin: 0 0 8px; }
.encart-abo p:last-child { margin-bottom: 0; }

/* ── Bandeau de chiffres (personnes inscrites, suivi des ventes) ──
   Un chiffre par tuile, avec sa légende SOUS lui : c'est ce qu'on lit en diagonale avant d'entrer
   dans les tableaux. La couleur ne décore pas, elle qualifie — vert « c'est acquis », orange « il
   reste à faire », rouge « ça bloque une vente ». Uniquement des variables : la page existe en
   clair ET en sombre. */
/* ⚠️ 170 px et pas 150 : sous cette largeur, les légendes (« e-mail confirmé — 67 % ») passent sur
   trois lignes ET il entre sept tuiles par rangée — la huitième se retrouve seule en dessous, ce
   qui se lit comme un oubli. À 170 px on obtient six colonnes : le suivi des ventes tient sur une
   rangée pleine, et les inscrits sur 6 + 2. */
.chiffres {
    display: grid;
    gap: 12px;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    margin-bottom: 14px;
}

.chiffre {
    background: var(--surface);
    border: 1px solid var(--bordure);
    border-radius: var(--rayon);
    padding: 14px 16px;
}

.chiffre b { display: block; font-size: 25px; line-height: 1.15; }
.chiffre span { display: block; color: var(--gris); font-size: 13px; margin-top: 2px; }
.chiffre-ok b { color: var(--vert); }
.chiffre-attention b { color: var(--orange); }
.chiffre-ko b { color: var(--rouge); }

/* ── Série jour par jour du suivi des ventes ──
   Des barres en CSS, pas une bibliothèque de graphiques : une page de backoffice qui charge un
   script tiers ne s'affiche plus le jour où le réseau du club filtre le CDN — et il n'y a ici rien
   de plus à montrer qu'une hauteur proportionnelle. Le tableau qui suit reste la source du chiffre ;
   la série n'est qu'un coup d'œil sur la forme de la période. */
.serie {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 120px;
    padding-top: 6px;
    overflow-x: auto;
}

.serie-barre { flex: 1 1 6px; min-width: 6px; display: flex; align-items: flex-end; height: 100%; }
.serie-barre i { display: block; width: 100%; background: var(--bleu); border-radius: 3px 3px 0 0; min-height: 2px; }
.serie-barre.serie-vide i { background: var(--bordure); }
.serie-legende { display: flex; justify-content: space-between; color: var(--gris); font-size: 12px; margin-top: 6px; }

/* ── Barre de filtres d'une liste ──
   Les champs sur une seule ligne qui se replie : sur un écran de guichet, un filtre qui prend six
   lignes repousse la liste hors de l'écran, et on ne voit plus ce qu'on filtre. */
.filtres { display: flex; flex-wrap: wrap; gap: 10px 14px; align-items: flex-end; }
.filtres label { margin: 0 0 4px; }
.filtres > div { flex: 1 1 170px; min-width: 150px; }
.filtres .filtres-actions { flex: 0 0 auto; display: flex; gap: 8px; }

/* Pagination : les deux flèches et le rang, sans numéroter cinquante pages. */
.pagination { display: flex; gap: 10px; align-items: center; justify-content: center; margin-top: 14px; color: var(--gris); font-size: 14px; }

/* Mention secondaire : la precision qu'on donne sans la mettre en avant. */
.discret { color: var(--gris); font-size: 13px; }

/* Le MENU du repas VIP.
   ⚠️⚠️ C'est un <pre> parce que le texte vient d'un DOCUMENT HTML aplati : ses retours a la ligne
   PORTENT le sens (« Entree : … » puis « Plat : … »), et un <p> les ecraserait tous. Mais un <pre>
   nu s'affiche en CHASSE FIXE : le menu prend alors l'air d'un bloc de code, ce qui est exactement
   l'inverse de l'effet voulu sur une carte de restaurant. On garde donc le pre pour les ruptures,
   et on lui rend la police du site. */
.menu {
    font-family: inherit;
    font-size: 15px;
    line-height: 1.55;
    white-space: pre-wrap;   /* les lignes longues se replient au lieu de deborder la carte */
    word-break: break-word;
    margin: 0;
    color: var(--texte);
}

/* Le lien « Reserver votre repas », sous la carte du match.
   ⚠️ Il vit HORS de la carte parce que celle-ci est deja un <a> : le HTML interdit d'imbriquer un
   lien dans un lien. Le style le recolle a la carte pour qu'ils se lisent d'un bloc. */
.bloc-rencontre { margin-bottom: 14px; }
.bloc-rencontre > .carte { margin-bottom: 0; }
.lien-repas {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin: -1px 0 0 0;               /* la bordure du haut se confond avec celle de la carte */
    padding: 9px 18px;
    border: 1px solid var(--bordure);
    border-top: 0;
    border-radius: 0 0 var(--rayon) var(--rayon);
    background: var(--gris-clair);
    color: var(--bleu-accent);
    font-weight: 600;
    font-size: 14px;
    text-decoration: none;
}
.lien-repas:hover { background: var(--surface); border-color: var(--bleu-accent); }
.lien-repas-prix { color: var(--gris); font-weight: 400; font-size: 13px; }

/* ═══ LE BANDEAU DU REPAS VIP — 10/09/2026 ════════════════════════════════════
   Demandé par Marcel : « une page plus animée, avec les logos et une image de repas VIP ».
   • Les photos du club (img/repas-vip* de son habillage _club-<site>) se relaient en fondu, avec
     un lent zoom ; sans elles, le dégradé, et le drapeau en filigrane si le club en a un.
   • Le bandeau porte SES couleurs : texte blanc sur un voile sombre, lisible en thème clair comme
     en thème sombre, et sur n'importe quelle photo.
   • Toutes les animations tombent sous prefers-reduced-motion. */
.repas-bandeau {
    position: relative; overflow: hidden; isolation: isolate;
    display: flex; align-items: flex-end; min-height: 270px;
    margin: 0 0 22px; border-radius: var(--rayon); color: #fff;
    background: linear-gradient(135deg, #0b4f9e 0%, #083a75 55%, #071a36 100%);
    box-shadow: 0 12px 32px rgba(8, 40, 90, .28);
    animation: repas-entree .7s ease-out both;
}
/* ═══ BANDEAU DE DÉMONSTRATION — 13/09/2026 ═══════════════════════════════════
   Sites rapid, stadium-be… (Billetterie:Demonstration). Couleurs FIXES, pas des jetons de thème :
   le bandeau doit rester le même, et visible, en clair comme en sombre. Ambre foncé + blanc =
   contraste 5,0:1. Il défile avec la page (pas collant) : il ne mange pas l'écran d'un téléphone. */
.bandeau-demo {
    background: #b45309;
    color: #fff;
    text-align: center;
    font-size: 14px;
    line-height: 1.4;
    padding: 8px 16px;
    border-bottom: 2px solid #78350f;
}
.bandeau-demo b { letter-spacing: .02em; text-transform: uppercase; }

/* Posée par la page SEULEMENT si l'habillage du club porte ce fichier (RepasInscription). */
.repas-bandeau-drapeau::before {
    content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
    background: url(/img/club-drapeau-480.webp) right -60px center / auto 140% no-repeat;
    opacity: .14;
}
/* Un reflet qui traverse le bandeau, lentement : le mouvement se voit sans distraire. */
.repas-bandeau::after {
    content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 45%; z-index: 1;
    pointer-events: none;
    background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .13), transparent);
    transform: translateX(-130%);
    animation: repas-reflet 7s ease-in-out 1.4s infinite;
}
.repas-bandeau-voile {
    position: absolute; inset: 0; z-index: 0;
    background: linear-gradient(180deg, rgba(4, 14, 32, .10) 0%, rgba(4, 14, 32, .55) 58%, rgba(4, 14, 32, .88) 100%);
}
/* Les photos, sous le voile : fondu enchaîné et lent zoom (le script alterne la classe « visible »). */
.repas-photos { position: absolute; inset: 0; z-index: 0; }
.repas-photo {
    position: absolute; inset: 0;
    background-position: center; background-size: cover; background-repeat: no-repeat;
    opacity: 0; transform: scale(1.03);
    transition: opacity 1.6s ease, transform 8s ease-out;
}
.repas-photo.visible { opacity: 1; transform: scale(1.12); }
.repas-bandeau-contenu { position: relative; z-index: 2; width: 100%; padding: 22px 26px 20px; }
.repas-bandeau h1 {
    color: #fff; font-size: 27px; line-height: 1.2; margin: 10px 0 4px;
    text-shadow: 0 2px 10px rgba(0, 0, 0, .45);
}
.repas-quand { margin: 0; color: rgba(255, 255, 255, .88); font-size: 15px; }

.repas-badge {
    display: inline-block; padding: 4px 12px; border-radius: 999px;
    font-size: 12px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
    color: #3b2a00; background: linear-gradient(90deg, #f5c542, #ffe28a, #f5c542);
    background-size: 200% 100%;
    box-shadow: 0 2px 8px rgba(245, 197, 66, .35);
    animation: repas-or 4s linear infinite;
}

.repas-duel { display: flex; align-items: center; gap: 16px; margin: 14px 0 2px; }
/* Plus aucun écusson (logos introuvables) : le « VS » seul n'aurait aucun sens. */
.repas-duel:not(:has(.repas-ecusson)) { display: none; }
.repas-ecusson {
    width: 76px; height: 76px; flex: 0 0 auto; display: grid; place-items: center;
    background: #fff; border-radius: 16px; padding: 8px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, .30);
    animation: repas-ecusson .6s cubic-bezier(.2, .9, .3, 1.3) .25s both;
    transition: transform .2s ease;
}
.repas-ecusson + .repas-vs + .repas-ecusson { animation-delay: .45s; }
.repas-ecusson:hover { transform: translateY(-3px) rotate(-2deg); }
.repas-ecusson img { max-width: 100%; max-height: 100%; object-fit: contain; }
.repas-vs {
    font-weight: 800; font-size: 18px; letter-spacing: .06em; color: #ffe28a;
    text-shadow: 0 0 12px rgba(245, 197, 66, .55);
    animation: repas-battement 2.4s ease-in-out 1s infinite;
}

.repas-compte {
    display: inline-flex; align-items: center; gap: 9px; margin: 14px 0 0;
    padding: 7px 14px; border-radius: 999px; font-weight: 600; font-size: 14px;
    background: rgba(255, 255, 255, .15); border: 1px solid rgba(255, 255, 255, .25);
    backdrop-filter: blur(4px);
}
.repas-compte-point {
    width: 9px; height: 9px; border-radius: 50%; background: #4ade80;
    box-shadow: 0 0 0 0 rgba(74, 222, 128, .7);
    animation: repas-pouls 1.8s ease-out infinite;
}
.repas-compte-fini .repas-compte-point { background: #f87171; animation: none; }

/* Les cartes du menu et du formulaire arrivent juste après le bandeau. */
.repas-bandeau ~ .carte { animation: repas-entree .6s ease-out .15s both; }
.repas-bandeau ~ .carte ~ .carte { animation-delay: .3s; }

@keyframes repas-entree { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes repas-reflet { 0% { transform: translateX(-130%); } 55%, 100% { transform: translateX(260%); } }
@keyframes repas-or { from { background-position: 0% 0; } to { background-position: 200% 0; } }
@keyframes repas-ecusson {
    from { opacity: 0; transform: scale(.55); }
    70% { opacity: 1; transform: scale(1.06); }
    to { opacity: 1; transform: scale(1); }
}
@keyframes repas-battement { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.12); } }
@keyframes repas-pouls {
    0% { box-shadow: 0 0 0 0 rgba(74, 222, 128, .7); }
    70% { box-shadow: 0 0 0 10px rgba(74, 222, 128, 0); }
    100% { box-shadow: 0 0 0 0 rgba(74, 222, 128, 0); }
}

@media (max-width: 620px) {
    .repas-bandeau { min-height: 230px; }
    .repas-bandeau-contenu { padding: 18px 16px 16px; }
    .repas-bandeau h1 { font-size: 21px; }
    .repas-ecusson { width: 58px; height: 58px; border-radius: 12px; padding: 6px; }
}

/* ⚠️ Moins de mouvements demandés : tout s'arrête, rien ne disparaît. */
@media (prefers-reduced-motion: reduce) {
    .repas-bandeau, .repas-bandeau *, .repas-bandeau::after,
    .repas-bandeau ~ .carte { animation: none !important; }
    .repas-bandeau::after { display: none; }
    .repas-ecusson { transition: none; }
    .repas-photo { transition: none; transform: none; }
}
