/* Revel — le mur, pas la salle.
   Voir DESIGN.md pour le systeme complet et ses raisons.

   Le principe : les affiches sont deja des objets graphiques travailles.
   Tout ce que l'interface ajoute — cadre, coin arrondi, degrade — leur
   enleve quelque chose. Le decor recule jusqu'a presque disparaitre, et la
   couleur de la page vient entierement des soirees.

   Ce qui a change le 4 septembre 2026, et pourquoi :

   LE FOND N'EST PLUS BLEU. Mesure sur les vraies affiches : un bleu-noir se
   bat avec les centaines de flyers roses et violets de la scene. Le fond est
   desormais un noir CHAUD — le platre Bauhaus de la Ville Blanche apres la
   tombee du jour.

   ET CHAQUE AFFICHE EST ECLAIREE. Sur fond sombre, une affiche a ciel noir se
   dissout : elle perd son contour et le mur devient une bouillie. Un filet de
   lumiere sur ses quatre cotes, plus marque en haut comme une cimaise, et une
   ombre portee dessous. C'est ce qu'un musee fait dans une salle sombre — il
   n'eclaire pas les murs, il eclaire les oeuvres. */

/* « hidden » DOIT CACHER, MEME QUAND UNE REGLE DONNE UN display.
   Le navigateur ne cache un element « hidden » qu'avec un display:none de
   priorite la plus basse : n'importe quelle regle de la feuille l'annule
   sans bruit. C'est arrive au bouton « voir tout », qui est en inline-flex :
   pose cache, il s'affichait quand meme, avec un compte vide. Il se trouve
   qu'aucun jour n'a assez peu de soirees pour que ça se voie aujourd'hui —
   c'etait un piege pose, pas encore un degat. */
[hidden] { display: none !important; }

:root {
  /* LA PALETTE, EN UN SEUL ENDROIT.
     Il y en avait deux : le platre chaud du premier systeme (#17140F sur
     #F2EDE3) puis, huit cents lignes plus bas, le neutre de la plateforme qui
     l'ecrasait entierement. Les deux blocs etaient des :root sans condition,
     donc le second gagnait toujours et le premier n'etait qu'un decor. Ce que
     la page rend vraiment est ici, et nulle part ailleurs. */
  --fond: #0a0a0c;
  --fond-creux: #131316;
  --fond-haut: #1c1c21;
  --encre: #f5f5f7;
  --encre-basse: #a1a1aa;
  /* Cette couleur porte le lieu sous CHAQUE tuile, le pied de page et tous
     les compteurs. A #6b6b75 elle donnait 3,75:1 sur le fond, sous le minimum
     de 4,5:1. Remontee a 5,3:1. */
  --encre-tres-basse: #8a8a94;
  /* Les heures d'avant la tombee de la nuit. */
  --encre-eteinte: #4A443A;

  /* 320 et 20 depuis le 10/09/2026 : la reference (rockstargames.com/VI) pose
     de grandes cartes tres arrondies, peu par rangee, avec de l'air. */
  --tuile-h: 320px;
  --rayon: 20px;
  /* LA TAILLE D'AFFICHAGE : les titres de nuit, centres, en capitales
     espacees. Elle suit la largeur de l'ecran comme le logotype, et comme
     lui elle est exemptee de l'echelle des six tailles (verifier-echelle). */
  --t-affiche: clamp(32px, 4.4vw, 56px);

  /* L'ACCENT N'EST PAS UNE COULEUR, C'EST LA LUMIERE.
     Le point du logotype est la seule chose allumee de la page ; le vermillon
     ne sert qu'aux etats — les heures d'apres minuit, une vente fermee, une
     alerte armee. Jamais en texte courant, jamais en decoration. */
  --signal: #FFE9BF;
  --signal-clair: #FFFDF6;
  --signal-sombre: #FFA848;
  --signal-rgb: 255, 233, 191;
  --signal-coeur: #FFFDF6;
  --vif: #E8391B;
  --vif-rgb: 232, 57, 27;

  /* L'ANNEAU DE FOCUS, DEFINI UNE FOIS.
     Mesure au clavier avant d'ecrire cette ligne : quatre anneaux differents
     coexistaient — l'ambre de la palette abandonnee sur la cloche, la langue,
     les onglets et les puces ; le blanc sur le hero et les fleches ; celui du
     navigateur sur les liens ; et RIEN du tout sur le selecteur de ville et le
     champ de recherche. Une correction precedente posait bien
     « :focus-visible { outline-color } », mais avec une specificite plus
     faible que les regles qu'elle pretendait remplacer : elle ne changeait que
     les liens. Un jeton evite que ca recommence. */
  /* L'ECHELLE DU TEXTE.
     Mesure avant de l'ecrire : vingt-six tailles distinctes dans la feuille,
     dont SEIZE sous 1 rem, et huit qui tenaient dans 3,2 px. Personne ne
     distingue 14,4 px de 14,08 px ; la page a juste l'air pas tout a fait
     resolue, et chaque nouvelle regle inventait sa propre valeur.
     Quatre pas pour l'interface. Les tailles d'affichage — le titre du hero,
     l'heure, les titres d'etagere — restent a part : elles sont peu
     nombreuses, chacune a sa raison, et elles varient deja avec la largeur. */

  --anneau: var(--encre);

  --trait: rgba(255, 255, 255, 0.08);
  --trait-net: rgba(255, 255, 255, 0.16);
  --attention: #e0a355;

  /* La marge de page SUIT la largeur de l'ecran : entre ses deux bornes elle
     passe par toutes les valeurs, et aucune grille ne peut l'y contraindre.
     Ce qu'on exige, ce sont ses BORNES — ce qu'on voit aux deux extremes. */
  --marge: clamp(16px, 4vw, 48px);

  /* L'ECHELLE. Il y avait 33 valeurs d'espacement sur la page — 6,4 px,
     11,2 px, 4,5 px, 5,4 px, 3,5 px, 54,4 px... des « rem » multiplies par
     des « clamp » qui retombent sur des fractions de pixel. Rien ne tombait
     jamais deux fois au meme endroit.
     Six valeurs, toutes multiples de 4. C'est invisible ligne a ligne, et
     c'est ce qui fait qu'une page parait calme sans qu'on sache dire
     pourquoi. outils/verifier-echelle.mjs refuse tout ce qui n'en est pas. */
  --e1: 4px;
  --e2: 8px;
  --e3: 16px;
  --e4: 24px;
  --e5: 48px;
  --e6: 64px;

  /* LA GAMME. Douze tailles de texte, dont 26, 34, 35 et 39 px utilisees UNE
     SEULE FOIS : des egarements, pas une gamme. Six suffisent. */
  --t-legende: 12px;
  --t-menu: 13px;
  --t-corps: 14px;
  --t-fort: 16px;
  --t-section: 24px;
  --t-titre: 32px;
  /* Une seule hauteur pour tout ce qui se clique dans la barre. Il y en
     avait quatre : 27, 31, 33 et 34 px. */
  --h-outil: 2.25rem;
  /* LE SITE PARLAIT AVEC LA VOIX DE ROBOTO.
     Heebo, qui portait tout le titrage, EST Roboto : mesure lettre par
     lettre, 68 % des 62 caracteres latins ont exactement la meme chasse que
     Roboto, et le reste tombe a 0,05 px pres — c'est le meme dessin, avec un
     hebreu greffe par Oded Ezer. Le titrage du site etait donc la police
     d'Android, celle que personne ne remarque. Temoin de la mesure :
     Assistant, 0 % de coincidence.
     Et la page n'avait qu'une voix : sur 1082 elements de texte, 997 en
     Assistant, 68 en Heebo, 2 en Instrument Serif.

     Le serif de journal (Frank Ruhl Libre) a tenu une matinee : Victor l'a
     trouve date, et il a donne deux references — supernaturalkitchen.com
     pour le logo (un mot ecrit a la main, d'un trait) et rockstargames.com/VI
     pour le reste (fond nuit, titres en capitales geometriques espacees).
     Les deux ensemble, c'est l'Art deco de Miami : une signature, et des
     capitales. Deux faces, toutes deux avec un hebreu DESSINE, pas rapporte :
     — Rubik pour le titrage : geometrique, hebreu et latin du meme dessin,
       en capitales espacees (voir .mosaique__titre).
     — IBM Plex Sans Hebrew pour le texte : une grotesque qui a un dessin,
       la ou Assistant n'avait qu'une bonne conduite. */
  --police: 'IBM Plex Sans Hebrew', -apple-system, 'Segoe UI', system-ui, sans-serif;
  --enseigne: 'Rubik', 'IBM Plex Sans Hebrew', sans-serif;
  /* LE LOGOTYPE N'EST PLUS L'ENSEIGNE, ET C'EST LE POINT DE TOUTE LA DA.
     Releve sur les six concurrents : Eventer, go-out et dice sont en
     grotesque geometrique gras ; Zygo est en capitales grasses larges —
     c'est-a-dire exactement ce qu'Afters faisait en Heebo 900. AUCUN des
     six n'a d'empattements. C'est l'ecart le plus net disponible, et il
     ne coute qu'une graisse : Instrument Serif n'a que du 400. */
  --logotype: 'Instrument Serif', 'Frank Ruhl Libre', serif;

  --pose: cubic-bezier(0, 0, 0.2, 1);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--fond);
  /* Le grain du platre. Tres faible, uniquement sur le fond : sans lui le mur
     est un vide, avec lui c'est une matiere. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.04'/%3E%3C/svg%3E");
  color: var(--encre);
  font-family: var(--police);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Le texte vient des billetteries : hebreu dans une page anglaise, latin dans
   une page hebreu. unicode-bidi: plaintext donne a chaque ligne son propre
   sens de lecture, ce qui la rend correcte quelle que soit la langue de la
   page.
   Mais l'alignement doit etre celui de la PAGE, pas celui du texte. D'ou un
   cote absolu (left/right) et non "start" : avec plaintext, "start" se
   recalcule lui aussi sur le sens detecte, et le lieu en hebreu repartait se
   coller a l'oppose du titre en latin, dans la meme vignette. */
.bidi { unicode-bidi: plaintext; }
:root[dir='ltr'] .bidi { text-align: left; }
:root[dir='rtl'] .bidi { text-align: right; }

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

/* ---------- en-tete ---------- */

.tete {
  position: sticky; top: 0; z-index: 20;
  padding: clamp(16px, 2vw, 24px) var(--marge) 0;
  background:
    color-mix(in srgb, var(--fond) 86%, transparent);
  backdrop-filter: saturate(170%) blur(20px);
  -webkit-backdrop-filter: saturate(170%) blur(20px);
  border-bottom: 1px solid var(--trait);
}

.tete__rang {
  display: flex; align-items: center;
  gap: clamp(16px, 2.6vw, 32px);
}
/* LE VIDE AU MILIEU, PAS AU BOUT.
   Les commandes se suivaient a partir du nom et s'arretaient a 834 px d'un
   ecran de 1280 : 395 px de vide colles au bord droit, ce qui donnait a la
   barre son air de travail inacheve. Les outils forment un bloc qui tient ce
   bord, et le vide tombe entre les sections et lui. */
.tete__outils {
  display: flex; align-items: center; flex: none;
  gap: clamp(4px, 1vw, 8px);
  margin-inline-start: auto;
}

/* Le logotype est une enseigne au neon, en latin dans les deux langues : la
   scene ecrit ses noms ainsi — MAINSTREAM, JIMMYwHO, GOAT, SHALVATA. Il garde
   son propre sens de lecture, sans quoi le point passerait a gauche du mot en
   page hebreu.

   Un vrai tube n'est pas rose : il est presque blanc, et c'est le halo qui
   est rose. D'ou six couches d'ombre, du coeur net a la floraison large, et un
   lavis du meme rose sur le mur derriere (dans .tete). */
/* LE LOGOTYPE : LE MOT EST LE MUR, LE POINT EST LA LUMIERE.
   L'enseigne au neon disait la salle ; nous ne sommes pas la salle. Le mot se
   tait — encre sur platre, comme peint dessus — et le point est la seule
   chose allumee de toute la page. */
/* LA TAILLE VIT SUR LE CONTENEUR, PAS SUR LE MOT.
   Le point est le FRERE du h1, pas son enfant : son « em » venait donc de
   .marque, restee a 16 px, et il faisait 3 px a cote d'un logotype de 34.
   Les deux partagent desormais la meme taille, donc le point grandit avec
   le mot, comme il l'a toujours fait quand le mot etait du texte. */
.marque {
  /* Le mot est une image : elle n'a pas de ligne de base, on centre. */
  display: inline-flex; align-items: center; gap: var(--e1);
  direction: ltr;
  /* L'empattement porte moins de matiere par « em » qu'une grotesque noire :
     a taille egale il paraissait plus petit que la geometrique noire qu'il
     remplaçait. Mesure sur la planche : il lui faut environ 17 % de plus. */
  font-size: clamp(1.82rem, 4.6vw, 2.45rem); line-height: 1;
  text-decoration: none; color: inherit;
}
/* LE LOGOTYPE EST DU TEXTE, ET C'EST CE QUE DESIGN.md A TOUJOURS DIT.
   Il a ete un trace du mot « Revel » pendant un temps ; le nom a change et le
   dessin est parti avec. Ecrit en Instrument Serif vivant, il change de mot
   sans qu'on redessine quoi que ce soit, et reste net a toute taille. */
.marque__mot {
  font-size: inherit; line-height: 1;
  font-family: var(--logotype); font-weight: 400; letter-spacing: -0.005em;
  color: var(--encre);
  display: flex; align-items: center;
  margin: 0;
}
/* LE DESSIN DU MOT. Le trait blanc est dans l'image ; sa hauteur suit le corps
   de .marque, donc la meme echelle qu'avant a toutes les largeurs. Le script a
   une grande capitale et un « f » qui descend : a 1,3em, la panse des lettres
   fait a peu pres la hauteur des anciennes minuscules. */
.marque__image { height: 1.3em; width: auto; display: block; }
.pied__image { height: 1.6rem; width: auto; display: block; opacity: 0.8; }
/* LE POINT SE POSE SUR LA LIGNE DE BASE DES LETTRES, PAS SOUS LE V.
   Un SVG n'a pas de ligne de base typographique : le navigateur aligne sur le
   BAS de sa boite, c'est-a-dire la pointe du cone. Le point flottait donc six
   pixels trop bas.
   Et une marge basse n'y change RIEN — mesure : 0, 0,216em et 0,4em donnent
   tous les trois le meme ecart. L'alignement sur la ligne de base ignore la
   marge de fin. Il faut partir du HAUT.
   Mesure dans le trace : le pied du « l » est a 78,4 % de la boite. Le point
   fait 0,21em, donc son haut se pose a 0,784 - 0,21 = 0,574em. */

/* Le point bat, une fois toutes les 4,2 secondes. Le nom pris au mot, une
   seule fois : ce n'est pas une animation decorative, c'est le mot rendu
   litteral. Un coeur blanc et un halo chaud qui deborde largement — sans le
   debordement il se lirait comme une ponctuation, pas comme une source. */
.marque__point {
  width: 0.21em; height: 0.21em; border-radius: 50%; flex: none;
  /* Le mot etant redevenu du TEXTE, le point retrouve une vraie ligne de
     base a laquelle s'aligner. Tout le calcul qui vivait ici — « le pied du
     l est a 78,4 % de la boite, donc le haut du point se pose a 0,574em » —
     compensait l'absence de ligne de base d'un SVG. Il n'a plus lieu d'etre. */
  /* Le mot est une image sans ligne de base : le point se cale sur le bas de
     la panse des lettres, mesure dans le dessin (le trait du « z » finit a
     environ 30 % du bas de l'image). */
  align-self: flex-end; margin-bottom: 0.36em;
  background: radial-gradient(circle at 50% 45%, #FFFDF6 0%, #FFE9BF 55%, #FFC876 100%);
  box-shadow:
    0 0 3px var(--signal-clair), 0 0 10px rgba(255, 233, 182, 0.95),
    0 0 26px rgba(255, 196, 110, 0.7), 0 0 54px rgba(255, 168, 72, 0.35);
  animation: battre 4.2s ease-in-out infinite;
}
@keyframes battre {
  0%, 86%, 100% { opacity: 1; transform: scale(1) }
  90% { opacity: 0.72; transform: scale(0.86) }
  94% { opacity: 1; transform: scale(1.06) }
}
}

/* La ville est un choix unique parmi beaucoup : c'est ce que fait un menu
   deroulant, la ou une rangee de puces demanderait trois lignes. Il vit dans
   la rangee du haut pour ne pas ajouter une troisieme rangee de commandes. */
.ou {
  position: relative; flex: none;
  display: inline-flex; align-items: center;
}
.ou select {
  appearance: none; cursor: pointer;
  padding: 8px 2rem 8px 12px;
  font: inherit; font-size: var(--t-corps); font-weight: 500; color: var(--encre);
  background: var(--fond-creux);
  border: 1px solid var(--trait); border-radius: 8px;
  max-width: 11rem; text-overflow: ellipsis;
  transition: border-color 160ms var(--pose), background-color 160ms var(--pose);
}
:root[dir='rtl'] .ou select { padding: 8px 12px 8px 2rem; }
.ou select:hover { border-color: var(--trait-net); }
.ou select:focus-visible { outline: 2px solid var(--anneau); outline-offset: 2px; }
.ou select option { background: var(--fond-haut); color: var(--encre); }
/* Le chevron n'avait AUCUNE position verticale : il se collait donc en haut de
   son conteneur, hors de la pilule qu'il est cense annoter. */
.ou__fleche {
  position: absolute; inset-inline-end: 0.75rem;
  inset-block-start: 50%; translate: 0 -50%;
  width: 9px; height: 6px; pointer-events: none;
  color: var(--encre-tres-basse);
}

