/* =============================================================================
   echecs — base.css : mise en page, typographie et composants COMMUNS.
   Réf : specs/30-identite-visuelle.md §2 (jeu de variables) ; décision #7 ;
         specs/40-ergonomie-et-responsive.md (points de rupture 480/768/1024/1440).

   Toujours chargé. Par-dessus, UN seul fichier de thème (club ou admin) ne fait
   que donner une valeur aux variables ci-dessous. Faire évoluer la charte =
   toucher ICI, pas les thèmes.
   ========================================================================== */

:root {
  /* --- couleurs (valeurs par défaut, surchargées par le thème) --- */
  --couleur-primaire:      #33438a;
  --couleur-accent:        #b5121b;
  --couleur-fond:          #f4f5f8;
  --couleur-surface:       #ffffff;
  --couleur-texte:         #1b1c22;
  --couleur-texte-attenue: #5b5d6b;
  --couleur-bordure:       #d9dbe3;
  --couleur-ok:            #1a7f4b;
  --couleur-erreur:        #b5121b;

  /* --- bandeau --- */
  --bandeau-fond:      var(--couleur-primaire);
  --bandeau-texte:     #ffffff;
  --bandeau-hauteur:   72px;

  /* --- barre de menus : 2e couleur du club (l'accent), pour la distinguer du
         bandeau. Un thème peut la surcharger sans toucher à l'accent. --- */
  --menus-fond:        var(--couleur-accent);
  --menus-texte:       #ffffff;

  /* --- mesures --- */
  --largeur-contenu:  1200px;
  --largeur-lecture:  72ch;     /* largeur de prose plafonnée (40 §3) */
  --rayon:            8px;
  --espace:           16px;
  --ombre-carte:      0 1px 3px rgba(0,0,0,.08), 0 1px 2px rgba(0,0,0,.06);

  --police: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
            Arial, sans-serif;
}

/* --- réinitialisation légère --------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font-family: var(--police);
  font-size: 16px;
  line-height: 1.55;
  color: var(--couleur-texte);
  background: var(--couleur-fond);
}
img { max-width: 100%; height: auto; }
a { color: var(--couleur-primaire); }
a:hover { color: var(--couleur-accent); }
h1, h2, h3 { line-height: 1.25; }

/* --- ossature ---------------------------------------------------------- */
.page { min-height: 100vh; display: flex; flex-direction: column; }

.bandeau {
  display: flex; align-items: center; gap: var(--espace);
  min-height: var(--bandeau-hauteur);
  padding: 0 var(--espace);
  background: var(--bandeau-fond);
  color: var(--bandeau-texte);
}
.bandeau a { color: inherit; text-decoration: none; }
.bandeau__logo { height: calc(var(--bandeau-hauteur) - 16px); width: auto; }
.bandeau__titre {
  margin: 0; font-size: 1.35rem; font-weight: 700; letter-spacing: .02em;
}
/* Variante « image-titre » : le nom du club est fourni en image par le thème.
   L'URL de l'image est posée en style inline par gabarits/bandeau.php
   (background-image), pour rester valable quel que soit le préfixe d'install. */
.bandeau__titre--image {
  flex: 1 1 auto; max-width: 520px; height: calc(var(--bandeau-hauteur) - 20px);
  background-position: left center; background-size: contain; background-repeat: no-repeat;
  text-indent: -9999px; overflow: hidden;
}
.bandeau__espace { flex: 1 1 auto; }
/* Pictogramme monochrome au trait (hérite la couleur du texte : currentColor). */
.icone { fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; vertical-align: -3px; }

.contenu {
  flex: 1 1 auto; width: 100%;
  max-width: var(--largeur-contenu);
  margin: 0 auto; padding: calc(var(--espace) * 1.5) var(--espace);
}
.contenu--prose { max-width: var(--largeur-lecture); }

