/* =====================================================================
   CLUB — la feuille.
   =====================================================================
   Les jetons sont dans themes/club/css/tokens.css, et la direction y est
   expliquée. Ici : les composants, dans l'ordre de la page.

   LA RÈGLE DE CE THÈME, en une phrase : tout ce qu'on vient chercher est
   une DONNÉE, et une donnée se range en ligne, pas en paragraphe.
   ===================================================================== */

/* ---------- 1. Polices auto-hébergées ------------------------------------
   Archivo porte tout : titres, texte, interface. C'est une grotesque
   dessinée pour la signalétique — panneaux, gros titres de presse — et
   c'est exactement le registre d'un panneau de club. Une seule famille,
   trois usages, aucune serif : la page a l'air d'un tableau bien tenu,
   pas d'une brochure.

   Geist 800 ne sert QU'AUX CHIFFRES. Un poids aussi lourd sur du texte
   courant serait illisible ; sur un nombre, c'est ce qui se voit de plus
   loin, et ce sont les nombres qu'on vient lire. */

@font-face {
  font-family: 'Archivo'; font-style: normal; font-weight: 400;
  font-display: swap; src: url('../../../assets/fonts/archivo-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Archivo'; font-style: normal; font-weight: 700;
  font-display: swap; src: url('../../../assets/fonts/archivo-700.woff2') format('woff2');
}
@font-face {
  font-family: 'Archivo'; font-style: normal; font-weight: 500;
  font-display: swap; src: url('../../../assets/fonts/archivo-500.woff2') format('woff2');
}
@font-face {
  font-family: 'Geist'; font-style: normal; font-weight: 800;
  font-display: swap; src: url('../../../assets/fonts/geist-800.woff2') format('woff2');
}

/* Replis métriques. LE DÉCALAGE DE MISE EN PAGE DE CE SOCLE EST À ZÉRO
   EXACT, et c'est ce bloc qui le tient : sans lui, la substitution de
   police au chargement fait sauter chaque ligne de la page.

   LES VALEURS SONT MESURÉES. Une même phrase française composée à 100 px
   dans chaque police : Archivo 1377,6 px contre Helvetica 1509,5 px,
   soit 0,9126. Le repli est rétréci dans ce rapport. */
@font-face {
  font-family: 'Archivo repli';
  src: local('Helvetica Neue'), local('Helvetica'), local('Arial'), local('Liberation Sans');
  size-adjust: 91.26%; ascent-override: 101%; descent-override: 26%; line-gap-override: 0%;
}
@font-face {
  font-family: 'Geist repli';
  src: local('Helvetica Neue'), local('Helvetica'), local('Arial'), local('Liberation Sans');
  size-adjust: 96%; ascent-override: 96%; descent-override: 24%; line-gap-override: 0%;
}

/* ---------- 2. Jetons ----------------------------------------------------
   Déclarés dans themes/club/css/tokens.css — voir la note en tête. */

/* ---------- 3. Remise à plat --------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  interpolate-size: allow-keywords;

  /* OÙ S'IMMOBILISE CE QU'UNE ANCRE VISE. Posée sur le conteneur de
     défilement, la réserve vaut pour TOUTES les ancres : le menu, les
     boutons du bandeau, ceux des sections, le lien d'information,
     « Aller au contenu », et le champ qu'une erreur ramène sous les
     yeux. Une règle, pas une par famille de cible.

     LES DEUX NOMS SONT CEUX DU SOCLE — « --ancre-haut » et
     « --ancre-retrait » — parce que tools/verifier-ancres.mjs les
     cherche par leur nom. Un thème choisit ses valeurs ; il ne choisit
     pas le vocabulaire du contrat. */
  --ancre-air: 12px;
  --ancre-haut: calc(var(--h-entete) + var(--ancre-air));
  scroll-padding-top: var(--ancre-haut);
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--fond);
  color: var(--encre);
  font-family: var(--texte);
  font-size: var(--t-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
body.bloque { overflow: hidden; }

img, picture, svg, video { display: block; max-width: 100%; }
img { height: auto; }
ul, ol { list-style: none; padding: 0; }
a { color: inherit; }
button, input, select, textarea { font: inherit; color: inherit; }

/* LE FOCUS EST VISIBLE PARTOUT. Trois pixels de rouge d'action, décollés
   de deux : il se voit sur le blanc comme sur la bande de club, et il ne
   recouvre jamais le caractère qu'il entoure. */
:focus-visible { outline: 3px solid var(--action); outline-offset: 2px; }
:focus:not(:focus-visible) { outline: none; }
::selection { background: var(--club); color: var(--encre-clair); }

.evitement {
  position: absolute; left: -9999px; top: 0; z-index: 300;
  background: var(--encre); color: var(--encre-clair);
  padding: 0.7em 1.1em; font-weight: 500;
}
.evitement:focus { left: 0; }

.hors-ecran {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

.defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ---------- 4. Rythme et enveloppes --------------------------------------
   LE FOND CHANGE OÙ LA PAGE CHANGE DE BUT, PAS UN RANG SUR DEUX.

   Ce thème a longtemps porté `main > .sec:nth-of-type(even)`, qui pose
   un gris une section sur deux. C'est commode — déplacer une section
   redistribue les bandes toute seule — et ça ne veut rien dire : le gris
   tombe où le rang le met, donc au hasard du contenu. Sur une page de
   vingt sections il produit dix alternances qui n'annoncent rien, et
   c'est exactement à ça qu'on reconnaît un gabarit rempli.

   Ce qui remplace : la page a DEUX MOMENTS, et le fond ne bouge qu'entre
   eux. Ce qu'on lit — le club, les sections, le calendrier, les
   nouvelles — est sur blanc. Ce qu'on REJOINT — l'adhésion, le
   bénévolat, les dons — est sur le bleu très pâle du club. Le
   changement de fond dit « à partir d'ici, ça vous concerne », et il
   ne le dit qu'une fois.

   LE FILET DE CLUB fait le reste du découpage : quatre pixels de bleu
   en tête de chaque section, la même bande que celle de l'en-tête. Un
   panneau de club est fait de plaques bordées les unes sous les autres,
   pas de rectangles gris alternés. */

main > .sec--adhesion,
main > .sec--benevoles,
main > .sec--dons { background: var(--club-pale); }

/* Le filet de tête, sur toutes les sections sauf l'accueil — qui porte
   déjà la photo — et sauf la première d'une suite de même fond, où il
   redoublerait le changement de couleur. */
main > .sec + .sec {
  border-top: var(--bande) solid var(--club);
}

.sec {
  padding: var(--section-y) var(--gouttiere);
  /* Toute règle qui touche au padding haut repose « --ancre-retrait »
     dans le même bloc : les deux valeurs sont la même mesure dite deux
     fois, et c'est le seul moyen qu'elles ne divergent pas. */
  --ancre-retrait: var(--section-y);
  scroll-margin-top: calc(0px - var(--ancre-retrait));
}

.sec--hero {
  padding: 0 0 var(--section-y);
  background: var(--fond) !important;
  --ancre-retrait: 0px;
}

.sec__entete { max-width: var(--large); margin: 0 auto clamp(20px, 3vw, 36px); }

/* LE TITRE DE SECTION, ET SA BANDE. Un trait de club de 4 px au-dessus,
   large de 2,4 rem : c'est la signature de ce thème, et c'est la même
   bande que celle des cartes et de l'en-tête. Un seul geste, répété. */
.sec__titre {
  /* GRAISSE 700, ET C'EST LE THÈME LE PLUS LOURD DES CINQ. Un panneau de
     club est fait pour être lu de loin, debout, dans un couloir de
     gymnase. Les quatre autres thèmes titrent entre 300 et 500 ; celui-ci
     assume d'être le seul à taper. */
  font-weight: 700;
  font-size: var(--t-h2);
  line-height: 1.12;
  letter-spacing: -0.03em;
  max-width: 24ch;
  text-wrap: balance;
  padding-top: 0.62em;
  position: relative;
}
.sec__titre::before {
  content: "";
  position: absolute; top: 0; left: 0;
  width: 2.4rem; height: var(--bande);
  background: var(--club);
}
.sec__texte { max-width: var(--lecture); color: var(--encre-douce); }
.sec__texte + .sec__texte { margin-top: 0.8em; }
.sec__texte p + p, .corps p + p { margin-top: 0.8em; }

.sec__corps { max-width: var(--large); margin: 0 auto; }

/* L'INTERTITRE. En capitales, petit, gris : c'est une étiquette de
   rubrique, pas un titre — et il ne doit jamais concurrencer le titre de
   section qui le domine. */
.sec__intitule {
  font-weight: 500;
  font-size: var(--t-mention);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--encre-douce);
  margin: 2em 0 0.8em;
}
.sec__intitule--passe { opacity: 0.75; }

.sec__categorie {
  font-weight: 500;
  font-size: var(--t-h3);
  margin: 1.6em 0 0.7em;
}

.sec__avis {
  max-width: var(--lecture);
  padding: 0.85em 1em;
  border: 1px solid var(--trait-fort);
  border-left: var(--bande) solid var(--action);
  background: var(--fond);
  color: var(--encre);
}

.secours { margin-top: 1.4em; color: var(--encre-douce); font-size: var(--t-petit); }
.lien { color: var(--club); text-underline-offset: 2px; }
.lien:hover { color: var(--club-fonce); }

.mention-donnees {
  margin-top: 0.9em;
  padding: 0.7em 0.9em;
  background: var(--fond-creux);
  font-size: var(--t-petit);
  color: var(--encre-douce);
}
.mention-donnees__texte + .mention-donnees__texte { margin-top: 0.4em; }

/* ---------- 5. Titres et texte ------------------------------------------- */

h1, h2, h3, h4 { font-weight: 500; line-height: 1.2; }
.ital { font-style: italic; }

/* LES POINTS D'UNE LISTE. Un carré, pas un disque : ce thème n'a aucune
   forme ronde en dehors des pastilles de compte. */
.sec__points { display: grid; gap: 0.5em; max-width: var(--lecture); }
.sec__points li { position: relative; padding-left: 1.1em; }
.sec__points li::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 6px; height: 6px; background: var(--club);
}