.chercher { flex: none; position: relative; }
.chercher input {
  width: 100%; padding: 8px 16px;
  font: inherit; font-size: var(--t-corps); font-weight: 400; color: var(--encre);
  background: var(--fond-creux);
  border: 1px solid var(--trait); border-radius: 8px;
  transition: border-color 180ms var(--pose), background-color 180ms var(--pose);
}
.chercher input::placeholder { color: var(--encre-tres-basse); }
.chercher input:focus {
  /* Pas d'« outline: none » ici : la regle porte sur :focus, plus specifique
     que l'anneau de base sur :focus-visible, et elle effacait donc l'anneau du
     champ de recherche. Son remplacant — une bordure et un fond — a lui-meme
     ete efface plus bas par la barre vitree, qui met « border: 0 ». */
  border-color: var(--trait-net);
  background: var(--fond-haut);
}
.chercher input::-webkit-search-cancel-button { filter: invert(1) opacity(0.35); }

/* La cloche vit a cote du selecteur de langue : ce sont les deux reglages de
   la personne, pas du contenu. Allumee, elle prend la couleur du signal. */
.cloche {
  flex: none; appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.1rem; height: 2.1rem; padding: 0; border-radius: 8px;
  color: var(--encre-basse);
  background: transparent; border: 1px solid var(--trait);
  transition: color 160ms var(--pose), border-color 160ms var(--pose);
}
.cloche:hover { color: var(--encre); border-color: var(--trait-net); }
.cloche:focus-visible { outline: 2px solid var(--anneau); outline-offset: 2px; }

.langue {
  flex: none; appearance: none; cursor: pointer;
  padding: 8px 12px; border-radius: 8px;
  font: inherit; font-size: var(--t-menu); font-weight: 600; letter-spacing: 0.04em;
  color: var(--encre-basse);
  background: transparent; border: 1px solid var(--trait);
  transition: color 160ms var(--pose), border-color 160ms var(--pose);
}
.langue:hover { color: var(--encre); border-color: var(--trait-net); }
.langue:focus-visible { outline: 2px solid var(--anneau); outline-offset: 2px; }

/* ---------- les deux sections, puis le tri fin ---------- */

.onglets { display: flex; gap: clamp(16px, 2.5vw, 24px); flex: none; }
.onglet {
  appearance: none; background: none; border: 0;
  padding: 0 0 0.75rem; cursor: pointer;
  font: inherit; font-weight: 600;
  font-size: clamp(1rem, 2.6vw, 1.16rem);
  letter-spacing: -0.01em;
  color: var(--encre-tres-basse);
  position: relative;
  transition: color 170ms var(--pose);
}
.onglet::after {
  content: ''; position: absolute; inset-inline: 0; bottom: -1px; height: 2px;
  background: var(--signal); border-radius: 2px;
  transform: scaleX(0); transition: transform 230ms var(--pose);
  box-shadow: 0 0 10px rgba(var(--signal-rgb), 0.7);
}
.onglet[aria-pressed='true'] { color: var(--encre); }
.onglet[aria-pressed='true']::after { transform: scaleX(1); }
.onglet:hover { color: var(--encre-basse); }
.onglet[aria-pressed='true']:hover { color: var(--encre); }
.onglet:focus-visible { outline: 2px solid var(--anneau); outline-offset: 3px; border-radius: 3px; }

/* Le tri fin suit la section, separe par un simple trait vertical. Ce n'est
   pas une commande a part : c'est un cran de plus dans le meme geste. */
.filtres {
  display: flex; gap: 8px; flex-wrap: wrap;
  align-items: center;
}
/* Le trait ne separe la section du tri fin que s'ils sont sur la meme ligne.
   Quand les filtres passent a la ligne, il devient un trait perdu au bord. */
.filtres::before {
  content: ''; width: 1px; align-self: stretch;
  background: var(--trait); margin-inline-end: 4px;
}
@media (max-width: 46rem) {
  .filtres::before { display: none; }
}
.filtres:empty { display: none; }

.puce {
  appearance: none; cursor: pointer;
  display: inline-flex; align-items: baseline; gap: 8px;
  padding: 4px 12px; border-radius: 7px;
  font: inherit; font-size: var(--t-menu); font-weight: 500;
  color: var(--encre-basse);
  background: transparent; border: 1px solid transparent;
  transition: color 160ms var(--pose), background-color 160ms var(--pose);
}
.puce:hover { color: var(--encre); background: var(--fond-creux); }
.puce[aria-pressed='true'] { color: var(--fond); background: var(--encre); }
.puce:focus-visible { outline: 2px solid var(--anneau); outline-offset: 2px; }
/* Le nombre dit ce qu'il y a derriere le filtre. Un filtre dont on ne sait
   pas s'il donnera trois resultats ou cinquante ne sert a rien. */
.puce__n {
  font-size: var(--t-legende); font-weight: 400; font-variant-numeric: tabular-nums;
  color: var(--encre-tres-basse);
}
.puce[aria-pressed='true'] .puce__n { color: color-mix(in srgb, var(--fond) 55%, transparent); }

/* ---------- la liste ---------- */

.liste { padding: 0 var(--marge) 64px; }
.etat { padding: 64px 0 1rem; text-align: center; color: var(--encre-tres-basse); font-size: var(--t-fort); }

.ailleurs {
  display: block; margin: 0 auto 64px; cursor: pointer;
  appearance: none; background: none;
  padding: 8px 4px;
  font: inherit; font-size: var(--t-fort); font-weight: 500;
  color: var(--signal); border: 0;
  border-bottom: 1px solid color-mix(in srgb, var(--signal) 40%, transparent);
  transition: color 160ms var(--pose), border-color 160ms var(--pose);
}
.ailleurs:hover { color: #fff; border-color: #fff; }
.ailleurs:focus-visible { outline: 2px solid var(--anneau); outline-offset: 3px; }

/* ---------- une soiree ---------- */

.soiree { display: block; text-decoration: none; color: inherit; transition: transform 140ms var(--pose); }
.soiree:active { transform: scale(0.978); }
.soiree:focus-visible { outline: 2px solid var(--anneau); outline-offset: 6px; border-radius: 8px; }

/* LES TROIS FORMATS DU FLYER ISRAELIEN.
   Sur 338 affiches mesurees : 46% en story (mediane 0.687), 34% en carre
   (1.000), 20% en banniere (1.783). Soit 2/3, 1/1 et 16/9 a la virgule pres —
   les trois formats d'export d'Instagram et de Facebook.
   On imposait 4/5 a tout le monde : une sur trois y tenait, les autres
   flottaient au milieu de bandes qu'il fallait remplir d'un flou. En donnant
   a chacune le cadre de sa famille, la part rognee tombe de 25% a 7%, et il
   n'y a plus rien a remplir. Le flou a disparu avec le probleme. */
/* CHAQUE AFFICHE EST ECLAIREE.
   Mesure sur les vraies affiches : sur un fond sombre, une affiche a ciel noir
   se dissout — elle perd son contour et le mur devient une bouillie — pendant
   qu une affiche claire eblouit.
   Un filet de lumiere sur ses quatre cotes, plus marque en haut comme une
   cimaise, et une ombre portee dessous. Ce n est pas une bordure de carte :
   c est la lumiere qui tombe sur une chose accrochee. Un musee ne peint pas
   ses murs en noir, il eclaire les oeuvres. */
.affiche {
  position: relative;
  width: 100%;
  aspect-ratio: var(--r, 1);
  overflow: hidden;
  background: var(--fond-creux);
  isolation: isolate;
  box-shadow: 0 16px 34px -12px rgba(0, 0, 0, 0.8), 0 2px 6px rgba(0, 0, 0, 0.55);
  transition: transform 160ms var(--pose), box-shadow 160ms var(--pose);
}
.affiche::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 2;
  box-shadow:
    inset 0 0 0 1px rgba(255, 244, 224, calc(0.13 * var(--lumiere, 1))),
    inset 0 1px 0 rgba(255, 244, 224, calc(0.40 * var(--lumiere, 1))),
    inset 0 -1px 0 rgba(0, 0, 0, 0.45);
}

.affiche__image {
  position: absolute; inset: 0; width: 100%; height: 100%;
  /* Le cadre a la forme exacte de l'affiche, donc il n'y a rien a rogner.
     « contain » est le filet : si la mesure a manque, on prefere une fine
     bande a une coupe. */
  object-fit: contain;
  /* L'image s'eteint bien moins que son cadre : a la quatrieme nuit elle
     garde 88 % de sa lumiere, la ou le cadre n'en garde que 76. */
  filter: brightness(calc(0.5 + 0.5 * var(--lumiere, 1)));
  opacity: 0; transition: opacity 380ms var(--pose);
}
.affiche.est-la .affiche__image { opacity: 1; }

/* Sans affiche, pas de rectangle vide : le titre devient le visuel. */
.affiche--sans {
  display: grid; place-items: center; padding: 1rem;
  width: 100%; aspect-ratio: 1 / 1;
  background: var(--fond-creux);
}
.affiche--sans span {
  font-size: var(--t-fort); font-weight: 500; line-height: 1.35;
  text-align: center; color: var(--encre-basse);
  display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical; overflow: hidden;
}

.soiree__texte { padding-top: 8px; }
.soiree__heure {
  font-size: var(--t-corps); font-weight: 600; font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em; color: var(--encre-basse);
}
.soiree--imminente .soiree__heure { color: var(--signal); }
/* Le titre occupe toujours deux lignes, meme quand il en tient une seule :
   sans ca, le lieu remonte sous les titres courts et descend sous les longs,
   et la rangee perd son alignement. C'est le prix d'une page rangee. */
.soiree__titre {
  margin: 4px 0 0; font-size: var(--t-corps); font-weight: 500; line-height: 1.34;
  letter-spacing: -0.005em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  min-height: calc(2 * 1.34em);
}
/* Une soiree dont la vente est fermee reste, mais s'efface un peu : on la
   voit, on comprend qu'on ne l'achete plus. */
.soiree--fermee .affiche { filter: saturate(0.55) brightness(0.8); }
.soiree--fermee .soiree__heure { color: var(--encre-tres-basse); text-shadow: none; }

.soiree__lieu {
  margin: 4px 0 0; font-size: var(--t-menu); font-weight: 300; color: var(--encre-tres-basse);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

@media (hover: hover) {
  .soiree:hover .soiree__titre { color: #fff; }
  .soiree:hover .affiche {
    transform: translateY(-2px);
    box-shadow: 0 22px 40px -12px rgba(0, 0, 0, 0.85), 0 3px 8px rgba(0, 0, 0, 0.6);
  }
  .soiree:hover .affiche::after {
    box-shadow:
      inset 0 0 0 1px rgba(255, 244, 224, 0.22),
      inset 0 1px 0 rgba(255, 244, 224, 0.62),
      inset 0 -1px 0 rgba(0, 0, 0, 0.45);
  }
  .affiche__image { transition: opacity 380ms var(--pose), transform 360ms var(--pose); }
}

/* ---------- le panneau des alertes ---------- */

/* LE PANNEAU PARLE LA LANGUE DE LA PAGE (10/09/2026). Il etait reste dans
   l'ancien monde : titre en gras a 19,5 px — hors echelle, invisible aux
   controles parce qu'un dialogue ferme ne se mesure pas —, coins a 14 px,
   boutons carres. Il prend les coins des cartes, un titre en capitales
   espacees, des pastilles, et un halo de la couleur de la nuit en haut. */
.panneau {
  width: min(30rem, calc(100vw - 2rem));
  padding: clamp(24px, 3vw, 2rem);
  border: 1px solid var(--trait-net); border-radius: var(--rayon);
  background: var(--fond-haut); color: var(--encre);
  font-family: var(--police);
  position: relative; overflow: hidden; isolation: isolate;
}
.panneau::before {
  content: ''; position: absolute; inset: -30% -20% auto; height: 70%; z-index: -1;
  pointer-events: none; filter: blur(32px);
  background: radial-gradient(60% 60% at 50% 0%, color-mix(in srgb, var(--nuit, transparent) 55%, transparent), transparent 70%);
}
.panneau::backdrop { background: rgba(10, 9, 7, 0.74); backdrop-filter: blur(4px); }

/* Un panneau entre doucement et sort vite : l'oeil suit l'arrivee, il n'a pas
   besoin d'accompagner le depart. 240 ms qui decelerent a l'ouverture, 150 ms
   qui accelerent a la fermeture. Seuls l'opacite et la transformation
   bougent — le reste ferait travailler la mise en page. */
@media (prefers-reduced-motion: no-preference) {
  .panneau[open] { animation: panneauEntre 240ms cubic-bezier(0, 0, 0.2, 1); }
  .panneau[open]::backdrop { animation: voileEntre 240ms linear; }
}
@keyframes panneauEntre {
  from { opacity: 0; transform: translateY(10px) scale(0.985) }
  to { opacity: 1; transform: none }
}
@keyframes voileEntre { from { opacity: 0 } to { opacity: 1 } }
.panneau h2 {
  margin: 0 0 8px; font-family: var(--enseigne); font-weight: 500;
  font-size: var(--t-section); line-height: 1;
  text-transform: uppercase; letter-spacing: 0.2em;
}
.panneau__quoi {
  margin: 0 0 24px; font-size: var(--t-corps); font-weight: 300; line-height: 1.5;
  color: var(--encre-basse);
}
.panneau__sous-titre {
  margin: 0 0 8px; font-size: var(--t-legende); font-weight: 600;
  letter-spacing: 0.32em; text-transform: uppercase; color: var(--encre-tres-basse);
}
.panneau__choix { display: flex; flex-wrap: wrap; gap: 8px 16px; margin-bottom: 16px; }
.panneau__sous-titre { flex-basis: 100%; }

.case {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: var(--t-corps); cursor: pointer; color: var(--encre-basse);
  transition: color 150ms var(--pose);
}
.case:hover { color: var(--encre); }
.case input {
  appearance: none; cursor: pointer; flex: none;
  width: 1.05rem; height: 1.05rem; border-radius: 5px;
  border: 1px solid var(--trait-net); background: var(--fond-creux);
  transition: background-color 150ms var(--pose), border-color 150ms var(--pose);
}
.case input { position: relative; }
.case input:checked { background: var(--signal); border-color: var(--signal); }
/* La coche est un trait plie, dessine par une bordure : rien a charger, et
   elle prend la couleur du fond quel que soit le theme. Deux degrades croises
   donnaient une croix, pas une coche. */
.case input:checked::after {
  content: '';
  position: absolute; left: 50%; top: 46%;
  width: 0.26rem; height: 0.52rem;
  border: solid var(--fond);
  border-width: 0 2px 2px 0;
  transform: translate(-50%, -50%) rotate(42deg);
}
.case input:focus-visible { outline: 2px solid var(--anneau); outline-offset: 2px; }

.panneau__note {
  margin: 0 0 16px; font-size: var(--t-corps); font-weight: 300; line-height: 1.45;
  color: var(--encre-tres-basse);
}
.panneau__note:empty { display: none; }

.panneau__actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
/* Deux pastilles : la pleine pour l'action, la bordee pour renoncer. Le meme
   dessin que « voir tout » sous un titre de nuit. */
.panneau__oui {
  appearance: none; cursor: pointer; border: 1px solid var(--encre);
  padding: 8px 24px; border-radius: 999px;
  font: inherit; font-size: var(--t-legende); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.16em;
  color: var(--fond); background: var(--encre);
  transition: opacity 150ms var(--pose);
}
.panneau__oui:hover { opacity: 0.85; }
.panneau__oui:disabled { opacity: 0.45; cursor: default; }
.panneau__non {
  appearance: none; cursor: pointer; border: 1px solid var(--trait-net); background: none;
  padding: 8px 24px; border-radius: 999px;
  font: inherit; font-size: var(--t-legende); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.16em;
  color: var(--encre-basse);
  transition: color 150ms var(--pose), border-color 150ms var(--pose);
}
.panneau__non:hover { color: var(--encre); border-color: var(--encre-basse); }
.panneau__oui:focus-visible, .panneau__non:focus-visible { outline: 2px solid var(--anneau); outline-offset: 3px; }

.panneau__fermer { position: absolute; inset-inline-end: 0.7rem; inset-block-start: 0.6rem; }
.panneau__fermer button {
  appearance: none; cursor: pointer; border: 0; background: none;
  font: inherit; font-size: 1.5rem; line-height: 1; padding: 4px 8px;
  color: var(--encre-tres-basse);
  transition: color 150ms var(--pose);
}
.panneau__fermer button:hover { color: var(--encre); }

/* ---------- pied ---------- */

.pied {
  padding: 32px var(--marge) 48px;
  border-top: 1px solid var(--trait);
  color: var(--encre-tres-basse); font-size: var(--t-menu); font-weight: 300;
}
.pied p { margin: 0 0 4px; max-width: 46ch; }
.pied__quand { font-variant-numeric: tabular-nums; }

/* LE HAUT DU PIED : LE NOM, PUIS CE QU'ON PEUT ALLER LIRE.
   Il n'y avait aucun lien du tout — ni ce que le site fait de vos donnees, ni
   ce qu'il fait pour l'accessibilite, ni a qui appartiennent les affiches.
   Et surtout PAS de « tous droits reserves » : les affiches et les titres
   appartiennent aux salles, aux organisateurs et aux billetteries. Le
   revendiquer serait une affirmation fausse, ecrite en petits caracteres. */
.pied__haut {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 16px clamp(16px, 4vw, 48px);
  margin-bottom: 24px; padding-bottom: 1.5rem;
  border-bottom: 1px solid var(--trait);
}
.pied__marque {
  display: block; color: var(--encre); font-size: 1.62rem; line-height: 1;
  font-family: var(--logotype); font-weight: 400; letter-spacing: -0.005em;
  text-decoration: none; direction: ltr;
}
.pied__liens { display: flex; flex-wrap: wrap; gap: 0.5rem clamp(1rem, 3vw, 32px); }
.pied__liens a {
  color: var(--encre-basse); text-decoration: none;
  font-size: var(--t-corps); font-weight: 600;
  border-bottom: 1px solid transparent;
  transition: color 160ms var(--pose), border-color 160ms var(--pose);
}
.pied__liens a:hover { color: var(--encre); border-bottom-color: var(--trait-net); }
.pied__liens a:focus-visible { outline: 2px solid var(--anneau); outline-offset: 3px; border-radius: 3px; }

/* D'ou viennent les soirees. C'est la seule chose qu'un visiteur ne peut pas
   deviner en regardant la page, et c'est ce qui fait la valeur du site : dix
   billetteries lues, une seule page a ouvrir. */

.pied__sources {
  max-width: 62ch;
  margin-block: 12px 8px;
  color: var(--encre-basse);
  line-height: 1.6;
}

/* ---------- entree ---------- */

/* LES AFFICHES MONTENT EN ARRIVANT — decision de Victor, 07/09/2026.
   La regle precedente disait l'inverse : « le mur est deja la, il ne se
   construit pas », et les affiches se contentaient d'un fondu. DESIGN.md a
   ete corrige avec la date et la raison, pour que la regle et le code ne
   disent pas deux choses differentes.
   Douze pixels, pas plus : au-dela ce n'est plus une arrivee, c'est un
   defilement. Le decalage entre voisines etait deja la — 18 ms, plafonne a
   320 — pour que cent images qui arrivent ensemble ne fassent pas un a-coup.
   Le « translate » vit A L'INTERIEUR du bloc « no-preference » : declare
   dehors, il aurait laisse chaque affiche decalee de 12 px pour toujours
   chez les personnes en mouvement reduit, dont l'animation ne touche que
   l'opacite. */
.entre { opacity: 0; }
@media (prefers-reduced-motion: no-preference) {
  .entre { translate: 0 12px; animation: monter 320ms var(--pose) forwards; animation-delay: var(--retard, 0ms); }
}
@keyframes monter { to { opacity: 1; translate: 0 0 } }

/* Le plancher : on remplace le deplacement par un fondu, jamais par rien. */
@media (prefers-reduced-motion: reduce) {
  .entre { animation: apparaitre 190ms linear forwards; animation-delay: var(--retard, 0ms); }
  .soiree, .affiche, .affiche__image { transition: none; }
  .marque__point, .os { animation: none; }
  .soiree:active { transform: none; }
}
@keyframes apparaitre { to { opacity: 1 } }

/* ---------- suivre ---------- */

/* LE BOUTON SUR L'AFFICHE.
   Le nom est deja sous les yeux — la salle, l'artiste, le collectif. Le
   bouton se pose donc la, plutot que de renvoyer chercher ce meme nom dans
   une liste de 268 entrees.
   Il reste discret tant qu'on ne suit rien : c'est une action offerte, pas
   une action demandee. Une fois qu'on suit, il s'allume et ne s'eteint plus,
   parce que c'est devenu une information. */
.soiree { position: relative; }
.suivre {
  position: absolute; inset-inline-end: 0.42rem; inset-block-start: 0.42rem;
  width: 1.85rem; height: 1.85rem; display: grid; place-items: center;
  border: 0; border-radius: 50%; cursor: pointer; padding: 0;
  color: #fff;
  background: rgba(7, 6, 26, 0.55);
  backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px);
  opacity: 0; transform: scale(0.9);
  transition: opacity 160ms var(--pose), transform 160ms var(--pose),
              background-color 160ms var(--pose), color 160ms var(--pose);
}
/* LE SURVOL PORTE SUR LA TUILE, PLUS SUR LE LIEN.
   Sortir le bouton du lien — pour qu'il ne soit plus un bouton dans un lien —
   l'a sorti de « .soiree » sans que cette regle suive. Mesure : opacite 0 sur
   toutes les vignettes d'un ecran de bureau, et la seule facon de le voir
   etait de tabuler jusqu'a lui. Le seul geste mesurable du produit etait
   invisible a la souris. */
.tuile:hover .suivre, .suivre:focus-visible { opacity: 1; transform: scale(1); }
.suivre:focus-visible { outline: 2px solid var(--anneau); outline-offset: 2px; }
.suivre.est-suivi {
  opacity: 1; transform: scale(1);
  color: var(--fond); background: var(--signal);
  box-shadow: 0 0 14px rgba(var(--signal-rgb), 0.7);
}
/* Sur un ecran tactile il n'y a pas de survol : le bouton doit etre la. */
@media (hover: none) {
  .suivre { opacity: 1; transform: scale(1); }
}

/* Le petit menu, quand une soiree nomme plusieurs choses a suivre. */
.choix-suivre {
  position: absolute; inset-inline-end: 0.42rem; inset-block-start: 2.5rem;
  z-index: 5; min-width: 11rem; max-width: 16rem;
  display: flex; flex-direction: column;
  border-radius: 12px; overflow: hidden;
  background: var(--fond-creux); border: 1px solid var(--trait-net);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.55);
}
.choix-suivre__ligne {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  padding: 8px 12px; border: 0; background: none; cursor: pointer;
  text-align: start; color: var(--encre); font: inherit; font-size: var(--t-corps);
}
.choix-suivre__ligne + .choix-suivre__ligne { border-block-start: 1px solid var(--trait); }
.choix-suivre__ligne:hover { background: rgba(var(--signal-rgb), 0.12); }
.choix-suivre__ligne.est-suivi { color: var(--signal); }
.choix-suivre__famille { font-size: var(--t-legende); color: var(--encre-tres-basse); flex: none; }