.pied {
  padding: var(--espace);
  background: var(--couleur-surface);
  border-top: 1px solid var(--couleur-bordure);
  color: var(--couleur-texte-attenue);
  font-size: .85rem; text-align: center;
}

/* --- composants de base --------------------------------------------------- */
.carte {
  background: var(--couleur-surface);
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  box-shadow: var(--ombre-carte);
  padding: var(--espace);
}

/* Carte isolée centrée (formulaires d'authentification/compte — un seul
   écran, pas de liste+détail) : `--carte-largeur` pose la largeur au cas par
   cas (420/480/640px selon l'écran), un seul endroit fixe le comportement
   responsive (40 §8) au lieu de le répéter en style inline sur chaque page. */
.carte-etroite { max-width: var(--carte-largeur, 640px); margin: 24px auto; }

.bouton {
  display: inline-block; padding: .55em 1.1em;
  border: 1px solid transparent; border-radius: var(--rayon);
  background: var(--couleur-primaire); color: #fff;
  font: inherit; text-decoration: none; cursor: pointer;
}
.bouton:hover { background: var(--couleur-accent); color: #fff; }
.bouton--secondaire {
  background: transparent; color: var(--couleur-primaire);
  border-color: var(--couleur-primaire);
}

label { display: block; margin: .75em 0 .25em; font-weight: 600; }
input, select, textarea {
  width: 100%; padding: .5em .6em; font: inherit;
  border: 1px solid var(--couleur-bordure); border-radius: var(--rayon);
  background: var(--couleur-surface); color: var(--couleur-texte);
}
input[type="checkbox"], input[type="radio"] { width: auto; }
input[type="date"] { max-width: 170px; }

/* --- champ = intitulé + saisie sur UNE ligne ------------------------------
   `.champ` regroupe un <label for> et son contrôle. Les deux restent côte à
   côte tant que la place le permet ; sur écran très étroit le contrôle passe
   sous son intitulé plutôt que de déborder (`flex-wrap`).
   Largeur des saisies : c'est l'attribut HTML `size="…"` qui la commande
   (login 30, mot de passe 20, nom/prénom 25, téléphone 15, adresse 30, code
   postal 5, ville 20, e-mail 40) — d'où `width: auto` ; `max-width: 100%`
   l'empêche de dépasser son conteneur. Pour des intitulés alignés en
   colonne, poser `champs-alignes` sur le <form> (largeur d'intitulé =
   `--intitule`, 9em par défaut, à ajuster sur le formulaire si un intitulé est
   plus long). */
input[size] { width: auto; max-width: 100%; }
.champ { display: flex; flex-wrap: wrap; align-items: center; gap: .2em .6em; margin: .5em 0; min-width: 0; }
.champ > label { margin: 0; }
.champ > :is(input, select) { width: auto; max-width: 100%; min-width: 0; }
@media (min-width: 481px) {
  .champs-alignes .champ > label { min-width: var(--intitule, 9em); }
}
/* Plusieurs contrôles d'un même champ (ex. arrondissement + école) : ils se
   suivent à droite de l'intitulé et passent à la ligne ensemble si besoin. */
.champ > .champ-groupe { display: flex; flex: 1 1 14em; flex-wrap: wrap; align-items: center; gap: .4em .6em; min-width: 0; max-width: 100%; }
.champ-groupe > select { width: auto; max-width: 100%; min-width: 0; }
.champ.choix-ecole { align-items: flex-start; }
.choix-ecole > label { padding-top: .5em; }
/* Listes déroulantes de largeur fixe, en caractères : école 50, cours 60.
   (`size` sur un <select> voudrait dire « nombre de lignes » : d'où ces classes.) */
/* Saisie texte SANS `size` : occupe le reste de la ligne (au moins 12em). */
.champ > input:is([type="text"], [type="search"]):not([size], .champ-code) { flex: 1 1 12em; width: auto; }
.champ > select.champ-ecole, select.champ-ecole { width: 50ch; max-width: 100%; }
.champ > select.champ-cours, select.champ-cours { width: 60ch; max-width: 100%; }

/* Variante compacte : <label class="champ-en-ligne">Intitulé <input …></label> —
   intitulé à gauche, saisie à droite, sur une ligne, dans une colonne étroite. */
label.champ-en-ligne { display: flex; align-items: center; justify-content: space-between; gap: .6em; font-weight: 400; }
label.champ-en-ligne > input { width: 7em; flex: 0 0 auto; }

/* Précision discrète sous un champ ou une option. */
.aide { margin: .1em 0 .6em; font-size: .9rem; color: var(--couleur-texte-attenue); }

table { width: 100%; border-collapse: collapse; }
th, td { padding: .5em .6em; border-bottom: 1px solid var(--couleur-bordure); text-align: left; }

/* Sous-titre de groupe dans un formulaire (« Qui voit cette page : »,
   « Comité directeur / animation »…) : remplace un idiome jusque-là répété
   en style inline sur 5 écrans admin (menus/pages/personnes) — un seul
   endroit, et il profite de la densité `.zone-admin` ci-dessous comme
   n'importe quel `<p>`/`<h2>`, sans marge fixée en dur qui la contournerait. */
.sous-titre { margin: .8em 0 .25em; font-weight: 600; }


/* --- accueil : contenu principal + colonne latérale (specs/40 §3) --------- */
.accueil-grille { display: grid; grid-template-columns: 1fr; gap: var(--espace); }
.accueil-cote   { display: flex; flex-direction: column; gap: var(--espace); }
@media (min-width: 900px) {
  .accueil-grille { grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr); }
}
.espace-club input { margin-bottom: 4px; }
.news-item { padding: 12px 0; border-bottom: 1px solid var(--couleur-bordure); }
.news-item:last-child { border-bottom: 0; }
.news-item h3 { margin: 2px 0 6px; font-size: 1rem; }
.news-item__date { margin: 0; font-size: .8rem; color: var(--couleur-texte-attenue); }
.news-item__corps { font-size: .9rem; }
.news-item__corps :is(img, table) { max-width: 100%; height: auto; }
.accueil-audience { font-size: .8rem; color: var(--couleur-texte-attenue); text-align: center; margin: 4px 0 0; }