.defs { display: none; }

/* ---------- 6. Boutons ---------------------------------------------------
   DEUX SEULEMENT, ET ILS NE SE RESSEMBLENT PAS. Le plein rouge est
   l'inscription : il n'apparaît qu'une fois par écran. Le bordé est tout
   le reste. Un troisième niveau ferait hésiter. */

.bouton, .sec__bouton, .menu__action {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 0.6em 1.3em;
  font-family: inherit; font-weight: 500; font-size: var(--t-petit);
  letter-spacing: 0.01em;
  text-decoration: none; cursor: pointer;
  border: 1px solid var(--encre); border-radius: var(--rayon);
  background: transparent; color: var(--encre);
  transition: background var(--survol) var(--ease), color var(--survol) var(--ease),
              border-color var(--survol) var(--ease);
}
.bouton:hover, .sec__bouton:hover, .menu__action:hover {
  background: var(--encre); color: var(--encre-clair);
}

/* L'ACTION. Rouge plein, et il ne se décline pas. */
.menu__action, .bouton--action {
  background: var(--action); border-color: var(--action); color: var(--encre-clair);
  text-transform: uppercase; letter-spacing: 0.06em; font-size: var(--t-mention);
}
.menu__action:hover, .bouton--action:hover {
  background: var(--action-fonce); border-color: var(--action-fonce); color: var(--encre-clair);
}

/* ---------- 7. Photos -----------------------------------------------------
   AUCUN EFFET DE COULEUR, NULLE PART. Pas de teinte, pas d'opacité, pas
   de filtre : ces gabarits sont réglés pour de VRAIES photographies
   déposées par un club, et une photo à laquelle le thème ajoute une
   dominante est une photo qu'on ne reconnaît plus. */

.sec__agrandir { display: block; position: relative; }
.sec__agrandir img { transition: opacity var(--survol) var(--ease); }
.sec__agrandir:hover img { opacity: 0.9; }

figure { margin: 0; }
figcaption {
  margin-top: 0.4em;
  font-size: var(--t-mention);
  color: var(--encre-douce);
}

/* ---------- 8. En-tête ----------------------------------------------------
   LA BANDE DE CLUB EN PREMIER. Quatre pixels pleins en haut de l'écran,
   collés : c'est la première chose qui se voit, et c'est le maillot. */

.entete {
  position: sticky; top: 0; z-index: 100;
  background: var(--fond);
  border-top: var(--bande) solid var(--club);
  border-bottom: 1px solid var(--trait);
}

.entete__barre {
  min-height: calc(var(--h-entete) - var(--bande));
  max-width: var(--large);
  margin: 0 auto;
  padding: 0 var(--gouttiere);
  display: flex; align-items: center; gap: 1rem;
}

/* LE NOM NE SE SERRE JAMAIS, ET LE MENU SE SERRE EN DERNIER.

   La barre tient une ligne — le contrat d'ancre l'exige, voir plus haut.
   Une ligne unique veut dire que quelque chose doit céder quand le menu
   est long, et il faut dire QUOI : sans `flex: none`, c'est le nom de
   l'association qui se comprimait, et il venait toucher la première
   entrée du menu. « L'Écho du PontACCUEIL », collés, sans un pixel entre
   eux. Le nom est ce qu'on ne peut pas abîmer. */
.entete__marque {
  flex: none; min-width: 0;
  display: inline-flex; align-items: center; gap: 0.55rem;
  text-decoration: none;
  font-weight: 500; font-size: 1.12rem; letter-spacing: -0.015em;
  line-height: 1.15;
}
.entete__embleme { width: 26px; height: 26px; flex: none; color: var(--club); }

