:root {
  --bg: #050505;
  --fg: #f2f0e9;
  --muted: rgba(242, 240, 233, 0.55);
  --line: rgba(242, 240, 233, 0.18);
}

* { box-sizing: border-box; }

html, body {
  width: 100%;
  height: 100%;
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  overflow: hidden;
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

button {
  color: inherit;
  font: inherit;
}

.screen {
  position: fixed;
  inset: 0;
}

.intro-screen {
  display: grid;
  place-items: center;
  background:
    radial-gradient(circle at 50% 42%, rgba(255,255,255,0.045), transparent 34%),
    #050505;
  transition: opacity 1.2s ease, visibility 1.2s ease;
  z-index: 4;
}

.intro-screen.is-hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.intro-content {
  width: min(720px, calc(100vw - 48px));
  text-align: center;
}

.eyebrow {
  margin: 0 0 1.2rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-size: 0.72rem;
}

h1 {
  margin: 0;
  font-weight: 420;
  letter-spacing: -0.045em;
  font-size: clamp(4rem, 12vw, 10rem);
  line-height: 0.9;
}

.intro-text {
  max-width: 600px;
  margin: 2rem auto 2.6rem;
  color: rgba(242,240,233,0.76);
  font-size: clamp(1rem, 2vw, 1.28rem);
  line-height: 1.55;
}

/* LE TITRE EST L'ENTRÉE.
   Le bouton hérite entièrement de la typographie du h1 : il n'a ni cadre, ni
   fond, ni remplissage. Aucun mot n'indique qu'il est actif — le journal du
   projet demande de supprimer les mots explicatifs. À la place, une respiration
   très lente, qui signale qu'il se passe quelque chose sans rien dire. */
#enterButton {
  display: inline-block;
  border: 0;
  padding: 0;
  margin: 0;
  background: transparent;
  cursor: pointer;
  animation: title-breathe 5.5s ease-in-out infinite;
}

/* Au survol, le halo se fixe à son maximum. */
#enterButton:hover,
#enterButton:focus-visible {
  animation: none;
  color: #fffdf3;
  text-shadow: 0 0 clamp(30px, 6.5vw, 90px) rgba(255,246,214,0.34);
  outline: none;
}

/* La respiration porte sur la couleur ET sur le halo. La première version
   n'allait que de 80 % à 100 % d'opacité : mesuré à l'œil, c'est sous le seuil
   de perception, surtout étalé sur sept secondes. Le halo, lui, se voit —
   et c'est celui de la couronne, donc l'indice vient de la matière de la pièce. */
@keyframes title-breathe {
  0%, 100% {
    color: rgba(242,240,233,0.56);
    text-shadow: 0 0 0 rgba(255,246,214,0);
  }
  50% {
    color: rgba(255,253,243,1);
    text-shadow: 0 0 clamp(24px, 5vw, 70px) rgba(255,246,214,0.24);
  }
}

/* Mouvement réduit : l'animation est coupée, mais l'indice reste. La version
   précédente ne laissait rien du tout — le titre devenait indistinguable d'un
   simple titre, et plus rien n'indiquait qu'on pouvait entrer.

   CE QUE CETTE RÈGLE NE COUVRE PAS, ET POURQUOI.

   Le défilement du bandeau et la traversée de la Lune continuent. Ce n'est pas
   un oubli : ce sont les deux mouvements dont la pièce est faite. Les supprimer
   ne donnerait pas une version accessible de la pièce, cela donnerait une image
   fixe et un texte immobile — c'est-à-dire autre chose.

   La demande de mouvement réduit vise les animations qui surprennent :
   apparitions brusques, parallaxes, éléments qui bondissent. Ici le bandeau met
   huit minutes et quarante secondes à faire un tour complet, et l'éclipse
   plusieurs dizaines de minutes à traverser. Ce sont des mouvements continus,
   lents et prévisibles, sans à-coup ni changement de direction.

   Ce qui EST coupé : la respiration du titre, seule animation cyclique rapide
   de la pièce. */
@media (prefers-reduced-motion: reduce) {
  #enterButton {
    animation: none;
    color: rgba(255,253,243,0.96);
    text-shadow: 0 0 clamp(20px, 4vw, 52px) rgba(255,246,214,0.18);
  }
}

.text-button {
  border: 0;
  background: transparent;
  padding: 0;
  cursor: pointer;
  color: var(--muted);
}