/* --- menus de navigation (specs/100 §A6) --------------------------------- */
.menus { background: var(--menus-fond); }
.menus__liste {
  display: flex; flex-wrap: wrap; list-style: none; margin: 0 auto; padding: 0;
  max-width: var(--largeur-contenu);
}
.menus__item { position: relative; }
.menus__lien, .menus__declencheur {
  display: block; padding: .65em 1em;
  color: var(--menus-texte); background: none; border: 0; font: inherit;
  text-decoration: none; cursor: pointer; white-space: nowrap;
}
.menus__lien:hover, .menus__declencheur:hover,
.menus__item--ouvert > .menus__declencheur { background: rgba(0,0,0,.16); color: var(--menus-texte); }
.menus__sous {
  display: none; position: absolute; top: 100%; left: 0; z-index: 50;
  min-width: 220px; margin: 0; padding: 4px 0; list-style: none;
  background: var(--couleur-surface); border: 1px solid var(--couleur-bordure);
  box-shadow: var(--ombre-carte);
}
.menus__sous a { display: block; padding: .5em 1em; color: var(--couleur-texte); text-decoration: none; }
.menus__sous a:hover { background: var(--couleur-fond); color: var(--couleur-primaire); }
.menus__item--ouvert > .menus__sous { display: block; }
.menus__sandwich {
  display: none; width: auto; margin: 0; padding: .55em 1em;
  color: var(--menus-texte); background: none; border: 0; font: inherit; cursor: pointer;
}
@media (hover: hover) {
  .menus__item--groupe:hover > .menus__sous,
  .menus__item--groupe:focus-within > .menus__sous { display: block; }
}
@media (max-width: 768px) {
  .menus__sandwich { display: block; }
  .menus__liste { display: none; flex-direction: column; }
  .menus--ouvert .menus__liste { display: flex; }
  .menus__sous { position: static; min-width: 0; border: 0; box-shadow: none;
                 background: rgba(0,0,0,.15); }
  .menus__sous a { color: var(--menus-texte); }
}