.menu { margin-left: auto; display: flex; align-items: center; gap: clamp(0.7rem, 1.6vw, 1.5rem); }
.menu__liste { display: flex; align-items: center; gap: clamp(0.7rem, 1.6vw, 1.5rem); }
.menu__liste a {
  text-decoration: none; font-size: var(--t-petit);
  padding: 0.35em 0; border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.menu__liste a:hover { border-bottom-color: var(--club); }

/* LE BOUTON DU MENU REPREND SES MARGES, ET IL LUI FAUT DEUX CLASSES POUR
   CELA. « .menu__liste a » ci-dessus pèse plus qu'un « .menu__action »
   seul — une classe et un type contre une classe — et il passe après :
   la marge du bouton était donc écrasée par la sienne, horizontale à
   ZÉRO. Mesuré sur les cinq thèmes : quatorze pixels au-dessus et en
   dessous du texte, UN SEUL à gauche et à droite — les capitales
   touchaient le bord de l'aplat, et la hauteur ne venait même pas de la
   marge mais du « min-height ».
   La marge est maintenant la même sur les quatre côtés. La valeur est
   calculée pour que la hauteur du bouton ne bouge pas : c'est la largeur
   qui prend la différence. */
.menu__liste .menu__action { padding: 0.75em; }
.menu__liste a[aria-current] { border-bottom-color: var(--club); font-weight: 500; }

.entete__bascule { display: none; }
.entete__trait2 { display: none; }

@media (max-width: 899px) {
  .entete__bascule {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; margin-left: auto;
    background: none; border: 1px solid var(--trait-fort); border-radius: var(--rayon);
    cursor: pointer;
  }
    /* LE BOUTON PORTE DEUX <span>, ET UN SEUL DOIT DESSINER.

     Le gabarit du socle en émet deux — c'est l'héritage d'un burger à
     deux barres qui se croisaient, celui des thèmes hôteliers. Ces
     cinq-ci dessinent leurs trois traits avec UN span et ses deux
     pseudo-éléments ; le second span, visé par la même règle, posait un
     second burger par-dessus le premier et débordait de vingt pixels à
     droite du bouton. Sur les cinq thèmes, à 375 comme à 768.

     `.entete__trait2 { display: none }` plus haut ne suffisait pas :
     `.entete__bascule span` a une spécificité supérieure et gagnait. On
     vise donc le premier, et le second reste caché. */
  .entete__bascule span:first-child {
    display: block; width: 18px; height: 2px; background: var(--encre); position: relative;
  }
  .entete__bascule span:first-child::before, .entete__bascule span:first-child::after {
    content: ""; position: absolute; left: 0; width: 18px; height: 2px; background: var(--encre);
    transition: transform 160ms var(--ease), top 160ms var(--ease);
  }
  .entete__bascule span:first-child::before { top: -6px; }
  .entete__bascule span:first-child::after  { top: 6px; }
  .entete[data-ouvert] .entete__bascule span:first-child { background: transparent; }
  .entete[data-ouvert] .entete__bascule span:first-child::before { top: 0; transform: rotate(45deg); }
  .entete[data-ouvert] .entete__bascule span:first-child::after  { top: 0; transform: rotate(-45deg); }

  /* LE MENU DU TÉLÉPHONE. Il se déplie SOUS la barre, il ne la recouvre
     pas : un club a jusqu'à douze entrées, et un panneau plein écran
     ferait perdre le nom du club. */
  .menu {
    position: absolute; left: 0; right: 0; top: 100%;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--fond);
    border-bottom: 1px solid var(--trait);
    padding: 0 var(--gouttiere) 1rem;
    max-height: calc(100dvh - var(--h-entete)); overflow-y: auto;
    transform: translateY(-6px); opacity: 0; visibility: hidden;
    transition: opacity 160ms var(--ease), transform 160ms var(--ease), visibility 160ms;
  }
  .entete[data-ouvert] .menu { transform: none; opacity: 1; visibility: visible; }
  .menu__liste { flex-direction: column; align-items: stretch; gap: 0; }
  .menu__liste a {
    padding: 0.85em 0; border-bottom: 1px solid var(--trait);
    font-size: 1.05rem;
  }
  .menu__action { margin-top: 1rem; }
}

/* ---------- 9. Le bandeau d'information -----------------------------------
   Plein, dans la couleur du club, au-dessus de tout : c'est l'annonce du
   forum des associations ou de la reprise des entraînements. */

.info {
  background: var(--club); color: var(--encre-clair);
  padding: 0.6em var(--gouttiere);
  font-size: var(--t-petit); text-align: center;
}
.info__mot { display: inline; }
.info__lien { color: var(--encre-clair); text-underline-offset: 3px; margin-left: 0.5em; }

/* ---------- 10. L'accueil -------------------------------------------------
   LA PLAQUE MONTÉE SUR LA PHOTO.

   Un panneau de club, c'est une plaque vissée sur un mur : le nom, les
   faits, et le lieu derrière. C'est ce que fait cet accueil — la photo
   du terrain en bandeau, puis une plaque blanche qui MORD dessus par le
   bas, bordée en tête du bleu du club. Le nom n'est pas posé SUR la
   photo (il faudrait l'assombrir, donc éteindre ce qu'on montrait) et
   il n'est pas simplement dessous (ce que font quatre thèmes sur cinq
   du marché) : il est devant.

   LE RECOUVREMENT N'EXISTE QU'À PARTIR DE 1000 px. En dessous, la
   plaque se pose à la suite de la photo, sans négatif : sur 375 px un
   recouvrement mangerait le tiers de l'image, et le nom se retrouverait
   sur des jambes de joueurs.

   AUCUN DÉCALAGE DE MISE EN PAGE : une marge négative est une position
   statique, calculée au premier rendu comme n'importe quelle autre. */

.sec--hero__media { width: 100%; aspect-ratio: 4 / 3; overflow: hidden; }
.sec--hero__media img { width: 100%; height: 100%; object-fit: cover; }
@media (min-width: 620px)  { .sec--hero__media { aspect-ratio: 16 / 9; } }
@media (min-width: 1000px) { .sec--hero__media { aspect-ratio: 21 / 9; } }

.sec--hero__texte {
  max-width: var(--large);
  margin: clamp(20px, 3vw, 32px) auto 0;
  padding: 0 var(--gouttiere);
}
.sec--hero--sobre { padding-top: 0; }
.sec--hero--sobre .sec--hero__texte { margin-top: clamp(32px, 6vw, 72px); }

.sec--hero__surtitre {
  font-weight: 500; font-size: var(--t-mention);
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--club);
  margin-bottom: 0.6em;
}
.sec--hero__titre {
  font-weight: 700;
  font-size: var(--t-display);
  line-height: 0.98;
  letter-spacing: -0.035em;
  max-width: 15ch;
  text-wrap: balance;
}
.sec--hero__soustitre {
  margin-top: 0.45em;
  font-size: var(--t-lead);
  color: var(--encre-douce);
  max-width: 40ch;
}
.sec--hero__intro { margin-top: 0.9em; max-width: var(--lecture); color: var(--encre-douce); }
.sec--hero__actions { margin-top: 1.3em; display: flex; flex-wrap: wrap; gap: 0.6em; }

@media (min-width: 1000px) {
  /* LA PLAQUE. Elle remonte de 92 px sur la photo, prend le fond de la
     page et la bande de club en tête. `position: relative` la met
     au-dessus de l'image sans qu'aucun z-index soit nécessaire : un
     élément positionné passe devant un élément qui ne l'est pas. */
  .sec--hero__texte {
    position: relative;
    margin-top: -92px;
    background: var(--fond);
    border-top: var(--bande) solid var(--club);
    padding: clamp(28px, 2.6vw, 40px) clamp(28px, 3vw, 48px) 0;
    max-width: calc(var(--large) - 2 * var(--gouttiere));

    display: grid;
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
    column-gap: clamp(28px, 4vw, 64px);
    align-items: start;
  }
  .sec--hero--sobre .sec--hero__texte {
    margin-top: clamp(32px, 6vw, 72px);
    border-top: 0; padding-left: 0; padding-right: 0;
    max-width: var(--large);
  }
  .sec--hero__surtitre { grid-column: 1; }
  .sec--hero__titre    { grid-column: 1; }
  .sec--hero__soustitre{ grid-column: 1; }
  /* UNE CLASSE POSÉE PAR riche() NE REÇOIT JAMAIS DE PLACEMENT EXPLICITE
     par élément : elle peut sortir en plusieurs paragraphes, et deux
     paragraphes dans la même case se superposeraient. On place le
     PREMIER, les suivants suivent. */
  .sec--hero__intro    { grid-column: 2; grid-row: 1 / span 3; margin-top: 0; }
  .sec--hero__intro + .sec--hero__intro { grid-row: auto; margin-top: 0.7em; }
  .sec--hero__actions  { grid-column: 1; }
}

/* ---------- 11. Le club (section « association ») -------------------------
   LES CHIFFRES D'ABORD. « Quatre sections · cent quatre-vingts licenciés ·
   depuis 1976 » dit en trois nombres ce qu'un paragraphe met quinze
   lignes à dire — et c'est vrai d'un club plus que de toute autre
   association. */

.sec--association .sec__corps { display: grid; gap: clamp(20px, 3vw, 40px); }

