/* =============================================================================
   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; }
/* Contenu éditorial (HTML saisi dans CKEditor : articles, présentations,
   notices, actualités). CKEditor pose les dimensions en style en ligne
   (style="width:600px;height:400px"), qui l'emporte sur la règle ci-dessus :
   sur smartphone la largeur était plafonnée mais la hauteur restait figée →
   image écrasée. `!important` est le seul moyen de primer sur un style en
   ligne ; hauteur recalculée depuis la largeur = proportions conservées
   (demande de l'auteur 2026-09-26). Tout conteneur de HTML éditorial doit
   porter la classe `contenu-editorial`. */
.contenu-editorial img { max-width: 100% !important; height: auto !important; }
.contenu-editorial table { max-width: 100%; }
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;
  flex: 1 1 auto; text-align: center; /* titre centré dans l'espace entre logo et actions */
}
/* 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; height: calc((var(--bandeau-hauteur) - 20px) * 1.2); /* +20 % (2026-10-14) */
  background-position: center center; background-size: contain; background-repeat: no-repeat;
  text-indent: -9999px; overflow: hidden;
}
/* Zone publique, écran large : l'image du nom du club est centrée sur TOUTE la largeur du bandeau (donc sur le menu
   dessous, lui aussi centré), et non dans l'espace restant entre le logo et le salut. Les marges latérales (340px,
   la plus grande des deux zones : « Accueil · Bonjour X · icône ») gardent l'image hors du logo et des actions. */
@media (min-width: 1200px) {
  .zone-user .bandeau { position: relative; }
  .zone-user .bandeau__espace { display: block; flex: 1 1 auto; }   /* pousse les actions à droite (le titre ne les pousse plus) */
  .zone-user .bandeau__titre--image { position: absolute; left: 340px; right: 340px; top: 50%; transform: translateY(-50%); flex: none; }
}
.bandeau__espace { display: none; } /* le titre, centré, occupe tout l'espace libre */
/* Actions de session (accueil, « Bonjour X », déconnexion) : rendues dans le
   bandeau ET dans la barre de menus (gabarits/actions-utilisateur.php) — un
   seul des deux est visible. Écran large : celles du bandeau (`contents` =
   leurs éléments restent des enfants directs du flex, mise en page inchangée). */
.bandeau__actions { display: contents; }
/* Zone publique : le menu et le contenu sont centrés (colonne de --largeur-contenu) ; le bandeau reste pleine largeur
   (logo à l'extrême gauche, Accueil / compte à l'extrême droite, titre au centre). */
.zone-user .menus__liste { justify-content: center; }
/* Menu du compte : icône bonhomme à côté de « Bonjour X » (bandeau et barre de menus), liste déroulante au clic. */
.compte-menu { position: relative; }
.compte-menu__icone { display: inline-flex; align-items: center; justify-content: center; padding: 4px; border-radius: 50%; cursor: pointer; list-style: none; color: inherit; }
.compte-menu__icone::-webkit-details-marker { display: none; }
.compte-menu__icone:hover, .compte-menu__icone:focus-visible, .compte-menu[open] > .compte-menu__icone { background: rgba(255,255,255,.22); }
.compte-menu__liste { position: absolute; right: 0; top: calc(100% + 6px); z-index: 60; min-width: 190px; margin: 0; padding: 4px 0; list-style: none;
  background: var(--couleur-surface); border: 1px solid var(--couleur-bordure); border-radius: 8px; box-shadow: var(--ombre-carte); }
.bandeau .compte-menu__liste a, .menus__actions .compte-menu__liste a { display: block; padding: .55em 1em; color: var(--couleur-texte); text-decoration: none; white-space: nowrap; }
.bandeau .compte-menu__liste a:hover, .menus__actions .compte-menu__liste a:hover { background: var(--couleur-fond); color: var(--couleur-primaire); }

.menus__actions { display: none; }
/* 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); }
/* Page d'article (pages/user/page.php) : barre d'admin, article et notice dans une
   même colonne de lecture CENTRÉE dans la page (demande de l'auteur 2026-09-26 —
   l'article restait collé à gauche d'une zone de 1200px sur grand écran). */
.colonne-lecture { max-width: var(--largeur-lecture); margin: 0 auto; }

.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;
}
/* Pied : icônes (contact, Instagram, FFE) et ligne « club · année » sur UNE ligne centrée (elle passe à la ligne si l'écran est trop étroit). */
.pied { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 6px 18px; }
.pied__liens { display: flex; align-items: center; gap: 14px; margin: 0; }
.pied__liens a { margin: 0; }
.pied__liens a { display: inline-flex; color: var(--couleur-primaire); line-height: 0; }
.pied__liens a:hover, .pied__liens a:focus-visible { opacity: .75; }
.pied__liens img, .pied__liens svg { width: 32px; height: 32px; object-fit: contain; }