/* --- écrans d'administration (listes + formulaires) -------------------- */
.admin-barre {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: center;
  margin-bottom: var(--espace);
}
.admin-barre form { display: flex; gap: 8px; align-items: center; margin: 0; }
.admin-barre input, .admin-barre select, .admin-barre button { width: auto; }
.tableau-admin td, .tableau-admin th { vertical-align: top; }
.tableau-admin .actions { white-space: nowrap; }
.tableau-admin tbody tr.ligne-active { background: var(--couleur-fond); font-weight: 600; }
.pagination { display: flex; gap: 8px; margin-top: var(--espace); align-items: center; }

/* --- liste + détail (specs/60-inventaire-ecrans.md) ---------------------
   Coquille de page FIGÉE sur ces écrans : bandeau/menu/pied ne défilent
   JAMAIS — seuls les panneaux liste et détail défilent, chacun pour soi,
   dans la hauteur restante. Sur desktop, liste à gauche + détail à droite,
   tous deux visibles. Sous 900px : un seul plan à la fois — repli SANS JS =
   détail empilé sous la liste (flux normal) ; AVEC JS, le détail devient un
   plan qui recouvre la liste (jamais en dessous), pour qu'en le refermant on
   retrouve la liste EXACTEMENT où on l'avait laissée (jamais reconstruite).
   `body:has(...)` limite cette coquille figée aux pages qui en ont besoin —
   toutes les autres pages gardent le défilement normal du document. */
body:has(.liste-detail) {
  height: 100vh; overflow: hidden;
  /* Écran de gestion de données, pas une page de lecture : exploite toute la
     largeur (au lieu du plafond --largeur-contenu réservé aux pages de
     contenu/prose). Le menu (.menus__liste) suit, pour rester aligné. */
  --largeur-contenu: none;
}
body:has(.liste-detail) .page { height: 100vh; }
body:has(.liste-detail) .bandeau,
body:has(.liste-detail) nav.menus,
body:has(.liste-detail) .bandeau-emprunt,
body:has(.liste-detail) .pied { flex: 0 0 auto; }
body:has(.liste-detail) main.contenu { flex: 1 1 auto; min-height: 0; display: flex; padding-bottom: calc(var(--espace) * 1.5); }

.liste-detail { position: relative; flex: 1 1 auto; min-height: 0; width: 100%; display: grid; grid-template-columns: minmax(240px, 34%) 1fr; gap: var(--espace); }
/* Chaque panneau est lui-même une colonne flex : un en-tête FIXE (titre,
   bouton « Nouveau », filtre / bouton « Retour à la liste ») + un corps qui
   défile pour lui seul — le défilement du corps ne doit JAMAIS emporter
   l'en-tête (specs/60-inventaire-ecrans.md). */
.liste-detail__liste,
.liste-detail__detail { height: 100%; min-width: 0; overflow: hidden; display: flex; flex-direction: column; }
.liste-detail__liste-entete { flex: 0 0 auto; padding-bottom: var(--espace); border-bottom: 1px solid var(--couleur-bordure); margin-bottom: var(--espace); }
.liste-detail__liste-entete .filtre-liste { margin-top: 10px; }
.liste-detail__liste-corps,
.liste-detail__detail-corps { flex: 1 1 auto; overflow: auto; min-height: 0; }
.liste-detail__vide { color: var(--couleur-texte-attenue); text-align: center; padding: 48px 20px; }
.liste-detail__fermer { display: none; flex: 0 0 auto; }