.sec__chiffres {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(150px, 45%), 1fr));
  border-top: 1px solid var(--trait);
}
.sec__chiffres > * {
  padding: 1rem 0 0;
  border-bottom: 1px solid var(--trait);
  padding-bottom: 1rem;
}
@media (min-width: 700px) {
  .sec__chiffres > * { padding: 1rem clamp(0.8rem, 2vw, 1.8rem) 1rem; border-bottom: 0; }
  .sec__chiffres > *:first-child { padding-left: 0; }
  .sec__chiffres > * + * { border-left: 1px solid var(--trait); }
}
.sec__chiffres dt, .sec__chiffres .valeur {
  font-family: var(--chiffre); font-weight: 800;
  font-size: var(--t-nombre); line-height: 1;
  letter-spacing: -0.03em;
  color: var(--club);
  font-variant-numeric: tabular-nums;
}
.sec__chiffres dd, .sec__chiffres .mot {
  margin: 0.4rem 0 0;
  font-size: var(--t-petit); color: var(--encre-douce);
}
/* LA CELLULE D'UN CHIFFRE — le couple « nombre + mot », enveloppé par le
   gabarit du socle depuis qu'un « 31 » s'est retrouvé en fin de ligne et
   son « bénévoles » seul à la ligne suivante. La grille place ce
   conteneur ; elle ne peut plus séparer ce qu'il contient.
   La règle est nommée, et pas seulement héritée d'un `> *` :
   tools/verifier-styles.php exige qu'une classe émise soit visée. */
.sec__chiffres .chiffre { min-width: 0; }


/* LES PHOTOS DU CLUB — une grande, deux dessous, et AUCUN RECADRAGE.

   La grande sortait en 16/9. Les photos du socle sont en 10/7 (1,43) et
   les vignettes en 4/3 (1,33) : forcer 1,78 rognait un cinquième de la
   hauteur, par le haut ET par le bas. Sur la photo du gymnase, ce qui
   restait au milieu était le sol — un aplat beige de mille cinq cents
   pixels de large, et pas un ballon dedans. Le cadrage annoncé décidait
   donc de ce qu'on ne verrait pas.

   Chaque format est maintenant celui de sa source, à un cheveu près :
   3/2 pour la grande, 4/3 pour les deux autres. On recadre de deux pour
   cent au lieu de vingt. */
.sec__medias {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.sec__medias li:first-child { grid-column: 1 / -1; }
.sec__medias li:first-child img { aspect-ratio: 3 / 2; }
.sec__medias img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
/* ---------- 12. Les sections du club — DES LIGNES, PAS DES CARTES --------
   C'EST LA COMPOSITION QUI FAIT CE THÈME, ET C'EST LA SEULE DU SOCLE À
   ÊTRE UN TABLEAU.

   Les cinq thèmes posaient ici la même chose : `repeat(auto-fit,
   minmax(min(290px, 100%), 1fr))` et des cartes en pile verticale. À la
   valeur du minimum près — 260, 280, 290, 300 —, c'était le MÊME dessin
   cinq fois, et c'est à ça qu'on reconnaît un gabarit rempli plutôt
   qu'un site dessiné.

   Deux défauts venaient avec, visibles à l'œil nu à 1440 px :

     — LE TROU. `.carte__prix` portait `margin-top: auto` pour coller le
       tarif en bas de carte. Dans une grille, toutes les cartes d'une
       ligne sont étirées à la hauteur de la plus haute : la section qui
       avait deux lignes de texte de moins se retrouvait avec deux cents
       pixels de blanc en plein milieu.

     — LES TARIFS NE SE COMPARAIENT PAS. 110, 135, 75 et 60 € tombaient
       à quatre hauteurs différentes, chacun suivant la fin de son propre
       texte. Or c'est LE chiffre qu'un parent compare.

   UNE LIGNE PAR SECTION règle les deux : plus de hauteur commune à
   étirer, et le tarif toujours à la même abscisse. On balaie la colonne
   des prix, ce qui est ce qu'on vient faire.

   CE THÈME ÉCRIT DONC SON GABARIT — voir
   themes/club/templates/sections/activites.php et la note qui l'ouvre.
   Il le faut : une grille partage ses RANGÉES entre ses colonnes, donc
   le tarif posé en colonne 3 rangée 1 imposait sa hauteur au nom de la
   section d'à côté. Trois colonnes verticalement indépendantes
   demandent trois conteneurs. */

.sec__grille {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
  max-width: var(--large);
  margin: 0 auto;
  border-top: var(--bande) solid var(--club);
}

.carte {
  background: var(--fond);
  border: 0;
  border-bottom: 1px solid var(--trait);
  border-radius: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(12px, 1.6vw, 18px) 0;
  padding: clamp(16px, 2.2vw, 26px) 0;
  scroll-margin-top: var(--ancre-air);
}

.carte__photo img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }

/* LA COLONNE DE LECTURE. Un conteneur, donc un flux vertical à elle,
   que ni le tarif ni le bouton ne peuvent contraindre. */
.carte__corps { display: flex; flex-direction: column; gap: 0.45rem; min-width: 0; }

.carte__nom {
  font-weight: 700; font-size: var(--t-h3); line-height: 1.15;
  letter-spacing: -0.02em;
}
.carte__accroche { color: var(--club); font-size: var(--t-petit); font-weight: 500; }
.carte__resume, .carte__texte { color: var(--encre-douce); font-size: var(--t-petit); }
.carte__type, .carte__depuis, .carte__categorie {
  font-size: var(--t-petit); color: var(--encre-douce);
}
.carte__intitule {
  font-size: var(--t-mention); letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--encre-douce); font-weight: 500;
  margin-top: 0.35rem;
}

/* LES FAITS EN UNE SEULE LIGNE, SÉPARÉS PAR UN POINT MÉDIAN.
   Dans une carte verticale, un fait par ligne se justifiait. Dans une
   ligne de tableau, trois lignes empilées feraient monter la rangée pour
   rien : « mardi et vendredi 18 h 30 · Stade municipal · à partir de
   5 ans » se lit d'un trait, et c'est la phrase qu'on cherche. Le point
   médian est un pseudo-élément : il ne se copie pas avec le texte et ne
   se lit pas à voix haute. */
.carte__faits {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 0.15em 0.6em;
  font-size: var(--t-petit); color: var(--encre);
}
.carte__faits li { display: flex; align-items: baseline; gap: 0.6em; }
.carte__faits li + li::before { content: "·"; color: var(--trait-fort); font-weight: 700; }

.carte__equipements {
  display: flex; flex-wrap: wrap; gap: 0.15em 0.9em;
  font-size: var(--t-petit); color: var(--encre-douce);
}
.carte__equipements li { position: relative; padding-left: 0.75em; }
.carte__equipements li::before {
  content: ""; position: absolute; left: 0; top: 0.55em;
  width: 4px; height: 4px; background: var(--trait-fort);
}

/* LA COLONNE DU TARIF. Elle aussi est un conteneur : le montant et le
   bouton s'y empilent sans que rien de la colonne de lecture ne bouge. */
.carte__tarif { display: flex; flex-direction: column; align-items: flex-start; gap: 0.75rem; }
.carte__prix { display: flex; flex-direction: column; gap: 0.15rem; }
.carte__montant {
  font-family: var(--chiffre); font-weight: 800;
  font-size: var(--t-nombre); line-height: 1; letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  /* PAS DE `white-space: nowrap` ICI, ET C'EST UNE LEÇON DÉJÀ APPRISE.
     Ce champ ne porte pas toujours un montant : le modèle y accepte
     n'importe quelle phrase, et les jeux de données y écrivent « compris
     dans l'adhésion », « entrée libre », « un cinquième du prix
     courant ». Rendu insécable, « compris dans l'adhésion » mesurait
     729 px dans une colonne de 200 et sortait la page de 485 px — sur
     les cinq largeurs et les deux moteurs.
     C'est mot pour mot le défaut corrigé la nuit précédente sur
     `.appel__nombre`, pour la même raison. Ce qui protège « 110 € »
     d'une coupure n'est pas cette règle : c'est l'espace insécable que
     les fichiers de langue écrivent entre le nombre et le symbole. */
  overflow-wrap: anywhere;
}
.carte__mention { font-size: var(--t-petit); color: var(--encre-douce); }
/* Le bouton de la fiche, dans la colonne du tarif. */
.carte__action { margin: 0; }