#aboutButton {
  display: block;
  margin: 1.4rem auto 0;
  padding-bottom: 3px;
  border-bottom: 1px solid transparent;
  transition: color 400ms ease, border-color 400ms ease;
}

/* Survol retenu : la couleur monte et un filet apparaît sous le mot. Rien de
   plus — c'est un lien secondaire, il ne doit pas rivaliser avec le titre. */
#aboutButton:hover,
#aboutButton:focus-visible {
  color: rgba(242,240,233,0.94);
  border-bottom-color: rgba(242,240,233,0.26);
  outline: none;
}

.artwork-screen {
  background: #000;
  z-index: 1;
}

#scene {
  display: block;
  width: 100%;
  height: 100%;
}

/* Les icônes sont plus grandes depuis qu'on peut les masquer par la touche H :
   il n'y a plus de raison de les rendre discrètes au point d'être difficiles
   à viser. En exposition elles disparaissent complètement. */
.topbar {
  position: fixed;
  inset: 26px 30px auto 30px;
  z-index: 3;
  display: flex;
  justify-content: space-between;
  pointer-events: none;
}

.topbar button {
  pointer-events: auto;
  text-transform: uppercase;
  letter-spacing: 0.13em;
  font-size: 0.68rem;
}

/* Le bandeau est ancré au bas de l'écran : noir plein à la base, puis
   dissipation vers le haut. Aucune bordure — les filets d'un pixel qui
   traînaient en haut et en bas étaient visibles sur fond noir.
   Les arrêts sont resserrés vers le bas pour approcher une courbe douce :
   un dégradé à deux arrêts sur cette hauteur produit du banding 8 bits. */
.ticker {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  height: 118px;
  overflow: hidden;
  border: 0;
  display: flex;
  align-items: flex-end;
  background: linear-gradient(
    to top,
    rgb(0,0,0)        0%,
    rgba(0,0,0,0.985) 22%,
    rgba(0,0,0,0.92)  36%,
    rgba(0,0,0,0.78)  48%,
    rgba(0,0,0,0.58)  60%,
    rgba(0,0,0,0.38)  71%,
    rgba(0,0,0,0.21)  81%,
    rgba(0,0,0,0.09)  90%,
    rgba(0,0,0,0.02)  96%,
    rgba(0,0,0,0)     100%
  );
  pointer-events: none;
}

.ticker-track {
  display: inline-flex;
  align-items: center;
  min-width: max-content;
  height: 46px;
  margin-bottom: 26px;
  padding-left: 100vw;
  color: rgba(255,255,255,0.39);
  font-size: 0.82rem;
  letter-spacing: 0.085em;
  text-transform: uppercase;
  white-space: nowrap;
  animation: ticker-scroll 520s linear infinite;
  will-change: transform;
}

.ticker-track span::after {
  content: "  ·  ";
  margin: 0 1.2rem;
  color: rgba(255,255,255,0.13);
}

@keyframes ticker-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-100%); }
}

dialog {
  width: min(760px, calc(100vw - 32px));
  max-height: min(82vh, 780px);
  border: 1px solid var(--line);
  color: var(--fg);
  background: rgba(8,8,8,0.97);
  padding: 0;
  box-shadow: 0 30px 100px rgba(0,0,0,0.65);
}

dialog::backdrop {
  background: rgba(0,0,0,0.78);
  backdrop-filter: blur(7px);
}



.close-button {
  position: absolute;
  top: 18px;
  right: 22px;
  border: 0;
  background: transparent;
  font-size: 2rem;
  font-weight: 200;
  cursor: pointer;
  color: var(--muted);
}

@media (max-width: 700px) {
  .topbar { inset: 18px 18px auto 18px; }
  .ticker { bottom: 0; height: 86px; }
  .ticker-track {
    height: 34px;
    margin-bottom: 14px;
    font-size: 0.66rem;
    animation-duration: 500s;
  }
}