/* LE CHAMP DE RECHERCHE, dans la cloche.
   Pour les noms qui ne sont pas a l'ecran ce soir-la. On cherche dans les
   deux langues a la fois : quelqu'un qui lit l'anglais tape parfois un nom
   hebreu, et l'inverse est constant. */
.panneau__recherche {
  flex-basis: 100%; width: 100%; margin-block-start: 4px;
  padding: 8px 16px; font: inherit; font-size: var(--t-corps);
  color: var(--encre); background: var(--fond-creux);
  border: 1px solid var(--trait-net); border-radius: 999px;
  unicode-bidi: plaintext;
}
.panneau__recherche::placeholder { color: var(--encre-tres-basse); }
.panneau__recherche:focus-visible { outline: 2px solid var(--anneau); outline-offset: 1px; }

.suivis { flex-basis: 100%; display: flex; flex-wrap: wrap; gap: 8px; }
.pastille {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 8px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: var(--t-corps);
  color: var(--signal-clair);
  background: rgba(var(--signal-rgb), 0.16);
  border: 1px solid rgba(var(--signal-rgb), 0.4);
  unicode-bidi: plaintext;
}
.pastille:hover { background: rgba(var(--signal-rgb), 0.26); }
.pastille__x { opacity: 0.65; font-size: var(--t-fort); line-height: 1; }

.resultats {
  flex-basis: 100%; display: flex; flex-direction: column;
  max-height: 15rem; overflow-y: auto;
  border-radius: 12px; border: 1px solid var(--trait);
}
.resultats:empty { display: none; }
.resultats__rien { padding: 12px 12px; font-size: var(--t-corps); color: var(--encre-tres-basse); }
.ligne {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 0.5rem 0.75rem; border: 0; background: none; cursor: pointer;
  text-align: start; color: var(--encre); font: inherit; font-size: var(--t-corps);
  unicode-bidi: plaintext;
}
.ligne + .ligne { border-block-start: 1px solid var(--trait); }
.ligne:hover { background: rgba(var(--signal-rgb), 0.12); }
.ligne__famille { font-size: var(--t-legende); color: var(--encre-tres-basse); flex: none; }

@media (prefers-reduced-motion: reduce) {
  .suivre { transition: none; }
}

/* ---------- l'attente ---------- */
/* Le message d'erreur et son bouton forment un bloc : sans ca le bouton
   heritait de la marge des liens "ailleurs", six rem plus bas. */
.etat__mot { margin: 0 0 16px; }
.etat .ailleurs { margin-bottom: 0; }

/* ---------- le decor entre dans le langage du mur ---------- */

/* Les commandes etaient des boites arrondies posees sur un fond bleu : le
   gabarit de tous les concurrents. Sur un mur de platre elles deviennent des
   choses ecrites dessus — un filet sous le champ, rien autour. Le decor
   recule ; les affiches sont les seules a parler. */
.tete {
  border-bottom: 1px solid var(--trait);
  background: color-mix(in srgb, var(--fond) 88%, transparent);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
}

.ou select,
.chercher input {
  border: 0; border-radius: 0;
  border-bottom: 1px solid var(--trait);
  background: transparent;
  padding-inline: 0px; padding-block: 0.5rem;
  color: var(--encre);
  transition: border-color 180ms var(--pose);
}
.ou select { padding-inline-end: 1.5rem; max-width: 12rem; }
:root[dir='rtl'] .ou select { padding-inline: 1.5rem 0px; }
.ou select:hover, .chercher input:hover,
.ou select:focus-visible, .chercher input:focus-visible {
  border-bottom-color: var(--encre-basse);
}
.ou select option { background: var(--fond-haut); color: var(--encre); }
/* La fleche est absolue : sans contexte de positionnement sur son parent elle
   part se coller dans le coin de l'ecran, a cote du bouton de langue. */
.ou { position: relative; }
.ou__fleche { inset-inline-end: 0.25rem; }

.cloche, .langue {
  border: 0; border-radius: 0;
  background: transparent;
  color: var(--encre-tres-basse);
  padding: 8px 4px;
  transition: color 160ms var(--pose);
}
.cloche:hover, .langue:hover { color: var(--encre); background: transparent; }

/* Les onglets : la section active se signale par un filet, pas par un halo.
   La seule lumiere de la page reste le point du logotype. */
.onglet {
  font-family: var(--enseigne);
  font-weight: 700;
  font-size: clamp(1.1rem, 2.8vw, 1.32rem);
  letter-spacing: -0.005em;
}
.onglet::after { box-shadow: none; background: var(--encre); height: 1px; }
.onglet[aria-pressed='true']::after { transform: scaleX(1); }

/* Les puces : du texte, pas des gelules. Celle qui est choisie s'ecrit en
   clair, les autres restent en retrait. */
.puce {
  border-radius: 0; border: 0;
  padding: 0.25rem 0; margin-inline-end: 16px;
  background: transparent;
}
.puce:hover { background: transparent; color: var(--encre); }
.puce[aria-pressed='true'] {
  background: transparent; color: var(--encre);
  box-shadow: inset 0 -1px 0 var(--encre);
}
.filtres::before { background: var(--trait); }

/* ---------- le panneau des alertes parle la meme langue ---------- */

/* CE BLOC DISAIT L'INVERSE DE CE QUE LE SITE EST DEVENU.
   Il commencait par « rien n'est encadre, tout est ecrit sur le mur ; les
   coins arrondis et les boites etaient le gabarit des concurrents ». C'etait
   la these du mur de platre, rejetee. Le panneau est donc reste la seule
   surface a angles vifs d'un site entierement arrondi :

     .panneau        0 px      .fiche    20 px
     .panneau__oui   0 px      .onglet  999 px
     .panneau h2     Karantina 41,6 px   — la police du logotype

   Une porte d'entree du produit qui a l'air d'appartenir a un autre. On la
   fait parler comme la fiche, dont elle est le pendant : meme rayon, meme
   ombre, meme bouton, meme croix ronde. */
.panneau {
  border: 0; border-radius: 20px;
  box-shadow: 0 40px 90px -20px rgba(0, 0, 0, 0.85);
}
.panneau::backdrop { background: rgba(6, 6, 8, 0.72); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
/* Assistant, pas Karantina : DESIGN.md reserve l'enseigne aux titres de jour
   et au logotype. Et la meme taille que le titre d'une fiche — les deux
   dialogues du site n'ont pas de raison de se crier dessus differemment. */
.panneau h2 {
  font-family: var(--police); font-weight: 700;
  font-size: 1.3rem; line-height: 1.16; letter-spacing: -0.01em;
}
.panneau__recherche {
  border: 0; border-radius: 10px;
  background: rgba(255, 255, 255, 0.07);
  padding: 8px 16px;
}
.panneau__recherche:focus-visible { background: rgba(255, 255, 255, 0.11); }

.resultats { border: 0; border-radius: 0; border-top: 1px solid var(--trait); }
.ligne { padding-inline: 8px; border-radius: 8px; }
.ligne + .ligne { border-block-start: 1px solid var(--trait); }
.ligne:hover { background: rgba(255, 255, 255, 0.06); color: var(--encre); }
.ligne__famille { letter-spacing: 0.1em; text-transform: uppercase; font-size: var(--t-legende); }

/* Ce qu'on suit : des pastilles, comme les puces de la barre. */
.pastille {
  border: 0; border-radius: 999px;
  background: rgba(255, 255, 255, 0.09); color: var(--encre);
  padding: 4px 12px;
  margin-inline-end: 8px;
}
.pastille:hover { background: rgba(255, 255, 255, 0.16); }

/* Le meme bouton que « Billets » : c'est la meme promesse, un cran plus loin. */
.panneau__oui { border-radius: 999px; padding: 12px 24px; font-weight: 700; }
.panneau__non { border-radius: 999px; }
.panneau__fermer { inset-inline-end: 0.6rem; inset-block-start: 0.6rem; }
.panneau__fermer button {
  width: 2rem; height: 2rem; border-radius: 50%;
  background: rgba(255, 255, 255, 0.1); color: var(--encre);
  font-size: 1.2rem; padding: 0;
  display: grid; place-items: center;
}
.panneau__fermer button:hover { background: rgba(255, 255, 255, 0.2); }

/* Le bouton suivre : rond comme tout ce qui se pose sur une affiche, et
   allume quand on suit. */
.suivre { background: rgba(0, 0, 0, 0.45); }
.suivre.est-suivi {
  background: var(--encre); color: var(--fond);
  box-shadow: none; filter: none;
}
.choix-suivre { border-radius: 14px; border-color: var(--trait-net); background: var(--fond-haut); }
.choix-suivre__ligne { border-radius: 8px; }
.choix-suivre__ligne:hover { background: rgba(255, 255, 255, 0.06); color: var(--encre); }
.choix-suivre__ligne.est-suivi { color: var(--encre); }


.pied__sources { color: var(--encre-tres-basse); }

/* ---------- changer de section ---------- */

/* Passer de Parties a Concerts remplace tout le mur d'un coup : sans rien,
   l'oeil ne sait pas si la page a change ou si elle a saute. Un fondu court
   le lui dit — 180 ms, assez pour etre percu, trop peu pour etre attendu.
   Uniquement au changement de SECTION : le meme fondu a chaque frappe dans
   la recherche serait insupportable. */
@media (prefers-reduced-motion: no-preference) {
  .liste--change { animation: apparaitre 180ms linear; }
}


/* ================================================================
   L'APPLE MUSIC DES SOIREES.
   Le mur de platre — sombre, retenu, justifie — a ete juge boring, et Victor
   a nomme la reference : Apple Music. Tout ce qui suit remplace l'idiome du
   mur par celui de la plateforme : une surface froide et neutre, des tuiles
   arrondies, la couleur qui vient de l'image, un hero qui fait defiler toute
   la nuit, et des etageres qu'on fait glisser. Ce bloc vient en dernier et
   l'emporte sur ce qui precede.
   ================================================================ */
body { background: var(--fond); }
/* Le grain etait la matiere du platre ; une plateforme n'a pas de matiere. */
body::before { display: none; }

/* ---------- la barre, vitree ---------- */
/* La barre est une surface posee sur le contenu, pas un bandeau colle en
   haut. Le degrade lui donne du poids sous le logotype et la laisse
   s'effacer vers le bas, ou les affiches commencent a passer dessous. */
.tete {
  background:
    linear-gradient(to bottom, color-mix(in srgb, var(--fond) 92%, transparent), color-mix(in srgb, var(--fond) 66%, transparent));
  backdrop-filter: saturate(180%) blur(22px); -webkit-backdrop-filter: saturate(180%) blur(22px);
  border-bottom: 1px solid var(--trait);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.04) inset;
  /* La seconde rangee donnait son air a la barre ; sans elle, la premiere se
     retrouvait collee au filet du bas. Le meme air, au-dessus et au-dessous. */
  /* L'ENCOCHE DE L'IPHONE. Depuis l'ecran d'accueil, la page s'etend sous la
     barre d'etat (viewport-fit=cover, barre translucide) : sans cette marge,
     le logo et les onglets se retrouvaient SOUS l'heure et la batterie, et en
     remontant la page on ne les atteignait jamais. Victor l'a vu le soir de
     la mise en ligne. « env(safe-area-inset-top) » vaut 0 partout ailleurs. */
  padding-block: calc(12px + env(safe-area-inset-top, 0px)) 0.75rem;
}
/* LA RECHERCHE RESTE OUVERTE — choix de Victor, 08/09/2026.
   Elle s'est repliee un temps en pastille : elle mesurait 320 px, le controle
   le PLUS large de la barre pour la fonction la moins utilisee. Mais une
   recherche repliee ne se propose pas ; il faut savoir qu'elle est la pour la
   chercher. Ouverte, elle dit ce qu'on peut y taper — « une soiree, un
   artiste, une salle » — et c'est une invitation que l'icone ne fait pas.
   Elle garde la largeur qu'elle prenait en s'ouvrant, 272 px et non 320 :
   assez pour lire ce qu'on tape, sans redevenir l'element dominant. */