/* LES AUTRES VUES — TROIS COLONNES FRANCHES, PAS UN CALCUL.
   Elles tenaient `repeat(auto-fill, minmax(64px, 1fr))` : dans une
   colonne large, ça fabriquait huit pistes pour deux photos, et les deux
   photos sortaient à soixante-quatre pixels avec six colonnes de vide à
   droite. C'est le défaut corrigé dans la galerie, et qui vivait encore
   ici — dans les cinq thèmes. */
.carte__vues {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px;
  max-width: 26rem;
}
.carte__vues img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.carte__vues figcaption {
  font-size: var(--t-mention); color: var(--encre-douce);
  margin-top: 0.25em; line-height: 1.3;
}

/* LA LIGNE, À PARTIR DE 760 px : vignette, lecture, tarif.
   En dessous, tout s'empile — trois colonnes sur 375 px donneraient
   quatre-vingts pixels au tarif, qui est ce qu'on vient lire. */
@media (min-width: 760px) {
  .carte {
    grid-template-columns:
      clamp(120px, 14vw, 176px)          /* la vignette */
      minmax(0, 1fr)                     /* ce qu'on lit */
      clamp(150px, 17vw, 210px);         /* ce qu'on compare */
    column-gap: clamp(18px, 2.2vw, 34px);
    align-items: start;
  }
  /* Chaque colonne est nommée : sans photo, la fiche ne laisse pas une
     case vide à gauche — elle décale, et la ligne reste une ligne. */
  .carte__photo { grid-column: 1; }
  .carte__corps { grid-column: 2; }
  .carte__tarif { grid-column: 3; }
  .carte:not(:has(.carte__photo)) .carte__corps { grid-column: 1 / 3; }
}

/* ---------- 13. Les appels du moment --------------------------------------
   Un appel est une annonce datée : arbitres recherchés, tournoi de fin de
   saison, collecte de maillots. Elle se lit comme une affiche punaisée —
   filet rouge à gauche, et rien d'autre. */

.appels { display: grid; gap: clamp(12px, 1.6vw, 20px); max-width: var(--large); margin: 0 auto; }
.appel {
  display: grid; gap: 0;
  border: 1px solid var(--trait);
  border-left: var(--bande) solid var(--action);
  background: var(--fond);
}
@media (min-width: 760px) {
  .appel { grid-template-columns: minmax(0, 260px) minmax(0, 1fr); align-items: stretch; }
  .appel__photo { grid-row: 1 / span 6; }
}
.appel__photo img { width: 100%; height: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.appel__nom { padding: 0.9rem 1rem 0; font-size: var(--t-h3); font-weight: 500; }
.appel__accroche { padding: 0.2rem 1rem 0; color: var(--encre-douce); }
.appel__mots { padding: 0.6rem 1rem 0; }
.appel__chiffre { padding: 0.7rem 1rem 0; display: flex; align-items: baseline; gap: 0.5rem; }
.appel__nombre {
  font-family: var(--chiffre); font-weight: 800; font-size: var(--t-nombre);
  line-height: 1; letter-spacing: -0.03em; color: var(--action);
  font-variant-numeric: tabular-nums;
}
.appel__mention { font-size: var(--t-petit); color: var(--encre-douce); }
.appel__validite {
  padding: 0.6rem 1rem 0;
  font-size: var(--t-mention); letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--encre-douce);
}
.appel__action { padding: 0.9rem 1rem 1rem; }

/* ---------- 14. L'agenda ---------------------------------------------------
   MATCHS, TOURNOIS, ASSEMBLÉE GÉNÉRALE. Une liste où la date est à
   gauche, en gros, dans la colonne : c'est un calendrier de saison, et il
   se parcourt à la verticale. */

.sec--evenements .sec__corps { max-width: var(--large); }

.agenda__liste { border-top: 1px solid var(--trait); }
.evenement {
  display: grid;
  gap: 0.15rem 1.2rem;
  padding: 0.9rem 0;
  border-bottom: 1px solid var(--trait);
}
@media (min-width: 700px) {
  .evenement {
    grid-template-columns: minmax(0, 11rem) minmax(0, 1fr) auto;
    align-items: baseline;
  }
  /* CHAQUE MORCEAU DIT SA COLONNE. Le lien arrive en dernier dans le
     balisage : placé par la seule ligne, il prendrait la case de la
     date. Une grille ne devine pas ce qu'on voulait dire. */
  .evenement__quand     { grid-column: 1; grid-row: 1; }
  .evenement__lieu      { grid-column: 1; grid-row: 2; }
  .evenement__nom       { grid-column: 2; grid-row: 1; }
  .evenement__texte     { grid-column: 2; }
  .evenement__categorie { grid-column: 3; grid-row: 1; text-align: right; }
  .evenement__action    { grid-column: 3; grid-row: 2; text-align: right; }
}
.evenement__quand {
  font-family: var(--chiffre); font-weight: 800;
  font-size: var(--t-petit); letter-spacing: -0.01em;
  color: var(--club);
  font-variant-numeric: tabular-nums;
  text-transform: uppercase;
}
.evenement__nom { font-size: var(--t-h3); font-weight: 500; }
.evenement__lieu, .evenement__categorie {
  font-size: var(--t-petit); color: var(--encre-douce);
}
.agenda__liste--passe .evenement { opacity: 0.66; }
.evenement__texte { font-size: var(--t-petit); }
.agenda__vide { color: var(--encre-douce); padding: 1rem 0; }

/* ---------- 15. Les actualités -------------------------------------------- */

.actus {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: clamp(12px, 1.6vw, 20px); max-width: var(--large); margin: 0 auto;
}
.actu { border: 1px solid var(--trait); background: var(--fond); display: flex; flex-direction: column; }
.actu__photo img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.actu__date {
  padding: 0.8rem 1rem 0;
  font-size: var(--t-mention); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--encre-douce);
}
.actu__nom { padding: 0.25rem 1rem 0; font-size: var(--t-h3); font-weight: 500; }
.actu__mots { padding: 0.5rem 1rem 0; color: var(--encre-douce); }
.actu__action { padding: 0.8rem 1rem 1rem; margin-top: auto; }

/* ---------- 16. La galerie ------------------------------------------------
   Des vignettes égales, rectangulaires, en 16/10 : le format d'une photo
   de match prise au téléphone en paysage, à un cheveu près.

   PAS 16/9, ET LA DIFFÉRENCE N'EST PAS UN DÉTAIL DE GOÛT. Une galerie
   d'association reçoit ce qu'on lui donne — et ce qu'on lui donne, c'est
   aussi des portraits pris à la verticale. Recadré en 16/9, un portrait
   perd une tête ; c'est la règle 2 de tools/verifier-galerie.mjs, et
   elle est mesurée, pas décrétée. 16/10 garde le paysage franc et la
   nervosité du thème sans couper personne. */

/* LA GALERIE A UN NOMBRE DE COLONNES CHOISI, PAS CALCULÉ.

   Elle tenait un `repeat(auto-fill, minmax(...))`, et c'était faux deux
   fois. `auto-fill` fabrique toutes les colonnes que la largeur permet
   PUIS y range ce qu'il y a : une série de trois photos dans une grille
   qui en tient sept sortait en trois vignettes minuscules serrées à
   gauche, avec quatre colonnes de vide à droite. Et comme le gabarit
   découpe la galerie en séries titrées dès qu'il y a des catégories, le
   cas n'était pas rare, c'était le cas COURANT.

   `auto-fit` réparait l'orphelin et en fabriquait un autre : les
   colonnes vides se replient, donc une série de deux photos les affiche
   à 586 px quand une série de quatre les affiche à 289. La taille d'une
   vignette dépendait du nombre de photos de sa catégorie, c'est-à-dire
   de rien.

   Un nombre FRANC de colonnes règle les deux : toutes les vignettes de
   la page ont la même taille, et une série courte laisse un vide en fin
   de ligne — ce qui se lit comme une ligne incomplète, pas comme une
   erreur. C'est aussi une décision de thème : chacun choisit sa trame et
   son cadrage, et c'est ce qui distingue une planche contact d'un mur
   d'affiches. */