.artist-name {
  margin: 2.3rem 0 0;
  color: rgba(242,240,233,0.58);
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

a,
a:visited {
  color: rgba(242,240,233,0.58);
  text-decoration: none;
}

a:hover,
a:focus-visible {
  color: rgba(242,240,233,0.9);
  text-decoration: none;
}

/* Lisez-moi : fenêtre de surimpression, et non plus une page plein écran.
   La pièce reste visible derrière, ce qui rappelle qu'on ne l'a pas quittée.
   Fermeture par la croix ou par Échap — le dialogue natif s'en charge. */
#aboutDialog {
  position: fixed;
  inset: 0;
  width: min(820px, calc(100vw - 40px));
  max-width: none;
  height: min(86dvh, 900px);
  max-height: none;
  margin: auto;
  border: 1px solid rgba(242,240,233,0.13);
  border-radius: 4px;
  padding: 0;
  background: rgba(10,10,11,0.96);
  backdrop-filter: blur(20px);
  box-shadow: 0 40px 120px rgba(0,0,0,0.8);
  color: var(--fg);
  /* La fenêtre ne défile pas : c'est .readme-scroll qui défile. La barre
     supérieure reste ainsi toujours en place, croix comprise. */
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.readme-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Cible de focus programmée, pas un élément interactif : aucun cadre.
   Le focus y est posé à l'ouverture pour que les flèches défilent tout de
   suite, et pour qu'aucun bouton ne se retrouve encadré. */
.readme-scroll:focus,
.readme-scroll:focus-visible { outline: none; }

/* Si le visiteur atteint FR ou EN au clavier, il doit le voir — mais par un
   fond discret plutôt que par le cadre par défaut du navigateur. */
.lang-switch button:focus-visible {
  outline: none;
  background: rgba(255,255,255,0.10);
  color: rgba(242,240,233,0.94);
}

.readme-topbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  padding: 12px 16px 10px;
  border-bottom: 1px solid rgba(242,240,233,0.07);
  background: rgba(10,10,11,0.6);
}

/* Doit rester « flex » : un « block » ici écraserait la colonne déclarée
   plus haut et la barre supérieure cesserait d'être fixe. */
#aboutDialog[open] {
  display: flex;
}

#aboutDialog::backdrop {
  background: rgba(0,0,0,0.62);
  backdrop-filter: blur(3px);
}

.readme-page {
  width: min(100% - 56px, 900px);
  margin: 0 auto;
  padding: 26px 0 64px;
}

.readme-header {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  padding-top: 22px;
  padding-bottom: 30px;
  border-bottom: 1px solid rgba(242,240,233,0.12);
}

.readme-header h2 {
  margin: 0;
  font-weight: 420;
  letter-spacing: -0.04em;
  font-size: clamp(2.4rem, 6vw, 3.6rem);
  line-height: 1;
}