.chercher { flex: none; width: min(17rem, 26vw); }
.chercher__loupe {
  position: absolute; inset-inline-start: 0.66rem;
  inset-block-start: 50%; translate: 0 -50%;
  width: 15px; height: 15px; pointer-events: none;
  color: var(--encre-tres-basse);
}
.chercher input {
  width: 100%; height: var(--h-outil);
  border: 0; border-radius: 999px;
  padding-block: 0; padding-inline: 32px 12px;
  background: rgba(255, 255, 255, 0.06); color: var(--encre);
  transition: background-color 160ms var(--pose);
}
.chercher input:hover, .chercher input:focus-visible { background: rgba(255, 255, 255, 0.11); border-bottom-color: transparent; }
/* UN SEUL LANGAGE DE FORME DANS LA BARRE.
   Il y en avait quatre : rayon 999 pour les onglets et les puces, rayon 10
   pour la recherche et le selecteur, et RIEN du tout pour la cloche et la
   langue, qui flottaient sans surface. Quatre hauteurs aussi — 27, 31, 32 et
   36 px. Tout ce qui se clique est desormais rond, a la meme hauteur. */
.ou select { border: 0; height: var(--h-outil); padding: 0 24px 0 16px; border-radius: 999px; background: rgba(255, 255, 255, 0.06); font-weight: 600; }
.ou select:hover { background: rgba(255, 255, 255, 0.11); }
.cloche, .langue {
  width: var(--h-outil); height: var(--h-outil); display: grid; place-items: center; flex: none;
  border-radius: 50%; background: rgba(255, 255, 255, 0.06);
  transition: background-color 160ms var(--pose), color 160ms var(--pose);
}
.cloche:hover, .langue:hover { background: rgba(255, 255, 255, 0.13); color: var(--encre); }
:root[dir='rtl'] .ou select { padding: 0 16px 0 24px; }
.ou__fleche { inset-inline-end: 0.55rem; }
/* ---------- LES SECTIONS NE SONT PAS DES FILTRES ----------

   Elles l'etaient devenues, visuellement : deux rangees de pilules arrondies,
   avec la meme pastille blanche pour dire « choisi ». Mesure avant :

     .onglet   31 px de haut, rayon 999, 14,08 px / 600
     .puce     27 px de haut, rayon 999, 12,80 px / 600

   Quatre pixels d'ecart entre la navigation du site et un filtre de genre.
   L'oeil ne pouvait pas les hierarchiser, et le contrôle segmente est aussi
   la forme la plus banale de l'interface contemporaine.

   Ce sont des TITRES DE SECTION. Ils prennent donc l'enseigne, comme les
   titres de jour, et ils abandonnent la pilule : le choisi est en encre
   pleine, les autres reculent. La difference n'est plus une nuance de gris,
   c'est un changement d'alphabet. */
/* Les sections ont quitte la seconde rangee pour monter a cote du nom : ce
   sont les seuls liens de navigation du site, et le nom est ce qu'ils
   naviguent. */
.onglets { background: none; padding: 0; border-radius: 0; gap: clamp(12px, 1.8vw, 24px); align-items: center; flex: none; }
/* LES ONGLETS SONT UNE NAVIGATION, PAS UN TITRE.
   Ils ont ete en Heebo 900, en Assistant 600, puis en serif 900 le temps
   d'une matinee : a chaque fois la barre pesait plus lourd que la page.
   Victor a donne une reference (supernaturalkitchen.com) : la navigation y
   est petite, legere, en grotesque, et c'est le LOGO qui porte le caractere.
   C'est la bonne hierarchie pour une barre : le nom est la seule chose qu'on
   regarde, les onglets sont ce qu'on lit. Ils prennent donc la police du
   texte, a 16 px, en 500 — assez pour tenir sur fond sombre, pas plus. */
.onglet {
  font-family: var(--police); font-weight: 500;
  font-size: var(--t-fort); line-height: 1;
  letter-spacing: 0.01em;
  padding: 0px 0; border-radius: 0; background: none;
  /* --encre-eteinte donnait 2,05:1 — sous le minimum de 4,5 — et c'est un brun
     chaud herite du mur abandonne, sur une page neutre. Ce sont les liens de
     navigation du site : ils doivent se lire. */
  color: var(--encre-tres-basse);
  transition: color 200ms var(--pose);
}
.onglet::after { display: none; }
.onglet[aria-pressed='true'] { background: none; color: var(--encre); }
.onglet:hover:not([aria-pressed='true']) { color: var(--encre-basse); }
.onglet:focus-visible { outline: 2px solid var(--anneau); outline-offset: 4px; border-radius: 4px; }
/* Posees sur la liste, sous le hero : elles ont besoin d'une marge a elles,
   que l'en-tete leur donnait avant. */
