/* ══════════════════════════════════════════════════════
   VARIABLES — voir static/css/socle.css

   La palette a quitte ce fichier : elle etait recopiee dans dix-sept
   gabarits qui n'ont pas main.css, et elle avait diverge. Elle vit
   desormais dans socle.css, charge avant main.css par base.html et par
   chaque gabarit autonome. Aucun jeton partage ne doit etre declare ici.
══════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════
   RESET & BASE
══════════════════════════════════════════════════════ */
/* ══════════════════════════════════════════════════════
   POINTS DE RUPTURE — échelle du projet
   Cinq paliers, tirés de l'usage réel plutôt qu'inventés :
     400px  très petit écran     (grilles et modales passent à une colonne)
     480px  petit téléphone      (lignes de formulaire → colonne)
     600px  grand téléphone      (tableaux publics → cartes, en-têtes empilés)
     768px  bascule mobile       (tableaux admin → cartes, barre du bas)
     900px  deux colonnes → une  (gabarits .layout des pages de gestion)
   L'échelle suit le code, pas l'inverse : 600px était plus employé que
   640px, et les valeurs sous 480px servaient de vrais petits écrans qu'on
   aurait dégradés en les y poussant. Les valeurs restantes ont donc été
   rapprochées du palier le plus proche, aucun déplacement n'excédant 40px.
   Le test BreakpointScaleTests refuse toute valeur hors échelle, main.css
   comprise.
══════════════════════════════════════════════════════ */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* ── Pages de terrain sur grand écran ──────────────────────────────────
   Ces écrans sont dessinés pour une main, pas pour un 27 pouces. Étirés sur
   toute la largeur ils perdent leur logique : champ de dossard démesuré,
   compteurs de tours écartelés, bandeau sans rapport avec son contenu. On
   garde donc la colonne à largeur de téléphone, centrée. Aucune media query
   n'est nécessaire : sous 560px la contrainte ne joue pas, le rendu mobile
   reste strictement identique. */
/* Ces pages remplacent la navbar standard par la leur : hauteur nulle, donc
   pas de retrait en haut. Les trois le déclaraient mot pour mot. */
body.page-aide-arbitre { --nav-h: 0px; padding-top: 0; }
body.page-aide-arbitre .page-wrap { max-width: 560px; }
/* Ce qui est en position fixe doit suivre la colonne plutôt que l'écran. */
body.page-aide-arbitre .save-bar {
    left: 50%; right: auto; transform: translateX(-50%);
    width: 100%; max-width: 560px;
}

/* Pages de terrain : animations et transitions coupées. Sur un téléphone en
   compétition elles n'apportent rien et coûtent du CPU donc de la batterie.
   La règle vivait à l'identique dans chaque gabarit aide-arbitre ; elle suit
   désormais la classe, et s'applique d'office à toute nouvelle page terrain. */
body.page-aide-arbitre *,
body.page-aide-arbitre *::before,
body.page-aide-arbitre *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
}

/* Mouvement réduit. L'utilisateur a demandé moins d'animation au niveau de
   son système : c'est une préférence d'accessibilité, pas un goût. On coupe
   ce qui se déplace — `transform`, `filter` — parce que c'est le déplacement
   qui provoque le malaise, et on garde les fondus de couleur et d'opacité,
   qui informent sans bouger.
   Les animations @keyframes ne sont pas touchées : le projet n'en a qu'une,
   le spinner, et l'arrêter ferait croire à un gel alors qu'il dit justement
   que l'application travaille. Une animation décorative ajoutée un jour
   devra, elle, être neutralisée ici. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        transition-property: opacity, visibility, color, background,
                             background-color, border-color, box-shadow,
                             fill, stroke !important;
        scroll-behavior: auto !important;
    }
}
/* ══════════════════════════════════════════════════════
   FOCUS CLAVIER
══════════════════════════════════════════════════════ */
/* Au clavier, l'anneau de focus est le seul repère de position : sans lui on
   tabule à l'aveugle. Le projet n'en déclarait que trois — le sélecteur de
   langue et les deux boutons de la barre — donc partout ailleurs c'était
   l'anneau par défaut du navigateur : différent d'un navigateur à l'autre,
   et quasi invisible sur le navy des en-têtes.
   `:focus-visible` et non `:focus` : le navigateur ne le pose qu'après une
   navigation au clavier, jamais sur un clic de souris, là où un anneau
   passerait pour un état sélectionné.
   La spécificité est volontairement basse (0,1,0) : les 61 champs de
   formulaire du projet coupent déjà `outline` sur leur `:focus` et le
   remplacent par un changement de bordure visible. Ils gardent leur
   traitement, et cet anneau prend le relais sur tout le reste — boutons,
   liens, cartes, pastilles. */
:focus-visible {
    outline: 2px solid var(--green);
    outline-offset: 2px;
}

/* Le bouton de `<input type="file">` est dessiné par le système : en thème
   sombre il sortait en gris Windows, seul élément de la page à ignorer le
   thème. On l'habille plutôt que de masquer l'input derrière un label — le
   JS des pages d'import et des logos lit `this.files[0]` et reçoit
   `this` en argument, et déplacer l'élément casserait cet appel. */
input[type="file"] {
    font-size: 13px;
    color: var(--text-muted);
    /* `width` et pas seulement `max-width` : la largeur par défaut d'un
       input fichier se calcule sur sa police, et en la passant à 13px le
       champ rétrécissait assez pour que Chrome élide son propre libellé
       en « Aucun f…er choisi ». */
    width: 100%;
    max-width: 100%;
}
input[type="file"]::file-selector-button {
    margin-right: 10px;
    padding: 7px 14px;
    border: 1.5px solid var(--border);
    border-radius: 8px;
    background: var(--bg-card);
    color: var(--text);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: border-color .15s, background .15s, color .15s,
                transform .15s var(--ease-out);
}
@media (hover: hover) {
    input[type="file"]::file-selector-button:hover {
        border-color: var(--navy); color: var(--navy);
    }
    [data-theme="dark"] input[type="file"]::file-selector-button:hover {
        border-color: var(--green); color: var(--green);
    }
}
input[type="file"]::file-selector-button:active { transform: scale(.97); }

html { -webkit-text-size-adjust: 100%; }
body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
    background: var(--bg);
    color: var(--text);
    padding-top: var(--nav-h);
    transition: background .25s, color .25s;
    /* Coupe le « tirer pour rafraîchir » de Chrome Android. Faire défiler
       une longue liste de pilotes depuis le haut de la page déclenchait un
       rechargement : en pleine saisie de scores, c'est une saisie perdue.
       Le rechargement reste accessible par le bouton du navigateur. */
    overscroll-behavior-y: contain;
}

/* ══════════════════════════════════════════════════════
   NAVBAR
══════════════════════════════════════════════════════ */
.navbar {
    position: fixed;
    top: 0; left: 0; right: 0;
    height: var(--nav-h);
    background: var(--navy-dark);
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    padding: 0 12px;
    z-index: 1000;
    box-shadow: 0 2px 12px rgba(0,0,0,.3);
    gap: 8px;
}
/* La marque vient du partial partagé (.tc-marque, dans socle.css) : cinq
   écritures du même objet vivaient dans cinq gabarits. */