@media (max-width: 900px) {
  .liste-detail { grid-template-columns: 1fr; }
  /* Un seul plan à la fois (specs/60) : sans sélection, le panneau détail ne
     contient que le placeholder « Sélectionnez… » (.liste-detail__vide) —
     on le retire du flux plutôt que de le laisser en second « rang » de la
     grille mobile. Sinon la grille (1 colonne) place liste ET détail sur deux
     rangées AUTO qui se partagent la hauteur disponible : la liste (207
     lignes) se retrouvait comprimée dans une fraction de la hauteur, son
     corps scrollable réduit à ~rien de visible — bug réel signalé par
     l'auteur (liste illisible, pagination et sélection inatteignables).
     Retiré du flux, la liste redevient la SEULE rangée -> même mécanisme
     d'étirement sur toute la hauteur que la colonne desktop (déjà correct). */
  .liste-detail__detail:has(.liste-detail__vide) { display: none; }
  .liste-detail--ouvert .liste-detail__detail {
    position: absolute; inset: 0; z-index: 40;
    background: var(--couleur-fond); padding: var(--espace);
  }
  .liste-detail--ouvert .liste-detail__liste { overflow: hidden; } /* figée derrière le plan du détail */
  /* Variante pour les listes dont l'EN-TÊTE (filtres, accès direct, exports) est
     haut : l'en-tête est FIXE (`flex: 0 0 auto`) et, sur un petit écran, il peut
     occuper presque toute la hauteur — le corps de liste, seul à défiler, se
     retrouvait réduit à ~0 (liste invisible, défilement impossible : bug signalé
     en recette sur smartphone, admin/inscriptions-ateliers). Ici, sous 900px, le
     panneau défile EN ENTIER (en-tête puis lignes) ; l'en-tête cesse d'être figé. */
  .liste-detail--defilement-global .liste-detail__liste { display: block; overflow: auto; }
  .liste-detail--defilement-global .liste-detail__liste-corps { overflow: visible; }
  .liste-detail--defilement-global.liste-detail--ouvert .liste-detail__liste { overflow: hidden; }
  /* Le bouton ne sert (et n'apparaît) que quand un détail réel recouvre la
     liste — rien à « refermer » sur le placeholder « Sélectionnez… ». */
  .liste-detail--ouvert .liste-detail__fermer {
    display: block; width: 100%; margin-bottom: var(--espace);
    padding: .6em 1em; text-align: left; font-weight: 600;
    background: var(--couleur-surface); border: 1px solid var(--couleur-bordure); border-radius: var(--rayon);
  }
}

.champ-droits { display: flex; flex-wrap: wrap; gap: 12px; margin: .5em 0; }
.champ-droits label { display: flex; align-items: center; gap: 6px; font-weight: 400; margin: 0; }
.champ-droits input { width: auto; }
/* Plusieurs champs sur une même ligne (chacun est un `.champ`), qui passent à
   la ligne suivante quand la place manque. */
.form-lien { display: flex; flex-wrap: wrap; align-items: center; column-gap: 1.25em; row-gap: 0; margin: 8px 0; }
.form-lien .champ { margin: .35em 0; }
.form-lien .champ > label { min-width: 0; }
textarea.editeur-riche { min-height: 320px; font-family: inherit; }

/* Tableau compact des liens de bas d'article : en-têtes une seule fois au lieu
   de répéter « Libellé/Page/Article/Galerie/Document » sur chacune des 3
   lignes — retour de l'auteur (2026-09-05). */
.tableau-liens th, .tableau-liens td { padding: .25em .4em; }
.tableau-liens th { font-size: .85rem; font-weight: 600; }
.tableau-liens select, .tableau-liens input { width: 100%; }