/* --- 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 réduit à la largeur de son contenu (ex. choix de la saison des calendriers). */
.largeur-utile { width: auto; max-width: 100%; }

/* --- 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); }
}
/* Accueil en DEUX colonnes (empilées sur smartphone) : sur desktop, la colonne 2 a une largeur double. */
.accueil-2col { display: grid; grid-template-columns: 1fr; gap: var(--espace); align-items: start; }
@media (min-width: 900px) { .accueil-2col { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); } }
.accueil-col { display: flex; flex-direction: column; gap: var(--espace); min-width: 0; }
/* Rubrique repliable : grand titre encadré, clic = ouvre / ferme (exclusif dans la colonne). */
.rubrique { background: var(--couleur-surface); border: 1px solid var(--couleur-bordure); border-radius: var(--rayon, 8px); box-shadow: var(--ombre-carte); }
.rubrique__titre { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 18px var(--espace); position: relative; justify-content: center; text-align: center; text-transform: uppercase;
  font-size: 1.4rem; font-weight: 700; color: var(--couleur-primaire); cursor: pointer; list-style: none; }
.rubrique__titre::-webkit-details-marker { display: none; }
.rubrique__titre::after { content: '▾'; font-size: 1.1rem; transition: transform .15s; position: absolute; right: var(--espace); }
.rubrique[open] > .rubrique__titre::after { transform: rotate(180deg); }
.rubrique[open] > .rubrique__titre { border-bottom: 1px solid var(--couleur-bordure); }
.rubrique__titre:hover, .rubrique__titre:focus-visible { background: var(--couleur-fond); }
.rubrique__corps { padding: var(--espace); }
.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; }
.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;
}
/* Icône « sandwich » : trois barres blanches (la barre du milieu est l'élément, les deux autres son ombre). */
.menus__sandwich-barres {
  display: block; width: 26px; height: 3px; margin: 8px 0; background: #fff; border-radius: 2px;
  box-shadow: 0 -8px 0 #fff, 0 8px 0 #fff;
}
@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; }

/* --- Banque d'images (galeries) à côté d'un CKEditor ----------------------
   Réf : Application/gabarits/banque-images.php, assets/js/banque-images.js.
   Reproduit un dispositif de l'ancienne appli (Repertoire.php, jamais repris) —
   demande de l'auteur 2026-09-23 : partagé entre articles et campagnes. */
.editeur-avec-banque { display: flex; gap: var(--espace); align-items: flex-start; flex-wrap: wrap; }
.editeur-avec-banque > :is(textarea.editeur-riche, .cke_chrome) { flex: 1 1 320px; min-width: 260px; }
.banque-images {
  flex: 1 1 460px; max-width: 100%; display: flex; flex-direction: column; gap: .5em;
  border: 1px solid var(--couleur-bordure); border-radius: var(--rayon);
  background: var(--couleur-surface); padding: .6em; max-height: 600px;
}
.banque-images__aide { margin: 0; font-size: .8rem; color: var(--couleur-texte-attenue); }
.banque-images__galeries {
  list-style: none; margin: 0; padding: 0; overflow: auto; max-height: 140px;
  border: 1px solid var(--couleur-bordure); border-radius: var(--rayon);
}
.banque-images__galeries li { border-bottom: 1px solid var(--couleur-bordure); }
.banque-images__galeries li:last-child { border-bottom: none; }
.banque-images__galeries button {
  display: block; width: 100%; text-align: left; padding: .35em .5em; border: 0; background: transparent;
  cursor: pointer; font: inherit; font-size: .85rem; color: var(--couleur-texte);
}
.banque-images__galeries button:hover, .banque-images__galeries button[aria-current="true"] { background: var(--couleur-fond); }
.banque-images__vignettes { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: .6em; overflow: auto; flex: 1 1 auto; }
.banque-images__vignettes button {
  padding: 0; border: 1px solid var(--couleur-bordure); border-radius: var(--rayon); background: none; cursor: pointer; line-height: 0;
}
.banque-images__vignettes img { width: 100%; height: 190px; object-fit: cover; display: block; cursor: grab; }
.banque-images__vignettes button:hover, .banque-images__vignettes button:focus-visible { outline: 2px solid var(--couleur-primaire); }
.banque-images__vide, .banque-images__chargement { font-size: .8rem; color: var(--couleur-texte-attenue); margin: 0; }