.nav-center {
    display: flex; align-items: center; justify-content: center;
    gap: 2px; overflow: hidden; min-width: 0;
}
.nav-link {
    display: flex; align-items: center; gap: 5px;
    padding: 6px 10px; border-radius: 6px; font-size: 12.5px;
    color: var(--on-navy-soft); text-decoration: none;
    transition: background .15s, color .15s, transform .15s var(--ease-out); white-space: nowrap; flex-shrink: 0;
}
@media (hover: hover) { .nav-link:hover { background: rgba(255,255,255,.1);  color: #fff; } }
.nav-link.active { background: rgba(105,202,69,.18); color: var(--green); }
.nav-sep { width: 1px; height: 18px; background: rgba(255,255,255,.15); margin: 0 2px; flex-shrink: 0; }
.nav-right { display: flex; align-items: center; gap: 6px; justify-content: flex-end; }


.nav-profile-btn {
    display: flex; align-items: center; gap: 6px;
    text-decoration: none; color: var(--on-navy-soft);
    padding: 4px 8px; border-radius: 6px; transition: background .15s, transform .15s var(--ease-out);
}
@media (hover: hover) { .nav-profile-btn:hover { background: rgba(255,255,255,.1); } }
.nav-avatar {
    width: 30px; height: 30px; border-radius: 50%;
    background: var(--navy-light); border: 2px solid rgba(105,202,69,.5);
    display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 12px; color: #fff; flex-shrink: 0;
}
.nav-username { color: var(--on-navy-soft); font-size: 12.5px; white-space: nowrap; }
.nav-drawer-langues { display: flex; gap: 6px; padding: 8px 14px; }
.nav-drawer-langue {
    flex: 1; padding: 7px 0; font-size: 12px; font-weight: 700;
    font-family: inherit; border: 1px solid var(--border-light);
    border-radius: 8px; cursor: pointer;
    background: var(--bg); color: var(--text-muted);
}
.nav-drawer-langue.active { background: var(--navy); border-color: var(--navy); color: #fff; }

.nav-btn-logout {
    padding: 5px 10px; background: transparent;
    border: 1px solid rgba(255,255,255,.22); border-radius: 5px;
    color: var(--on-navy-dim); font-size: 12px; cursor: pointer;
    text-decoration: none; transition: background-color .15s, color .15s, border-color .15s; white-space: nowrap; font-family: inherit;
}
@media (hover: hover) { .nav-btn-logout:hover { background: rgba(255,255,255,.1); color: #fff; border-color: rgba(255,255,255,.45); } }

/* Hamburger */
.nav-hamburger {
    display: none; flex-direction: column; justify-content: center;
    align-items: center; gap: 5px; width: 36px; height: 36px;
    border: none; background: rgba(255,255,255,.1); border-radius: 8px;
    cursor: pointer; flex-shrink: 0; padding: 0; -webkit-tap-highlight-color: transparent;
}
.nav-hamburger span {
    display: block; width: 18px; height: 2px;
    background: rgba(255,255,255,.85); border-radius: 2px;
    transition: transform .22s var(--ease-in-out), opacity .22s var(--ease-in-out);
}
.nav-hamburger.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-hamburger.open span:nth-child(2) { opacity: 0; transform: scaleX(0); }
.nav-hamburger.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* Drawer mobile */
/* Ouverture et fermeture en transition, non en @keyframes. Un keyframe
   repart de zéro et ne s'interrompt pas, et le hamburger est tapé en
   rafale : une ouverture annulée à mi-course se rejouait depuis le début.
   Une transition, elle, se retourne depuis la position courante. Au passage
   le tiroir gagne une fermeture animée, qu'il n'avait pas du tout —
   `display:none` le coupait net.
   `visibility` remplace `display` parce qu'on ne peut pas animer depuis
   `display:none`. Le délai de .2s sur `visibility` à la fermeture laisse le
   fondu finir avant que le tiroir quitte la page ; fermé, il reste hors du
   parcours clavier et hors de l'arbre d'accessibilité, exactement comme
   avec `display:none`. */
.nav-drawer {
    position: fixed;
    top: var(--nav-h); left: 0; right: 0;
    background: var(--navy-dark); z-index: 999;
    padding: 8px 10px 20px;
    box-shadow: 0 8px 32px rgba(0,0,0,.45);
    border-top: 1px solid rgba(255,255,255,.07);
    max-height: calc(100dvh - var(--nav-h));
    overflow-y: auto; -webkit-overflow-scrolling: touch;
    overscroll-behavior-y: contain;
    visibility: hidden; opacity: 0; transform: translateY(-8px);
    transition: opacity .2s var(--ease-drawer),
                transform .2s var(--ease-drawer),
                visibility 0s linear .2s;
}
.nav-drawer.open {
    visibility: visible; opacity: 1; transform: translateY(0);
    transition: opacity .2s var(--ease-drawer),
                transform .2s var(--ease-drawer),
                visibility 0s;
}
.nav-drawer .nav-link {
    display: flex; padding: 11px 12px; border-radius: 8px;
    font-size: 14px; color: var(--on-navy-soft); margin-bottom: 1px;
    text-decoration: none; transition: background .15s, transform .15s var(--ease-out);
}
@media (hover: hover) { .nav-drawer .nav-link:hover { background: rgba(255,255,255,.07); color: #fff; } }
.nav-drawer .nav-link.active { background: rgba(105,202,69,.15); color: var(--green); }
.nav-drawer .nav-sep { width: 100%; height: 1px; margin: 6px 0; background: rgba(255,255,255,.09); }
.nav-drawer-section {
    font-size: 10px; font-weight: 700; text-transform: uppercase;
    letter-spacing: .8px; color: var(--on-navy-dim); padding: 10px 12px 4px;
}
.nav-drawer-user {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 12px 12px; border-bottom: 1px solid rgba(255,255,255,.08); margin-bottom: 4px;
}
.nav-drawer-user .nav-avatar  { width: 36px; height: 36px; font-size: 13px; }
.nav-drawer-user-info { flex: 1; }
.nav-drawer-user-name { color: #fff; font-size: 14px; font-weight: 600; }
.nav-drawer-user-role { color: var(--green); font-size: 11px; margin-top: 2px; }
.nav-drawer-logout {
    width: 100%; text-align: left; border: none; background: transparent;
    cursor: pointer; color: var(--on-navy-dim); font-size: 14px;
    padding: 11px 12px; border-radius: 8px; font-family: inherit;
    transition: background .15s, color .15s, transform .15s var(--ease-out);
    display: flex; align-items: center; gap: 8px;
}
@media (hover: hover) { .nav-drawer-logout:hover { background: rgba(255,255,255,.07); color: #fff; } }
.nav-overlay {
    position: fixed; inset: 0;
    background: rgba(0,0,0,.5); z-index: 998;
    backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
    visibility: hidden; opacity: 0;
    transition: opacity .2s var(--ease-out), visibility 0s linear .2s;
}
.nav-overlay.open {
    visibility: visible; opacity: 1;
    transition: opacity .2s var(--ease-out), visibility 0s;
}

/* ══════════════════════════════════════════════════════
   PAGE WRAPPER
══════════════════════════════════════════════════════ */
.page-wrap {
    max-width: 1400px;
    margin: 0 auto;
    width: 100%;
    box-sizing: border-box;
    padding: var(--page-pad-y) var(--page-pad-x) 0;
    /* dvh et non vh : `100vh` vaut la hauteur de l'écran barre d'adresse
       exclue, donc sur mobile la page réclame plus de hauteur qu'il n'y en
       a et on gagne un défilement de quelques pixels qui ne mène à rien.
       `100dvh` suit la hauteur réellement disponible. Le tiroir de
       navigation le faisait déjà, juste au-dessus. */
    min-height: calc(100dvh - var(--nav-h));
}
.page-content { }

/* ══════════════════════════════════════════════════════
   BUTTONS — voir static/css/socle.css

   Les boutons ont rejoint le socle : la page de connexion ecrivait
   `class="btn btn-navy"` sans charger main.css, et son bouton principal
   sortait donc en gris systeme du navigateur. Les pages autonomes ont
   toutes un bouton principal, elles doivent toutes avoir le meme.
══════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════
   CARDS
══════════════════════════════════════════════════════ */
.card {
    background: var(--bg-card); border-radius: var(--radius);
    box-shadow: var(--shadow); border: 1px solid var(--border-light);
    transition: background .25s, border-color .25s;
}

/* ══════════════════════════════════════════════════════
   INPUTS
══════════════════════════════════════════════════════ */
.controls { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; align-items: center; }
input[type="text"], input[type="search"], input[type="email"],
input[type="number"], input[type="password"], input[type="date"],
select, textarea {
    padding: 7px 10px; border: 1.5px solid var(--border);
    border-radius: var(--radius); font-size: 13px;
    background: var(--bg-input); color: var(--text);
    font-family: inherit; transition: border-color .15s, background .25s, color .25s;
    width: 100%;
}
input:focus, select:focus, textarea:focus {
    outline: none; border-color: var(--navy);
    box-shadow: 0 0 0 3px rgba(18,56,101,.1);
}
[data-theme="dark"] input:focus,
[data-theme="dark"] select:focus,
[data-theme="dark"] textarea:focus {
    border-color: var(--green); box-shadow: 0 0 0 3px rgba(105,202,69,.12);
}
input::placeholder, textarea::placeholder { color: var(--text-muted); opacity: .7; }
select option { background: var(--bg-card); color: var(--text); }
/* Sans ces règles, le survol d'une <option> passe au surlignage natif du
   navigateur (fond clair) alors que le texte garde sa couleur var(--text) —
   illisible en thème sombre, et parfois aussi en thème clair selon l'OS. */
select option:hover,
select option:checked,
select option:focus { background: var(--navy) !important; color: #fff !important; }
label {
    display: block; font-size: 12px; font-weight: 600;
    color: var(--text-muted); margin-bottom: 5px;
}

/* ══════════════════════════════════════════════════════
   CHAMP DE RECHERCHE AVEC ICÔNE
══════════════════════════════════════════════════════ */
.search-input-wrap,
.search-input-row {
    position: relative;
}
.search-icon,
.search-icon-s {
    position: absolute;
    left: 11px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 15px;
    pointer-events: none;
    color: var(--text-muted);
    line-height: 1;
    z-index: 1;
}
/* Spécificité input.class (0,1,1) > input[type] (0,1,1) par ordre → place après */
input.search-inp,
input.search-inp-s {
    width: 100%;
    padding: 9px 36px 9px 36px;
    border: 1.5px solid var(--border);
    border-radius: 10px;
    font-size: 14px;
    background: var(--bg-input);
    color: var(--text);
    font-family: inherit;
    transition: border-color .15s, background .25s;
    box-sizing: border-box;
}
input.search-inp:focus,
input.search-inp-s:focus {
    outline: none;
    border-color: var(--navy);
    box-shadow: 0 0 0 3px rgba(18,56,101,.1);
}
[data-theme="dark"] input.search-inp:focus,
[data-theme="dark"] input.search-inp-s:focus {
    border-color: var(--green);
    box-shadow: 0 0 0 3px rgba(105,202,69,.12);
}

/* ══════════════════════════════════════════════════════
   MODALES (base canonique — surchargeables localement)
══════════════════════════════════════════════════════ */
.modal-overlay {
    position: fixed; inset: 0; background: rgba(0,0,0,.45);
    display: flex; align-items: center; justify-content: center;
    z-index: 1000; padding: 16px;
}
.modal-box {
    background: var(--bg-card); border-radius: 14px; padding: 24px;
    width: 100%; max-width: 480px; box-shadow: var(--shadow-lg);
    max-height: 90vh; overflow-y: auto;
}
.modal-title { font-size: 17px; font-weight: 800; color: var(--text); margin-bottom: 16px; }

/* ══════════════════════════════════════════════════════
   FORM INLINE PANELS (new club / new commune)
══════════════════════════════════════════════════════ */
.new-club-wrap    { background:var(--navy-bg); border:1.5px solid #90c0f0; border-radius:8px; padding:12px; }
.new-commune-wrap { background:var(--warning-bg); border:1.5px solid var(--warning-line); border-radius:8px; padding:12px; }
.new-club-head    { font-size:11px; font-weight:700; color:#1a5490; margin-bottom:8px; }
.new-commune-head { font-size:11px; font-weight:700; color:var(--on-warning-bg); margin-bottom:8px; }
.new-entry-cancel { background:none; border:none; cursor:pointer; text-decoration:underline;
                    margin-top:8px; font-size:11px; padding:0; }
.new-club-wrap    .new-entry-cancel { color:#1a5490; }
.new-commune-wrap .new-entry-cancel { color:var(--on-warning-bg); }
[data-theme="dark"] .new-club-wrap    { background:rgba(18,56,101,.18); border-color:rgba(30,79,140,.45); }
[data-theme="dark"] .new-commune-wrap { background:rgba(196,154,0,.12); border-color:rgba(196,154,0,.4); }
[data-theme="dark"] .new-club-head,
[data-theme="dark"] .new-club-wrap    .new-entry-cancel { color:var(--text-muted); }
[data-theme="dark"] .new-commune-head,
[data-theme="dark"] .new-commune-wrap .new-entry-cancel { color:var(--gold); }

/* ══════════════════════════════════════════════════════
   BADGES
══════════════════════════════════════════════════════ */
.badge { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 700; color: #fff; }
.badge-ok        { background: var(--success); }

/* ══════════════════════════════════════════════════════
   TABLES
══════════════════════════════════════════════════════ */
.tbl-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: var(--radius); box-shadow: var(--shadow); }
table { width: 100%; border-collapse: collapse; background: var(--bg-card); border-radius: var(--radius); overflow: hidden; transition: background .25s; }
.tbl-wrap table { border-radius: 0; box-shadow: none; }

/* ── Panel (composant carte avec header navy) ── */
.panel { background: var(--bg-card); border-radius: 12px; box-shadow: var(--shadow); overflow: hidden; border: 1px solid var(--border-light); }
.panel-head { background: var(--navy); padding: 12px 18px; display: flex; align-items: center; justify-content: space-between; gap: 8px; border-bottom: 2px solid rgba(255,255,255,.15); }
/* Le titre porte son icône, comme `.page-title` : sans `inline-flex`
   l'icône s'assoit sur la ligne de base au lieu de s'aligner sur la
   majuscule. */
.panel-head h2 {
    display: inline-flex; align-items: center; gap: 8px;
    color: #fff; font-size: 14px; font-weight: 700; margin: 0;
}
.panel-head span { color: var(--on-navy-soft); font-size: 12px; }
.panel-body { padding: 16px 18px; }
/* Quand tbl-wrap est à l'intérieur d'un .panel, le panel gère déjà le border-radius et l'ombre */
.panel .tbl-wrap { border-radius: 0; box-shadow: none; }
/* Le .panel gère déjà overflow:hidden + border-radius — annuler sur les tables directes */
.panel table { border-radius: 0; overflow: visible; }
thead th {
    background: var(--navy); color: #fff; padding: 10px 12px;
    font-size: 12.5px; text-align: left; white-space: nowrap;
}
td {
    padding: 8px 12px; font-size: 13px;
    border-bottom: 1px solid var(--table-border);
    vertical-align: middle; color: var(--text); transition: background .15s;
}
tbody tr:last-child td { border-bottom: none; }
@media (hover: hover) { tbody tr:hover td { background: var(--row-hover); } }

/* ══════════════════════════════════════════════════════
   TOAST
══════════════════════════════════════════════════════ */
.toast {
    position: fixed; bottom: 20px; right: 16px;
    background: var(--navy-dark); color: #fff;
    padding: 10px 18px; border-radius: 8px; font-size: 13px;
    opacity: 0; transition: opacity .3s var(--ease-out); z-index: var(--z-toast); pointer-events: none;
    max-width: calc(100vw - 32px); box-shadow: 0 4px 16px rgba(0,0,0,.3);
}
.toast.show    { opacity: 1; }
.toast.error,
.toast.err     { background: var(--danger-dark); }
.toast.ok,
.toast.success { background: var(--green-dark); }

/* ══════════════════════════════════════════════════════
   SPINNER
══════════════════════════════════════════════════════ */
.spinner {
    display: inline-block; width: 13px; height: 13px;
    border: 2px solid rgba(0,0,0,.1); border-top-color: var(--navy);
    border-radius: 50%; animation: spin .55s linear infinite; vertical-align: middle;
}
[data-theme="dark"] .spinner { border-color: rgba(255,255,255,.12); border-top-color: var(--green); }
@keyframes spin { to { transform: rotate(360deg); } }

/* ══════════════════════════════════════════════════════
   ROLE PILLS
══════════════════════════════════════════════════════ */
.role-pill { display: inline-block; padding: 2px 9px; border-radius: 10px; font-size: 11px; font-weight: 700; }
.role-gestionnaire { background: var(--success-dark); color: var(--on-success-dark); }
.role-admin_compet { background: var(--navy); color: #fff; }
.role-pdj          { background: #8e44ad; color: #fff; }
.role-aide_arbitre { background: var(--success); color: var(--on-success); }

/* ══════════════════════════════════════════════════════
   TWEMOJI — rendu emoji cohérent cross-OS
══════════════════════════════════════════════════════ */
img.emoji {
    height: 1.1em; width: 1.1em;
    margin: 0 .05em 0 .1em;
    vertical-align: -0.15em;
    display: inline-block;
}

/* ══════════════════════════════════════════════════════
   UTILITAIRES
══════════════════════════════════════════════════════ */
.text-muted { color: var(--text-muted) !important; }
.text-navy  { color: var(--navy); }
.text-green { color: var(--green); }
.extra-badge { display: inline-block; background: var(--border-light); color: var(--text); font-size: 11px; padding: 2px 6px; border-radius: 8px; margin: 1px; }
.cat-badge { display: inline-block; background: var(--border-light); color: var(--navy); font-size: 11px; padding: 2px 7px; border-radius: 8px; }
[data-theme="dark"] .cat-badge { background: rgba(30,79,140,.2); color: var(--text-muted); }

/* ══════════════════════════════════════════════════════
   BARRES CATÉGORIES / CHIPS
   Règle : .cat-bar (wrapper) > .cat-scroll/.cat-filters/.cat-chips-row (flex)
   Les puces s'enroulent plutôt que de défiler : une catégorie poussée hors
   de l'écran ne se devine pas, et six des sept pages qui emploient cette
   barre réécrivaient déjà le défaut pour l'enrouler.
══════════════════════════════════════════════════════ */
.cat-bar {
    width: 100%;
    margin-bottom: 14px;
}
.cat-scroll,
.cat-filters,
.cat-chips-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding: 4px 0;
}

.cat-btn,
.cat-chip,
.cat-chip-s {
    flex-shrink: 0;
    white-space: nowrap;
}

/* ══════════════════════════════════════════════════════
   BOTTOM NAV — Mobile
══════════════════════════════════════════════════════ */
.bottom-nav {
    display: none;
    position: fixed; bottom: 0; left: 0; right: 0;
    height: 60px;
    background: var(--navy-dark);
    border-top: 1px solid rgba(255,255,255,.08);
    z-index: var(--z-nav); padding-bottom: env(safe-area-inset-bottom);
    box-shadow: 0 -2px 12px rgba(0,0,0,.25);
}
.bottom-nav-inner { display: flex; align-items: stretch; height: 60px; }
.bn-item {
    flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px; text-decoration: none; color: var(--on-navy-dim);
    font-size: 10px; font-weight: 600; letter-spacing: .2px;
    transition: color .15s, background .15s; -webkit-tap-highlight-color: transparent;
    border: none; background: transparent; cursor: pointer; font-family: inherit;
    padding: 0 2px; position: relative;
}
.bn-item:active { background: rgba(255,255,255,.06); }
.bn-item.active  { color: var(--green); }
.bn-item.active .bn-icon { transform: scale(1.1); }
.bn-icon { font-size: 20px; line-height: 1; display: block; transition: transform .15s var(--ease-out); }
.bn-label { line-height: 1; }
.bn-item.active::after {
    content: ''; position: absolute; top: 0; left: 15%; right: 15%;
    height: 2px; background: var(--green); border-radius: 0 0 3px 3px;
}
.bn-item.bn-more { color: var(--on-navy-dim); }
.bn-item.bn-more.open { color: var(--on-navy-soft); }

/* ══════════════════════════════════════════════════════
   RESPONSIVE — Mobile
══════════════════════════════════════════════════════ */
@media (max-width: 768px) {
    body { padding-bottom: var(--bottom-h); }

    .navbar            { justify-content: space-between; }
    .nav-center        { display: none !important; }
    .nav-hamburger     { display: flex; }
    .nav-username      { display: none; }
    .nav-btn-logout    { display: none; }
    .nav-profile-btn   { display: none; }

    .page-wrap { padding: var(--page-pad-y) var(--page-pad-x) calc(var(--bottom-h) + 12px); }

    table { min-width: 480px; }
    .tbl-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

    .controls { gap: 6px; }

    /* Plancher de 16px sur les champs de saisie.
       Safari iOS agrandit la page dès qu'on prend le focus sur un champ dont
       le texte fait moins de 16px, et ne dézoome jamais tout seul : il faut
       pincer après chaque saisie. Un plancher supprime le problème partout.
       !important est nécessaire ici : ces tailles sont déclarées par classe
       dans chaque gabarit (.ins-sel, .mob-pen-inp, .fg input…), qui
       l'emporteraient sur un simple sélecteur d'élément. Les cases à cocher,
       boutons radio, curseurs et sélecteurs de fichier ne déclenchent pas ce
       zoom : on les laisse tranquilles. Un champ volontairement plus grand
       rétablit sa taille avec la même force (voir .bib-input). */
    input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]):not([type=color]),
    select,
    textarea { font-size: 16px !important; }
    /* .cselect remplace visuellement un <select> par un <button> : il ne
       déclenche pas le zoom, mais il côtoie ces champs dans les barres de
       filtres et paraîtrait plus petit qu'eux. */
    .cselect-trigger { font-size: 16px; }

    .bottom-nav { display: block; }
    .site-footer { display: none; }
}
/* ══════════════════════════════════════════════════════
   COMPOSANTS PARTAGÉS
   Ces trois blocs vivaient recopiés dans chaque gabarit, avec des
   valeurs qui divergeaient au fil des pages (18 variantes de .page-header,
   14 de .empty-state). Une seule définition ici, les pages n'en gardent
   que leurs éventuelles particularités.
══════════════════════════════════════════════════════ */

/* Titre de page : intitulé à gauche, actions à droite. Le passage à la
   ligne est indispensable — sans lui, titre et boutons se serrent au lieu
   de s'empiler sur un téléphone étroit. */
.page-header {
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: 10px; margin-bottom: 20px;
}
.page-header h1 { font-size: 20px; color: var(--text); margin: 0; }
.page-header p  { font-size: 13px; color: var(--text-muted); margin: 2px 0 0; }

/* Bandeau pleine largeur : déborde dans la gouttière de .page-wrap, dont il
   lit la mesure (voir --page-pad-*). La couleur du texte est posée ici :
   sans elle, toute ligne ajoutée s'écrit en bleu foncé sur bleu foncé. */
.page-banner {
    background: var(--navy); color: #fff; padding: 14px 16px 12px;
    margin: calc(-1 * var(--page-pad-y)) calc(-1 * var(--page-pad-x)) 0;
}
.page-banner h1 { font-size: 17px; font-weight: 700; margin: 0; }

/* L'intérieur du bandeau, qui vivait recopié sous quinze noms — .ins-header,
   .res-header, .imp-header, .arb-header, .pdj-header, .z-header,
   .score-header, .t-header, .zone-page-header, .page-header-nav… — avec le
   même fond, le même retrait et la même marge négative. Sept de ces copies
   étaient identiques au caractère près ; les autres différaient de deux
   pixels de retrait, ce que personne n'avait décidé.

   Trois éléments, et ils suffisent à tous les bandeaux du site :
     .page-banner-top  la rangée titre / actions,
     .page-title       l'intitulé,
     .page-sub         la ligne de contexte sous l'intitulé.

   `.page-title` est un `inline-flex` parce que presque tous les titres du
   projet portent une icône : sans ça l'icône ne s'aligne pas sur la
   majuscule, elle s'assoit sur la ligne de base. */
.page-banner-top {
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: 10px;
}
.page-title {
    display: inline-flex; align-items: center; gap: 8px;
    font-size: 17px; font-weight: 700; color: #fff; margin: 0;
}
/* La ligne de contexte prend un niveau de l'échelle plutôt qu'un voile :
   `opacity` sur du blanc donnait 2,8:1 sur le navy (voir socle.css). */
.page-sub { font-size: 11px; color: var(--on-navy-dim); margin-top: 2px; }
/* Bande horizontale prolongeant le bandeau : même débordement, pour que son
   fond et son filet atteignent les mêmes bords. Sans cela la bande s'arrête
   avant l'en-tête posé juste au-dessus, ce qui se voit immédiatement. Elle
   garde son propre retrait intérieur, qui aligne son contenu sur celui du
   bandeau. */
.page-strip { margin-inline: calc(-1 * var(--page-pad-x)); }
.page-banner p  { font-size: 11px; color: var(--on-navy-dim); margin: 0; }

/* Bouton de retour posé sur un bandeau. Décliné à l'identique dans trois
   pages et à deux pixels près dans la quatrième. */
.z-back {
    display: inline-flex; align-items: center; gap: 6px;
    background: rgba(255,255,255,.15); color: white;
    font-size: 12px; font-weight: 600; text-decoration: none;
    padding: 5px 12px 5px 8px; border-radius: 20px;
    margin-bottom: 10px; border: 1px solid rgba(255,255,255,.2);
    transition: background .15s, transform .15s var(--ease-out);
}
@media (hover: hover) { .z-back:hover { background: rgba(255,255,255,.25); color: white; } }
.z-back i { flex-shrink: 0; }

/* ══════════════════════════════════════════════════════
   TUILES DE CHIFFRES
   ─────────────────────────────────────────────────────
   Une rangée de tuiles, chacune portant un chiffre et ce qu'il compte.
   Le même objet existait sous onze noms — .hstat-s, .hstat (deux fois, dans
   une feuille ET dans un gabarit, aux mêmes valeurs), .ins-stat,
   .stat-pill, .pp-stat, .stat-chip, .stat-card, .res-stat, .hub-stat, et
   une onzième écrite entièrement en attributs `style=`. Mesuré sur les
   sources : 29 noms de classe, six tailles de chiffre (15, 18, 20, 22, 28,
   36 px) sur dix déclarations, quatre tailles de libellé, neuf retraits de
   tuile, onze recettes de rangée et neuf voiles écrits en dur — dont trois
   alphas pour le même vert.

   Le composant porte la géométrie et l'échelle ; le CONTEXTE décide la
   peau, parce que c'est la seule chose qui change vraiment :

     dans un bandeau   la tuile est un voile sur le navy, et le chiffre y
                       est secondaire (20 px) à côté du titre ;
     dans le contenu   elle est posée sur la page, et le chiffre EST le
                       contenu (22 px).

   Quatre parties : .stat-row la rangée, .stat la tuile, .stat-n le chiffre
   (.stat-u pour son unité ou sa fraction), .stat-l le libellé.
══════════════════════════════════════════════════════ */
/* Une tuile se dimensionne sur son contenu, jamais sur l'écran : trois
   tuiles étirées sur 1400 px pour y écrire « 29 », c'est le défaut
   d'origine, et il valait dans le contenu comme dans le bandeau.
   `minmax(108px, max-content)` leur donne un plancher confortable —
   aucun libellé du projet n'atteint 108 px, donc toutes sortent à la même
   largeur sans qu'on la fixe, et « hors-compétition », le plus long, garde
   sa place s'il la dépasse un jour. Premier essai : `flex: 0 1 auto` +
   `min-width: 84px`, qui serrait chaque tuile sur son libellé et les rendait
   moins lisibles qu'étirées.
   Au téléphone, remplir la ligne redevient le bon réflexe. */
.stat-row {
    display: grid; grid-auto-flow: column;
    grid-auto-columns: minmax(108px, max-content);
    justify-content: start; gap: 8px;
}
@media (max-width: 768px) {
    .stat-row { grid-auto-columns: 1fr; justify-content: stretch; }
}
.stat {
    --stat-ink-l: var(--text-muted);
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    background: var(--bg); border: 1px solid var(--border);
    border-radius: 8px; padding: 8px 14px;
    color: var(--text); flex-shrink: 0;
}
.stat-n { font-size: 22px; font-weight: 800; line-height: 1; }
.stat-u { font-size: 13px; font-weight: 400; margin-left: 1px; }
.stat-l { font-size: 11px; margin-top: 3px; color: var(--stat-ink-l); }

/* Dans un bandeau. Le voile éclaircit le navy, donc il resserre le
   contraste : le libellé prend `--on-navy-soft` et non `--on-navy-dim`, qui
   tombait à 3,86:1 sur une tuile verte (table dans socle.css).

   L'écart avec la rangée du titre fait partie du bandeau : il s'écrivait
   `.page-banner-top { margin-bottom: 10px }` dans les quatre pages qui
   posent des tuiles, et une cinquième écrivait `margin-top: 12px` sur la
   rangée. */
/* Les chiffres qualifient le titre — « Inscriptions : 29 inscrits » — donc
   ils se lisent à son niveau. La rangée du titre a de la place libre entre
   l'intitulé et les actions ; les tuiles prenaient pourtant une bande
   entière en dessous, soit une cinquantaine de pixels de bandeau pour
   trois nombres.

   `margin-right: auto` les garde contre le titre : sans lui, le
   `space-between` de la rangée les poserait au milieu, à égale distance de
   deux choses qu'elles ne qualifient pas toutes les deux.

   Sous 769px la rangée se replie et les tuiles reprennent une ligne
   entière. C'est `width: 100%` qui la leur donne : le `flex-wrap` seul les
   laisse se serrer à côté du titre, puisqu'elles tiennent dans ce qui
   reste. */
.page-banner-top > .stat-row { margin-right: auto; }
@media (max-width: 768px) {
    .page-banner-top > .stat-row { width: 100%; margin-top: 2px; }
}
.page-banner .stat {
    --stat-ink-l: var(--on-navy-soft);
    background: var(--on-navy-fill); border-color: transparent;
    color: #fff;
}
.page-banner .stat-n { font-size: 20px; font-weight: 700; }
/* Les libellés d'un bandeau sont des mots, pas des phrases : ils tiennent sur
   une ligne, et « hors-compétition » garde sa place. Dans le contenu, les
   libellés sont des phrases (« Communes en base ») — les forcer sur une ligne
   y débordait de 4 px à 390 px. */
.page-banner .stat-l { white-space: nowrap; }

/* Variante jointe : les tuiles partagent un seul cadre, séparées par un
   filet, pour un relevé compact serré dans une carte — l'en-tête du hub en
   met trois dans 210 px, à côté de la date et du lieu. La page ne garde
   alors que cette largeur, qui est la seule chose qui lui appartienne. */
.stat-row.joined {
    display: flex; gap: 0;
    border: 1px solid var(--border-light);
    border-radius: 10px; overflow: hidden;
}
.stat-row.joined .stat {
    flex: 1; background: none; border: none; border-radius: 0;
    border-right: 1px solid var(--border-light);
    padding: 10px 4px 8px;
}
.stat-row.joined .stat:last-child { border-right: none; }

/* Accents. Une tuile accentuée porte son encre : sur le navy c'est un voile
   coloré sous du blanc, dans le contenu c'est une teinte sous son
   `--on-X-bg`. Le libellé suit l'encre de la tuile au lieu de s'atténuer :
   atténuer une couleur, c'est la casser. */
.stat.ok, .stat.warn, .stat.danger, .stat.info {
    --stat-ink-l: currentColor;
    border-color: transparent;
}
.stat.ok      { background: var(--success-bg); color: var(--on-success-bg); }
.stat.warn    { background: var(--warning-bg); color: var(--on-warning-bg); }
.stat.danger  { background: var(--danger-bg);  color: var(--on-danger-bg); }
.stat.info    { background: var(--purple-bg);  color: var(--on-purple-bg); }
/* Sur le navy, l'accent change le fond et rien d'autre : le chiffre reste
   blanc et le libellé garde son niveau de l'échelle (4,65:1 au plus serré,
   sur la tuile verte). */
.page-banner .stat.ok, .page-banner .stat.warn,
.page-banner .stat.danger, .page-banner .stat.info {
    --stat-ink-l: var(--on-navy-soft); color: #fff;
}
.page-banner .stat.ok     { background: var(--navy-fill-ok); }
.page-banner .stat.warn   { background: var(--navy-fill-warn); }
.page-banner .stat.danger { background: var(--navy-fill-danger); }
.page-banner .stat.info   { background: var(--navy-fill-info); }


/* Message « rien à afficher », toujours posé sur une carte. */
.empty-state {
    text-align: center; padding: 48px 20px; color: var(--text-muted);
    background: var(--bg-card); border-radius: 10px; box-shadow: var(--shadow);
}
.empty-state .big { font-size: 40px; margin-bottom: 10px; line-height: 1; }

/* ══════════════════════════════════════════════════════
   SITE FOOTER — Admin
══════════════════════════════════════════════════════ */
.site-footer {
    background: var(--navy-dark);
    border-top: 1px solid rgba(255,255,255,.07);
    padding: 24px 20px 16px;
    margin-top: 48px;
}
.site-footer-inner {
    max-width: 1400px; margin: 0 auto;
    display: flex; align-items: flex-start;
    justify-content: space-between; flex-wrap: wrap; gap: 20px;
}
/* La marque du pied vient du partial partagé, variante discrète
   (.tc-marque-discret, dans socle.css). */
.footer-nav-cols {
    display: flex; gap: 32px; flex-wrap: wrap;
}
.footer-nav-col { display: flex; flex-direction: column; gap: 6px; }
.footer-nav-label {
    font-size: 10px; font-weight: 700; color: var(--on-navy-dim);
    text-transform: uppercase; letter-spacing: .6px; margin-bottom: 2px;
}
.footer-nav-link {
    color: var(--on-navy-dim); font-size: 12px; text-decoration: none;
    transition: color .15s; white-space: nowrap;
}
@media (hover: hover) { .footer-nav-link:hover { color: var(--on-navy); } }
.footer-divider {
    max-width: 1400px; margin: 14px auto 0;
    border: none; border-top: 1px solid rgba(255,255,255,.07);
}
.footer-bottom {
    max-width: 1400px; margin: 10px auto 0;
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: 8px;
}
.footer-copy {
    font-size: 11px; color: var(--on-navy-dim);
}
.footer-rgpd {
    font-size: 10px; color: var(--on-navy-dim);
    line-height: 1.5; text-align: right; max-width: 480px;
}
/* Le nom du logiciel portait son style en clair dans la phrase traduite :
   `<strong style="color:rgba(255,255,255,.35)">`. La couleur était donc dans
   le catalogue, hors de portée de la palette, et à 2,2:1. Le style vit ici,
   la phrase ne porte plus que du texte. */
.footer-rgpd strong { color: var(--on-navy-soft); font-weight: 700; }
.footer-rgpd a {
    color: var(--on-navy-soft); text-decoration: underline;
    text-decoration-color: var(--on-navy-line); transition: color .15s;
}
@media (hover: hover) { .footer-rgpd a:hover { color: var(--on-navy); } }

@media (max-width: 768px) {
    .site-footer { padding-bottom: calc(var(--bottom-h) + 16px); }
    .site-footer-inner { flex-direction: column; gap: 16px; }
    .footer-nav-cols { gap: 20px; }
    .footer-rgpd { text-align: left; }
    .footer-bottom { flex-direction: column; align-items: flex-start; }
}

/* ── Bannière compétition clôturée ──────────────────────────────── */
.closed-banner {
    background: var(--danger-bg);
    border: 1.5px solid var(--danger-line);
    border-radius: 9px;
    padding: 11px 16px;
    margin: 16px 0 18px;
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 13px;
    color: var(--on-danger-bg);
}
[data-theme="dark"] .closed-banner {
    background: #2c1810;
    border-color: #7b3328;
    color: var(--danger);
}

/* ── Sélecteur custom (remplace <select> natif) ────────────────────
   Un <select> natif ne permet pas de styler le survol des options dans
   sa popup (limitation navigateur, notamment Chrome) : la surbrillance
   retombe sur le gris natif au lieu de var(--navy), y compris en mode
   sombre. Ce composant reproduit le <select> avec une popup HTML/CSS
   stylable, tout en gardant le <select> d'origine comme source de
   vérité (valeur + évènement "change") pour rester compatible avec le
   JS existant qui lit .value ou écoute "change". */
.cselect { position: relative; flex: 1; min-width: 160px; }
.cselect-trigger {
    width: 100%; padding: 8px 12px; border: 1.5px solid var(--border); border-radius: 8px;
    font-size: 13px; background: var(--bg-input); color: var(--text);
    display: flex; align-items: center; justify-content: space-between; gap: 6px;
    cursor: pointer; text-align: left; font-family: inherit;
}
.cselect-trigger:focus { outline: none; border-color: var(--navy); }
[data-theme="dark"] .cselect-trigger:focus { border-color: var(--green); }
.cselect-trigger i { font-size: 14px; color: var(--text-muted); transition: transform .15s var(--ease-out); flex-shrink: 0; }
.cselect.open .cselect-trigger i { transform: rotate(180deg); }
.cselect-drop {
    position: absolute; left: 0; right: 0; top: 100%; margin-top: 4px; z-index: 300;
    background: var(--bg-card); border: 1.5px solid var(--navy); border-radius: 8px;
    box-shadow: var(--shadow-lg); max-height: 260px; overflow-y: auto; display: none;
}
.cselect.open .cselect-drop { display: block; }
.cselect-item { padding: 8px 12px; font-size: 13px; cursor: pointer; color: var(--text); transition: background .12s, transform .12s var(--ease-out); }
@media (hover: hover) { .cselect-item:hover { background: var(--row-hover); } }
.cselect-item.active { background: var(--navy); color: white; font-weight: 600; }
[data-theme="dark"] .cselect-item.active { background: var(--green); color: var(--on-green); }
.closed-banner i { font-size: 16px; flex-shrink: 0; }

/* ══════════════════════════════════════════════════
   RETOUR AU DOIGT
   Au doigt il n'y a pas de survol : `:active` est le seul retour qu'un
   élément pressé sache donner. Sans lui, un chip tapé ne répond rien et on
   le tape une seconde fois en croyant l'avoir manqué. L'échelle reste
   discrète — 3 % : l'œil le sent sans le voir.
   ══════════════════════════════════════════════════ */
.nav-link:active,
.nav-profile-btn:active,
.nav-drawer-logout:active,
.z-back:active,
.cselect-item:active { transform: scale(.97); }

/* ══════════════════════════════════════════════════════
   TABLEAU DE RÉSULTATS — qualification et finale

   Deux pages rendent ce tableau : les résultats d'une compétition et le
   classement du championnat. Le composant vivait recopié dans les deux,
   et il avait divergé. Mesure du 23 octobre 2026 : sur leurs quarante
   sélecteurs communs, vingt-trois étaient identiques au caractère près et
   dix-sept avaient divergé — l'en-tête de finale noir d'un côté et doré de
   l'autre, le filet des lignes, la couleur du total, celle des pastilles
   de rang. Deux pages qui montrent la même chose ne se ressemblaient plus.

   Ce qui se répète vraiment derrière ces couleurs, c'est le tableau
   lui-même, et c'est ce fichier-ci qui le porte désormais. Les pages ne
   gardent que ce qui leur est propre : la table dépliable et les cartes
   mobiles pour l'une, les colonnes de championnat pour l'autre.
══════════════════════════════════════════════════════ */

/* ── Pastilles de filtre par catégorie ────────────────── */
.cat-btn {
    padding: 5px 13px; border: 1.5px solid var(--border);
    border-radius: 20px; font-size: 12px; font-weight: 500;
    background: var(--bg-card); color: var(--text); cursor: pointer;
    /* `white-space` vient du raccourci qui groupe les pastilles plus haut
       dans ce fichier : le reposer ici serait la même décision deux fois,
       dans la même feuille. */
    text-decoration: none;
    transition: border-color .15s, background .15s, color .15s,
                box-shadow .15s, transform .15s var(--ease-out),
                opacity .15s;
}
@media (hover: hover) {
    .cat-btn:hover { border-color: var(--navy); background: var(--row-hover); }
}
.cat-btn.active {
    background: var(--navy); border-color: var(--navy); color: #fff;
    font-weight: 600;
}
/* Retour au doigt : sans souris, `:active` est le seul retour qu'un
   élément pressé sache donner. */
.cat-btn:active { transform: scale(.97); }

/* ── Blocs ────────────────────────────────────────────── */
.cat-block { margin-bottom: 32px; }
.table-section { margin-bottom: 12px; }

.section-header {
    padding: 10px 16px; border-radius: 8px 8px 0 0;
    display: flex; align-items: center; justify-content: space-between;
}
.section-header h2 { font-size: 15px; margin: 0; font-weight: 700; }
.section-header .ct { font-size: 11px; color: inherit; opacity: .85; }
.section-header.qual { background: var(--navy); color: #fff; }
/* La finale est dorée, dans les deux pages : c'est son identité, et le
   noir que l'une d'elles posait n'était pas une décision, c'était une
   copie qui n'avait pas suivi. */
.section-header.finale {
    background: var(--warning-dark); color: var(--on-warning-dark);
}
.section-header.finale h2 { color: var(--on-warning-dark); }
.badge-top {
    background: rgba(0, 0, 0, .18); font-size: 10px; padding: 2px 8px;
    border-radius: 5px; font-weight: 700; white-space: nowrap;
    margin-left: 8px;
}

/* ── Mise en page d'une page de résultats ──────────────────
   Le bandeau file jusqu'aux deux bords de l'écran, et c'est le CONTENU
   qui se recentre sur une colonne de lecture. Sans cela, sur un écran
   large, le bandeau s'arrête à la largeur de `.page-wrap` et laisse du
   fond de page à sa gauche et à sa droite, pendant que la barre du haut,
   elle, va d'un bord à l'autre.

   La page Résultats portait cette mécanique dans son propre `<style>`,
   avec deux `!important` pour battre `.page-wrap`. Le Classement
   Championnat n'en avait rien, et son bandeau s'arrêtait donc à 1400 px.
   Ici la classe sur le corps suffit à la spécificité, et les `!important`
   tombent.

   `--res-col` est le réglage que chaque page pose pour elle-même : la
   page Résultats tient dans 1140 px, le Championnat prend la largeur de
   la page, son tableau portant cinq colonnes de plus. Sans la variable,
   le contenu prend toute la largeur. */
body.page-resultats .page-wrap {
    max-width: 100%;
    padding-left: var(--page-pad-x); padding-right: var(--page-pad-x);
}
body.page-resultats .page-banner-top,
body.page-resultats .res-body {
    max-width: var(--res-col, none); margin-inline: auto; width: 100%;
}
.res-body { padding: 16px 0; }

/* ── Barre de filtres par catégorie ───────────────────── */
.cat-filter-bar {
    position: sticky; top: var(--nav-h); z-index: 20;
    background: var(--bg); padding: 8px 14px;
    border-bottom: 1px solid var(--gray-light);
    box-shadow: 0 2px 8px rgba(0, 0, 0, .07);
    margin: 0 calc(-1 * var(--page-pad-x)); overflow-x: auto;
}
.cat-filter-inner {
    display: flex; gap: 6px; white-space: nowrap; align-items: center;
    /* Une page peut resserrer ses pastilles sur sa colonne de lecture ;
       sans `--res-col` elles prennent la largeur de la page. */
    max-width: var(--res-col, none); margin-inline: auto;
}
/* Sur téléphone, un défilement horizontal de pastilles cache les dernières
   catégories et entre en concurrence avec le défilement de la page : on les
   fait passer à la ligne pour que tout soit visible d'un coup. La barre
   cesse alors d'être collante — déroulée sur plusieurs lignes, elle
   mangerait l'écran. Même choix que la barre de la page publique. */
@media (max-width: 768px) {
    .cat-filter-bar { position: static; overflow-x: visible; }
    .cat-filter-inner { flex-wrap: wrap; white-space: normal; }
}

/* ── Tables ───────────────────────────────────────────── */
/* `.tbl-wrap` est le conteneur à défilement du projet, déclaré plus haut
   dans ce fichier. Ce composant le redéclarait, donc l'écrasait pour
   TOUTES les tables du site : son rayon passait des quatre coins aux deux
   du bas. Ce qu'il fallait dire n'était pas « le conteneur est différent »
   mais « ici une bande de titre le surmonte », et c'est le contexte qui le
   dit — `.table-section` est précisément ce contexte. */
.table-section .tbl-wrap { border-radius: 0 0 8px 8px; }
table.rt {
    border-collapse: collapse; background: var(--bg-card);
    font-size: 12px; min-width: 400px; width: 100%;
}
table.rt th {
    background: var(--navy); color: #fff; padding: 6px 8px;
    text-align: center; white-space: nowrap; font-size: 11px;
    font-weight: 600; vertical-align: middle;
}
table.rt th.th-pilot {
    text-align: left; min-width: 155px; padding-left: 14px;
    background: var(--navy-dark);
}
table.rt th.th-bibs { background: var(--navy-dark); }
table.rt th.th-total { background: var(--col-total); }
table.rt th.th-pen { background: var(--col-penalite); }
table.rt th.th-rank { background: var(--col-rang); width: 52px; }
table.rt th.th-zone-hdr { background: var(--col-zone); font-size: 10px; }
table.rt th.grp-sep { border-left: 2px solid rgba(255, 255, 255, .2); }
table.rt td.grp-sep { border-left: 2px solid var(--border); }
table.rt td {
    padding: 5px 8px; border-bottom: 1px solid var(--row-sep);
    text-align: center; vertical-align: middle;
}
table.rt td.td-pilot { text-align: left; padding-left: 14px; }

/* Table finale — en-têtes dorés.

   L'encre est posée ici et non héritée. `table.rt th` donne du blanc, ce
   qui convient au brun du thème clair (#ab590a, 5,04:1) mais pas au jaune
   que le même jeton devient dans le thème sombre : #fcd34d, et le blanc y
   tombe à 1,44:1 — « Né », « Dos. » et « Total Finale » n'étaient plus
   lisibles. Mesuré le 23 octobre 2026. La bande du titre, elle, posait
   déjà `--on-warning-dark`, qui bascule ; c'est la table qui l'avait
   oublié.

   Les cellules qui reprennent un fond sombre réaffirment donc le blanc :
   `--on-warning-dark` vaut `--navy-dark` dans le thème sombre, et
   l'hériter les rendrait sombres sur sombre. */
table.rt-finale th {
    background: var(--warning-dark); color: var(--on-warning-dark);
}
table.rt-finale th.th-pilot { background: var(--col-finale); color: #fff; }
table.rt-finale th.th-bibs { background: var(--col-finale); color: #fff; }
table.rt-finale th.th-rank { background: #4a3300; color: #fff; }
table.rt-finale th.th-total { background: var(--col-finale); color: #fff; }
table.rt-finale th.th-zone-hdr {
    background: var(--gold-dark); color: var(--on-gold-dark);
}
table.rt-finale td.grp-sep { border-left: 2px solid #c8a000; }

/* Rangs — la teinte est posée sur la LIGNE et non sur ses cellules : une
   cellule rendue transparente au survol laisse alors voir la teinte du
   rang au lieu de l'effacer. L'autre page la posait sur les cellules, et
   la ligne d'ex æquo y restait d'un jaune franc dans le thème sombre,
   faute de l'atténuation qui suit. */
tr.rank-1 { background: rgba(250, 220, 90, .1); }
tr.rank-2 { background: rgba(192, 192, 192, .1); }
tr.rank-3 { background: rgba(205, 127, 50, .1); }
tr.tie-row { background: rgba(255, 250, 120, .35); }
[data-theme="dark"] tr.tie-row { background: rgba(255, 250, 120, .07); }
tr.abandoned { background: rgba(170, 30, 30, .04); opacity: .75; }

/* Le survol annonce « cette ligne se clique ». Seules les lignes de
   pilotes de la table de qualification ouvrent quelque chose ; ailleurs
   — grille des zones, table de finale, panneau de détail — il suivait la
   souris sans rien désigner. */
@media (hover: hover) {
    table.rt tbody tr:hover td { background: transparent; }
    table.rt-list tbody tr.pilot-row:hover { background: var(--row-hover); }
}

.rank-badge {
    display: inline-flex; align-items: center; justify-content: center;
    width: 26px; height: 26px; border-radius: 50%;
    font-weight: 700; font-size: 12px;
}
tr.rank-1 .rank-badge, tbody.rank-1 .rank-badge {
    background: var(--medal-gold); color: var(--on-medal);
}
tr.rank-2 .rank-badge, tbody.rank-2 .rank-badge {
    background: var(--medal-silver); color: var(--on-medal);
}
tr.rank-3 .rank-badge, tbody.rank-3 .rank-badge {
    background: var(--medal-bronze); color: var(--on-medal);
}
tr.rank-n .rank-badge, tr.tie-row .rank-badge,
tbody.rank-n .rank-badge, tbody.tie-row .rank-badge {
    background: var(--border-light); color: var(--text);
}

.aba-badge {
    display: inline-block; background: var(--danger-bg);
    color: var(--danger-dark); font-size: 10px; padding: 2px 8px;
    border-radius: 5px; font-weight: 600;
}
.tie-badge {
    display: inline-block; background: var(--warning-bg);
    color: var(--warning-dark); font-size: 10px; padding: 2px 6px;
    border-radius: 5px; font-weight: 700; margin-left: 3px;
}
/* `--navy` est un FOND : une encre se prend dans `--text-brand`, qui
   bascule avec le thème. Les deux pages écrivaient l'une `var(--navy)`
   avec un correctif pour le thème sombre, l'autre `var(--text)`. */
.total-val { font-weight: 700; font-size: 14px; color: var(--text-brand); }
.total-val-gold {
    font-weight: 700; font-size: 14px; color: var(--warning-dark);
}
.pen-neg { color: var(--danger); font-weight: 600; }
.cnt-60 { color: var(--success-dark); font-weight: 600; }
.cnt-z { color: var(--text-muted); }
.tour-total { font-weight: 600; color: var(--text-brand); }

.no-finale {
    text-align: center; padding: 16px; color: var(--warning-dark);
    background: var(--warning-bg); font-size: 12px;
    border-top: 1px solid var(--warning); border-radius: 0 0 8px 8px;
}

/* ── Vue mobile en cartes ─────────────────────────────────────────
   Sous 769px, la table se cache et les cartes paraissent. Les deux moitiés
   de ce couple sont indissociables : séparées, un téléphone reçoit soit les
   deux, soit aucune. C'est arrivé — en extrayant le composant du tableau,
   `.tbl-wrap { display: none }` est parti avec les autres occurrences de ce
   nom, et la page Résultats a montré la table large sous les cartes.

   Le bloc vivait dans resultats.html, donc dans la seule page qui avait des
   cartes. Le Classement Championnat rend le même classement et n'avait
   aucune règle mobile : son tableau de onze colonnes faisait 876 px dans un
   téléphone de 390, à explorer au doigt. Mesuré le 25 octobre 2026. */
@media (max-width: 768px) {
    .table-section .tbl-wrap { display: none; }
}

/* ── Vue mobile cartes ─────────────────────────────────────────── */
.mob-res-cards { display: none; }

@media (max-width: 768px) {
  .mob-res-cards { display: block; border-radius: 0 0 10px 10px; overflow: hidden; box-shadow: var(--shadow); }

  /* Carte pilote */
  .mob-res-card {
    border: 1px solid var(--border); border-top: none;
    background: var(--bg-card);
  }
  .mob-res-card:last-child { border-radius: 0 0 10px 10px; }
  .mob-res-card.mob-r1 { border-left: 4px solid var(--medal-gold); }
  .mob-res-card.mob-r2 { border-left: 4px solid var(--medal-silver); }
  .mob-res-card.mob-r3 { border-left: 4px solid var(--medal-bronze); }
  .mob-res-card.mob-aba { opacity: .7; }

  /* En-tête de carte */
  .mob-res-hdr {
    display: flex; align-items: center; padding: 11px 12px;
    gap: 10px; cursor: pointer; user-select: none;
    -webkit-tap-highlight-color: transparent;
  }
  .mob-res-rank { flex-shrink: 0; min-width: 28px; text-align: center; }
  .mob-res-pilot { flex: 1; min-width: 0; }
  .mob-res-name {
    font-weight: 700; font-size: 14px; color: var(--navy);
    display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .mob-res-club { font-size: 10px; color: var(--text-muted); display: block; margin-top: 1px; }
  .mob-res-right { display: flex; align-items: center; gap: 7px; flex-shrink: 0; }
  .mob-res-total { font-weight: 700; font-size: 18px; color: var(--navy); min-width: 30px; text-align: right; }
  .mob-r1 .mob-res-total { color: var(--warning-dark); }
  .mob-res-bib { font-size: 10px; background: var(--navy); color: white; padding: 2px 6px; border-radius: 4px; }
  .mob-chevron { font-size: 10px; color: var(--text-muted); transition: transform .15s var(--ease-out); flex-shrink: 0; }
  .mob-res-card.open .mob-chevron { transform: rotate(90deg); }

  /* Corps de carte */
  .mob-res-body {
    display: none; padding: 10px 12px 14px;
    border-top: 1px solid var(--border-light);
  }
  .mob-res-card.open .mob-res-body { display: block; }

  /* Bloc tour */
  .mob-tour-bloc { margin-bottom: 12px; }
  .mob-tour-hdr {
    display: flex; justify-content: space-between; align-items: center;
    font-size: 11px; font-weight: 700; color: var(--text-muted);
    text-transform: uppercase; letter-spacing: .5px;
    padding-bottom: 6px; border-bottom: 1px solid var(--border-light); margin-bottom: 8px;
  }
  .mob-tour-tot {
    font-size: 14px; font-weight: 700; color: var(--navy);
    text-transform: none; letter-spacing: 0;
  }

  /* Grille zones */
  .mob-zones-grid { display: flex; flex-wrap: wrap; gap: 5px; }
  .mob-zone-chip {
    display: flex; flex-direction: column; align-items: center;
    min-width: 42px; padding: 4px 6px; border-radius: 7px;
    border: 1px solid var(--border); background: var(--bg);
  }
  .mob-zone-chip.zv-60 { border-color: var(--success); background: var(--success-bg); }
  .mob-zone-chip.zv-0  { border-color: var(--border); background: var(--bg); }
  .mob-zone-chip.zv-na { opacity: .35; }
  .mob-zone-lbl { font-size: 9px; color: var(--text-muted); font-weight: 600; }
  .mob-zone-pts { font-size: 14px; font-weight: 700; color: var(--navy); line-height: 1.2; }
  .mob-zone-chip.zv-60 .mob-zone-pts { color: var(--success-dark); }

  /* Pénalité */
  .mob-pen-row {
    display: flex; align-items: center; gap: 8px;
    padding: 7px 0 5px; border-top: 1px solid var(--border-light); margin-top: 6px;
    font-size: 12px;
  }
  .mob-pen-lbl { color: var(--text-muted); font-weight: 600; }
  .mob-pen-val { color: var(--danger); font-weight: 700; }

  /* Départage */
  .mob-dep-row {
    display: flex; flex-wrap: wrap; gap: 5px; align-items: center;
    padding-top: 7px; border-top: 1px solid var(--border-light); margin-top: 4px;
  }
  .mob-dep-lbl { font-size: 10px; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: .4px; flex-basis: 100%; margin-bottom: 2px; }
  .mob-dep-chip {
    font-size: 11px; font-weight: 600; padding: 2px 9px;
    border-radius: 10px; background: var(--bg); border: 1px solid var(--border);
    color: var(--text-muted);
  }
  .mob-dep-chip.dep-60 { background: var(--success-bg); border-color: var(--success); color: var(--success-dark); }

  /* Finale cards — teinte dorée */
  .mob-res-cards.mob-finale-cards .mob-res-total { color: var(--warning-dark); }
  .mob-res-cards.mob-finale-cards .mob-zone-pts  { color: var(--col-finale); }
  .mob-res-cards.mob-finale-cards .mob-tour-tot  { color: var(--warning-dark); }

  /* Badges de rang dans les cartes mobiles */
  .mob-res-card .rank-badge { width: 28px; height: 28px; font-size: 13px; background: var(--border-light); color: var(--text); }
  .mob-res-card.mob-r1 .rank-badge { background: var(--medal-gold); color: var(--on-medal); }
  .mob-res-card.mob-r2 .rank-badge { background: var(--medal-silver); color: var(--on-medal); }
  .mob-res-card.mob-r3 .rank-badge { background: var(--medal-bronze); color: var(--on-medal); }

  /* Dark mode */
  [data-theme="dark"] .mob-res-name  { color: var(--text); }
  [data-theme="dark"] .mob-res-total { color: var(--text); }
  [data-theme="dark"] .mob-tour-tot  { color: var(--text); }
  [data-theme="dark"] .mob-zone-pts  { color: var(--text); }
  [data-theme="dark"] .mob-zone-chip { background: var(--bg-card); }
}