/* Quatre colonnes en 16/10 : le format d'une photo de terrain prise au
   téléphone, et le nombre de vignettes qui tient sur une ligne sans les
   rendre illisibles. */
.galerie-mosaique {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px; max-width: var(--large); margin: 0 auto;
}
@media (min-width: 640px)  { .galerie-mosaique { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .galerie-mosaique { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
/* LE RAPPORT SE POSE SUR LA CASE, PAS SUR LA PHOTO : « aspect-ratio »
   sur un <img> qui porte ses attributs width et height se fait doubler
   par le rapport intrinsèque du fichier dans WebKit. Une case qui tient
   le rapport et une photo qui la remplit ne dépendent d'aucun moteur. */
.galerie-mosaique > li { aspect-ratio: 16 / 10; }
.galerie-mosaique > li > figure,
.galerie-mosaique .sec__agrandir,
.galerie-mosaique picture { display: block; height: 100%; }
.galerie-mosaique img { width: 100%; height: 100%; object-fit: cover; }
.galerie-mosaique figcaption { display: none; }
.sec--gallery__couverture { margin-bottom: 12px; }
.sec--gallery__couverture img { width: 100%; aspect-ratio: 21 / 9; object-fit: cover; }

/* ---------- 17. Les services ---------------------------------------------- */

.sec__services {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: clamp(12px, 1.8vw, 22px); max-width: var(--large); margin: 0 auto;
}
/* LE PICTOGRAMME EST FACULTATIF, ET LA GRILLE DOIT LE SAVOIR.
   Le gabarit ne l'émet que si une icône est choisie ; sans lui, le nom
   tombe dans la PREMIÈRE colonne, qui est en « auto » — donc à la
   largeur de son contenu, donc sans rétrécissement possible. Une
   mission un peu longue débordait alors de sa carte, et la page avec.
   Chaque morceau déclare donc sa colonne, et la colonne de texte
   déclare qu'elle peut rétrécir. */
.sec__services > li {
  display: grid; grid-template-columns: 1.4em minmax(0, 1fr); gap: 0.2em 0.7em;
  padding: 0.9rem 0; border-top: 1px solid var(--trait);
}
.service__pictogramme { width: 1.4em; height: 1.4em; grid-column: 1; grid-row: 1 / span 2; color: var(--club); }
.service__nom { grid-column: 2; min-width: 0; font-weight: 500; overflow-wrap: anywhere; }
.service__detail { grid-column: 2; min-width: 0; font-size: var(--t-petit); color: var(--encre-douce); overflow-wrap: anywhere; }

/* ---------- 18. Les stages et les cours ----------------------------------- */

.ateliers { display: grid; gap: clamp(12px, 1.6vw, 20px); max-width: var(--large); margin: 0 auto; }
.atelier {
  border: 1px solid var(--trait);
  border-top: var(--bande) solid var(--club);
  background: var(--fond);
  display: grid;
}
@media (min-width: 760px) {
  .atelier { grid-template-columns: minmax(0, 260px) minmax(0, 1fr); }
  .atelier__photo { grid-row: 1 / span 8; }
}
.atelier__photo img { width: 100%; height: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.atelier__nom { padding: 0.9rem 1rem 0; font-size: var(--t-h3); font-weight: 500; }
.atelier__pour, .atelier__categorie {
  padding: 0.2rem 1rem 0; font-size: var(--t-petit); color: var(--encre-douce);
}
.atelier__mots { padding: 0.6rem 1rem 0; }
.atelier__intitule {
  padding: 0.8rem 1rem 0.2rem;
  font-size: var(--t-mention); letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--encre-douce); font-weight: 500;
}
.atelier__suite { padding: 0 1rem; display: grid; gap: 0.25em; font-size: var(--t-petit); }
.atelier__suite li { position: relative; padding-left: 0.9em; color: var(--encre-douce); }
.atelier__suite li::before {
  content: ""; position: absolute; left: 0; top: 0.55em;
  width: 5px; height: 5px; background: var(--trait-fort);
}
.atelier__prix {
  padding: 0.9rem 1rem 1rem; display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap;
}
.atelier__montant {
  font-family: var(--chiffre); font-weight: 800; font-size: var(--t-nombre);
  line-height: 1; letter-spacing: -0.03em; font-variant-numeric: tabular-nums;
}
.atelier__mention { font-size: var(--t-petit); color: var(--encre-douce); }
.atelier__compte { font-size: var(--t-petit); color: var(--encre-douce); padding: 0 1rem 0.8rem; }
.atelier__groupe { padding: 0 1rem; }
.atelier__releve { padding: 0 1rem 0.8rem; font-size: var(--t-petit); color: var(--encre-douce); }
.atelier__serie, .atelier__vues {
  padding: 0 1rem 0.8rem;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)); gap: 6px;
}
.atelier__vues img, .atelier__serie img { aspect-ratio: 1; object-fit: cover; }

/* ---------- 19. Les informations pratiques --------------------------------
   Des <details>, et c'est le bon élément : un club a dix à quinze
   rubriques — certificat médical, licence, matériel, vacances scolaires.
   Repliées, elles se parcourent ; dépliées une à une, elles se lisent. */

.sec__rubriques { max-width: var(--lecture); margin: 0 auto; border-top: 1px solid var(--trait); }
.rubrique { border-bottom: 1px solid var(--trait); }
.rubrique__ligne {
  display: flex; align-items: center; justify-content: space-between; gap: 1em;
  padding: 0.9em 0; min-height: 44px; cursor: pointer; list-style: none;
}
.rubrique__ligne::-webkit-details-marker { display: none; }
.rubrique__nom { font-weight: 500; font-size: var(--t-body); }
.rubrique__ligne::after {
  content: ""; flex: none; width: 12px; height: 12px;
  background:
    linear-gradient(var(--club), var(--club)) center / 100% 2px no-repeat,
    linear-gradient(var(--club), var(--club)) center / 2px 100% no-repeat;
}
.rubrique[open] .rubrique__ligne::after {
  background: linear-gradient(var(--club), var(--club)) center / 100% 2px no-repeat;
}
.rubrique__detail { padding-bottom: 1em; color: var(--encre-douce); }

/* ---------- 20. Le mot de la présidence ----------------------------------- */

.sec--about .sec__corps { display: grid; gap: clamp(20px, 3vw, 40px); }
/* LE PORTRAIT EST CARRÉ. Ce thème n'a aucune forme ronde : un rond ferait
   un geste doux au milieu d'un panneau. */
.sec--about__portrait { max-width: 260px; }
.sec--about__portrait img { width: 100%; aspect-ratio: 1; object-fit: cover; }
.sec--about__signature {
  font-weight: 500; color: var(--club);
  font-size: var(--t-petit); letter-spacing: 0.02em;
}
.sec--about__histoire { max-width: var(--lecture); color: var(--encre-douce); }
@media (min-width: 900px) {
  .sec--about .sec__corps {
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: clamp(24px, 3vw, 48px);
    align-items: start;
  }
  .sec--about__portrait { grid-row: 1 / span 4; width: 220px; }
}

/* ---------- 21. Le bureau -------------------------------------------------- */

.bureau {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(160px, 45%), 1fr));
  gap: clamp(14px, 2vw, 26px); max-width: var(--large); margin: 0 auto;
}
.membre__photo img { width: 100%; aspect-ratio: 1; object-fit: cover; }
.membre__nom { font-weight: 500; margin-top: 0.5em; }
.membre__role {
  font-size: var(--t-mention); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--club); margin-top: 0.15em;
}
.membre__depuis { font-size: var(--t-petit); color: var(--encre-douce); }

/* ---------- 22. Les témoignages -------------------------------------------
   Sobres : un club n'a pas besoin de guillemets décoratifs. Un filet à
   gauche, le texte, la signature. */