/* --- création de compte : bloc enfant révélé sans JS (specs/110 §A3) --- */
.creation-compte .bloc-enfant { display: none; padding-top: var(--espace); margin-top: var(--espace); border-top: 1px solid var(--couleur-bordure); }
.creation-compte:has(#avecEnfant:checked) .bloc-enfant { display: block; }

/* --- authentification d'une adresse par code court (creer-compte, mon-compte) --- */
/*     Réf : specs/110 §A3/§A4 (décision #14 amendée) — piloté par compte-email.js. */
.etape-code, .etape-connexion { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--couleur-bordure); }
.champ > input.champ-code { width: 8em; }
.champ-code { max-width: 8em; letter-spacing: .35em; font-size: 1.25rem; text-align: center; }
.parcours-email__message { margin: .5em 0 0; font-size: .95rem; min-height: 1.2em; }
.parcours-email__message--erreur { color: var(--couleur-erreur); }
.lien-bouton { display: inline-block; width: auto; background: none; border: 0; padding: 0; margin-top: 8px;
  color: var(--couleur-accent); text-decoration: underline; cursor: pointer; font: inherit; }
.lien-bouton:hover { background: none; color: var(--couleur-accent); }

/* --- galeries de photos ----------------------------------------------- */
.galerie-grille {
  display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}
.galerie-vignette { margin: 0; }
.galerie-vignette img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--rayon); display: block; background: var(--couleur-bordure);
}
.galerie-vignette form { margin: 4px 0 0; }
.galerie-vignette button { padding: .25em .6em; font-size: .8rem; }
.galerie-vignette > a { display: block; cursor: zoom-in; }

/* --- visionneuse plein écran (galerie-lightbox.js) --------------------- */
.lightbox {
  display: none; position: fixed; inset: 0; z-index: 1000;
  background: rgba(0, 0, 0, .88);
  align-items: center; justify-content: center; padding: 24px;
}
.lightbox--ouvert { display: flex; }
.lightbox img { max-width: 92vw; max-height: 92vh; border-radius: var(--rayon); }
.lightbox__fermer {
  position: absolute; top: 12px; right: 16px; z-index: 1001;
  background: none; border: none; color: #fff; font-size: 2.2rem;
  line-height: 1; cursor: pointer; padding: 4px 10px;
}

/* --- liens de bas d'article + notice ----------------------------------- */
.article-liens { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--espace); }
.notice { margin-top: var(--espace); }
.notice > summary { cursor: pointer; font-weight: 600; }
.notice__corps { margin-top: 8px; font-size: .95rem; }
.notice__edition { margin-top: 8px; }
.notice__edition button { margin-top: .75em; }