.filtres { margin: 0 var(--marge); padding: 16px 0 4px; gap: 8px; }
.filtres::before { display: none; }
.puce {
  border-radius: 999px; padding: 4px 0.75rem; margin: 0;
  background: rgba(255, 255, 255, 0.06); color: var(--encre-basse); font-weight: 600; font-size: var(--t-menu);
}
.puce:hover { background: rgba(255, 255, 255, 0.11); color: var(--encre); }
.puce[aria-pressed='true'] { background: var(--encre); color: #000; box-shadow: none; }
.puce[aria-pressed='true'] .puce__n { color: rgba(0, 0, 0, 0.55); }
.cloche, .langue { color: var(--encre-basse); }

.liste { padding: 24px 0 64px; }
.etat { padding: 4rem var(--marge) 1rem; }
.ailleurs { margin-inline: var(--marge); }

/* ---------- le hero : plein ecran, toute la nuit qui defile ---------- */
/* Le hero d'avant — l'affiche a l'echelle du cinema, le titre en Karantina
   par-dessus — que Victor a prefere a la carte arrondie. Ce qui change par
   rapport a la une d'alors : il ne choisit personne. Toute la nuit passe, dans
   l'ordre des heures, en partant de ce qui joue maintenant. */
.hero {
  --vive: var(--signal-sombre);
  position: relative; overflow: hidden; isolation: isolate;
  margin: -24px 0 0;
  height: clamp(520px, 74vh, 780px);
  background: var(--fond-creux); color: var(--encre);
}
.hero:focus-visible { outline: 2px solid var(--anneau); outline-offset: -4px; }
.hero__fond {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 28%; z-index: 0;
  opacity: 0; transition: opacity 700ms var(--pose);
}
.hero__fond--actif { opacity: 1; }
/* Sur bureau la copie floue ne sert pas : l'affiche remplit le cadre. Elle
   n'est floue que sur telephone, ou l'affiche reste entiere. */
/* Pas de z-index sur le cadre : il ferait un contexte d'empilement, et le
   degrade du hero (z-index 3) passerait au-dessus du texte qui est dedans.
   Le texte a son propre z-index, dans le contexte du hero. */
.hero__cadre { position: absolute; inset: 0; }
.hero__affiche { position: absolute; inset: 0; display: block; z-index: 1; }
.hero__image {
  width: 100%; height: 100%; display: block; object-fit: cover; object-position: center 28%;
  opacity: 0; transition: opacity 600ms var(--pose);
}
.hero__image[src] { opacity: 1; }
.hero::before {
  content: ''; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background:
    /* Le voile avait un trou entre 26 % et 52 %, la ou le titre remonte :
       mesure sur dix diapositives, le contraste tombait a 1,1 — le sur-titre
       etait invisible sur dix affiches sur dix. La marche remonte. */
    linear-gradient(180deg, rgba(10, 10, 12, 0.7) 0%, rgba(10, 10, 12, 0.3) 22%, rgba(10, 10, 12, 0.55) 50%, rgba(10, 10, 12, 0.94) 86%, var(--fond) 100%),
    linear-gradient(90deg, rgba(10, 10, 12, 0.6), rgba(10, 10, 12, 0.15) 55%, transparent 75%);
}
:root[dir='rtl'] .hero::before {
  background:
    linear-gradient(180deg, rgba(10, 10, 12, 0.7) 0%, rgba(10, 10, 12, 0.3) 22%, rgba(10, 10, 12, 0.55) 50%, rgba(10, 10, 12, 0.94) 86%, var(--fond) 100%),
    linear-gradient(270deg, rgba(10, 10, 12, 0.6), rgba(10, 10, 12, 0.15) 55%, transparent 75%);
}
.hero__texte {
  position: absolute; z-index: 4; inset-inline-start: var(--marge); bottom: 4.6rem;
  max-width: min(62rem, calc(100% - 2 * var(--marge)));
}
.hero__sur {
  font-size: var(--t-corps); font-weight: 600; letter-spacing: 0.34em; text-transform: uppercase;
  color: var(--encre); opacity: 0.9; font-variant-numeric: tabular-nums;
}
/* UN TITRE LONG SE REDUIT, IL NE SE COUPE PAS.
   « BUBBLES x NOYA CHEKORAL BDAY 05.09 | SATURDAY » reclamait trois lignes
   sur un telephone et se faisait tronquer aux deux tiers. Mesure : sur 13
   soirees, deux etaient coupees a 390 px, aucune au-dela de 820. Deux
   reponses plutot qu'une troncature — la taille suit la longueur du titre,
   et le telephone accorde une ligne de plus. */
.hero__titre {
  font-family: var(--enseigne); font-weight: 700;
  font-size: var(--taille-titre, clamp(3.2rem, 7.6vw, 7.2rem)); line-height: 0.84; letter-spacing: -0.005em;
  margin: 0.45em 0 0.3em; text-shadow: 0 10px 40px rgba(0, 0, 0, 0.6);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.hero--long { --taille-titre: clamp(2.6rem, 5.6vw, 5.4rem); }
/* Au-dela de 48 signes, la reduction ne suffit pas : trois titres du
   catalogue montent a 89 signes et reclamaient une troisieme ligne meme sur
   un grand ecran. On la leur donne plutot que de les couper. */
.hero--tres-long { --taille-titre: clamp(2.2rem, 4.4vw, 4.2rem); }
.hero--tres-long .hero__titre { -webkit-line-clamp: 3; }
/* La reglette : une ligne de faits, comme au dos d'un billet. L'heure et
   l'attente en Karantina — c'est ce que l'affiche ne dit jamais — la salle en
   petites capitales, le prix au bout. Des filets, pas des puces. */
.hero__reglette {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 12px; color: var(--encre);
}
.hero__filet { width: 1px; height: 1.5rem; background: rgba(255, 255, 255, 0.28); flex: none; }
.hero__heure {
  font-family: var(--enseigne); font-weight: 700; font-size: 2.5rem; line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em;
}
.hero__lieu {
  margin: 0; font-size: var(--t-menu); font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase; opacity: 0.88; color: var(--encre);
  max-width: 18rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hero__prix {
  font-family: var(--enseigne); font-weight: 700; font-size: 1.7rem; line-height: 1;
  font-variant-numeric: tabular-nums; opacity: 0.92;
}
.hero__dans {
  margin: 0; font-family: var(--enseigne); font-weight: 400; font-size: 1.7rem; line-height: 1;
  opacity: 0.92; font-variant-numeric: tabular-nums; color: var(--encre);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
/* En cours : un point qui bat dans la couleur de l'affiche. Le seul endroit
   du hero ou quelque chose bouge, et il dit une chose vraie — ca joue
   maintenant. Sous mouvement reduit, le point reste, il cesse de battre. */
.hero__live {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 4px 12px 4px 8px; border-radius: 999px;
  background: color-mix(in srgb, var(--vive) 26%, transparent);
  font-size: var(--t-corps); font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  opacity: 1;
}
:root[dir='rtl'] .hero__live { padding: 4px 8px 4px 12px; }
.hero__pouls {
  width: 0.5rem; height: 0.5rem; border-radius: 50%; flex: none;
  background: var(--encre); box-shadow: 0 0 0 0 color-mix(in srgb, var(--encre) 60%, transparent);
}
@media (prefers-reduced-motion: no-preference) {
  .hero__pouls { animation: pouls 2.4s ease-out infinite; }
}
@keyframes pouls {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--encre) 55%, transparent); }
  70% { box-shadow: 0 0 0 0.5rem transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.hero__ferme { font-size: var(--t-corps); opacity: 0.6; font-weight: 500; }
.hero__actions { display: flex; gap: 8px; align-items: center; margin-top: 16px; flex-wrap: wrap; }
.hero__billets {
  display: inline-block; padding: 12px 1.5rem; border-radius: 999px; text-decoration: none;
  background: var(--encre); color: var(--fond); font-weight: 700; font-size: var(--t-fort);
  box-shadow: 0 14px 40px color-mix(in srgb, var(--vive) 55%, transparent);
  transition: transform 160ms var(--pose), box-shadow 160ms var(--pose);
}
.hero__billets:hover { transform: translateY(-1px); box-shadow: 0 18px 48px color-mix(in srgb, var(--vive) 75%, transparent); }
/* Le bouton suivre, dans le hero : un cercle a la hauteur du bouton billets.
   Un padding asymetrique — 17,6 px de cote pour 29,6 px de large — elargissait
   la boite sans toucher la hauteur : un ovale, pas un cercle. */
.hero .suivre {
  position: static; opacity: 1; transform: none; flex: none;
  width: 2.75rem; height: 2.75rem; padding: 0; border-radius: 50%;
  background: rgba(255, 255, 255, 0.14); color: var(--encre);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.hero .suivre svg { width: 17px; height: 17px; }
.hero .suivre.est-suivi { background: var(--encre); color: var(--fond); box-shadow: none; }
/* Le pied : deux fleches, un compteur, une barre de temps. Pas de points. */
.hero__pied {
  position: absolute; z-index: 4; inset-inline-start: var(--marge); bottom: 1.5rem;
  display: flex; align-items: center; gap: 0.5rem;
}
.hero__compteur { font-size: var(--t-menu); font-weight: 600; color: var(--encre-basse); font-variant-numeric: tabular-nums; min-width: 3.4rem; text-align: center; }
.hero__fleche {
  /* Un <button> n'herite pas de la police du document : sans cette ligne il
     tombe sur l'Arial du navigateur. Les deux fleches et la pause du hero
     etaient les trois seuls elements en Arial de tout le site. */
  font-family: inherit;
  width: 2rem; height: 2rem; border-radius: 50%; border: 0; cursor: pointer;
  background: rgba(255, 255, 255, 0.12); color: var(--encre); font-size: 1.25rem; line-height: 1;
  backdrop-filter: blur(8px); transition: background-color 160ms var(--pose);
}
.hero__fleche:hover { background: rgba(255, 255, 255, 0.24); }
.hero__fleche:focus-visible { outline: 2px solid var(--anneau); outline-offset: 2px; }
.hero__temps { position: absolute; left: 0; bottom: 0; height: 2px; width: 100%; background: var(--vive); transform-origin: left; transform: scaleX(0); opacity: 0.9; z-index: 5; }
:root[dir='rtl'] .hero__temps { transform-origin: right; }
@media (prefers-reduced-motion: no-preference) { .hero__temps--court { animation: remplir 6s linear forwards; } }
@keyframes remplir { from { transform: scaleX(0) } to { transform: scaleX(1) } }

/* ---------- les etageres ---------- */
/* LE NAVIGATEUR NE DESSINE PLUS CE QUE PERSONNE NE REGARDE.
   Mesure : dans l'onglet « Tout », 823 tuiles etaient dessinees, dont 781 —
   95 % — a plus de deux ecrans sous la ligne de flottaison. 9 735 noeuds et
   152 ms de travail bloquant pour montrer une trentaine de vignettes.

   « content-visibility: auto » laisse le navigateur sauter la mise en page et
   la peinture d'une etagere hors champ, et la rattraper quand elle approche.
   La taille intrinseque evite que la barre de defilement saute : les dix-huit
   etageres mesurent toutes entre 414 et 415 px, donc le chiffre est sur.

   La recherche dans la page continue de fonctionner : Chrome et Safari
   fouillent l'interieur des sous-arbres ainsi rendus. */
.etagere {
  /* Chaque nuit a son ciel (voir .mosaique::before, partage) : la section
     le contient, et il passe sous l'en-tete et la rangee. L'estimation de
     hauteur suit les cartes de 320 px : une etagere mesure ~560 px. */
  position: relative; overflow: clip;
  padding: 48px 0 32px;
  content-visibility: auto;
  contain-intrinsic-size: auto 560px;
}
.etagere__tete, .etagere__rang { position: relative; z-index: 1; }
.etagere__tete { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 0 var(--marge); margin-bottom: 48px; gap: 12px; }
/* LES TITRES DE JOUR RETROUVENT L'ENSEIGNE.
   DESIGN.md dit depuis le debut que Karantina sert « aux titres de jour et au
   logotype ». Le code l'avait oublie : sur 1013 elements de texte, TROIS
   etaient en Karantina — tous dans le hero — et les 1010 autres en Assistant.
   Le site possede une condensee dessinee pour les affiches de concert, avec
   l'hebreu et le latin ensemble, et ne s'en servait nulle part. C'est la
   raison pour laquelle la page n'avait qu'une seule voix.
   Karantina est condensee : a taille egale elle se lit plus petite qu'une
   Assistant. On monte donc l'echelle, sinon les jours reculent au lieu
   d'avancer. */
.etagere__titre {
  margin: 0; display: flex; flex-direction: column; align-items: center; gap: 8px;
  font-family: var(--enseigne); font-weight: 500;
  font-size: var(--t-affiche);
  text-transform: uppercase; letter-spacing: 0.24em; text-indent: 0.24em; line-height: 1;
  color: var(--encre);
}
/* La date se tient contre son jour : plus petite, plus pale, mais du meme
   bloc — « Sunday 13/09 » se lit d'un trait. C'est le compte glisse entre
   les deux qui cassait la lecture. */
.etagere__date { font-size: var(--t-legende); font-weight: 600; color: var(--encre-tres-basse); letter-spacing: 0.32em; text-indent: 0.32em; }
/* « nowrap » : a 390 px le libelle se cassait en « See / all 17 », deux
   lignes pour trois mots. Le bouton passait de 25 a 44 px de haut et
   entrainait tout l'en-tete du jour avec lui — 53 px au lieu de 34. Le
   libelle tient largement sur une ligne a cette largeur ; il n'avait aucune
   raison de se couper. Mesure : verifier-squelette, aux trois largeurs. */
/* LA PASTILLE. Un bouton borde d'un filet, arrondi a fond, en petites
   capitales espacees : c'est le bouton de la reference, et c'est le seul
   bouton pose sur un ciel. Il se lit comme une invitation, pas comme un
   lien de plus. */
.etagere__tout {
  appearance: none; border: 1px solid var(--trait-net); background: none; cursor: pointer; flex: none;
  display: inline-flex; align-items: baseline; gap: 8px; white-space: nowrap;
  border-radius: 999px; padding: 8px 24px;
  font: inherit; font-size: var(--t-legende); font-weight: 600; color: var(--encre);
  text-transform: uppercase; letter-spacing: 0.16em;
  transition: color 160ms var(--pose), background-color 160ms var(--pose), border-color 160ms var(--pose);
}
.etagere__tout:hover { background: rgba(255, 255, 255, 0.08); border-color: var(--encre-basse); }
/* Le compte vit dans le bouton : il annonce ce qu'on va ouvrir. */
.etagere__n { font-weight: 500; color: var(--encre-tres-basse); font-variant-numeric: tabular-nums; }
.etagere__tout:hover .etagere__n { color: var(--encre-basse); }
.etagere__tout:hover { color: var(--encre); }
.etagere__tout:focus-visible { outline: 2px solid var(--anneau); outline-offset: 3px; border-radius: 4px; }
/* La rangee glisse a l'horizontale, sans barre de defilement visible ; le
   bord de la page est le seul indice, et il suffit : la tuile coupee dit
   qu'il y en a d'autres. */
.etagere__rang {
  display: flex; gap: var(--e4); align-items: flex-start;
  padding: 4px var(--marge) 8px;
  overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity;
  /* Sans ca, scroll-snap aimante la premiere tuile sur le bord du conteneur
     en avalant la marge : la seule rangee qui deborde etait la seule
     desalignee, et son affiche touchait le bord de l'ecran. */
  scroll-padding-inline: var(--marge);
  scrollbar-width: none;
}
.etagere__rang::-webkit-scrollbar { display: none; }
.etagere--ouverte .etagere__rang { flex-wrap: wrap; overflow: visible; }

/* ---------- les tuiles : la forme de l'affiche, a hauteur fixe ---------- */
/* La tuile porte la largeur et le bouton suivre ; le lien est dedans. Un
   bouton a l'interieur d'un lien est du HTML non conforme. */
/* LA TUILE A LE DROIT D'ETRE PLUS LARGE QUE L'ECRAN.
   Une banniere 3:1 fait 570 px sur un telephone de 390. La brider a la
   largeur de la page paraissait prudent, mais cela rendait a « cover » ce
   qu'on venait de lui reprendre : 47 % de l'affiche a nouveau rognes. La
   rangee glisse deja a l'horizontale — un panorama qu'on fait defiler est
   une chose normale ; une affiche coupee en deux n'en est pas une. La borne
   de forme, a 3, suffit a empecher qu'une tuile devienne un ruban. */
.tuile { position: relative; flex: none; width: calc(var(--r, 1) * var(--tuile-h)); scroll-snap-align: start; }
.soiree { display: block; width: 100%; max-width: none; }
.affiche {
  height: var(--tuile-h); width: 100%; aspect-ratio: auto;
  border-radius: var(--rayon); background: var(--fond-creux);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45);
  transition: transform 220ms var(--pose), box-shadow 220ms var(--pose);
}
.affiche::after { display: none; }
.affiche__image { filter: none; object-fit: cover; }
.affiche--sans { height: var(--tuile-h); aspect-ratio: auto; border-radius: var(--rayon); }
.soiree__texte { padding-top: 8px; }
/* Deux lignes toujours, meme pour un titre court : sinon le lieu remonte
   sous les titres d'une ligne et descend sous ceux de deux, et la rangee
   perd son alignement. C'est le prix d'une page rangee. */
.soiree__titre { font-size: var(--t-corps); font-weight: 600; min-height: calc(2 * 1.34em); -webkit-line-clamp: 2; }
.soiree__heure { font-size: var(--t-menu); color: var(--encre-basse); }
.soiree__lieu { font-size: var(--t-menu); color: var(--encre-tres-basse); }
.soiree--imminente .soiree__heure { color: var(--encre); }
@media (hover: hover) {
  .soiree:hover .affiche { transform: translateY(-3px) scale(1.02); box-shadow: 0 18px 40px rgba(0, 0, 0, 0.6); }
  .soiree:hover .soiree__titre { color: #fff; }
}
/* Le bouton suivre garde sa place sur la tuile, dans le coin. */

/* ---------- l'attente ---------- */
.etagere__rang--os { margin-top: 32px; overflow: hidden; }

/* ---------- telephone ---------- */
/* LA RANGEE UNIQUE A UNE LARGEUR MINIMALE, ET ELLE A GRANDI.
   Le nom, quatre sections et quatre outils tenaient sur une ligne a partir de
   992 px tant que la recherche etait une pastille de 36 px. Ouverte en
   permanence elle en prend 272, ce qui avait remonte la frontiere a 1 248.
   Fondre le stand-up dans les concerts en a rendu une bonne part : trois
   onglets au lieu de quatre, et la frontiere est redescendue a 1 088. Elle a
   bouge de quelques pixels a chaque changement de police des onglets ; on la
   garde a 1 088, qui est rond et qui a de l'air. Ce qui compte n'est pas le
   chiffre mais la mesure : verifier-barre passe la barre de 320 a 1 600 px
   dans les deux langues, et c'est lui qui a le dernier mot.
   C'est l'ANGLAIS qui la fixe : « Parties Shows Everything » demande plus de
   place que « מסיבות הופעות הכל », et l'anglais debordait encore la ou
   l'hebreu passait deja. Une seule regle pour les deux langues, calee sur la
   plus large. */
/* LE POINT DE BASCULE SUIT LE NOMBRE D'ONGLETS.
   Il etait a 68 rem — 1088 px — et tenait pour trois sections. Le stand-up
   ayant retrouve la sienne, ils sont quatre, et la barre debordait de 94 px a
   1090 px : le groupe d'outils sortait par la droite.
   Mesure, plutot qu'une valeur choisie a l'oeil : une rangee unique tient a
   partir de 1210 px (94 px de debord a 1090, 21 a 1180, 0 a 1210). 76 rem —
   1216 px — laisse la marge d'un caractere. */
@media (max-width: 76rem) {
  .tete__rang { flex-wrap: wrap; }
  .onglets { order: 5; flex-basis: 100%; margin-top: 8px; }
  .ou select { max-width: 9.5rem; }
}

/* Les tres petits ecrans. « Tel Aviv · 196 » est le mot le plus long de la
   barre : c'est lui qui la fait deborder en premier, et il debordait de 17 px
   a 320. Il retrecit d'abord ; sous 352 px le groupe d'outils prend sa propre
   ligne, parce qu'il n'y a plus de largeur a negocier. */
@media (max-width: 26rem) {
  .ou select { max-width: 6.5rem; }
  /* « Parties Concerts Stand-up Everything » demande 299 px et l'ecran en
     donne 282 : les sections glissent, comme les puces le font deja. En
     hebreu les quatre mots tiennent, mais la regle ne coute rien. */
  .onglets { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .onglets::-webkit-scrollbar { display: none; }
}

@media (max-width: 40rem) {
  :root { --tuile-h: 190px; }
  /* SUR TELEPHONE, LA RECHERCHE OUVERTE PREND SA PROPRE LIGNE.
     C'est le prix de la garder ouverte, et il est mesure : a 390 px les
     quatre outils demandent 385 px pour 352 disponibles, et ça debordait
     de 50 px — 88 a 320 px.
     « display: contents » fait disparaitre la BOITE du groupe sans toucher a
     ses enfants : les quatre outils deviennent alors des elements de la
     rangee elle-meme, et chacun peut prendre sa place. Sans cela, la
     recherche ne pourrait pas sortir du groupe pour occuper toute la
     largeur — l'ordre du HTML l'y enferme.
     Le groupe ne se disperse pas pour autant : la ville, la cloche et la
     langue restent cote a cote a droite du nom, dans cet ordre. */
  .tete__outils { display: contents; }
  /* LA VILLE RETRECIT, LE BOUTON DE LANGUE NE DESCEND JAMAIS.
     Mesure a 390 px, le 10/09 : pendant le squelette, le selecteur est court
     et tout tient sur une ligne (barre : 205 px) ; une fois « Tel Aviv · 202 »
     charge, il s'elargit, le bouton de langue passe a la ligne et la barre
     fait 265 px. Soixante pixels de saut, a l'instant ou la page se remplit.
     Le selecteur est le seul element de la rangee qui ait de la largeur a
     rendre : il devient le seul a retrecir. « min-width: 0 » est ce qui
     l'y autorise — sans lui, une boite flex ne descend pas sous la largeur
     de son contenu, et c'est la rangee qui plie a sa place. */
  .ou { order: 2; margin-inline-start: auto; flex: none; width: 7rem; }
  .cloche { order: 3; }
  .langue { order: 4; }
  .chercher { order: 5; flex: 1 1 100%; width: auto; margin-top: 8px; }
  /* UNE LARGEUR FIXE, PAS UN MAXIMUM. Premiere tentative : « flex-shrink »
     avec un maximum. Ca ne pouvait pas marcher : dans une rangee qui replie,
     le navigateur range les elements en lignes d'apres leur largeur
     NATURELLE, et ne retrecit qu'ensuite, a l'interieur d'une ligne deja
     decidee. Un selecteur de 40 px vide et de 120 px plein donnait donc deux
     pliages. A 7 rem dans les deux cas, il n'y en a qu'un. */
  .ou select { width: 100%; max-width: none; }
  /* Le dessin du mot est plus large que le mot qu'il remplace : 113 px contre
     95. Un cran plus bas sur telephone, et la premiere ligne — nom, ville,
     cloche, langue — tient a 390 px avec 18 px d'air. */
  .marque__image { height: 1.15em; }
  .filtres { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; padding: 16px 0 4px; }
  .filtres::-webkit-scrollbar { display: none; }
  /* Sur telephone, l'affiche reste entiere sur sa copie floue : une banniere
     en 16:9 rognee a la verticale ne dirait plus rien. */
  .hero { height: 66vh; min-height: 460px; margin-top: -24px; }
  .hero__fond { filter: blur(40px) saturate(1.5) brightness(0.55); transform: scale(1.15); }
  .hero__image { object-fit: contain; object-position: center 34%; }
  .hero__texte { bottom: 4rem; }
  /* Le hero fait 66vh : il y a la place d'une ligne de plus, et mieux vaut
     trois lignes lisibles qu'un titre tronque. */
  .hero__titre { --taille-titre: clamp(2.2rem, 10vw, 3rem); -webkit-line-clamp: 3; }
  /* Sur telephone la reglette se replie : l'heure et l'attente restent
     ensemble, la salle et le prix passent dessous. */
  .hero__reglette { gap: 8px; margin-top: 0.5rem; }
  .hero__heure { font-size: 1.9rem; }
  .hero__dans, .hero__prix { font-size: 1.3rem; }
  .hero__lieu { max-width: 10rem; }
  .hero__filet { height: 1.1rem; }
  .hero--long .hero__titre { --taille-titre: clamp(1.9rem, 8.4vw, 2.5rem); }
  .hero--tres-long .hero__titre { --taille-titre: clamp(1.7rem, 7.2vw, 2.2rem); }
  .hero__pied { bottom: 1.1rem; }
}
@media (prefers-reduced-motion: reduce) {
  .hero__fond, .hero__fleche, .hero__billets, .affiche { transition: none; }
  .hero__temps { display: none; }
}

/* ---------- la fiche d'une soiree ---------- */
/* Un clic ouvre la fiche plutot que d'envoyer aussitot chez la billetterie.
   Elle porte ce que la billetterie sait et que personne ne montre : le prix,
   les billets restants, le lieu avec sa carte, a qui ecrire pour annuler.
   Le bouton d'achat reste a un clic, et c'est le plus gros element. */
.fiche {
  width: min(34rem, calc(100vw - 2rem));
  max-height: min(88vh, 52rem);
  padding: 0; border: 0; border-radius: 20px;
  background: var(--fond-haut); color: var(--encre);
  box-shadow: 0 40px 90px -20px rgba(0, 0, 0, 0.85);
  overflow: hidden;
}
.fiche::backdrop { background: rgba(6, 6, 8, 0.72); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
.fiche__fermer { position: absolute; inset-inline-end: 0.6rem; inset-block-start: 0.6rem; z-index: 2; margin: 0; }
.fiche__fermer button {
  width: 2rem; height: 2rem; border: 0; border-radius: 50%; cursor: pointer;
  /* « font: inherit » : sans lui, un <button> garde la police du systeme.
     C'etait le SEUL element de la page en Arial — mesure sur 1082 textes. */
  font: inherit;
  background: rgba(0, 0, 0, 0.45); color: var(--encre); font-size: 1.2rem; line-height: 1;
  backdrop-filter: blur(8px);
}
.fiche__fermer button:hover { background: rgba(0, 0, 0, 0.7); }
.fiche__corps { padding: 24px; display: flex; flex-direction: column; gap: 1rem; overflow-y: auto; max-height: inherit; }
.fiche__tete { display: flex; gap: 1rem; align-items: flex-start; }
.fiche__affiche { width: 7.5rem; flex: none; aspect-ratio: var(--r, 1); object-fit: cover; border-radius: 10px; display: block; background: var(--fond-creux); }
.fiche__intro { min-width: 0; padding-inline-end: 2rem; }
.fiche__titre { margin: 0; font-size: 1.3rem; font-weight: 700; line-height: 1.16; letter-spacing: -0.01em; }
.fiche__quand { margin: 8px 0 0; color: var(--encre-basse); font-size: var(--t-fort); font-variant-numeric: tabular-nums; }
/* Les lignes : une etiquette pale, une valeur nette. Pas de tableau, pas de
   cadre — la fiche est deja une boite, il ne faut pas en empiler d'autres. */
.fiche__lignes { display: grid; grid-template-columns: auto 1fr; gap: 8px 1rem; margin: 0; align-items: baseline; }
.fiche__lignes dt { color: var(--encre-tres-basse); font-size: var(--t-menu); font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; }
.fiche__lignes dd { margin: 0; font-size: var(--t-fort); }
.fiche__lien { color: var(--encre); text-decoration: none; border-bottom: 1px solid var(--trait-net); }
.fiche__lien:hover { border-bottom-color: var(--encre); }
/* Ce qui reste : la seule chose qu'aucun autre site ne montre. Elle a sa
   ligne, et elle change de couleur quand il n'en reste plus beaucoup. */
.fiche__stock {
  margin: 0; padding: 12px 16px; border-radius: 12px;
  background: rgba(255, 255, 255, 0.06); font-size: var(--t-fort); font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.fiche__stock--rare { background: color-mix(in srgb, var(--vif) 18%, transparent); color: #ffb4a4; }
.fiche__stock--fermee { background: rgba(255, 255, 255, 0.05); color: var(--encre-tres-basse); font-weight: 400; }
.fiche__actions { display: flex; gap: 8px; align-items: center; }
.fiche__billets {
  flex: 1; text-align: center; padding: 12px 24px; border-radius: 999px; text-decoration: none;
  background: var(--encre); color: var(--fond); font-weight: 700; font-size: var(--t-fort);
  transition: transform 160ms var(--pose);
}
.fiche__billets:hover { transform: translateY(-1px); }
.fiche .suivre { position: static; opacity: 1; transform: none; flex: none; width: 2.9rem; height: 2.9rem; border-radius: 50%; background: rgba(255, 255, 255, 0.1); color: var(--encre); }
.fiche .suivre.est-suivi { background: var(--encre); color: var(--fond); box-shadow: none; }
.fiche__pied { margin: 0; color: var(--encre-tres-basse); font-size: var(--t-corps); }
@media (max-width: 30rem) {
  .fiche { width: 100vw; max-width: 100vw; max-height: 92vh; border-radius: 18px 18px 0 0; margin: auto auto 0; }
  .fiche__affiche { width: 5.5rem; }
}
@media (prefers-reduced-motion: reduce) { .fiche__billets { transition: none; } }

/* Le prix et la rarete sous chaque tuile. Le prix existe pour 507 soirees et
   ne se lisait que dans la fiche, a un clic de la ; « Free – 80 ₪ » est
   pourtant le fait le plus decisif pour quelqu'un hors du milieu. */
/* ---------- la legende d'une tuile : trois etages, pas quatre lignes ----------

   Avant : l'heure, le titre, le lieu, le prix — quatre lignes empilees dont
   TROIS faisaient la meme taille, et l'heure exactement la meme que le titre
   (14,08 px, graisse 600 toutes les deux). Aucune hierarchie. Pire, le prix
   etait plus clair et plus gras que le lieu juste au-dessus : l'oeil y allait
   en premier. Sous une affiche de cette qualite, ca ressemblait a une ligne
   de tableur.

   Maintenant, trois etages qui se distinguent d'un coup d'oeil :

     l'heure    12,8 px  encre vive   graisse 600, chasse ouverte  -> une etiquette
     le titre   15,4 px  encre vive   graisse 600, chasse serree   -> le plus gros
     ou/combien 12,8 px  encre basse  graisse 400, une seule ligne -> le detail

   C'est la TAILLE qui porte la hierarchie, pas la couleur : les deux premiers
   etages sont aussi lumineux l'un que l'autre, et se lisent quand meme dans
   l'ordre. */

/* LA RESERVE DE PLACE VA EN BAS, PAS AU MILIEU.
   Le titre reservait lui-meme ses deux lignes pour que les rangees restent
   alignees. Mais sur un titre d'une seule ligne, le vide tombait ENTRE le
   titre et le lieu : le lieu flottait seul, a vingt pixels de ce qu'il
   nomme. C'est le bloc entier qui porte la hauteur, maintenant, et la
   legende reste un groupe serre — le vide passe sous le lieu, ou personne
   ne le voit. */
.soiree__texte {
  padding-top: 12px;
  min-height: 5.9rem;
  display: flex; flex-direction: column; align-items: stretch;
}
.soiree__heure {
  display: flex; align-items: center; gap: 8px;
  font-size: var(--t-menu); font-weight: 600; color: var(--encre);
  letter-spacing: 0.06em; font-variant-numeric: tabular-nums;
}
.soiree__titre {
  margin: 4px 0 0; font-size: var(--t-fort); font-weight: 600; line-height: 1.28;
  letter-spacing: -0.012em; min-height: 0;
}
.soiree__lieu {
  margin: 4px 0 0; font-size: var(--t-menu); font-weight: 400;
  color: var(--encre-tres-basse);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Le point qui bat, le meme que celui du hero, en plus petit. */
.soiree__pouls {
  width: 0.4rem; height: 0.4rem; border-radius: 50%; flex: none;
  background: var(--encre);
}
@media (prefers-reduced-motion: no-preference) {
  .soiree__pouls { animation: pouls 2.4s ease-out infinite; }
}

/* ---------- le jeton : ce qui n'est pas du texte va sur l'affiche ----------

   Un prix et un nom de salle ne sont pas la meme nature de chose. Sous le
   lieu, le prix faisait une quatrieme ligne ; a cote de lui, il faisait une
   phrase qui ne veut rien dire. Il n'appartient pas a la legende.

   Il va donc la ou l'oeil passe deja — sur l'affiche, dans le coin bas, en
   diagonale du bouton « suivre » qui occupe le coin haut oppose. Il ne rogne
   rien : un jeton de onze pixels avec un flou derriere, qui se lit sur
   n'importe quelle image.

   UN SEUL A LA FOIS. L'etat passe avant le prix — quand la vente est fermee,
   ce que ca coutait n'interesse plus personne. */
.soiree__jeton {
  position: absolute; inset-block-end: 0.5rem; inset-inline-start: 0.5rem; z-index: 2;
  max-width: calc(100% - 1rem);
  font-size: var(--t-legende); font-weight: 600; font-variant-numeric: tabular-nums;
  padding: 4px 8px; border-radius: 999px;
  background: rgba(8, 8, 10, 0.72); color: var(--encre-basse);
  -webkit-backdrop-filter: blur(12px) saturate(1.4); backdrop-filter: blur(12px) saturate(1.4);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12), 0 3px 12px rgba(0, 0, 0, 0.4);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: transform 220ms var(--pose);
}
/* LE JETON EST TOUJOURS SOMBRE, ET C'EST LE TEXTE QUI CHANGE.
   Il l'a d'abord ete clair pour la gratuite — et une affiche sur deux est
   claire : un jeton blanc sur le flyer blanc du Panda disparaissait. Un voile
   sombre floute se lit sur n'importe quelle image, alors que rien de clair ne
   le fait. La gratuite garde son pas au-dessus : encre vive et graisse 700,
   contre une encre basse en 600 pour un montant. */
.soiree__jeton--gratuit { color: var(--encre); font-weight: 700; }
.soiree__jeton--rare {
  background: color-mix(in srgb, var(--vif) 82%, transparent); color: #fff; font-weight: 700;
  /* var(--t-legende) et non 0,66rem : 10,56 px etait la seule taille hors
     echelle de la page, invisible tant que les jetons « sale closed »
     n'etaient pas a l'ecran. Les grandes cartes du 10/09 l'ont montree. */
  letter-spacing: 0.04em; text-transform: uppercase; font-size: var(--t-legende);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
}
.soiree__jeton--fermee {
  background: rgba(10, 10, 12, 0.72); color: var(--encre-basse); font-weight: 700;
  /* var(--t-legende) et non 0,66rem : 10,56 px etait la seule taille hors
     echelle de la page, invisible tant que les jetons « sale closed »
     n'etaient pas a l'ecran. Les grandes cartes du 10/09 l'ont montree. */
  letter-spacing: 0.04em; text-transform: uppercase; font-size: var(--t-legende);
}
:root[dir='rtl'] .soiree__jeton--rare,
:root[dir='rtl'] .soiree__jeton--fermee { letter-spacing: 0; text-transform: none; }
/* Le jeton suit l'affiche quand elle se souleve au survol. */
@media (hover: hover) {
  .soiree:hover .soiree__jeton { transform: translateY(-2px); }
}

/* Une soiree qui a commence : l'affiche ne s'eteint pas, mais l'heure s'allume. */
.soiree--en-cours .soiree__heure { color: var(--encre); }
.soiree--fermee .soiree__pouls { display: none; }


/* ---------- corrections d'audit ---------- */
/* La base, pour tout ce qui n'a pas de regle a soi — les liens du pied, le
   lien d'evitement, le logotype. Sans elle ils gardaient l'anneau du
   navigateur, d'une autre epaisseur et d'un autre style. */
:focus-visible { outline: 2px solid var(--anneau); outline-offset: 2px; }
.fiche__fermer button:focus-visible, .panneau__fermer button:focus-visible {
  outline: 2px solid var(--anneau); outline-offset: 2px;
}
/* Cibles tactiles : 44 px est le minimum sur un ecran ou l'on vise au doigt.
   La cloche des alertes est la seule porte de la retention, et elle faisait
   34 px ; la bascule de langue, 22. */
@media (max-width: 40rem) {
  .cloche, .langue { min-width: 44px; min-height: 44px; display: inline-grid; place-items: center; }
  .onglet { min-height: 44px; display: inline-flex; align-items: center; }
  .hero__fleche { width: 44px; height: 44px; }
  .etagere__tout { min-height: 44px; padding-inline: var(--e4); }
}
/* Le bouton suivre reste sur l'affiche, mais hors du lien. */
.tuile > .suivre { position: absolute; inset-inline-end: 0.42rem; inset-block-start: 0.42rem; z-index: 2; }

/* Le bouton pause du carrousel. WCAG 2.2.2 niveau A : un mouvement
   automatique de plus de cinq secondes doit pouvoir s'arreter, et le survol
   ne compte pas — il n'existe pas au doigt. */
.hero__pause {
  font-family: inherit;
  width: 2rem; height: 2rem; border-radius: 50%; border: 0; cursor: pointer;
  background: rgba(255, 255, 255, 0.12); color: var(--encre);
  font-size: var(--t-legende); line-height: 1; backdrop-filter: blur(8px);
  transition: background-color 160ms var(--pose);
}
.hero__pause:hover { background: rgba(255, 255, 255, 0.24); }
.hero__pause:focus-visible { outline: 2px solid var(--anneau); outline-offset: 2px; }
@media (max-width: 40rem) { .hero__pause { width: 44px; height: 44px; } }
/* Une affiche de hero cassee : on la masque, le fond floute reste. */
.hero--sans-affiche .hero__image { opacity: 0; }
/* En hebreu, l'interlettrage large et les capitales sont un procede LATIN :
   l'hebreu n'a pas de capitales, et espacer ses lettres le fait lire comme
   un texte casse. La hierarchie s'y marque par la graisse et la taille. */
:root[dir='rtl'] .hero__sur,
:root[dir='rtl'] .hero__lieu,
:root[dir='rtl'] .fiche__lignes dt { letter-spacing: 0; text-transform: none; }

/* La barre de temps est enfant du pied : son 100 % faisait 134 px et se
   lisait comme un soulignement sous les fleches. */
.hero__pied .hero__temps { left: calc(-1 * var(--marge)); width: 100vw; }

/* Le lien d'evitement : invisible jusqu'a ce qu'on tabule dessus. Sans lui,
   atteindre le pied de page au clavier demande de traverser 446 arrets. */
.evitement {
  position: absolute; inset-inline-start: -9999px; top: 0; z-index: 100;
  padding: 12px 16px; border-radius: 0 0 10px 0;
  background: var(--encre); color: var(--fond); font-weight: 700; text-decoration: none;
}
.evitement:focus { inset-inline-start: 0; }
/* Le logotype est un h1 : la page n'avait aucun titre principal, et 233 h2
   a l'interieur de liens. Seule la marge du h1 est a neutraliser — reinitialiser
   aussi la taille l'ecrasait, puisque cette regle vient apres .marque__mot. */
h1.marque__mot { margin: 0; }

/* ================================================================
   LE MOUVEMENT
   Intentionnel, et rare — DESIGN.md. Ce qui suit n'ajoute rien au mur : il
   ne se construit toujours pas, aucune affiche ne monte a l'arrivee, aucune
   image ne change d'echelle. On repond a trois questions que l'oeil posait
   sans reponse : d'ou vient ce panneau, ou est passee la page, et est-ce que
   ce bouton m'a entendu.
   ================================================================ */

@media (prefers-reduced-motion: no-preference) {
  /* ---------- la reponse au toucher ---------- */
  /* Une commande qui ne bouge pas sous le doigt est une image de commande.
     Sur les COMMANDES seulement : les affiches ont deja la leur, et
     DESIGN.md interdit le scale sur les images.
     « scale » est une propriete a part entiere, pas « transform » : elle
     s'ajoute sans effacer le soulevement du bouton suivre ni celui des
     boutons de billets, qui, eux, se servent de transform. */
  .onglet { transition: color 200ms var(--pose), scale 120ms var(--pose); }
  .puce { transition: color 160ms var(--pose), background-color 160ms var(--pose), scale 120ms var(--pose); }
  .cloche, .langue { transition: background-color 160ms var(--pose), color 160ms var(--pose), scale 120ms var(--pose); }
  .etagere__tout { transition: color 160ms var(--pose), scale 120ms var(--pose); }
  .suivre { transition: opacity 160ms var(--pose), transform 160ms var(--pose), background-color 160ms var(--pose), color 160ms var(--pose), scale 120ms var(--pose); }
  .hero__billets { transition: transform 160ms var(--pose), box-shadow 160ms var(--pose), scale 120ms var(--pose); }
  .fiche__billets { transition: transform 160ms var(--pose), scale 120ms var(--pose); }

  .onglet:active, .etagere__tout:active { scale: 0.955; }
  .puce:active, .cloche:active, .langue:active, .suivre:active { scale: 0.92; }
  .hero__billets:active, .fiche__billets:active { scale: 0.972; }

  /* ---------- le panneau arrive et s'en va ---------- */
  /* L'entree est ecrite en JavaScript : elle part du rectangle exact de
     l'affiche cliquee, que le CSS ne peut pas connaitre. Le voile et la
     sortie restent ici. La sortie est plus courte que l'entree — on ne
     regarde pas partir ce qu'on vient de fermer. */
  .fiche, .panneau {
    transition: opacity 170ms var(--pose), scale 170ms var(--pose),
                display 170ms allow-discrete, overlay 170ms allow-discrete;
  }
  .fiche:not([open]), .panneau:not([open]) { opacity: 0; scale: 0.97; }

  .fiche::backdrop, .panneau::backdrop {
    opacity: 0;
    transition: opacity 240ms var(--pose), display 240ms allow-discrete, overlay 240ms allow-discrete;
  }
  .fiche[open]::backdrop, .panneau[open]::backdrop { opacity: 1; }
  @starting-style {
    .fiche[open]::backdrop, .panneau[open]::backdrop { opacity: 0; }
  }

}

/* ================================================================
   LA MOSAIQUE DU SOIR — 09/09/2026, en remplacement du hero.

   Le hero faisait 780 px : on ouvrait le site et on ne voyait AUCUNE soiree
   sans faire defiler. Son titre etait le texte brut de la billetterie, en
   capitales de 109 px. Une seule soiree occupait tout l'ecran.

   Sept soirees tiennent maintenant dans la meme place, et la page prend la
   couleur des affiches du soir — mesuree sur l'affiche elle-meme (voir
   teinteVive dans src/images.js), donc differente chaque nuit. C'est la
   reponse au « trop sombre, trop plat » : la matiere de la page est celle
   des soirees, et aucun concurrent a palette fixe ne peut la copier.
   ================================================================ */

/* « overflow: clip » et non « hidden » : clip ne cree pas de conteneur de
   defilement. Sans lui, le lavis — qui deborde volontairement de 14 % de
   chaque cote — faisait defiler la PAGE ENTIERE a l'horizontale. */
.mosaique { position: relative; overflow: clip; padding: 48px var(--marge) 32px; }

/* Le lavis. Il deborde largement de la section et se dilue vers le bas :
   c'est une lumiere qui vient de derriere les affiches, pas un fond colore. */
.mosaique::before, .etagere::before {
  content: ''; position: absolute; inset: -12% -14% 34%; z-index: 0;
  pointer-events: none; filter: blur(30px);
  /* LE CIEL DE LA NUIT. Depuis le 10/09/2026 le lavis a un haut : une lueur
     qui tombe du bord superieur, au centre — c'est le ciel de la reference
     (rockstargames.com/VI), un degrade de nuit qui s'allume en haut. Les
     deux lueurs de cote restent ; elles sont la couleur des affiches. */
  background:
    radial-gradient(80% 58% at 50% 0%, var(--lueur-a, transparent), transparent 70%),
    radial-gradient(58% 52% at 20% 28%, var(--lueur-a, transparent), transparent 70%),
    radial-gradient(48% 44% at 80% 18%, var(--lueur-b, transparent), transparent 72%);
}
.mosaique__tete, .mosaique__rang { position: relative; z-index: 1; }

/* L'EN-TETE D'UNE NUIT EST CENTRE, ET C'EST UNE DECISION DU 10/09/2026.
   DESIGN.md interdisait « le tout centre ». Victor a donne rockstargames.com/VI
   en reference : les titres y sont centres, enormes, en capitales espacees,
   avec le sous-titre dessous et un bouton en pastille. On a rendu la page
   entiere dans cette grammaire, il a garde ceci — le ciel, les titres, les
   grandes cartes — et refuse le plein ecran force. Le reste de la page
   reste aligne a gauche : seul le titre d'une nuit se regarde ; les
   legendes, elles, se lisent. */
.mosaique__tete { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 12px; margin-bottom: 48px; }
/* LES TITRES DE JOUR SONT DES CAPITALES ESPACEES.
   La reference (rockstargames.com/VI) titre en capitales geometriques avec
   0,15em d'espace entre les lettres, sur fond nuit. C'est ce qui, avec le
   logo manuscrit, fait le duo Art deco. Un corps de 24 px : des capitales
   espacees prennent deja plus de place qu'un mot en bas de casse, un corps
   de 32 aurait crie. */
.mosaique__titre {
  margin: 0; font-family: var(--enseigne); font-weight: 500;
  font-size: var(--t-affiche); line-height: 1;
  /* « text-indent » de la meme valeur que l'espacement : un mot espace porte
     son dernier ecart a droite, et un titre centre penchait d'autant. */
  text-transform: uppercase; letter-spacing: 0.24em; text-indent: 0.24em;
  color: var(--encre);
}
.mosaique__sous {
  margin: 0; font-size: var(--t-menu); font-weight: 600;
  letter-spacing: 0.32em; text-indent: 0.32em; text-transform: uppercase; color: var(--encre-tres-basse);
}

/* LA GRILLE DONNE LA HAUTEUR, PAS LES PROPORTIONS DES AFFICHES.
   En laissant les « aspect-ratio » decider, la grande tuile faisait 762 px et
   la mosaique 1 287 — soit presque le hero de 780 px qu'elle remplace. Une
   rangee bornee garde l'ensemble sous 600 px : on voit sept soirees ET le
   debut de la rangee suivante sans faire defiler. */
/* DEUX RANGEES JUSTIFIEES, ET AUCUNE AFFICHE ROGNEE.
   La premiere version posait les affiches dans une grille de cases fixes et
   laissait « cover » couper la difference — ce que le site refuse depuis le
   debut, et que les rangees horizontales n'ont jamais fait.

   « flex-basis » et « flex-grow » sont tous deux proportionnels a --r, la
   forme de l'affiche. Apres etirement les largeurs restent donc exactement
   proportionnelles a --r, et comme « aspect-ratio: var(--r) » fixe la
   hauteur a largeur/r, toutes les tuiles d'une rangee retombent a la MEME
   hauteur. Une galerie justifiee, sans une ligne de JavaScript de mise en
   page, qui se recalcule seule au redimensionnement. */
.mosaique__rang { display: flex; flex-wrap: wrap; gap: 16px; }
/* LA BASE EST EN « vw », PAS EN PIXELS.
   Elle ne fixe pas la hauteur finale — celle-ci vaut (largeur - ecarts) /
   somme des formes — mais elle decide COMBIEN d'affiches tiennent sur une
   ligne. En pixels, ce nombre changeait avec la largeur : quatre affiches a
   1 440 px, une seule a 768, d'ou une mosaique de 1 136 px sur tablette. En
   « vw », le compte reste le meme partout : quatre en tete, sept dessous. */
/* La base decide combien d'affiches tiennent par ligne, et donc leur taille.
   Le plancher de 150 px empeche une tablette de poser sept affiches de 100 px
   de large ; le plafond de 200 empeche un grand ecran d'en poser quatre
   enormes. Entre les deux, « vw » suit la largeur. */
/* 200-300 px et non 150-200 depuis le 10/09/2026 : de grandes cartes, quatre
   ou cinq par rangee sur un bureau au lieu de six ou sept. */
.mosaique__rang { --h-rang: clamp(200px, 19vw, 300px); }

.carreau {
  flex: var(--r, 1) 1 calc(var(--r, 1) * var(--h-rang));
  aspect-ratio: var(--r, 1); min-width: 0;
  position: relative; display: block; overflow: hidden;
  border-radius: var(--rayon); text-decoration: none; color: inherit;
  background: var(--fond-creux);
  box-shadow: 0 16px 40px -16px var(--lueur, rgba(0, 0, 0, 0.6)), 0 2px 10px rgba(0, 0, 0, 0.55);
  transition: transform 220ms var(--pose), box-shadow 220ms var(--pose);
}
.carreau--grand { border-radius: calc(var(--rayon) + 4px); }

/* dessinerAffiche() rend une .affiche calee sur --tuile-h, faite pour les
   rangees horizontales. Ici c'est la tuile qui donne la taille, et comme sa
   proportion est celle de l'affiche, « cover » ne coupe rien. */
.carreau .affiche { height: 100%; width: 100%; border-radius: 0; box-shadow: none; aspect-ratio: auto; }
.carreau .affiche__image { width: 100%; height: 100%; object-fit: cover; }

.carreau__texte {
  position: absolute; inset: auto 0 0 0; z-index: 2;
  padding: 16px 16px; display: flex; flex-direction: column; gap: 0px;
  background: linear-gradient(to top, rgba(4, 4, 6, 0.94), rgba(4, 4, 6, 0.45) 62%, transparent);
}
.carreau--grand .carreau__texte { padding: 1.5rem; gap: 4px; }
.carreau__heure {
  font-family: var(--enseigne); font-weight: 600; font-size: 1.02rem; line-height: 1;
  font-variant-numeric: tabular-nums; display: inline-flex; align-items: center; gap: 8px;
}
.carreau--grand .carreau__heure { font-size: clamp(1.5rem, 2.6vw, 2.2rem); }
.carreau__titre {
  font-size: var(--t-corps); font-weight: 600; line-height: 1.25; color: var(--encre-basse);
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
}
.carreau--grand .carreau__titre {
  font-size: clamp(1.02rem, 1.7vw, 1.26rem); font-weight: 700; color: var(--encre); -webkit-line-clamp: 2;
}
.carreau__lieu { font-size: var(--t-corps); color: var(--encre-basse); }
.carreau .suivre { z-index: 3; }
.carreau--fermee .affiche__image { filter: saturate(0.55) brightness(0.72); }

@media (hover: hover) {
  .carreau:hover { transform: translateY(-3px); }
}
@media (prefers-reduced-motion: reduce) { .carreau { transition: none; } }

/* SUR TELEPHONE, DEUX COLONNES ET LA GRANDE SUR TOUTE LA LARGEUR.
   A quatre colonnes une petite tuile ferait 80 px : une affiche illisible. */
@media (max-width: 46rem) {
  .mosaique__rang { gap: 12px; }
  /* Sur telephone, quatre affiches par ligne feraient 88 px de large : on ne
     verrait plus rien. La base monte donc, ce qui en fait tenir deux en tete
     et trois dessous. Mesure : a 180 px de base, deux carrees demandaient
     371 px pour 352 disponibles — elles tombaient a UNE par ligne, etirees a
     352 x 352, et la mosaique atteignait 1 498 px. */
  .mosaique__rang { --h-rang: clamp(130px, 38vw, 180px); }
}

/* LE JETON MONTE, PARCE QUE LE TEXTE A PRIS LE BAS.
   Dans une rangee, la legende est SOUS l'affiche et le jeton occupe seul le
   bas de l'image. Dans la mosaique le texte est DESSUS : les deux se
   cognaient, « SALE CLOSED » passant sous l'heure et le titre. Le jeton va
   donc en haut a gauche — le bouton suivre tenant deja le haut a droite. */
.carreau .soiree__jeton {
  inset-block: 0.62rem auto; inset-inline-start: 0.62rem;
  max-width: calc(100% - 3.4rem);
}

/* Les cales de fin de rangee : voir rangee() dans app.js. Hauteur nulle,
   base nulle, et elles poussent — donc elles prennent toute la place laissee
   par la derniere ligne sans rien occuper a l'ecran. Le « margin-block-start »
   negatif annule l'ecart de ligne qu'elles creeraient si elles passaient
   elles-memes a la ligne. */
.mosaique__cale { flex: 1 1 0; height: 0; margin-block-start: -16px; }

/* ---------- l'avis de panne ---------- */
/* Il vivait dans le pied de page, sous les mentions legales. Zygo y a annonce
   « 25 pages sur 26 en echec » pendant des semaines, en perdant 60 % de ses
   soirees, sans que personne le lise. Il est desormais sous la barre.

   Il ne crie pas pour autant : ce n'est pas une erreur de la personne qui
   lit, c'est une information. Un point ambre — la seule lumiere du site —
   et une phrase. Pas de fond rouge, pas de bordure epaisse : DESIGN.md
   interdit les aplats, et une source muette n'est pas une catastrophe. */
/* « hidden » NE SUFFIT PAS QUAND ON REDEFINIT « display ».
   L'attribut hidden vaut « display: none » par la feuille du navigateur — et
   n'importe quelle regle d'auteur le bat. Le bandeau restait donc affiche,
   vide, sur toute la largeur, en permanence : une barre grise sous l'en-tete
   que Victor a vue avant moi. Elle etait la sur le site en ligne. */
.avis[hidden] { display: none; }
/* UNE PASTILLE, PAS UNE BOITE. L'avis etait un pave gris de deux lignes sous
   la barre — « c'est laid », Victor, sur son telephone. Il prend la forme des
   autres pastilles du site, borde d'un filet dans l'ambre du signal, et une
   phrase plus courte : ce qu'il faut savoir tient en une ligne. */
.avis {
  display: inline-flex; align-items: center; gap: 8px;
  margin: 16px var(--marge) 0;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid rgba(255, 184, 92, 0.32);
  background: rgba(255, 184, 92, 0.06);
  color: var(--encre-basse); font-size: var(--t-menu); line-height: 1.4;
}
.avis__point {
  flex: none; width: 7px; height: 7px; border-radius: 50%;
  background: #FFB85C;
  box-shadow: 0 0 10px 2px rgba(255, 184, 92, 0.55);
  translate: 0 -0.1em;
}
@media (max-width: 40rem) { .avis { font-size: var(--t-menu); } }

/* ================================================================
   LE SYSTEME — 10/09/2026
   « Si Apple avait fait ce site. » Apple ne dessine pas des ecrans, elle
   applique un systeme : tout tombe sur la meme grille, la gamme de textes
   est courte, le decor s'efface devant le contenu, et un seul accent parle.
   Mesure avant : 33 espacements, 12 tailles, 10 colonnes de depart.
   ================================================================ */

/* ---------- 1. TOUT SUR LA MEME GRILLE ---------- */
.mosaique { padding: var(--e5) var(--marge) var(--e4); }
.mosaique__tete { margin-bottom: var(--e5); gap: var(--e3); align-items: center; }
.mosaique__rang { gap: var(--e4); }
.etagere { margin-bottom: var(--e5); }
.etagere__tete { padding: 0 var(--marge); margin-bottom: var(--e5); gap: var(--e3); }
.etagere__rang { gap: var(--e4); padding: 0 var(--marge); }
.filtres { margin: 0 var(--marge); padding: var(--e4) 0 var(--e2); gap: var(--e2); }
.avis { margin: var(--e2) var(--marge) 0; padding: var(--e2) var(--e3); }
.liste { padding-block: 0 var(--e6); }

/* ---------- 1b. SIX TAILLES ---------- */
.mosaique__titre, .etagere__titre {
  font-size: var(--t-affiche); text-transform: uppercase; letter-spacing: 0.24em; text-indent: 0.24em; font-weight: 500;
}
.mosaique__sous, .etagere__date { font-size: var(--t-legende); letter-spacing: 0.32em; text-indent: 0.32em; }
.carreau__heure, .carreau--grand .carreau__heure { font-size: var(--t-fort); }
.carreau__titre, .carreau--grand .carreau__titre { font-size: var(--t-corps); }
.carreau__lieu, .soiree__lieu, .etagere__tout, .puce { font-size: var(--t-menu); }

/* ---------- 2. LE TEXTE SORT DE L'AFFICHE ----------
   Dans Apple Music, une pochette n'est JAMAIS recouverte de texte : la
   legende vit dessous, alignee sur son bord gauche. Notre mosaique posait
   l'heure et le titre SUR l'affiche, avec un degrade qui en mangeait le bas
   — le dernier endroit ou l'affiche etait encore abimee. */
.carreau {
  aspect-ratio: auto; overflow: visible; background: none; box-shadow: none;
  display: flex; flex-direction: column;
}
/* UNE RANGEE JUSTIFIEE N'A PAS LE DROIT D'ETIRER SES TUILES.
   Par defaut, flexbox donne a chaque tuile la hauteur de la plus haute de sa
   ligne. Tant que la tuile ETAIT l'affiche, cet etirement se voyait tout de
   suite. Depuis que la legende vit dessous, il tombe sur l'affiche : elle
   recevait 209,5 px de haut pour 202,1 de large — une affiche carree rendue
   en 0,96, avec sept pour cent de l'image coupes par « object-fit: cover ».
   Onze affiches etaient dans ce cas. Mesure : verifier-rognage.
   Les tuiles d'une meme ligne gardent malgre tout la meme hauteur : leurs
   largeurs sont proportionnelles a --r et « aspect-ratio: var(--r) » en
   deduit une hauteur identique pour toutes. */
.mosaique__rang { align-items: flex-start; }
.carreau .affiche {
  aspect-ratio: var(--r, 1); border-radius: 10px; overflow: hidden;
  box-shadow: 0 8px 24px -12px var(--lueur, rgba(0, 0, 0, 0.7));
}
/* Une hauteur FIXE, pas un minimum : dans une rangee justifiee toutes les
   tuiles font la meme hauteur, et une legende plus haute que les autres
   deborde sur la rangee suivante. */
/* Une hauteur FIXE, pas un minimum : dans une rangee justifiee toutes les
   tuiles font la meme hauteur, et une legende plus haute que les autres
   deborde sur la rangee suivante. 56 px, soit quatorze pas de 4.
   L'ecart entre l'heure et le titre etait de 2 px ici et de 0,16 rem sur la
   grande tuile — 2,56 px. Deux valeurs, aucune sur la grille, et la seconde
   gagnait en silence parce qu'elle est plus specifique. */
.carreau__texte,
.carreau--grand .carreau__texte {
  position: static; background: none; padding: var(--e2) 0 0;
  gap: var(--e1); height: 56px; overflow: hidden;
}
.carreau__titre, .carreau--grand .carreau__titre {
  color: var(--encre); -webkit-line-clamp: 1; font-weight: 600;
}
.carreau__lieu { color: var(--encre-tres-basse); }
/* Le jeton monte : le bas de l'affiche n'est plus assombri, il redeviendrait
   illisible sur une affiche claire. */
.carreau .soiree__jeton { inset-block: var(--e2) auto; inset-inline-start: var(--e2); }

/* ---------- 3. LE DECOR S'EFFACE ----------
   Les commandes avaient une surface grise permanente. Apple les laisse nues
   et ne montre la surface qu'au contact : l'interface recule, les affiches
   parlent. */
.ou select, .chercher input, .cloche, .langue { background: transparent; }
.ou select:hover, .cloche:hover, .langue:hover { background: rgba(255, 255, 255, 0.08); }
.chercher input:hover, .chercher input:focus { background: rgba(255, 255, 255, 0.08); }
.puce {
  background: transparent; padding-inline: 0; margin-inline-end: var(--e3);
  border-radius: 0;
}
.puce:hover { background: transparent; color: var(--encre); }
.puce[aria-pressed='true'] {
  background: transparent; color: var(--encre);
  box-shadow: inset 0 -1px 0 var(--encre);
}
.puce[aria-pressed='true'] .puce__n { color: var(--encre-tres-basse); }

/* ---------- 4. UN SEUL ACCENT ----------
   L'ambre etait sur le point du logotype, celui du bandeau, le pouls « en
   cours » et la barre de progression. Il ne reste qu'a la marque. */
.avis__point { background: var(--encre-tres-basse); box-shadow: none; }
.soiree__pouls, .carreau__heure > i { background: var(--encre-basse); box-shadow: none; }

/* ---------- 5. LA BARRE ---------- */

/* Zero pixel, tout en haut : c'est elle qui dit si on est en haut de page. */
.sentinelle { position: absolute; top: 0; height: 1px; width: 1px; pointer-events: none; }

/* AU REPOS, ELLE N'EST PAS LA. Le lavis colore de la mosaique passe dessous,
   et rien ne separe le nom du contenu. Elle ne prend son fond, son flou et
   son filet qu'une fois qu'on descend — c'est-a-dire au moment ou des
   affiches commencent a passer derriere elle. */
.tete {
  background: transparent; backdrop-filter: none; -webkit-backdrop-filter: none;
  border-bottom-color: transparent; box-shadow: none;
  transition: background-color 260ms var(--pose), border-color 260ms var(--pose);
}
.tete--posee {
  /* Assez opaque pour que rien ne transparaisse : a 72 % en bas, les puces
     de filtre se lisaient A TRAVERS la barre, et ça ressemblait a un defaut
     d'affichage plutot qu'a de la matiere. */
  background: linear-gradient(to bottom,
    color-mix(in srgb, var(--fond) 97%, transparent),
    color-mix(in srgb, var(--fond) 90%, transparent));
  backdrop-filter: saturate(180%) blur(22px); -webkit-backdrop-filter: saturate(180%) blur(22px);
  /* LE FILET PREND LA COULEUR DE LA NUIT — celle des affiches du soir, donc
     differente chaque soir. C'est le seul endroit ou la barre appartient a
     ce qu'elle annonce. Il retombe sur un gris tant qu'aucune teinte n'a
     encore ete mesuree. */
  border-bottom-color: var(--nuit, var(--trait));
}
@media (prefers-reduced-motion: reduce) { .tete { transition: none; } }

/* LE TRAIT QUI SUIT LA SECTION. Il repond a « ou suis-je » par un mouvement,
   la ou une nuance de gris oblige a comparer les quatre mots entre eux. */
.onglets { position: relative; padding-bottom: var(--e2); }
.onglets__trait {
  position: absolute; inset-block-end: 0; inset-inline-start: 0;
  height: 2px; border-radius: 2px; background: var(--encre);
  opacity: 0; width: 0;
  transition: translate 300ms var(--pose), width 300ms var(--pose), opacity 200ms var(--pose);
}
:root[dir='rtl'] .onglets__trait { inset-inline-start: auto; inset-inline-end: 0; }
@media (prefers-reduced-motion: reduce) { .onglets__trait { transition: opacity 200ms var(--pose); } }
/* Le soulignement portait deja la section choisie ; deux traits pour la meme
   chose feraient bavard. */
.onglet[aria-pressed='true']::after { display: none; }

/* ================================================================
   LA MATIERE — 10/09/2026
   « Un design interactif, moderne, soigné. »
   Mesure avant d'ecrire : au survol, une tuile se deplaçait de TROIS
   pixels et rien d'autre. Meme ombre, meme image, aucune reaction. La
   page connaissait pourtant deja la couleur mesuree de chaque affiche —
   douze tuiles sur douze la portent — et ne s'en servait nulle part.
   ================================================================ */

/* ---------- 1. L'AFFICHE EST UN OBJET ECLAIRE ----------
   Son ombre n'est pas un noir generique pose sous elle : c'est SA propre
   lumiere, la couleur la plus vive mesuree sur son image, qui deborde sur
   la page. Deux couches — une proche qui la decolle, une large qui la fait
   rayonner — parce qu'une seule se lit comme un flou. */
.carreau .affiche,
.soiree .affiche {
  transition:
    transform 280ms var(--pose),
    box-shadow 280ms var(--pose),
    filter 280ms var(--pose);
}

@media (hover: hover) {
  .carreau:hover .affiche,
  .carreau:focus-visible .affiche,
  .tuile:hover .affiche,
  .soiree:focus-visible .affiche {
    transform: translateY(-6px) scale(1.014)
      rotateX(var(--incl-x, 0deg)) rotateY(var(--incl-y, 0deg));
    box-shadow:
      0 20px 44px -18px var(--lueur, rgba(0, 0, 0, 0.75)),
      0 0 72px -24px var(--lueur, transparent),
      0 4px 14px rgba(0, 0, 0, 0.5);
    /* Elle s'allume, elle ne s'agrandit pas : 4 % de saturation suffisent
       a faire la difference entre une image posee et une image vivante. */
    filter: saturate(1.05) brightness(1.03);
  }
  /* Le voisinage recule d'un cheveu. Sans ca, la tuile survolee monte
     seule dans le vide ; avec, c'est toute la rangee qui lui fait place. */
  .mosaique__rang:hover .carreau:not(:hover) .affiche,
  .etagere__rang:hover .tuile:not(:hover) .affiche {
    filter: saturate(0.88) brightness(0.86);
  }
}

/* ---------- 2. ELLE S'INCLINE VERS LA MAIN ----------
   Trois degres et demi au maximum, pilotes par le pointeur (voir
   donnerDeLaMatiere dans app.js). C'est ce qui separe une carte qui monte
   d'un OBJET qu'on regarde de biais. Au-dela de quatre degres l'effet
   devient un gadget de portfolio ; en dessous de deux il ne se sent pas. */
.mosaique__rang,
.etagere__rang {
  perspective: 1000px;
}

/* ---------- 3. LA PAGE PREND LA COULEUR DE CE QU'ON REGARDE ----------
   Le lavis derriere les affiches etait fige sur les deux premieres teintes
   de la nuit. Il suit desormais l'affiche sous le curseur, en 700 ms — le
   temps qu'il faut pour que ça se sente sans que ça clignote.
   « @property » est ce qui rend une couleur de variable animable ; sans
   lui le navigateur saute d'une valeur a l'autre. */
@property --lueur-a {
  syntax: '<color>';
  inherits: true;
  initial-value: transparent;
}
@property --lueur-b {
  syntax: '<color>';
  inherits: true;
  initial-value: transparent;
}
.mosaique, .etagere {
  transition: --lueur-a 700ms var(--pose), --lueur-b 700ms var(--pose);
}

/* ---------- 4. UNE ETAGERE DIT QU'ELLE CONTINUE ----------
   Elle se coupait net au bord de l'ecran. Un fondu au bout de la rangee
   dit qu'il y a une suite, et il disparait quand il n'y en a plus. */
.etagere__rang {
  -webkit-mask-image: linear-gradient(to right,
    transparent 0, #000 var(--voile-debut, 0px),
    #000 calc(100% - var(--voile-fin, 48px)), transparent 100%);
  mask-image: linear-gradient(to right,
    transparent 0, #000 var(--voile-debut, 0px),
    #000 calc(100% - var(--voile-fin, 48px)), transparent 100%);
  transition: -webkit-mask-image 200ms linear, mask-image 200ms linear;
}
:root[dir='rtl'] .etagere__rang {
  -webkit-mask-image: linear-gradient(to left,
    transparent 0, #000 var(--voile-debut, 0px),
    #000 calc(100% - var(--voile-fin, 48px)), transparent 100%);
  mask-image: linear-gradient(to left,
    transparent 0, #000 var(--voile-debut, 0px),
    #000 calc(100% - var(--voile-fin, 48px)), transparent 100%);
}

/* ---------- LE PLANCHER ----------
   Rien de tout cela n'est necessaire a la lecture. Sous « reduce », la
   tuile ne bouge plus, ne s'incline plus, et le voisinage ne recule plus :
   il reste la lumiere, qui est une information — la couleur de l'affiche —
   et non un mouvement. */
@media (prefers-reduced-motion: reduce) {
  .carreau .affiche, .soiree .affiche { transition: box-shadow 200ms linear; }
  .carreau:hover .affiche, .tuile:hover .affiche,
  .carreau:focus-visible .affiche, .soiree:focus-visible .affiche {
    transform: none;
    filter: none;
  }
  .mosaique__rang:hover .carreau:not(:hover) .affiche,
  .etagere__rang:hover .tuile:not(:hover) .affiche { filter: none; }
  .mosaique, .etagere { transition: none; }
}

/* ================================================================
   LA FICHE EST L'AFFICHE — 10/09/2026
   Victor : « trop sobre, trop simple ». Elle l'etait, et pour une raison
   precise : elle reduisait l'affiche a une vignette de 7,5 rem posee a
   cote d'un titre, dans un panneau gris sur gris. C'etait le seul endroit
   du site qui contredisait sa propre these — « l'image porte tout, la
   surface s'efface » — et la couleur mesuree de cette affiche, que la
   page connait, n'y servait nulle part.
   ================================================================ */

/* Le panneau s'assombrit sous l'affiche : c'est elle qui doit etre la
   chose la plus claire de l'ecran. Le filet prend sa teinte — un rebord
   de lumiere, pas une bordure grise. */
.fiche {
  width: min(38rem, calc(100vw - 32px));
  background: #0d0d10;
  border: 1px solid color-mix(in srgb, var(--lueur, var(--trait)) 22%, transparent);
  box-shadow:
    0 48px 120px -32px rgba(0, 0, 0, 0.9),
    0 0 80px -40px var(--lueur-douce, transparent);
}
.fiche::backdrop {
  background: rgba(4, 4, 6, 0.78);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  backdrop-filter: blur(16px) saturate(140%);
}

.fiche__corps { padding: 24px; gap: 24px; }

/* ---------- LA SCENE ----------
   L'affiche prend toute la largeur, a sa forme exacte, sans rognage —
   « object-fit: contain », parce que « aucune affiche n'est rognee » ne
   souffre pas d'exception ici plus qu'ailleurs. Plafonnee en hauteur pour
   qu'une story de 0,66 ne pousse pas le reste hors de l'ecran. */
.fiche__scene {
  position: relative;
  margin: -24px -24px 0;
  padding: 32px 24px 8px;
  display: grid;
  place-items: center;
  isolation: isolate;
}
/* Le halo. Il vient de DERRIERE l'affiche et deborde sur le panneau :
   c'est la meme grammaire que le lavis de la mosaique. */
.fiche__scene::before {
  content: '';
  position: absolute;
  inset: -24% -12% -8%;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(52% 50% at 50% 42%, var(--lueur-douce, transparent), transparent 72%);
  filter: blur(32px);
}
.fiche__affiche {
  width: auto; height: auto;
  max-width: 100%;
  max-height: min(44vh, 24rem);
  aspect-ratio: var(--r, 1);
  object-fit: contain;
  border-radius: var(--rayon);
  display: block;
  background: none;
  box-shadow:
    0 28px 64px -28px var(--lueur-douce, rgba(0, 0, 0, 0.8)),
    0 4px 16px rgba(0, 0, 0, 0.55);
}

/* ---------- CE QUE L'AFFICHE NE DIT JAMAIS ----------
   Elle porte le nom, l'artiste, souvent la salle. Elle n'ecrit jamais
   « dans 2 h 13 » : c'est la seule chose qu'on apporte, et elle a donc
   sa ligne, dans la couleur de l'affiche. */
.fiche__intro { padding-inline-end: 0; display: flex; flex-direction: column; gap: 8px; }
.fiche__titre { font-size: var(--t-section); line-height: 1.14; letter-spacing: -0.015em; }
/* La date en petites capitales espacees : la meme ligne que sous un titre
   de nuit — « 10/09 · 27 EVENTS » la-bas, « TODAY · 10/09 · 12:00 » ici. */
.fiche__quand {
  margin: 0; color: var(--encre-tres-basse); font-size: var(--t-legende); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.24em;
}

.fiche__etat {
  margin: 0;
  align-self: start;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: var(--t-menu); font-weight: 600;
  letter-spacing: 0.04em;
  color: color-mix(in srgb, var(--lueur, var(--encre)) 88%, white);
  background: color-mix(in srgb, var(--lueur, var(--encre)) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--lueur, var(--encre)) 26%, transparent);
  font-variant-numeric: tabular-nums;
}
.fiche__point {
  flex: none; width: 8px; height: 8px; border-radius: 50%;
  background: var(--lueur, var(--encre));
  box-shadow: 0 0 10px 1px var(--lueur, transparent);
}
@media (prefers-reduced-motion: no-preference) {
  .fiche__etat--en-cours .fiche__point { animation: fichebat 2.4s ease-in-out infinite; }
  @keyframes fichebat { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
}

/* ---------- LES FAITS ----------
   Les libelles reculent, les valeurs avancent : c'est la valeur qu'on est
   venu lire, pas le mot « OU ». */
.fiche__lignes { gap: 12px 24px; }
.fiche__lignes dt { font-size: var(--t-legende); letter-spacing: 0.16em; color: var(--encre-tres-basse); }
.fiche__lignes dd { font-size: var(--t-fort); font-weight: 600; }
.fiche__lien { border-bottom-color: color-mix(in srgb, var(--lueur, var(--trait-net)) 45%, transparent); }
.fiche__lien:hover { border-bottom-color: var(--lueur, var(--encre)); }

/* ---------- L'ACTION ----------
   Le bouton etait blanc — le seul element bruyant du panneau, et il ne
   disait rien de la soiree. Il prend la couleur de l'affiche : c'est la
   regle du site, « un seul accent, et il vient de l'image ». */
.fiche__billets {
  background: var(--lueur, var(--encre));
  color: var(--encre-bouton, #0a0a0c);
  font-size: var(--t-fort);
  box-shadow: 0 8px 28px -12px var(--lueur, transparent);
  transition: transform 200ms var(--pose), box-shadow 200ms var(--pose), filter 200ms var(--pose);
}
.fiche__billets:hover {
  transform: translateY(-2px);
  filter: brightness(1.08);
  box-shadow: 0 14px 36px -12px var(--lueur, transparent);
}
.fiche__pied { font-size: var(--t-menu); }

/* ---------- LA FERMETURE RECULE ----------
   Elle etait un disque sombre pose sur le titre. Elle se pose maintenant
   sur l'affiche, discrete, et ne s'affirme qu'au survol. */
.fiche__fermer { inset-inline-end: 12px; inset-block-start: 12px; }
.fiche__fermer button {
  background: rgba(8, 8, 10, 0.55);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: var(--encre-basse);
  transition: color 180ms var(--pose), background-color 180ms var(--pose);
}
.fiche__fermer button:hover { background: rgba(8, 8, 10, 0.8); color: var(--encre); }

@media (prefers-reduced-motion: reduce) {
  .fiche__billets { transition: none; }
  .fiche__billets:hover { transform: none; }
}

/* ---------- LA MOSAIQUE SE PLIE, ELLE NE SE COUPE PAS ----------
   Elle montrait douze affiches en annonçant « 44 events », sans rien pour
   dire que trente-deux manquaient. Elle les porte toutes desormais, et
   plafonne sa hauteur a deux rangees — la hauteur est mesuree sur la mise
   en page reelle (voir plierLesMosaiques), parce qu'un plafond en NOMBRE
   ferait deux rangees sur un bureau et neuf sur un telephone. */
.mosaique__rang {
  max-height: var(--haut-replie, none);
  overflow: hidden;
  transition: max-height 420ms var(--pose);
}
.mosaique--ouverte .mosaique__rang { max-height: var(--haut-tout, 400vh); }

/* Le bouton vit dans la meme famille que celui des etageres : meme forme,
   meme compte a l'interieur. Ce qu'il annonce est ce qui RESTE, pas le
   total — un « 27 » au-dessus de douze affiches ne dit rien d'utile. */
.mosaique__tout { margin: 0; }

@media (prefers-reduced-motion: reduce) {
  .mosaique__rang { transition: none; }
}

/* ---------- L'ETAT VIDE ----------
   Il n'affichait qu'« aucun evenement », seul au milieu d'un grand vide,
   avec le pied de page juste dessous : ça ressemblait a une page cassee.
   Il ne nommait ni le mot cherche, ni la ville, ni la section — les trois
   choses qui viennent de masquer la page — et rien n'offrait d'effacer la
   recherche, qui est pourtant ce qui la vide le plus souvent.

   Aligne a gauche, dans la marge, comme tout le reste : « le tout centre »
   est un interdit de DESIGN.md, et un etat vide n'a aucune raison d'y
   echapper. */
.etat {
  text-align: start;
  padding: 64px var(--marge) 16px;
  display: flex; flex-direction: column; gap: 8px;
  color: var(--encre-tres-basse);
}
.etat__titre {
  margin: 0;
  font-size: var(--t-section);
  font-weight: 600;
  color: var(--encre);
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.etat__sous {
  margin: 0;
  font-size: var(--t-legende);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--encre-tres-basse);
}
.etat__sorties {
  display: flex; flex-wrap: wrap; gap: 8px;
  padding: 8px var(--marge) 64px;
}
/* Les sorties partagent la forme du « voir tout » des etageres : meme
   bouton, meme compte a l'interieur. Ce qu'elles annoncent est ce qu'elles
   RENDENT — un bouton qui ne rendrait rien ne s'affiche pas. */
.etat__sorties .ailleurs {
  margin: 0;
  display: inline-flex; align-items: center; gap: 8px;
  /* La pastille du site, pas un lien souligne : la meme forme que « voir
     tout » sous un titre de nuit, avec son compte a l'interieur. */
  border: 1px solid var(--trait-net); border-radius: 999px; padding: 8px 24px;
  font-size: var(--t-legende); font-weight: 600; text-transform: uppercase; letter-spacing: 0.16em;
  color: var(--encre); text-decoration: none; background: none;
}
.etat__sorties .ailleurs:hover { background: rgba(255, 255, 255, 0.08); border-color: var(--encre-basse); }
.etat__sous { letter-spacing: 0.32em; }
.ailleurs__n {
  font-variant-numeric: tabular-nums;
  color: var(--encre-tres-basse);
  font-weight: 400;
}

/* ================================================================
   LE CHARGEMENT N'EST PAS UN VIDE — 10/09/2026
   Mesure avant : l'os avait 1,07:1 de contraste sur le fond. Un rapport
   de 1 signifie « la meme couleur » : le squelette etait litteralement
   invisible, indiscernable d'une page vide. Il dessinait en plus un hero
   qui n'existe plus depuis que la mosaique l'a remplace, et il faisait
   glisser un reflet — « aucun scintillement de squelette » est pourtant un
   interdit de DESIGN.md, ecrit avant lui.
   ================================================================ */

/* L'os n'est pas un rectangle gris : c'est une FLAQUE DE LUMIERE, comme si
   l'affiche allait s'allumer par derriere. C'est le vocabulaire du site —
   la lumiere, jamais l'aplat — et il rend l'attente lisible sans crier. */
.os {
  /* Le socle porte le contraste, le degrade ne fait que le modeler. La
     premiere version confiait TOUT au degrade : au centre de la tuile, la
     ou il s'eteint, l'os retombait a 1,15:1 sur le fond — au bord de
     l'invisible. Le socle a 8 % d'encre tient 1,36:1 partout, et la flaque
     de lumiere monte a ~1,45:1 en haut. Mesure : verifier-squelette. */
  background:
    radial-gradient(120% 100% at 50% 0%,
      color-mix(in srgb, var(--encre) 6%, transparent),
      transparent 70%),
    color-mix(in srgb, var(--encre) 8%, var(--fond-creux));
  background-size: auto;
  border-radius: 10px;
  animation: none;
}

/* L'ALLUMAGE SE FAIT UNE FOIS, PUIS PLUS RIEN NE BOUGE.
   C'est le meme geste que les vraies affiches, qui montent en arrivant. Une
   boucle serait le scintillement que DESIGN.md interdit ; et la page n'est
   pas muette pour autant — le point du logotype bat toutes les 4,2 s, et
   c'est lui, le signe que ça travaille. */
@media (prefers-reduced-motion: no-preference) {
  .mosaique--os .carreau {
    opacity: 0;
    animation: allumer 420ms var(--pose) forwards;
    animation-delay: var(--retard, 0ms);
  }
  @keyframes allumer {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: none; }
  }
}

/* LE SQUELETTE SE PLIE COMME LA VRAIE MOSAIQUE.
   Sans ça il posait onze tuiles sur trois rangees — 957 px — la ou la page
   se replie a deux, et tout remontait de 78 px quand les affiches
   arrivaient. Le pliage n'est pas mesurable ici, faute de donnees : on
   applique la meme formule que la vraie rangee — deux fois la hauteur d'une
   rangee, plus sa legende et son ecart. */
/* Le repli est MESURE, comme celui de la vraie mosaique : plierLesMosaiques()
   pose --haut-replie sur les deux rangees reellement dessinees. La hauteur
   ecrite ici en dur ne valait qu'a une largeur d'ecran, et le squelette
   s'arretait 49 px avant la vraie page. */
/* (rien a ecrire ici : .mosaique__rang porte deja le plafond mesure) */

.mosaique--os { pointer-events: none; }
.mosaique--os .carreau { cursor: default; }
.mosaique--os .affiche { aspect-ratio: var(--r, 1); }
.mosaique--os .carreau__texte { gap: var(--e1); }

/* Les lignes de texte : la largeur varie, comme de vrais titres. */
/* UN OS DE TITRE N'A PAS DE HAUTEUR ECRITE : IL A LA TYPOGRAPHIE DU TITRE.
   L'en-tete aligne ses elements sur la LIGNE DE BASE du texte. Un rectangle
   vide n'en a pas : il s'aligne par son bas, et l'en-tete du squelette
   faisait 8 px de plus que le vrai a toutes les largeurs. En donnant a l'os
   le corps et l'interligne du vrai titre — et une espace insecable pour
   qu'il ait une ligne — sa hauteur ET sa ligne de base tombent juste toutes
   seules, dans toutes les langues. Les deux nombres magiques ont disparu. */
.os--titre {
  width: 12rem; border-radius: 4px;
  font-family: var(--enseigne); font-size: var(--t-affiche); line-height: 1;
}
.os--sous {
  width: 7rem; border-radius: 4px;
  /* Le vrai sous-titre n'a pas d'interligne ecrit : « normal », donc 15 px
     pour 12 de corps. L'os doit avoir le meme, sinon 3 px de saut. */
  font-size: var(--t-legende); line-height: normal;
}
.os--heure { width: 3rem; height: 16px; border-radius: 4px; }
.os--titre-court { width: 76%; height: 14px; border-radius: 4px; }

/* LE SQUELETTE DOIT COMMENCER OU COMMENCE LA VRAIE PAGE.
   Il vit dans #etat, qui est un <p> : le navigateur donne 16px de marge a
   tout paragraphe, et comme la liste n'a pas de rembourrage en haut cette
   marge RESSORT du parent et pousse la page entiere. Avec les 64px de
   rembourrage de .etat, le squelette commençait 80px trop bas et tout
   sautait au moment ou les vraies affiches se posaient. */
.etat--squelette {
  margin: 0;
  padding: 0;
  display: block;
  text-align: start;
}