.sec__temoignages {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: clamp(14px, 2vw, 26px); max-width: var(--large); margin: 0 auto;
}
.temoignage { border-left: 2px solid var(--club); padding-left: 1rem; }
.temoignage__texte p { color: var(--encre); }
.temoignage__auteur { margin-top: 0.7em; font-weight: 500; font-size: var(--t-petit); }
.temoignage__qualite, .temoignage__source, .temoignage__date {
  font-size: var(--t-mention); color: var(--encre-douce);
}
.temoignage__photo img { width: 44px; height: 44px; object-fit: cover; margin-bottom: 0.6em; }

/* ---------- 23. Les documents ---------------------------------------------
   Statuts, règlement intérieur, comptes rendus d'AG, certificat médical.
   Une liste de fichiers : un nom, une nature, une date, un lien. */

.documents { max-width: var(--large); margin: 0 auto; border-top: 1px solid var(--trait); }
.document {
  display: grid; gap: 0.15rem 1rem;
  padding: 0.8rem 0; border-bottom: 1px solid var(--trait);
}
@media (min-width: 700px) {
  .document { grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; }
}
.document__nom { font-weight: 500; }
.document__nature, .document__faits {
  font-size: var(--t-petit); color: var(--encre-douce);
}

/* ---------- 24. L'accès ---------------------------------------------------- */

.sec--access .sec__corps { display: grid; gap: 1.1em; max-width: var(--lecture); }
.sec--access__adresse { font-weight: 500; font-size: var(--t-lead); }
.sec--access__reperes { display: grid; gap: 0.8em; }
.sec--access__reperes dt {
  font-size: var(--t-mention); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--encre-douce); font-weight: 500;
}
.sec--access__reperes dd { margin: 0.15em 0 0; }
.sec--access__carte { margin-top: 0.6em; }
.defs + * { margin-top: 0; }

/* ---------- 25. Adhérer — le barème puis le formulaire --------------------
   LE BARÈME EST UN TABLEAU. Une licence a un montant, une durée, un
   public : trois colonnes, des filets, des chiffres alignés. C'est ce
   qu'un trésorier reconnaît, et c'est ce qu'un parent compare. */

.formules { max-width: var(--large); margin: 0 auto 2rem; border-top: 1px solid var(--trait); }
.formule {
  display: grid; gap: 0.2rem 1.2rem;
  padding: 0.9rem 0; border-bottom: 1px solid var(--trait);
}
/* TROIS COLONNES, ET CHACUNE SAIT LAQUELLE ELLE EST.
   L'ordre du document est nom, montant, description — le montant vient
   AVANT la description, parce qu'il se lit en premier quand la feuille
   ne s'applique pas. Laissé au placement automatique, il tombait donc
   dans la colonne du milieu, que la description réduisait à zéro : le
   montant sortait d'une case large de rien. Le nom et le montant sont
   donc posés, la description suit dans la colonne qui reste.

   LA DESCRIPTION N'A QUE SA COLONNE, JAMAIS SA LIGNE : riche() met sa
   classe sur CHAQUE paragraphe, et fixer la ligne les empilerait tous
   dans la même case. */
@media (min-width: 720px) {
  .formule { grid-template-columns: minmax(0, 16rem) minmax(0, 1fr) minmax(7rem, auto); align-items: baseline; }
  .formule__nom     { grid-column: 1; grid-row: 1; }
  .formule__mention { grid-column: 3; grid-row: 1; text-align: right; }
  .formule__texte   { grid-column: 2; }
}
.formule__nom { font-weight: 500; font-size: var(--t-h3); }
.formule__texte { color: var(--encre-douce); font-size: var(--t-petit); }
/* LE MONTANT NE SE COUPE PAS ; LA MENTION, SI.
   « 55 € · jusqu'au 31 août » tenait sur une seule ligne insécable, et
   cette ligne dépassait sa colonne dès 768 px. Ce qui ne doit pas se
   couper, c'est le montant et son symbole, et il tient tout seul :
   les fichiers de langue écrivent « 55 € » avec une espace insécable. La
   mention, elle, se coupe au point médian comme n'importe quel texte. */
.formule__mention {
  font-family: var(--chiffre); font-weight: 800; font-size: var(--t-h3);
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}

.formulaire { max-width: 44rem; }
.champs { display: grid; gap: 0.9rem; }
@media (min-width: 700px) { .champs { grid-template-columns: 1fr 1fr; } }
.champ { display: grid; gap: 0.3em; grid-column: 1 / -1; }
.champ--moitie { grid-column: span 1; }
@media (max-width: 699px) { .champ--moitie { grid-column: 1 / -1; } }
.etiquette { font-weight: 500; font-size: var(--t-petit); }
.etiquette__note { font-weight: 400; color: var(--encre-douce); }

.controle {
  width: 100%; min-height: 46px; padding: 0.55em 0.7em;
  background: var(--fond); color: var(--encre);
  border: 1px solid var(--trait-champ); border-radius: var(--rayon);
  font-size: var(--t-body);
}
.controle--zone { min-height: auto; resize: vertical; }
.controle:focus-visible { outline: 3px solid var(--action); outline-offset: 0; border-color: var(--action); }
.controle[aria-invalid="true"] { border-color: var(--alerte); border-width: 2px; }

.champ--case { grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 0.6rem; }
.case { width: 24px; height: 24px; margin-top: 1px; accent-color: var(--club); }
.case__etiquette { font-size: var(--t-petit); color: var(--encre-douce); }
.champ--case .erreur { grid-column: 2; }

.erreur { color: var(--alerte); font-size: var(--t-petit); min-height: 0; }
.erreur--visible { min-height: 1.3em; }
.indication { font-size: var(--t-petit); color: var(--encre-douce); }
.indication--visible { display: block; }

.appat { position: absolute; left: -9999px; }
.envoi { margin-top: 1.2rem; }

.confirme {
  border: 1px solid var(--oui); border-left: var(--bande) solid var(--oui);
  padding: 1.1em 1.2em; background: var(--fond);
}
.confirme__titre { font-weight: 500; font-size: var(--t-h3); }
.confirme__actions { margin-top: 0.9em; display: flex; flex-wrap: wrap; gap: 0.7em; }

/* ---------- 26. Les bénévoles --------------------------------------------- */

.missions {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  gap: clamp(12px, 1.8vw, 22px); max-width: var(--large); margin: 1.4rem auto;
}
.mission {
  display: grid; grid-template-columns: 1.4em minmax(0, 1fr); gap: 0.2em 0.7em;
  padding: 0.8rem 0; border-top: 1px solid var(--trait);
}
.mission__pictogramme { width: 1.4em; height: 1.4em; grid-column: 1; grid-row: 1 / span 2; color: var(--club); }
.mission__nom { grid-column: 2; min-width: 0; font-weight: 500; overflow-wrap: anywhere; }
.mission__detail { grid-column: 2; min-width: 0; font-size: var(--t-petit); color: var(--encre-douce); overflow-wrap: anywhere; }

/* ---------- 27. Les dons --------------------------------------------------- */

.dons__emplois {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(180px, 45%), 1fr));
  gap: clamp(12px, 2vw, 24px); margin: 1.4rem 0;
  border-top: 1px solid var(--trait);
}
.dons__emplois > * { padding-top: 1rem; }
.dons__emplois dt {
  font-family: var(--chiffre); font-weight: 800; font-size: var(--t-nombre);
  line-height: 1; letter-spacing: -0.03em; color: var(--action);
  font-variant-numeric: tabular-nums;
}
.dons__emplois dd { margin: 0.35rem 0 0; font-size: var(--t-petit); color: var(--encre-douce); }
/* LE COUPLE « montant + phrase », enveloppé par le gabarit du socle :
   la grille place ce conteneur, elle ne peut plus séparer ce qu'il
   contient. Règle nommée, et pas seulement héritée du `> *` :
   tools/verifier-styles.php exige qu'une classe émise soit visée. */