/* --- bandeau « emprunt » : rappel permanent d'une session « en tant que » --- */
.bandeau-emprunt {
  background: #8a5a00; color: #fff;
  padding: .5em var(--espace); font-size: .9rem; text-align: center;
}
.bandeau-emprunt a { color: #fff; font-weight: 700; }

/* --- zone de message (remplace alert(), specs/130 §A10) --------------- */
.message { padding: .8em 1em; border-radius: var(--rayon); margin: 0 0 var(--espace); }
.message--ok     { background: #e6f4ec; color: var(--couleur-ok); }
.message--erreur { background: #fbe9ea; color: var(--couleur-erreur); }
.message--info   { background: #e8eefb; color: #23407a; }
.message[hidden] { display: none; }

/* --- points de rupture (40 §2) + densité petit écran (40 §8, décision #33) */
@media (max-width: 1024px) {
  :root { --largeur-contenu: 900px; }
  /* Bandeau compact : NE PAS passer par `--bandeau-hauteur` ici — chaque
     thème de club fixe cette variable en dur dans son `:root` (ex.
     `theme.css` LuteceEchecs/ElanParisEchecs : 84px, pour le logo), et une
     règle de thème l'emporterait sur celle-ci même hors de son media query
     (ordre de cascade, pas la largeur d'écran). On contraint donc directement
     les propriétés de mise en page des éléments, que les thèmes ne touchent
     jamais (décision #7 : un thème ne pose QUE des valeurs de variables).
     Le titre ne passe plus à la ligne non plus — c'est LA cause du bandeau
     à 30% d'écran observé par l'auteur sur un vrai smartphone — il est
     tronqué proprement plutôt que de pousser la hauteur du bandeau. */
  .bandeau { min-height: 48px; }
  .bandeau__logo { height: 32px; }
  .bandeau__titre--image { height: 32px; }
  .bandeau__titre {
    font-size: 1.05rem; white-space: nowrap; overflow: hidden;
    text-overflow: ellipsis; min-width: 0; flex: 1 1 auto;
  }
  .bandeau__salut { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 9em; }
}
@media (max-width: 768px)  {
  /* Pied de page : rien d'utile pour la tâche en cours, sur un écran où la
     hauteur est rare (40 §8). Son contenu reste lisible en grand écran. */
  .pied { display: none; }
  /* Cartes empilées (ex. mon-compte.php) : l'espacement pensé pour le grand
     écran (24px, .carte-etroite) est réduit de moitié — la marge horizontale
     du conteneur de page ne s'ajoute plus pleinement à celle de la carte. */
  .carte-etroite { margin: 12px auto; }
  .carte  { padding: calc(var(--espace) * .75); }
  .contenu { padding: var(--espace) 12px; }
  /* Boutons compacts. */
  .bouton, .liste-detail__fermer, .pagination a { padding: .4em .8em; }
  /* Icônes à la place du texte pour les actions répétitives (déconnexion,
     retour à la liste, pagination) : le texte reste dans le DOM pour un
     lecteur d'écran / la dégradation sans style, juste masqué visuellement —
     l'icône ou le symbole voisin (⏻, ←, →) porte l'information à l'écran,
     `aria-label` sur le lien/bouton porte l'information hors écran. */
  .texte-bouton { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
@media (max-width: 480px)  {
  body { font-size: 15px; }
  .bandeau__titre--image { max-width: 60vw; }
}

/* --- zone Administration : densité (40 §8, décision #33) -----------------
   Un écran d'admin affiche plus de contenu utile par page qu'un écran public
   et n'a pas besoin du même confort de lecture (retours successifs de
   l'auteur, capture à l'appui — 2e passe : « on peut aller plus loin sans
   dégrader la lisibilité », donc la TAILLE du texte ne bouge pas ici,
   seulement l'espace autour). Portée par `.page.zone-admin` (posée par
   layout.php selon zone_courante()) : ne touche JAMAIS les pages `user/`
   (club), qui gardent l'espacement aéré voulu pour elles. Densité
   SYSTÉMATIQUE (pas seulement sous 768px) — la zone n'a besoin d'aération à
   aucune taille d'écran.
   BLOC VOLONTAIREMENT EN TOUTE FIN DE FICHIER : plusieurs règles ci-dessous
   font le même métier qu'une règle déjà posée plus haut (`.contenu`,
   `.liste-detail__fermer`…) avec une spécificité CSS égale ou même
   légèrement inférieure sur le papier — être déclaré EN DERNIER est ce qui
   leur permet de gagner (à spécificité égale, la cascade tranche par ordre
   d'apparition). Un override `.zone-admin` ajouté plus haut dans le fichier
   perdrait silencieusement contre une règle de ce genre plus bas — piège déjà
   rencontré deux fois dans cette passe (bouton fermer, rembourrage de
   `.contenu`), voir les commentaires ligne par ligne. */
.zone-admin h1 { font-size: 1.3rem; margin: 0 0 .2em; }
.zone-admin h2 { font-size: 1.05rem; margin: .7em 0 .2em; }
.zone-admin p  { margin: .3em 0; }
.zone-admin label { margin: .35em 0 .1em; }
.zone-admin .champ > label { margin: 0; }
.zone-admin .champ { margin: .3em 0; }
.zone-admin .sous-titre { margin: .6em 0 .2em; }
.zone-admin .carte { padding: 10px; }
.zone-admin input, .zone-admin select, .zone-admin textarea { padding: .35em .5em; }
.zone-admin .form-lien { margin: 4px 0; }
.zone-admin .form-lien .champ { margin: .25em 0; }
.zone-admin th, .zone-admin td { padding: .3em .5em; }
/* Le rembourrage de `.contenu` (pensé pour une page de lecture) n'a pas de
   raison d'être sur un écran de travail déjà rythmé par ses propres cartes/
   entêtes — le lui laisser est de la marge perdue sur les deux bords ET en
   haut/bas, à chaque écran d'admin. Le `padding-bottom` se règle À PART :
   `body:has(.liste-detail) main.contenu` (plus haut) le fixe avec une
   spécificité (2 classes + 2 éléments) que `.zone-admin .contenu` seul
   (2 classes, 0 élément) ne peut pas battre — `body:has(.zone-admin)
   main.contenu` reproduit exactement ce gabarit de spécificité pour gagner
   le match nul par l'ordre (cette règle est plus bas dans le fichier). */
.zone-admin .contenu { padding: 10px 12px; }
body:has(.zone-admin) main.contenu { padding-bottom: 10px; }
.zone-admin .liste-detail__liste-entete { padding-bottom: 8px; margin-bottom: 8px; }
.zone-admin .liste-detail--ouvert .liste-detail__fermer { margin-bottom: 8px; }

/* Pied de page toujours masqué en admin (quelle que soit la largeur d'écran) :
   ces écrans affichent plus de contenu et n'ont pas les mêmes exigences
   esthétiques que le site club — cf. retour de l'auteur (2026-09-05). */
.zone-admin .pied { display: none; }

/* Étiquette d'état (tournois : « Inscriptions ouvertes », « Complet »…). Sobre :
   une pastille de texte, jamais la couleur seule (le libellé porte le sens). */
.etiquette {
  display: inline-block; padding: .1em .6em; border-radius: 999px; font-size: .85rem; font-weight: 600;
  border: 1px solid var(--couleur-bordure); color: var(--couleur-texte-attenue); background: var(--couleur-surface);
}
.etiquette--ok        { color: var(--couleur-ok);     border-color: var(--couleur-ok); }
.etiquette--attention { color: var(--couleur-erreur); border-color: var(--couleur-erreur); }

/* Agenda de l'accueil : une ligne par échéance, le type en petit au-dessus du lien. */
.agenda__liste { list-style: none; margin: 0; padding: 0; }
.agenda__ligne { padding: .5em 0 .5em .7em; border-left: 4px solid var(--couleur-bordure); margin-bottom: .4em; }
.agenda__ligne--tournoi-scolaire { border-left-color: var(--couleur-ok); }
.agenda__ligne--tournoi-club     { border-left-color: var(--couleur-primaire); }
.agenda__ligne--tournoi-elite    { border-left-color: var(--couleur-accent); }
.agenda__ligne--stage            { border-left-color: var(--couleur-primaire); border-left-style: dashed; }
.agenda__type { display: block; font-size: .8rem; color: var(--couleur-texte-attenue); }

/* Fiche d'un stage (admin) : tarifs et jours « à la journée » n'apparaissent que
   si la case « fractionnable » est cochée (pas de JavaScript). */
.stage-form .stage-frac { display: none; }
.stage-form:has(#fractionnable:checked) .stage-frac { display: block; }

/* Formulaire d'inscription à un stage : « stage entier » et « à la journée » s'excluent
   (gabarits/choix-formule-stage.php ; pas de JavaScript). */
.stage-inscription:not(:has(input[name="couverture"][value="P"]:checked)) .stage-jours { display: none; }
.stage-inscription:has(input[name="couverture"][value="P"]:checked) .stage-entier { display: none; }