.readme-author {
  margin: 1.15rem 0 0;
  color: rgba(242,240,233,0.58);
  font-size: 0.74rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* Le texte était aligné à gauche dans un conteneur bien plus large :
   sur grand écran il flottait dans le vide à droite. Il est désormais
   centré dans la page, sa largeur de ligne restant celle de la lecture. */
.readme-content {
  width: 100%;
  margin: 0 auto;
  padding: 42px 0 0;
}

/* Sources — crédits des flux et des stations. Petit corps, séparé du texte. */
/* NOTE D'APPAREIL
   ---------------
   Invisible par défaut. Elle n'apparaît que là où elle dit vrai : app.js pose
   data-compact-audio sur <html> quand la couche radio est effectivement
   retirée. La note et le son obéissent donc à la MÊME condition — sinon la
   note finirait par décrire un comportement que l'appareil n'a pas, ce qui est
   pire que pas de note du tout.

   Elle n'est pas dans le corps du texte : c'est une précision technique sur ce
   qu'on entend, pas une phrase de la pièce. */
.note-appareil { display: none; }
html[data-compact-audio] .note-appareil { display: block; }

.note-appareil p {
  margin: 44px 0 0;
  padding-left: 14px;
  border-left: 1px solid rgba(242,240,233,0.16);
  font-size: 0.86rem;
  line-height: 1.6;
  color: rgba(242,240,233,0.56);
}

.readme-sources {
  margin-top: 56px;
  padding-top: 30px;
  border-top: 1px solid rgba(242,240,233,0.12);
}

.readme-sources h3 {
  margin: 0 0 14px;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(242,240,233,0.42);
}

.readme-sources h3:not(:first-child) { margin-top: 30px; }

.readme-sources p,
.readme-sources ul {
  margin: 0 0 10px;
  font-size: 0.83rem !important;
  line-height: 1.65 !important;
  color: rgba(242,240,233,0.52) !important;
}

.readme-sources ul {
  list-style: none;
  padding: 0;
  columns: 2;
  column-gap: 32px;
}

@media (max-width: 620px) {
  .readme-sources ul { columns: 1; }
}

.readme-sources li { margin: 0 0 4px; break-inside: avoid; }

/* Bascule de langue, dans la barre supérieure fixe. */
.lang-switch {
  display: flex;
  gap: 2px;
  align-items: center;
  flex: 0 0 auto;
  margin-right: auto;
}

.lang-switch button {
  border: 0;
  background: transparent;
  /* Remonté de 0,34 à 0,52 le 5 août 2026. À 0,34, le contraste sur le fond de
     la pièce tombait à 2,73:1, très en dessous du seuil de 4,5:1 : le bouton de
     langue inactif était à peine lisible. Ce n'est pas un parti plastique comme
     l'est la pâleur du bandeau — c'est une commande d'interface, et une
     commande doit se lire. À 0,52 le rapport passe à 5,10:1, et l'écart avec
     l'état actif (0,94) reste parfaitement net. */
  color: rgba(242,240,233,0.52);
  cursor: pointer;
  padding: 4px 7px;
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transition: color 0.35s ease;
}

.lang-switch button:hover { color: rgba(242,240,233,0.7); }
.lang-switch button[aria-pressed="true"] { color: rgba(242,240,233,0.94); }
.lang-switch .sep { color: rgba(242,240,233,0.18); font-size: 0.68rem; }

/* Une seule langue visible à la fois. Les deux restent dans le document, ce qui
   les laisse indexables et traduisibles.
   La sélection est portée par un attribut sur <html>, posé par un script en
   tête de page : la bonne langue est donc peinte dès le premier rendu, sans
   que l'autre n'apparaisse au passage. */
[data-lang] { display: none; }

html[data-lang-pref="fr"] [data-lang="fr"],
html[data-lang-pref="en"] [data-lang="en"] { display: block; }

html[data-lang-pref="fr"] span[data-lang="fr"],
html[data-lang-pref="en"] span[data-lang="en"] { display: inline; }

/* Sans JavaScript, aucun attribut n'est posé : on affiche le français. */
html:not([data-lang-pref]) [data-lang="fr"] { display: block; }
html:not([data-lang-pref]) span[data-lang="fr"] { display: inline; }

.readme-content p {
  margin: 0 0 1.65rem;
  color: rgba(242,240,233,0.69);
  font-size: clamp(1rem, 1.5vw, 1.14rem);
  line-height: 1.82;
}

.readme-content .readme-lead {
  margin-bottom: 2.2rem;
  color: rgba(242,240,233,0.92);
  font-size: clamp(1.1rem, 2vw, 1.42rem);
  line-height: 1.5;
  letter-spacing: -0.008em;
}

.site-link {
  margin-top: 2.4rem !important;
}

/* Toujours visible : elle est dans la barre fixe, hors du flux défilant. */
.close-button {
  position: static;
  flex: 0 0 auto;
  margin: 0;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  line-height: 1;
  border-radius: 4px;
  font-size: 1.55rem;
  transition: color .25s ease, background .25s ease;
}

.close-button:hover,
.close-button:focus-visible {
  color: rgba(242,240,233,0.95);
  background: rgba(255,255,255,0.07);
  outline: none;
}

@media (max-width: 700px) {
  .readme-page {
    width: min(100% - 32px, 1120px);
    padding-top: 18px;
  }

  .readme-header {
    min-height: 45vh;
    padding-top: 82px;
  }

  .readme-content {
    padding-top: 52px;
  }
}



/* Commandes de la pièce : signes uniquement, sans intitulé visible. */
.icon-button {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 0;
  padding: 0;
  background: transparent;
  color: rgba(210, 210, 206, 0.52);
  cursor: pointer;
  transition: color 700ms ease, opacity 700ms ease;
}

.icon-button:hover,
.icon-button:focus-visible {
  color: rgba(232, 232, 227, 0.82);
  outline: none;
}

.icon-button svg {
  width: 27px;
  height: 27px;
  overflow: visible;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.25;
  stroke-linecap: round;
  stroke-linejoin: round;
}

#soundButton svg path:first-child {
  fill: currentColor;
  stroke: none;
}

#soundButton[aria-pressed="false"] .sound-wave {
  opacity: 0;
}

#soundButton[aria-pressed="false"]::after {
  content: "";
  position: absolute;
  width: 19px;
  height: 1px;
  background: currentColor;
  transform: rotate(-45deg);
  transform-origin: center;
}

#soundButton {
  position: relative;
}

.sound-wave {
  transition: opacity 800ms ease;
}

@media (max-width: 700px) {
  .icon-button {
    width: 46px;
    height: 46px;
  }
}