.dons__emplois .emploi { min-width: 0; }

/* ---------- 28. Le pied de page -------------------------------------------
   Dense, factuel, et la bande de club en tête : le pied redit le nom, le
   lieu et les moyens de joindre. C'est là qu'on cherche un numéro. */

.pied {
  border-top: var(--bande) solid var(--club);
  background: var(--fond-bande);
  padding: clamp(28px, 4vw, 48px) var(--gouttiere);
  font-size: var(--t-petit);
}
.pied__grille {
  max-width: var(--large); margin: 0 auto;
  display: grid; gap: clamp(18px, 3vw, 36px);
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
}
.pied__nom { font-weight: 500; font-size: var(--t-h3); }
.pied__devise, .pied__adresse, .pied__contacts, .pied__mention { color: var(--encre-douce); }
.pied__intitule {
  font-size: var(--t-mention); letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--encre-douce); font-weight: 500; margin-bottom: 0.4em;
}
.pied__contacts a, .pied__legal a, .pied__reseaux a { color: var(--encre); }
.pied__reseaux { display: flex; flex-wrap: wrap; gap: 0.8em; }
.pied__legal { display: flex; flex-wrap: wrap; gap: 0.8em; }
.pied__signature {
  max-width: var(--large); margin: clamp(18px, 3vw, 32px) auto 0;
  padding-top: 1rem; border-top: 1px solid var(--trait);
  display: flex; flex-wrap: wrap; gap: 0.6em 1.2em;
  color: var(--encre-douce); font-size: var(--t-mention);
}
.pied__annee { white-space: nowrap; }

/* ---------- 29. Le sélecteur de langue ------------------------------------ */

.langues { margin-left: 0.6rem; }
.langues__liste { display: flex; gap: 0.5em; }
.langues__lien {
  text-decoration: none; font-size: var(--t-mention);
  letter-spacing: 0.06em; text-transform: uppercase;
  padding: 0.3em 0.45em; border: 1px solid var(--trait);
}
.langues__lien[aria-current] { background: var(--club); color: var(--encre-clair); border-color: var(--club); }

/* ---------- 30. Les pages légales ------------------------------------------ */

.sec--legal .sec__corps { max-width: var(--lecture); }
.sec--legal__mentions h2 { font-size: var(--t-h3); margin-top: 1.5em; }
.sec--legal__retour { margin-top: 2em; }

/* ---------- 31. Apparition au défilement -----------------------------------
   COURTE, ET UNIQUEMENT EN OPACITÉ. Un déplacement à l'apparition
   décalerait la mise en page — et ce socle tient son décalage à zéro. */

.reveal { opacity: 0; transition: opacity var(--apparition) var(--ease); }
.reveal--vu { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transition: none; }
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* ---------- 32. La visionneuse ---------------------------------------------
   ELLE N'EST PLUS HABILLÉE ICI, ET C'EST UNE CORRECTION.

   Son balisage est fabriqué par assets/js/commun.js, pas par un
   gabarit : sept parties, dont ce thème n'en habillait que trois. Le
   <dialog> restait rétracté au milieu de l'écran — l'agent utilisateur
   le pose en « width: fit-content » —, le bouton de fermeture n'avait
   pas de croix, et les deux chevrons s'empilaient sous l'image. Elle
   était inutilisable sur les trois thèmes à la fois, ce qui est le signe
   qu'une règle recopiée trois fois n'était à sa place nulle part.

   Elle vit maintenant dans assets/css/visionneuse.css, du socle, servie
   uniquement quand la page porte un lien agrandissable. Une photo
   agrandie se regarde sur du noir, quel que soit le site : cette
   feuille-là n'a aucune raison d'appartenir à un thème. */

/* ---------- 33. Le calendrier partagé -------------------------------------
   Sa feuille vit dans assets/css/calendrier.css et n'emploie aucune
   couleur de thème. Ces deux règles-ci ne font que l'accorder. */

.calendrier { max-width: var(--large); margin: 0 auto; }
.calendrier--agenda { border: 1px solid var(--trait); padding: 0.8rem; }
.calendrier__etat { font-size: var(--t-petit); color: var(--encre-douce); }
.apercu-section { display: block; }
/* `.serie` NE REÇOIT AUCUNE RÈGLE, ET C'EST VOULU.

   C'est un repère de script — assets/js/commun.js s'en sert pour
   composer le groupe que la visionneuse feuillette — et il est TOUJOURS
   posé à côté d'une classe qui, elle, habille : `galerie-mosaique
   serie`, `carte serie`, `sec__grille serie`. verifier-styles.php garde
   les LISTES de classes et n'exige une règle que pour la liste ; aucune
   ne sort donc nue à cause de lui.

   Il a porté un moment `display: block`, et cette ligne a coûté cher :
   posée après `.galerie-mosaique { display: grid }`, à spécificité
   égale, elle gagnait — la mosaïque tombait en colonne unique sur les
   trois thèmes, à toutes les largeurs, et chaque photo occupait la
   pleine largeur du cadre. Une règle écrite pour satisfaire un contrôle
   qui ne la demandait pas. */

/* ---------- 34. Ce que riche() classe, et qu'on oublie ---------------------
   riche() pose SA classe sur chaque paragraphe qu'elle produit : ce ne
   sont pas des conteneurs, ce sont les paragraphes eux-mêmes. Chacune
   doit donc avoir sa règle, sinon la section sort avec des blocs nus.
   tools/verifier-styles.php les relève sur le rendu ET sur les gabarits,
   ce qui attrape aussi les sections qu'un jeu de données laisse vides. */

.sec__intro { max-width: var(--lecture); color: var(--encre-douce); margin-top: 0.5em; }
.sec__intro + .sec__intro { margin-top: 0.7em; }

.appel__texte { padding: 0.5rem 1rem 0; color: var(--encre-douce); }
.actu__texte { padding: 0.5rem 1rem 0; color: var(--encre-douce); }
.atelier__texte { padding: 0.5rem 1rem 0; color: var(--encre-douce); }
.document__texte { font-size: var(--t-petit); color: var(--encre-douce); }
.membre__texte { font-size: var(--t-petit); color: var(--encre-douce); margin-top: 0.3em; }
.dons__moyens { max-width: var(--lecture); margin-top: 1rem; }
.dons__fiscal {
  max-width: var(--lecture); margin-top: 1rem;
  padding: 0.7em 0.9em; background: var(--fond-creux);
  font-size: var(--t-petit); color: var(--encre-douce);
}
.sec--access__lieu { color: var(--encre-douce); }
.pied__mot { color: var(--encre-douce); }

/* UNE FICHE DE MEMBRE SANS PHOTO N'EST PAS UNE FICHE VIDE. Le socle pose
   « membre--sans-photo » quand aucune photo n'a été déposée : le bureau
   d'une association en compte toujours au moins un. On lui rend une
   place — un filet de club à gauche — plutôt qu'un cadre absent. */
.membre { display: block; }
.membre--sans-photo {
  padding-left: 0.8rem;
  border-left: var(--bande) solid var(--trait-fort);
}

/* LE PREMIER BOUTON DE L'ACCUEIL EST L'ACTION. Le gabarit du socle
   distingue déjà les deux — « sec__bouton » et « sec__bouton--doux » —
   et ce thème ne s'en servait pas : les deux sortaient bordés, donc de
   même poids, et un visiteur n'avait aucune raison d'appuyer sur l'un
   plutôt que sur l'autre. Le premier prend le rouge d'action, le second
   garde le bord. */
.sec--hero .sec__bouton:not(.sec__bouton--doux) {
  background: var(--action); border-color: var(--action); color: var(--encre-clair);
  text-transform: uppercase; letter-spacing: 0.06em; font-size: var(--t-mention);
}
.sec--hero .sec__bouton:not(.sec__bouton--doux):hover {
  background: var(--action-fonce); border-color: var(--action-fonce); color: var(--encre-clair);
}