/* --- Écran mailing : 3 colonnes (liste | contenu | droite) ---------------
   Réf : pages/admin/mailing.php, gabarits/mailing-diffusion.php. Demande de
   l'auteur 2026-09-23 : plus de place pour choisir/illustrer, cible+envoi
   dans une colonne à part plutôt qu'empilés sous le formulaire. */
.mailing-ecran { display: flex; gap: var(--espace); align-items: flex-start; flex-wrap: wrap; }
/* Éditeur FIXE (ne grandit pas) : le volet galerie (droite) absorbe l'espace
   restant — demande de l'auteur 2026-09-23, largeurs liste/contenu
   réaugmentées un peu le même jour (première répartition trop serrée). */
.mailing-ecran__contenu { flex: 0 0 480px; min-width: 320px; max-width: 100%; }
.mailing-ecran__droite { flex: 1 1 480px; min-width: 320px; max-width: 100%; }

/* Liste des campagnes plus étroite QUE SUR CET ÉCRAN (pas les autres liste+détail,
   `.liste-detail` reste partagé) — demande de l'auteur 2026-09-23. */
.liste-detail--mailing { grid-template-columns: minmax(210px, 22%) 1fr; }

/* Largeur d'un smartphone (~ iPhone standard) : un message de campagne est
   d'abord lu sur mobile — demande explicite de l'auteur 2026-09-23, l'éditeur
   doit rendre cette contrainte VISIBLE pendant la rédaction, pas juste être
   étroit par manque de place. */
.mailing-largeur-mobile { max-width: 430px; }
.mailing-largeur-mobile .cke_chrome, .mailing-largeur-mobile textarea.editeur-riche { max-width: 430px; }
.mailing-largeur-mobile__etiquette {
  display: inline-block; margin: .3em 0 .4em; padding: .15em .6em; border-radius: 999px;
  background: var(--couleur-fond); font-size: .75rem; color: var(--couleur-texte-attenue);
}

/* Bascule Images / Diffusion en CSS pur (radios masqués + <label> = bouton) :
   robuste à un rechargement AJAX du panneau détail, aucun état JS à
   réinitialiser (contrairement à banque-images.js, qui lui DOIT être
   ré-appelé — cf. window.activerBanqueImages). */
.mailing-onglets input[type="radio"] { position: absolute; opacity: 0; width: 1px; height: 1px; }
.mailing-onglets__barre { display: flex; gap: .4em; margin-bottom: .6em; }
.mailing-onglets__barre label {
  border: 1px solid var(--couleur-bordure); border-radius: var(--rayon);
  padding: .35em .8em; font-size: .9rem; cursor: pointer; color: var(--couleur-texte);
}
#ongletImages:checked ~ .mailing-onglets__barre label[for="ongletImages"],
#ongletDiffusion:checked ~ .mailing-onglets__barre label[for="ongletDiffusion"] {
  background: var(--couleur-primaire); color: #fff; border-color: var(--couleur-primaire);
}
#ongletImages:focus-visible ~ .mailing-onglets__barre label[for="ongletImages"],
#ongletDiffusion:focus-visible ~ .mailing-onglets__barre label[for="ongletDiffusion"] { outline: 2px solid var(--couleur-primaire); }
.mailing-onglets__panneau { display: none; }
#ongletImages:checked ~ [data-panneau="images"] { display: block; }
#ongletDiffusion:checked ~ [data-panneau="diffusion"] { display: block; }

/* 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, ModifierCompte) --- */
/*     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); }
.news-item .article-liens { margin-top: 8px; }
.article-liens .bouton { padding: .35em .8em; font-size: .9rem; }
.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; }
/* « Inscrire un enfant » repliable dans Adhesion.php (ajout sans quitter la page). */
.ajout-enfant { margin: 0 0 var(--espace); }
.ajout-enfant > summary { cursor: pointer; font-weight: 600; color: var(--couleur-primaire); }
.ajout-enfant[open] > summary { margin-bottom: .6em; }

