/* ─────────────────────────────────────────────────────────────────────────
   Harmonie La Fleurantine — système du site public.
   Source de vérité des jetons et des composants partagés (voir DESIGN.md).
   Aucun fichier n'est partagé avec le site de la banda : identité autonome.
   ───────────────────────────────────────────────────────────────────────── */

:root {
  /* Couleurs */
  --noir: #0B0B0C;          /* noir de salle : première vue, pied de page */
  --papier: #F7F7F5;        /* blanc de partition : fond des pages */
  --papier-creux: #EDEDEA;  /* creux du papier : lignes alternées, zones calmes */
  /* UN SEUL doré, sur papier comme sur noir. Mesuré : 5,15:1 sur le noir de
     salle, 3,56:1 sur le papier — au-dessus du seuil des grands textes et des
     éléments graphiques. Un laiton plus clair (#C8A046) tomberait à 2,3:1 sur
     le papier, donc illisible dès qu'il sert de texte. */
  --or: #A57C1B;            /* laiton des cuivres : action, imminence, tampons */
  --or-clair: #D3A94A;      /* laiton éclairé : survol sur fond noir */
  --or-encre: #A57C1B;      /* conservé comme alias : même doré, partout */
  --encre: #16161A;         /* texte courant */
  --encre-2: #55555F;       /* texte secondaire — 7.1:1 sur papier */
  --encre-3: #7A7A85;       /* mentions, tampons — réservé au texte ≥ 1.25rem */
  --filet: rgba(11, 11, 12, 0.16);
  --filet-clair: rgba(247, 247, 245, 0.22);

  /* Typographie */
  --affiche: "Antonio", "Arial Narrow", sans-serif;  /* capitales condensées */
  --courant: "Public Sans", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* Grille : l'axe du bloc de titre règle toute la page */
  --marge: clamp(20px, 5vw, 76px);
  --largeur: 1560px;
  --colonne-texte: 68ch;

  /* Rythme vertical */
  --pas: clamp(56px, 8vw, 128px);
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* Le fond du CORPS est noir, celui du contenu papier : Safari teinte la
   barre d'état et le bas de l'écran avec le fond de `body`. En papier,
   l'affiche noire paraissait coupée en haut et en bas sur iPhone. */
body {
  margin: 0;
  background: var(--noir);
  color: var(--encre);
  font-family: var(--courant);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  line-height: 1.6;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

/* Surfaces que le navigateur dessine : elles portent aussi l'identité. */
::selection { background: var(--or); color: var(--noir); }
:focus-visible { outline: 2px solid var(--or); outline-offset: 3px; border-radius: 2px; }
.sur-noir :focus-visible, .pied :focus-visible { outline-color: #FFF; }
@supports (scrollbar-color: red blue) {
  html { scrollbar-color: var(--encre-3) var(--papier-creux); scrollbar-width: thin; }
}
a { color: var(--or-encre); text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
a:hover { text-decoration-thickness: 2px; }

h1, h2, h3 { font-family: var(--affiche); font-weight: 600; text-transform: uppercase; letter-spacing: 0.005em; line-height: 1.28; text-wrap: balance; margin: 0; }
p { text-wrap: pretty; overflow-wrap: anywhere; }

main { background: var(--papier); }
.contenu { max-width: var(--largeur); margin-inline: auto; padding-inline: var(--marge); }
.texte { max-width: min(var(--colonne-texte), 100%); }
.hors-ecran {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.saut-contenu {
  position: absolute; left: var(--marge); top: -100%; z-index: 50;
  background: #FFF; color: var(--encre); padding: 10px 18px; font-weight: 600;
}
.saut-contenu:focus { top: 12px; }

/* ── En-tête ─────────────────────────────────────────────────────────────
   Posé sur la première vue, sans fond, jusqu'au premier défilement.        */
.entete {
  position: fixed; inset: 0 0 auto 0; z-index: 40;
  display: flex; align-items: center; gap: 24px;
  padding: 14px var(--marge);
  color: #FFF;
  transition: background-color 220ms ease, color 220ms ease, border-color 220ms ease;
  border-bottom: 1px solid transparent;
}
.entete.pose {
  background: var(--papier); color: var(--encre); border-bottom-color: var(--filet);
}
.entete .marque {
  display: flex; align-items: center; gap: 12px;
  font-family: var(--affiche); font-size: clamp(1.05rem, 1.6vw, 1.35rem);
  text-transform: uppercase; line-height: 1; letter-spacing: 0.01em;
  color: inherit; text-decoration: none; margin-right: auto; max-width: 52vw;
}
.entete .marque .nom { display: block; font-size: 1em; letter-spacing: 0.01em; opacity: 1; }
.entete .marque .nom span { display: block; font-size: 0.62em; letter-spacing: 0.16em; opacity: 0.72; }
/* Le logo de l'orchestre, en blanc sur la première vue et en noir une fois
   l'en-tête posé sur le papier. */
.entete .logo { width: auto; height: clamp(38px, 4.4vw, 52px); flex: none; }
.entete .logo.noir, .entete.pose .logo.blanc { display: none; }
.entete.pose .logo.noir { display: block; }
/* Menu ouvert : la barre du haut rejoint le noir du panneau, et tout ce
   qu'elle porte (nom, bouton, logo) repasse en blanc. */
.entete.menu-ouvert {
  background: var(--noir); color: #FFF; border-bottom-color: transparent;
}
.entete.menu-ouvert .logo.noir { display: none; }
.entete.menu-ouvert .logo.blanc { display: block; }
@media (max-width: 420px) {
  .entete .marque { gap: 9px; font-size: 0.95rem; }
  .entete .logo { height: 34px; }
}
.entete nav { display: flex; align-items: center; gap: clamp(14px, 2vw, 30px); }
.entete nav a {
  color: inherit; text-decoration: none; font-size: 0.9375rem; font-weight: 500;
  padding: 6px 0 8px; position: relative;
}
/* Une barre droite sous le lien : toujours tirée sous la page en cours,
   déployée de gauche à droite au survol, repliée vers la droite quand le
   pointeur s'en va. */
.entete nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: currentColor; transform: scaleX(0); transform-origin: right center;
  transition: transform 460ms cubic-bezier(0.16, 1, 0.3, 1);
}
.entete nav a:hover::after, .entete nav a[aria-current="page"]::after {
  transform: scaleX(1); transform-origin: left center;
}
@media (prefers-reduced-motion: reduce) { .entete nav a::after { transition: none; } }
/* Accès à l'espace membre Sonora : discret, à droite du menu, comme sur le
   site de la banda. */
.entete .lien-membre {
  display: grid; place-items: center; width: 40px; height: 40px; flex: none;
  color: inherit; border: 1px solid currentColor; border-radius: 999px;
  opacity: 0.75; transition: opacity 140ms ease, background-color 140ms ease, color 140ms ease;
}
.entete .lien-membre:hover { opacity: 1; background: currentColor; }
/* Le survol remplit la pastille de la couleur du texte : l'icône doit donc
   prendre la couleur du FOND du bandeau, pas celle du texte. En haut de page
   le bandeau est sombre (texte blanc → pastille blanche → icône noire) ;
   posé, il est clair (texte encre → pastille encre → icône papier). */
.entete .lien-membre:hover svg { color: var(--noir); }
.entete.pose .lien-membre:hover svg { color: var(--papier); }
.entete .lien-membre svg { width: 20px; height: 20px; }
.entete .menu-bouton { display: none; }
/* Le doublon du menu n'existe qu'en écran étroit ; déclaré APRÈS la règle
   générale des liens de nav pour la couvrir. */
.entete nav .lien-membre-menu { display: none; }

@media (max-width: 860px) {
  .entete nav { display: none; }
  .entete .lien-membre { display: none; }
  .entete nav .lien-membre-menu { display: block; }
  /* Le panneau s'ouvre SOUS le bandeau, jamais par-dessus : l'en-tête reste
     entièrement affiché et cliquable, c'est lui qui porte la croix qui referme.
     `--h-entete` est mesurée à l'ouverture (installerEntete) — la hauteur du
     bandeau change avec la largeur de l'écran, et une valeur écrite en dur
     laissait soit un liséré noir, soit un chevauchement. */
  .entete nav.ouvert {
    display: flex; position: fixed; inset: var(--h-entete, 72px) 0 0 0;
    background: var(--noir); color: #FFF;
    flex-direction: column; align-items: flex-start; justify-content: center;
    gap: 6px; padding: var(--marge); font-size: 1.5rem; overflow-y: auto;
  }
  .entete nav.ouvert a { font-family: var(--affiche); text-transform: uppercase; font-size: 2rem; }
  .entete .menu-bouton {
    display: inline-flex; align-items: center; gap: 9px; background: none; border: 0;
    color: inherit; font: inherit; font-weight: 600; cursor: pointer; padding: 8px 0;
  }
  .entete .menu-bouton svg { width: 22px; height: 22px; }

  /* Menu ouvert : le bandeau rejoint le noir du panneau, quoi qu'en dise
     `.pose`, et tout ce qu'il porte repasse en blanc. Déclaré APRÈS `.pose`,
     de même spécificité : c'est l'ordre qui tranche. */
  .entete.menu-ouvert {
    background: var(--noir); color: #FFF; border-bottom-color: transparent;
  }
  .entete.menu-ouvert .logo.noir { display: none; }
  .entete.menu-ouvert .logo.blanc { display: block; }
}

/* ── Ouverture du menu mobile ────────────────────────────────────────────
   Le panneau descend du bandeau sous un rideau, puis chaque lien entre par
   la gauche pendant que sa barre se tire sous lui, et la barre se rétracte
   aussitôt vers la droite. Décalées d'un cran et menées en accélération
   puis freinage, les barres font passer une onde à travers le menu. Seule
   celle de la page en cours reste, dorée. Les animations partent quand
   `display` passe de none à flex : aucun script, et le menu rouvert rejoue
   l'entrée. */
@media (max-width: 860px) {
  .entete nav.ouvert a[aria-current="page"]::after {
    transform: scaleX(1); transform-origin: left center; background: var(--or);
  }
}
@media (max-width: 860px) and (prefers-reduced-motion: no-preference) {
  .entete nav.ouvert { animation: rideau-menu 520ms cubic-bezier(0.16, 1, 0.3, 1) both; }
  .entete nav.ouvert a {
    --retard: calc(120ms + var(--i, 0) * 80ms);
    animation: lien-menu 640ms var(--retard) cubic-bezier(0.16, 1, 0.3, 1) both;
  }
  .entete nav.ouvert a::after {
    animation: onde-barre 1300ms var(--retard) cubic-bezier(0.65, 0, 0.35, 1) both;
  }
  .entete nav.ouvert a[aria-current="page"]::after {
    animation: tirer-barre 650ms var(--retard) cubic-bezier(0.65, 0, 0.35, 1) both;
  }
  .entete nav.ouvert a:nth-child(2) { --i: 1; }
  .entete nav.ouvert a:nth-child(3) { --i: 2; }
  .entete nav.ouvert a:nth-child(4) { --i: 3; }
  .entete nav.ouvert a:nth-child(5) { --i: 4; }
}
@keyframes rideau-menu { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes lien-menu { from { opacity: 0; translate: -48px 0; } to { opacity: 1; translate: 0 0; } }
@keyframes tirer-barre { from { transform: scaleX(0); } to { transform: scaleX(1); } }
/* L'origine change pendant que la barre est entière : le saut ne se voit
   pas, et la barre repart du côté où elle est arrivée. */
@keyframes onde-barre {
  0%   { transform: scaleX(0); transform-origin: left center; }
  48%  { transform: scaleX(1); transform-origin: left center; }
  52%  { transform: scaleX(1); transform-origin: right center; }
  100% { transform: scaleX(0); transform-origin: right center; }
}

/* ── L'icône du menu devient une croix ───────────────────────────────────
   Trois traits distincts plutôt qu'un seul chemin : c'est ce qui permet de
   les faire pivoter séparément. `fill-box` prend pour repère la boîte du
   trait lui-même, donc chaque rotation se fait autour de son propre milieu. */
.entete .menu-bouton .barre {
  transform-box: fill-box; transform-origin: center;
  transition: transform 260ms cubic-bezier(.4, 0, .2, 1), opacity 140ms ease;
}
.entete.menu-ouvert .menu-bouton .haut { transform: translateY(6px) rotate(45deg); }
.entete.menu-ouvert .menu-bouton .milieu { opacity: 0; transform: scaleX(.3); }
.entete.menu-ouvert .menu-bouton .bas { transform: translateY(-6px) rotate(-45deg); }
@media (prefers-reduced-motion: reduce) {
  .entete .menu-bouton .barre { transition: none; }
}

/* ── Boutons ─────────────────────────────────────────────────────────── */
.bouton {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 14px 26px; border-radius: 999px; border: 1px solid transparent;
  background: var(--or); color: var(--noir); text-decoration: none;
  font-weight: 600; font-size: 1rem; line-height: 1; cursor: pointer;
  transition: background-color 160ms ease, color 160ms ease, border-color 160ms ease;
}
.bouton:hover { background: var(--or-clair); }
.bouton.blanc { background: #FFF; color: var(--noir); }
.bouton.blanc:hover { background: var(--or); color: var(--noir); }
/* « Ajouter à mon agenda » : doré au repos, blanc au survol, texte noir dans
   les deux cas. */
.bouton.agenda { background: var(--or); color: var(--noir); }
.bouton.agenda:hover { background: var(--papier); color: var(--noir); }
.bouton.contour { background: none; border-color: currentColor; color: inherit; }
/* Fond et texte fixés explicitement : `background: currentColor` prenait la
   couleur réécrite par la même règle, et le bouton devenait papier sur
   papier — illisible au survol. */
.bouton.contour:hover { background: var(--encre); color: var(--papier); border-color: var(--encre); }
/* Sur un fond sombre, le contour est blanc : au survol, le fond passe au blanc
   et le texte au noir. Les deux sont fixés explicitement — écrire seulement
   `color` changerait aussi le `currentColor` du fond, et le bouton
   deviendrait noir sur noir. */
.affiche .bouton.contour:hover,
.tete-concert .bouton.contour:hover,
.tete-page .bouton.contour:hover,
.programme-section .bouton.contour:hover,
.ecouter .bouton.contour:hover,
.pied .bouton.contour:hover {
  background: var(--papier); color: var(--noir); border-color: var(--papier);
}
.bouton svg { width: 18px; height: 18px; flex: none; }

/* ── Tampon : l'état est une marque, jamais une couleur seule ─────────── */
.tampon {
  display: inline-block; font-family: var(--affiche); text-transform: uppercase;
  font-size: 0.9375rem; letter-spacing: 0.12em; line-height: 1;
  padding: 7px 11px 5px; border: 1.5px solid currentColor; color: var(--encre-2);
  transform: rotate(-3deg); transform-origin: right center;
}
.tampon.or { color: var(--or-encre); }

/* ── Titres de section ───────────────────────────────────────────────── */
.section { padding-block: var(--pas); }
.section > .contenu > h2 {
  font-size: clamp(2.25rem, 6vw, 4.5rem);
  margin-bottom: 8px;
}
.section-intro {
  color: var(--encre-2); max-width: 54ch; margin: 0 0 clamp(28px, 4vw, 48px);
  font-size: 1.0625rem;
}

/* ── Placard de la saison : un tableau de dates, pas des cartes ───────── */
.placard { border-top: 1px solid var(--filet); }
.ligne {
  display: grid;
  grid-template-columns: 4px minmax(112px, 138px) minmax(0, 1fr) clamp(190px, 26vw, 380px) auto;
  gap: clamp(14px, 2.5vw, 34px);
  align-items: end;
  padding: clamp(18px, 2.4vw, 28px) 0;
  border-bottom: 1px solid var(--filet);
  text-decoration: none; color: inherit;
  position: relative;
  transition: background-color 140ms ease;
}
a.ligne:hover { background: var(--papier-creux); }
a.ligne:hover .ligne .annee { display: block; }
.ligne-titre { color: var(--or-encre); }

/* Jauge d'imminence : le trait raccourcit à mesure que la date s'éloigne.
   L'information reste écrite en toutes lettres à côté — jamais portée par
   la seule couleur. */
.ligne .jauge { align-self: stretch; background: var(--or); border-radius: 2px; }
.ligne.passe .jauge { background: var(--filet); }

/* La date est calée EN HAUT de la ligne : c'est le repère qu'on parcourt du
   pouce, il doit tomber à la même hauteur sur toutes les lignes, quelle que
   soit la place prise par le titre ou la mention de première partie. */
.ligne .quand { font-family: var(--affiche); line-height: 1; align-self: start; }
.ligne .jour {
  display: block; font-size: clamp(2.5rem, 5.4vw, 3.9rem); letter-spacing: -0.01em; line-height: 0.8;
}
.ligne .mois {
  display: block; font-family: var(--courant); font-weight: 600;
  font-size: 0.8125rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--encre-2); margin-top: 10px; white-space: nowrap; line-height: 1.5;
}
.ligne .annee { display: block; }
.ligne-titre {
  display: block;
  font-family: var(--affiche); font-size: clamp(1.4rem, 2.6vw, 2.1rem);
  text-transform: uppercase; line-height: 1.22; margin: 0;
  transition: color 140ms ease;
}
.ligne-lieu { display: block; margin: 8px 0 0; color: var(--encre-2); font-size: 0.9375rem; }
/* La première partie se lit DANS la ligne de la saison : c'est souvent elle
   qui décide de la soirée. Discrète mais écrite en toutes lettres — jamais
   portée par la seule couleur. */
.ligne-premiere {
  display: block; margin: 6px 0 0; color: var(--encre-2);
  font-size: 0.875rem; line-height: 1.35;
}
.ligne .fin { text-align: right; white-space: nowrap; display: flex; flex-direction: column;
  align-items: flex-end; gap: 10px; }
.ligne .heure { font-weight: 600; font-size: 1.0625rem; display: block; }
/* Le tarif est porté par l'écriteau de la ligne, à la même place que le
   tampon « Joué » des concerts passés : jamais en double. */
.ligne.passe .ligne-titre, .ligne.passe .jour { color: var(--encre-2); }

/* La photo de l'évènement se dévoile dans la ligne, de la droite vers la
   gauche, avec un léger recadrage qui se détend. Décor : l'information reste
   écrite, et rien ne bouge en mouvement réduit. */
@property --biseau-haut {
  syntax: "<percentage>"; inherits: false; initial-value: 14%;
}
@property --biseau-bas {
  syntax: "<percentage>"; inherits: false; initial-value: 8%;
}

.ligne .vignette {
  --biseau-haut: 14%;
  --biseau-bas: 8%;
  animation: biseau-haut 7.3s ease-in-out infinite alternate,
             biseau-bas 9.7s ease-in-out infinite alternate;
  align-self: stretch; overflow: hidden; display: block; position: relative;
  margin-block: calc(-1 * clamp(18px, 2.4vw, 28px));
  clip-path: polygon(var(--biseau-haut) 0, 100% 0,
                     calc(100% - var(--biseau-bas)) 100%, 0 100%);
  opacity: 0;
  transition: opacity 260ms ease, clip-path 620ms cubic-bezier(0.16, 1, 0.3, 1);
}
.ligne .vignette img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
  transform: translateX(14%) scale(1.14);
  transition: transform 820ms cubic-bezier(0.16, 1, 0.3, 1);
}
a.ligne:hover .vignette, a.ligne:focus-visible .vignette { opacity: 1; }
a.ligne:hover .vignette img, a.ligne:focus-visible .vignette img {
  transform: translateX(0) scale(1);
}
/* Les côtés ondulent d'eux-mêmes, sans que le pointeur ait à bouger.
   Chaque ligne reçoit un décalage négatif aléatoire (installerBiseaux) pour
   que les lignes ne soient jamais en phase. */
@keyframes biseau-haut {
  from { --biseau-haut: var(--bh-min, 3%); }
  to   { --biseau-haut: var(--bh-max, 27%); }
}
@keyframes biseau-bas {
  from { --biseau-bas: var(--bb-min, 26%); }
  to   { --biseau-bas: var(--bb-max, 4%); }
}

@media (prefers-reduced-motion: reduce) {
  .ligne .vignette { animation: none; }
  .ligne .vignette, .ligne .vignette img { transition: none; }
  .ligne .vignette img { transform: none; }
}

@media (max-width: 680px) {
  .ligne { grid-template-columns: 3px 100px minmax(0, 1fr); row-gap: 10px; }
  .ligne .vignette { display: none; }
  /* Le tarif puis l'heure côte à côte sur leur propre ligne, posés sur la
     MÊME ligne de base malgré deux tailles de police. */
  /* L'heure se cale sur le bord droit de la ligne et l'écriteau du prix se
     range juste à sa gauche : `row-reverse` empile depuis la droite, donc
     l'ordre du balisage (heure puis écriteau) se lit de droite à gauche. */
  .ligne .fin {
    grid-column: 2 / -1; text-align: right; flex-direction: row-reverse;
    align-items: baseline; justify-content: flex-start; gap: 14px;
  }
  .ligne .fin .tampon { transform-origin: right center; }
  .ligne .heure { display: inline; }
}

/* ── Vide et erreur ──────────────────────────────────────────────────── */
.vide {
  border: 1px dashed var(--filet); padding: clamp(22px, 4vw, 40px);
  color: var(--encre-2); max-width: 60ch;
}
.vide strong { color: var(--encre); display: block; font-size: 1.125rem; margin-bottom: 6px; }

/* ── Squelette de chargement ─────────────────────────────────────────── */
.squelette { background: var(--papier-creux); border-radius: 2px; display: block; }
@media (prefers-reduced-motion: no-preference) {
  .squelette { animation: pouls 1.4s ease-in-out infinite; }
  @keyframes pouls { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
}

/* ── Pied de page ────────────────────────────────────────────────────── */
.pied {
  background: var(--noir); color: var(--papier);
  padding-block: clamp(48px, 7vw, 92px) 32px;
}
.pied a { color: inherit; }
.pied .grille {
  display: grid; grid-template-columns: 1.6fr repeat(3, minmax(0, 1fr));
  gap: clamp(28px, 4vw, 56px); padding-bottom: 40px; border-bottom: 1px solid var(--filet-clair);
}
@media (max-width: 1040px) {
  /* Deux colonnes franches plutôt que trois colonnes serrées et un orphelin. */
  .pied .grille { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px; }
  .pied .grille > :first-child { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .pied .grille { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .pied .grille > :first-child { grid-column: auto; }
}
.pied h2 { font-size: clamp(2rem, 5vw, 3.25rem); margin-bottom: 24px; }
/* Même composition que le bandeau, en plus grand : le logo et les
   espacements sont exprimés en `em`, donc tout garde ses proportions quelle
   que soit la taille choisie ici. */
.pied-marque {
  display: flex; align-items: center; gap: 0.5em;
  font-size: clamp(1.5rem, 3vw, 2.2rem);
}
.pied-marque .logo-pied { width: auto; height: 2.45em; flex: none; }
.pied-marque .nom {
  font-family: var(--affiche); font-weight: 600; font-size: 1em;
  text-transform: uppercase; line-height: 1; letter-spacing: 0.01em; margin: 0;
}
.pied-marque .nom span {
  display: block; font-size: 0.62em; letter-spacing: 0.16em; opacity: 0.72;
}
.pied h3 {
  font-family: var(--courant); text-transform: uppercase; letter-spacing: 0.14em;
  font-size: 0.75rem; font-weight: 700; color: rgba(247, 247, 245, 0.62); margin: 0 0 12px;
}
.pied ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.pied .bas {
  display: flex; flex-wrap: wrap; gap: 12px 26px; align-items: center;
  padding-top: 24px; font-size: 0.875rem; color: rgba(247, 247, 245, 0.66);
}
@media (max-width: 760px) {
  .pied .bas { flex-direction: column; align-items: flex-start; gap: 14px; }
  .pied .bas .reseaux { margin-left: 0; margin-top: 4px; }
}
.pied .bas a:hover { color: #FFF; }
/* L'adresse est un lien vers la carte : soulignée seulement au survol, pour
   ne pas transformer le pied en page de liens. */
.pied .adresse a, .pied .bas [data-adresse-ligne] a { text-decoration: none; }
.pied .adresse a:hover, .pied .bas [data-adresse-ligne] a:hover {
  text-decoration: underline; text-underline-offset: 0.2em; color: #FFF;
}
.reseaux { display: flex; gap: 12px; margin-left: auto; }
.reseaux a {
  display: grid; place-items: center; width: 40px; height: 40px;
  border: 1px solid var(--filet-clair); border-radius: 999px; color: inherit;
}
.reseaux a:hover { background: #FFF; color: var(--noir); border-color: #FFF; }
.reseaux svg { width: 19px; height: 19px; fill: currentColor; }
@media (max-width: 680px) { .reseaux { margin-left: 0; } }

/* ── Programme musical d'un concert ──────────────────────────────────────
   Une feuille de programme : une œuvre par ligne, compositeur aligné à
   droite, numérotation discrète parce que l'ordre est ici une information. */
.programme {
  border-top: 1px solid var(--filet); margin: 0; padding: 0;
  list-style: none; counter-reset: oeuvre;
}
.programme li { border-bottom: 1px solid var(--filet); }
.programme .rang {
  display: grid; grid-template-columns: 2.5ch minmax(0, 1fr) minmax(0, 0.8fr);
  gap: clamp(12px, 2vw, 28px); align-items: baseline; min-width: 0;
}
.programme li > .rang { padding: clamp(14px, 1.8vw, 20px) 0; }

/* Une œuvre documentée se déplie sur place : notice, portrait et sources. */
.programme details summary {
  display: grid; grid-template-columns: minmax(0, 1fr) 24px;
  gap: 16px; align-items: center; cursor: pointer; list-style: none;
  padding: clamp(14px, 1.8vw, 20px) 0;
}
.programme details summary::-webkit-details-marker { display: none; }
.programme details summary:hover .titre-oeuvre { color: var(--or); }
.programme .chevron {
  width: 14px; height: 14px; justify-self: center;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-3px, -3px);
  transition: transform 220ms cubic-bezier(0.16, 1, 0.3, 1); opacity: 0.6;
}
.programme details[open] .chevron { transform: rotate(225deg) translate(-3px, -3px); }
.programme .notice {
  padding: 4px 0 clamp(20px, 3vw, 30px); margin-left: calc(2.5ch + clamp(12px, 2vw, 28px));
  display: grid; gap: 20px; max-width: 78ch;
}
@media (max-width: 680px) { .programme .notice { margin-left: 0; } }
.programme .presentation { margin: 0; }
.programme .qui {
  display: grid; grid-template-columns: clamp(150px, 17vw, 208px) minmax(0, 1fr);
  gap: clamp(20px, 3vw, 34px); align-items: start;
}
.programme .qui > div:only-child { grid-column: 2; }

/* Les portraits viennent de Wikimedia : gravure du XIXe, huile sur toile,
   photo de studio, capture de concert. Un cadrage unique et un passage en
   gris les font tenir ensemble ; la couleur revient au survol, parce que
   l'original a sa valeur. */
.programme .portrait { margin: 0; position: relative; }
.programme .portrait img {
  width: 100%; aspect-ratio: 3 / 4; object-fit: cover; object-position: center 22%;
  display: block; background: var(--papier-creux);
  filter: grayscale(1) contrast(1.06);
  transition: filter 480ms ease, transform 620ms cubic-bezier(0.16, 1, 0.3, 1);
}
/* Voile doré très léger : il réchauffe les gris sans teinter la peau. */
.programme .portrait::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, rgba(200, 160, 70, 0.22), rgba(11, 11, 12, 0.42));
  mix-blend-mode: multiply; transition: opacity 480ms ease;
}
.programme .qui:hover .portrait img { filter: none; transform: scale(1.015); }
.programme .qui:hover .portrait::after { opacity: 0; }
.programme .portrait figcaption {
  font-size: 0.6875rem; line-height: 1.35; margin-top: 8px; opacity: 0.55;
  letter-spacing: 0.01em;
}
@media (prefers-reduced-motion: reduce) {
  .programme .portrait img { transition: none; }
}

/* Le nom se lit à l'échelle d'un titre de pupitre, avec un filet doré qui
   l'accroche au portrait. */
.programme .qui h4 {
  font-family: var(--affiche); text-transform: uppercase; font-weight: 600;
  font-size: clamp(1.25rem, 2.2vw, 1.6rem); line-height: 1.15;
  margin: 0 0 12px; padding-bottom: 10px;
  border-bottom: 1px solid var(--or);
}
.programme .qui .role {
  font-family: var(--courant); font-size: 0.6875rem; font-weight: 700;
  letter-spacing: 0.12em; opacity: 0.6;
}
.programme .qui p { margin: 0; font-size: 0.9375rem; }
.programme .source { margin-top: 8px !important; font-size: 0.8125rem; }
@media (max-width: 560px) {
  .programme .qui { grid-template-columns: 116px minmax(0, 1fr); gap: 16px; }
  .programme .qui h4 { font-size: 1.15rem; }
  .programme .qui > div:only-child { grid-column: 1 / -1; }
}
.programme .rang::before {
  counter-increment: oeuvre; content: counter(oeuvre);
  font-variant-numeric: tabular-nums; color: var(--or-encre); font-size: 0.875rem;
}
.programme .titre-oeuvre {
  font-family: var(--affiche); text-transform: uppercase;
  font-size: clamp(1.15rem, 2vw, 1.55rem); line-height: 1.22;
}
.programme .auteur { color: var(--encre-2); font-size: 0.9375rem; text-align: right; }
.programme .auteur .arrangeur { display: block; color: var(--encre-3); font-size: 0.875rem; }
@media (max-width: 680px) {
  .programme .rang { grid-template-columns: 2.5ch minmax(0, 1fr); row-gap: 6px; }
  .programme .auteur { grid-column: 2; text-align: left; }
}
.programme-sur-noir { border-top-color: var(--filet-clair); }
.programme-sur-noir li { border-bottom-color: var(--filet-clair); }
.programme-sur-noir .auteur { color: rgba(247, 247, 245, 0.72); }
.programme-sur-noir .auteur .arrangeur { color: rgba(247, 247, 245, 0.54); }
.programme-sur-noir .rang::before { color: var(--or); }
.pied .fleche-page, .ecouter .fleche-page { color: var(--or); }
.programme-sur-noir .portrait img { border-color: var(--filet-clair); }

/* ── Feuilletage des concerts déjà joués ─────────────────────────────── */
/* Les concerts déjà joués sont une autre section que la saison à venir :
   l'écart doit se voir. */
.passes-entete {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 16px; border-bottom: 1px solid var(--filet);
  margin-top: clamp(76px, 11vw, 160px);
}
.passes-entete .passes-tete { margin: 0; padding: 0 0 10px; }

/* Flèches nues, serrées l'une contre l'autre, étirées en hauteur. */
.pages { display: flex; align-items: center; gap: 2px; padding-bottom: 4px; }
.pages .compte {
  font-size: 0.8125rem; font-weight: 700; color: var(--encre-2);
  font-variant-numeric: tabular-nums; min-width: 4ch; text-align: center;
  margin-inline: 6px;
}
.fleche-page {
  display: grid; place-items: center; width: 22px; height: 44px;
  border: 0; background: none; color: var(--or-encre); cursor: pointer;
  padding: 0; transition: color 140ms ease, opacity 140ms ease, transform 140ms ease;
}
.fleche-page svg { width: 11px; height: 34px; }
.fleche-page:hover:not(:disabled) { color: var(--or); transform: scaleY(1.1); }
.fleche-page:disabled { opacity: 0.25; cursor: default; }

/* ── Visionneuse plein écran ─────────────────────────────────────────────
   La photo s'ouvre par-dessus le site, jamais dans un nouvel onglet. */
/* `display: grid` ci-dessous écrase le `display: none` que porte l'attribut
   `hidden` : sans cette règle, la visionneuse reste étalée sur toute la page,
   invisible mais interceptant chaque clic. */
.visionneuse[hidden] { display: none; }
.visionneuse {
  position: fixed; inset: 0; z-index: 100;
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center;
  gap: clamp(8px, 2vw, 28px); padding: clamp(16px, 4vw, 56px);
  background: rgba(11, 11, 12, 0.94);
  opacity: 0; transition: opacity 220ms ease;
}
.visionneuse { pointer-events: none; }
.visionneuse.ouverte { opacity: 1; pointer-events: auto; }
.visionneuse .v-scene {
  margin: 0; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 14px; min-width: 0; max-height: 100%;
}
.visionneuse img {
  max-width: 100%; max-height: calc(100svh - clamp(90px, 16vw, 190px));
  width: auto; height: auto; object-fit: contain; display: block;
  transform: scale(0.98); transition: transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
}
.visionneuse.ouverte img { transform: scale(1); }
.visionneuse figcaption {
  color: rgba(247, 247, 245, 0.78); font-size: 0.9375rem; text-align: center;
  max-width: 60ch;
}
.visionneuse .v-fermer {
  position: absolute; top: clamp(12px, 2vw, 24px); right: clamp(12px, 2vw, 24px);
  width: 46px; height: 46px; display: grid; place-items: center;
  background: none; border: 1px solid var(--filet-clair); border-radius: 999px;
  color: #FFF; cursor: pointer; transition: background-color 140ms ease, color 140ms ease;
}
.visionneuse .v-fermer:hover { background: #FFF; color: var(--noir); }
.visionneuse .v-fermer svg { width: 20px; height: 20px; }
.visionneuse .v-nav {
  width: clamp(28px, 4vw, 44px); height: 64px; display: grid; place-items: center;
  background: none; border: 0; color: var(--or); cursor: pointer; padding: 0;
  transition: color 140ms ease, transform 140ms ease;
}
.visionneuse .v-nav:hover { color: var(--or-clair); transform: scaleY(1.12); }
.visionneuse .v-nav svg { width: 13px; height: 40px; }
@media (prefers-reduced-motion: reduce) {
  .visionneuse, .visionneuse img { transition: none; }
}

/* ── Mécènes : deux bandes qui défilent ──────────────────────────────────
   Les logos sont blancs et détourés : ils exigent un fond sombre. */
.mecenes { background: var(--noir); color: #FFF; padding: clamp(34px, 5vw, 68px) 0; }
.mecenes h2 {
  color: #FFF; font-size: clamp(1.8rem, 3.6vw, 3rem);
  margin: 0 0 clamp(18px, 2.4vw, 30px);
}
.mecenes .defile {
  overflow-x: auto; scrollbar-width: none;
  -webkit-mask: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
          mask: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}
.mecenes .defile::-webkit-scrollbar { display: none; }
.mecenes .defile + .defile { margin-top: clamp(6px, 1vw, 14px); }
.mecenes .piste { list-style: none; margin: 0; padding: 0; display: flex; gap: 14px; width: max-content; }
.mecenes .piste li { flex: 0 0 auto; display: grid; place-items: center; width: 200px; height: 112px; padding: 14px; }
.mecenes .piste img { max-width: 100%; max-height: 80px; width: auto; height: auto; object-fit: contain; }
/* Logo absent ou illisible : le nom du mécène prend sa place, il ne doit jamais disparaître. */
.mecenes .nom-mecene { color: #fff; font: 700 .95rem/1.2 var(--titre, inherit); text-align: center; text-transform: uppercase; letter-spacing: .02em; }
.mecenes .defile.anime { overflow: hidden; }
.mecenes .defile.anime .piste { animation: defile-mecenes 46s linear infinite; }
.mecenes .defile.anime.inverse .piste { animation-direction: reverse; }
.mecenes .defile.anime:hover .piste,
.mecenes .defile.anime:focus-within .piste { animation-play-state: paused; }
@keyframes defile-mecenes { to { transform: translateX(calc(-50% - 7px)); } }
/* Sur la page dédiée, les logos sont le sujet : on leur donne plus d'air. */
.mecenes.grand .piste li { width: 240px; height: 134px; }
.mecenes.grand .piste img { max-height: 98px; }
@media (max-width: 560px) {
  .mecenes .piste li, .mecenes.grand .piste li { width: 150px; height: 92px; padding: 10px; }
  .mecenes .piste img, .mecenes.grand .piste img { max-height: 62px; }
  .mecenes .defile.anime .piste { animation-duration: 34s; }
}

/* ── Photo dans le bandeau noir de titre ─────────────────────────────────
   La photo occupe la moitié droite et s'éteint vers la gauche : le titre
   garde son fond noir plein, donc son contraste, sans cadre ni séparation. */
.tete-page { position: relative; overflow: hidden; }
.tete-page > .contenu { position: relative; z-index: 1; }
.tete-page .fond-photo {
  position: absolute; inset: 0 0 0 auto; width: min(54%, 820px);
  opacity: 0; transition: opacity 900ms ease, transform 1400ms cubic-bezier(0.16, 1, 0.3, 1);
  transform: scale(1.04);
  pointer-events: none;
}
.tete-page .fond-photo.visible { opacity: 1; transform: scale(1); }
.tete-page .fond-photo img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  filter: grayscale(0.15) contrast(1.04);
}
.tete-page .fond-photo::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(to right, var(--noir) 0%, rgba(11, 11, 12, 0.86) 24%, rgba(11, 11, 12, 0.1) 78%, transparent),
    linear-gradient(to top, rgba(11, 11, 12, 0.55), transparent 42%);
}
/* Écran étroit : plus de place pour deux colonnes, la photo passe derrière
   le titre et se met franchement en retrait pour rester lisible. */
@media (max-width: 760px) {
  .tete-page .fond-photo { width: 100%; }
  .tete-page .fond-photo::after {
    background:
      linear-gradient(to right, rgba(11, 11, 12, 0.88), rgba(11, 11, 12, 0.7)),
      linear-gradient(to top, var(--noir), rgba(11, 11, 12, 0.3) 60%);
  }
}
@media (prefers-reduced-motion: reduce) {
  .tete-page .fond-photo { transition: opacity 200ms ease; transform: none; }
  .tete-page .fond-photo.visible { transform: none; }
}

/* ── Visages repérés sur une photo agrandie ──────────────────────────────
   Les points sont posés en pourcentage de l'image, jamais en pixels : c'est
   ce qui les garde justes quelle que soit la taille d'affichage. */
.v-cadre { position: relative; display: block; line-height: 0; }
.v-reperes { position: absolute; inset: 0; display: block; }
/* 7 % de la LARGEUR DE L'IMAGE, jamais de la fenêtre : c'est la seule mesure
   que l'app peut reproduire à l'identique quand on pointe les visages. */
.v-repere {
  position: absolute; transform: translate(-50%, -50%);
  width: 7%; aspect-ratio: 1;
  background: none; border: 0; padding: 0; cursor: default;
  display: grid; place-items: center;
}
/* Un cerceau vide, assez large pour ENTOURER le visage : un point posé
   dessus cacherait exactement ce qu'il désigne. Au repos il n'existe pas —
   un visage ne se regarde pas à travers un rond doré. */
.v-point {
  width: 100%; height: 100%; border-radius: 50%;
  border: 1.5px solid var(--or-clair); background: none; opacity: 0;
  transition: opacity 240ms ease, transform 320ms cubic-bezier(0.16, 1, 0.3, 1),
              border-color 320ms ease, box-shadow 320ms ease;
}
/* À l'ouverture de la photo, les visages s'entourent une fois en cascade,
   scintillent, puis s'effacent : le temps de comprendre qu'il y a quelque
   chose à survoler, sans laisser de marques sur la photo. */
@media (prefers-reduced-motion: no-preference) {
  .v-reperes.amorce .v-point {
    animation: amorce-cerceau 3s cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: var(--retard, 0ms);
  }
  @keyframes amorce-cerceau {
    0%   { opacity: 0; transform: scale(1.55); box-shadow: 0 0 0 0 rgba(211, 169, 74, 0); }
    14%  { opacity: 1; transform: scale(1); box-shadow: 0 0 20px 3px rgba(211, 169, 74, 0.6); }
    28%  { opacity: 1; box-shadow: 0 0 5px 0 rgba(211, 169, 74, 0.15); }
    42%  { opacity: 1; box-shadow: 0 0 20px 3px rgba(211, 169, 74, 0.55); }
    56%  { opacity: 1; box-shadow: 0 0 5px 0 rgba(211, 169, 74, 0.15); }
    70%  { opacity: 1; box-shadow: 0 0 14px 2px rgba(211, 169, 74, 0.4); }
    100% { opacity: 0; transform: scale(1.08); box-shadow: 0 0 0 0 rgba(211, 169, 74, 0); }
  }
}
/* Après hover : même spécificité que l'amorce, donc placé APRÈS pour gagner. */
.v-repere:hover .v-point, .v-repere:focus-visible .v-point {
  opacity: 1; animation: none; border-width: 2px;
  box-shadow: 0 0 16px rgba(211, 169, 74, 0.45);
}

/* L'étiquette monte du point et se déplie : elle n'existe que le temps du
   survol, pour ne pas couvrir les visages. */
.v-etiquette {
  position: absolute; bottom: calc(100% + 8px); left: 50%;
  transform: translate(-50%, 8px) scale(0.96);
  display: grid; gap: 2px; padding: 8px 12px; white-space: nowrap;
  background: rgba(11, 11, 12, 0.92); border: 1px solid var(--or);
  color: #FFF; opacity: 0; pointer-events: none;
  transition: opacity 260ms ease, transform 380ms cubic-bezier(0.16, 1, 0.3, 1);
}
.v-etiquette::after {
  content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  border: 6px solid transparent; border-top-color: var(--or);
}
.v-repere:hover .v-etiquette, .v-repere:focus-visible .v-etiquette {
  opacity: 1; transform: translate(-50%, 0) scale(1);
}
.v-nom {
  font-family: var(--affiche); text-transform: uppercase; font-size: 1rem;
  line-height: 1.1; letter-spacing: 0.01em;
}
.v-instrument {
  font-size: 0.6875rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--or);
}
@media (prefers-reduced-motion: reduce) {
  .v-point, .v-etiquette { transition: none; }
}

/* ── Mouvement : apparitions et parallaxe ────────────────────────────────
   - Apparitions : jouées UNE fois, en temps, quand le bloc entre à l'écran
     (installerApparitions, commun.js). Liées au défilement, elles se
     jouaient sur la seule hauteur du bloc : un cran de molette suffisait à
     les sauter, et sur ordinateur on ne les voyait pas. Les titres entrent
     par la gauche, les autres blocs montent et se posent.
   - Parallaxe : liée au défilement par `animation-timeline`. Les photos des
     bandeaux de tête descendent moins vite que la page et le texte s'efface
     en montant. Navigateur sans `animation-timeline` : rien ne bouge.
   Mouvement réduit : rien ne bouge, rien n'est masqué. */
@media (prefers-reduced-motion: no-preference) {
  /* Ouverture des bandeaux de tête : au chargement, ils sont déjà à l'écran. */
  .tete-page h1, .tete-concert h1 { animation: entrer-titre 1000ms cubic-bezier(0.16, 1, 0.3, 1) both; }
  .tete-page h1 ~ *, .tete-concert h1 ~ * { animation: monter 900ms 160ms cubic-bezier(0.16, 1, 0.3, 1) both; }
  .tete-concert .retour { animation: monter 700ms cubic-bezier(0.16, 1, 0.3, 1) both; }

  .a-apparaitre { opacity: 0; }
  .a-apparaitre.apparu {
    animation: monter 900ms var(--retard, 0ms) cubic-bezier(0.16, 1, 0.3, 1) both;
  }
  h2.a-apparaitre.apparu { animation-name: entrer-titre; animation-duration: 1100ms; }

  /* Contreparties du Mécénat (même geste que sur le site de la banda) :
     chaque ligne glisse et sa coche se trace. Jouées au chargement quand la
     liste est à l'écran d'emblée ; plus bas, elle est masquée
     (`.a-apparaitre`), l'animation est coupée puis relancée à l'apparition. */
  .contreparties li {
    animation: entrer-coche 600ms calc(var(--retard, 0ms) + 250ms + var(--n, 0) * 130ms) cubic-bezier(.34, 1.3, .64, 1) both;
  }
  .contreparties path {
    stroke-dasharray: 30;
    animation: tracer 520ms calc(var(--retard, 0ms) + 400ms + var(--n, 0) * 130ms) ease-out both;
  }
  .contreparties li:nth-child(2) { --n: 1; }
  .contreparties li:nth-child(3) { --n: 2; }
  .contreparties li:nth-child(4) { --n: 3; }
  .contreparties li:nth-child(5) { --n: 4; }
  .contreparties.a-apparaitre :is(li, path) { animation-name: none; }
  .contreparties.apparu li { animation-name: entrer-coche; }
  .contreparties.apparu path { animation-name: tracer; }

  @supports (animation-timeline: view()) {
    /* Les bandeaux de tête sont en haut du document : la frise de défilement
       de la page suffit. La photo descend au tiers de la vitesse de la page —
       son bord haut reste toujours au-dessus de l'écran, donc jamais de trou. */
    :is(.affiche .photo, .tete-concert .photo-fond, .tete-page .fond-photo img) {
      animation: arrivee-photo 1800ms cubic-bezier(0.16, 1, 0.3, 1) both, parallaxe-photo linear both;
      animation-timeline: auto, scroll(root);
      animation-range: normal, 0 100vh;
    }
    /* Le quantième est le plan du fond : il traîne encore plus. */
    .affiche .quantieme {
      animation: parallaxe-fond linear both;
      animation-timeline: scroll(root);
      animation-range: 0 100vh;
    }
    :is(.affiche, .tete-page, .tete-concert) > .contenu {
      animation: parallaxe-texte linear both;
      animation-timeline: scroll(root);
      animation-range: 0 80vh;
    }
    /* Les photos de la galerie glissent dans leur cadre. La frise est celle
       du CADRE : en `overflow: hidden`, il est lui-même une zone de
       défilement, et `view()` sur la photo ne bougerait jamais. */
    .galerie .vignette { view-timeline: --cadre-photo; }
    .galerie .vignette img {
      scale: 1.14;
      animation: glisse-cadre linear both;
      animation-timeline: --cadre-photo;
    }
  }
}
@keyframes entrer-titre { from { opacity: 0; clip-path: inset(0 100% 0 0); translate: -0.6em 0; } to { opacity: 1; clip-path: inset(0 -10% -10% 0); translate: 0 0; } }
@keyframes entrer-coche { from { opacity: 0; translate: -18px 0; } to { opacity: 1; translate: 0 0; } }
@keyframes tracer { from { stroke-dashoffset: 30; } to { stroke-dashoffset: 0; } }
@keyframes monter { from { opacity: 0; translate: 0 36px; } to { opacity: 1; translate: 0 0; } }
@keyframes arrivee-photo { from { scale: 1.08; opacity: 0; } to { scale: 1; opacity: 1; } }
@keyframes parallaxe-photo { to { translate: 0 33vh; } }
@keyframes parallaxe-fond { to { translate: 0 48vh; } }
@keyframes parallaxe-texte { to { translate: 0 -8vh; opacity: 0.15; } }
@keyframes glisse-cadre { from { translate: 0 -6%; } to { translate: 0 6%; } }