/* --- 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: 60px; }
  .bandeau__logo { height: 44px; }
  .bandeau__titre--image { height: 40px; }
  .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)  {
  /* Le pied reste visible (icônes contact / réseaux), en flux normal, plus compact. */
  .pied { padding: calc(var(--espace) * .6); }
  /* Cartes empilées (ex. ModifierCompte.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: 768px)  {
  /* Smartphone : les actions de session passent du bandeau à la barre de
     menus, à droite du bouton « Menu » (il y a de la place là, pas dans le
     bandeau où le titre-image du club doit avoir toute la largeur). Si la page
     n'a AUCUNE barre de menus (site d'administration sans club…), les actions
     restent dans le bandeau : `:has()` ne masque celles-ci que si la barre
     porte son propre exemplaire. La liste déroulante du menu passe à la ligne
     sous cette rangée. */
  .menus { display: flex; flex-wrap: wrap; align-items: center; }
  .menus__liste { flex: 0 0 100%; }
  .menus__actions {
    display: flex; align-items: center; gap: 10px;
    margin-left: auto; padding-right: 10px; color: var(--menus-texte);
  }
  .menus__actions a { color: var(--menus-texte); text-decoration: none; }
  .menus__actions .bouton {
    background: none; color: var(--menus-texte); border-color: currentColor;
    padding: .2em .6em;
  }
  .menus__actions .bouton:hover { background: rgba(0,0,0,.16); color: var(--menus-texte); }
  .menus__actions .bandeau__salut { max-width: 12em; }
  body:has(.menus__actions) .bandeau__actions { display: none; }
}
@media (max-width: 480px)  {
  body { font-size: 15px; }
  /* Smartphone : l'image-titre reçoit TOUTE la largeur libre (plus de plafond à
     60vw, plus d'espaceur qui se partageait le reste avec elle) — sinon un
     lettrage large et fin (Lutèce, Élan, 7 Échecs : rapport 8:1 à 10:1) se
     réduit à quelques pixels de haut et devient illisible (retour de l'auteur,
     capture d'iPhone). Le salut se tasse pour lui laisser la place. */
  .bandeau { gap: 8px; padding: 0 10px; }
  .bandeau__espace { display: none; }
  .bandeau__titre--image { max-width: none; flex: 1 1 0; min-width: 0; }
}

/* --- 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; margin-bottom: .4em; }
.agenda__type { display: block; font-size: .8rem; color: var(--couleur-texte-attenue); }
/* Inscriptions du foyer (agenda de l'accueil, cartes de la liste des tournois). */
.agenda__inscrits, .inscrits-foyer { display: block; margin-top: .15em; font-size: .85rem; color: var(--couleur-ok); font-weight: 600; }
.inscrits-foyer { margin: .4em 0; font-size: .9rem; }
.agenda__inscrits a, .inscrits-foyer a { font-weight: 400; }
/* Fiche d'un tournoi : la mention se place à côté du bouton « S'inscrire » (dessous si trop étroit). */
.inscription-et-inscrits { display: flex; flex-wrap: wrap; align-items: center; gap: .4em 1em; }
.inscription-et-inscrits .inscrits-foyer { margin: 0; }

/* 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; }

/* --- Double marge sur smartphone (demande de l'auteur 2026-09-26) ---------
   1) 12 pages (inscrire-tournoi/stage/atelier, tournois, stages, vos-*…)
      enveloppent leur contenu dans un `<div class="contenu">` alors que le
      gabarit le place déjà dans `<main class="contenu">` : la marge de page
      s'appliquait DEUX fois (côtés et haut). Le conteneur interne ne garde
      que sa largeur maximale. Placé après `.zone-admin .contenu` (même
      spécificité) pour l'emporter par l'ordre.
   2) Sur smartphone, l'encadré d'une carte ajoutait sa propre marge interne
      à celle de la page. La carte de premier niveau passe « à plat » : elle
      s'étend jusqu'aux bords de l'écran (marges négatives = marge de page de
      12px, cf. `.contenu` sous 768px et `.zone-admin .contenu`), perd ses
      bords latéraux, son arrondi et son ombre, et garde son fond et ses filets
      haut/bas pour séparer les blocs. Le texte s'aligne ainsi sur le titre de
      la page. Exclus : cartes imbriquées dans une carte, et cartes d'un
      écran liste + détail (leurs zones défilantes couperaient le débord). */
.contenu .contenu { padding: 0; }
@media (max-width: 480px) {
  .contenu .carte:not(.carte .carte, .liste-detail .carte) {
    margin-left: -12px; margin-right: -12px;
    padding-left: 12px; padding-right: 12px;
    border-left: 0; border-right: 0; border-radius: 0; box-shadow: none;
  }
}

/* Fiche du site : boutons « Voir » / « Ouvrir » à côté de chaque combo d'article. */
.article-boutons { display: inline-flex; gap: 6px; margin-left: 8px; vertical-align: middle; }
.article-boutons[hidden] { display: none; }
.article-boutons .bouton { width: auto; padding: .3em .8em; }
