/* ─────────────────────────────────────────────────────────────────────────────
   Ancestral Beat — proto lecteur.
   Reprend les tokens du portfolio : Inter, #1C1C1E sur blanc, accent #3700FF,
   nav en colonne à gauche.
   ───────────────────────────────────────────────────────────────────────────── */

/* ── Grille ───────────────────────────────────────────────────────────────
   Deux mesures gouvernent la mise en page : la colonne réservée à la nav, et
   la largeur du contenu. Tous les blocs s'y alignent, et les marges gauche et
   droite sont égales pour que l'ensemble reste centré dans la fenêtre. */
:root {
  --marge-laterale: 170px;   /* de chaque côté, la nav tient dans celle de gauche */
  --contenu: 1080px;         /* largeur de la grille de contenu */
  --gouttiere: 56px;         /* entre la colonne de texte et son visuel */
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: #fff;
  color: #1C1C1E;
  /* Inter ne contient aucun caractère chinois : sans ces trois secours, le
     texte zh tomberait sur la police système par défaut, souvent laide et
     d'une graisse qui jure avec le reste. PingFang sur macOS et iOS,
     YaHei sur Windows, Noto Sans SC ailleurs. */
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue',
               'PingFang SC', 'Microsoft YaHei', 'Noto Sans SC', sans-serif;
  -webkit-font-smoothing: antialiased;
  /* Les navigateurs des téléphones agrandissent d'eux-mêmes le texte qu'ils
     jugent trop petit, surtout dans un bloc long (le crédit défilant, les
     paragraphes de Jouer) : le crédit passait de 14,5 à ~26 px et Jouer
     débordait sous le nom de page. Les tailles du site sont voulues. */
  -webkit-text-size-adjust: 100%;
          text-size-adjust: 100%;
}

body { overflow: hidden; }

/* ── Chargement du moteur audio ──────────────────────────────────────────────
   Les 79 échantillons mettent plusieurs secondes à arriver, surtout sur un
   réseau mobile. Le moteur commence à charger dès l'ouverture du site, quelle
   que soit la page — mais on peut descendre jusqu'à Écouter plus vite que le
   réseau. Sans signe visible, le visiteur touche l'écran, rien ne se passe, et
   il en conclut que le site est cassé.

   Deux signes, aucun élément nouveau : les commandes restent en retrait et
   sourdes aux clics, et la ligne d'état respire. Tout revient à la normale
   quand player.js pose `moteur-pret` sur le corps du document.

   Portée limitée à la page Écouter : les commandes vidéo de Jouer n'ont rien à
   voir avec le moteur audio, les éteindre pendant son chargement serait faux. */

body:not(.moteur-pret) #page-listen .transport,
body:not(.moteur-pret) #page-listen .track {
  opacity: 0.3;
  pointer-events: none;
}

#page-listen .transport,
#page-listen .track { transition: opacity 0.5s ease; }

/* La respiration est limitée à Écouter, comme l'affichage du statut lui-même.

   Sans ce `[data-page="listen"]`, elle s'appliquait partout — et une animation
   l'emporte sur les déclarations normales dans la cascade. Elle imposait donc
   son opacité par-dessus `#status { opacity: 0 }` et par-dessus la règle qui
   réserve le message à Écouter : pendant tout le chargement du moteur, la
   phrase respirait sur l'accueil et sur Jouer, où elle n'a rien à faire.

   C'est aussi pour ça que scoper la visibilité ne suffisait pas : les règles
   d'opacité étaient écrites, correctes, et sans effet. */
body[data-page="listen"]:not(.moteur-pret) #status {
  animation: respiration 1.6s ease-in-out infinite;
}

@keyframes respiration {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 1; }
}

/* ── Bouton de langue ───────────────────────────────────────────────────────
   Disque noir de 40 px en haut à droite, repris du portfolio. Il vit hors des
   pages, en `fixed`, pour rester au même endroit d'une page à l'autre pendant
   que celles-ci glissent. */

.lang-cycle {
  position: fixed;
  /* En haut à droite, où l'on cherche la langue ; en simple texte noir, sans
     disque autour : il ne pèse pas plus que le menu. Au survol, le violet des
     liens du site. */
  top: 26px;
  right: 26px;
  padding: 6px 4px;
  border: none;
  background: none;
  color: #1C1C1E;
  font: 500 13px/1 'Inter', 'PingFang SC', 'Microsoft YaHei', 'Noto Sans SC', sans-serif;
  letter-spacing: 0.05em;
  cursor: pointer;
  user-select: none;
  transition: color 0.2s ease;
  z-index: 300;
}

.lang-cycle:hover { color: #3700FF; }
.lang-cycle:focus-visible { outline: 2px solid #3700FF; outline-offset: 3px; }

/* L'icône mail, à gauche de la langue et sur sa ligne (contact.js). */
#contact-mail {
  position: fixed;
  top: 21px;
  right: 56px;
  padding: 8px;
  color: #1C1C1E;
  line-height: 0;
  transition: color 0.2s ease;
  z-index: 300;
}
@media (hover: hover) {
  #contact-mail:hover { color: #3700FF; }
}
#contact-mail:focus-visible { outline: 2px solid #3700FF; outline-offset: 1px; }
#contact-mail svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linejoin: round;
  stroke-linecap: round;
  transform-origin: 50% 20%;   /* accrochée par le haut, comme un balancier */
}
#contact-mail svg.balance { animation: balancier 1.3s ease-in-out; }

/* Une oscillation amortie : chaque aller moins ample que le précédent. */
@keyframes balancier {
  0%   { transform: rotate(0); }
  14%  { transform: rotate(-20deg); }
  32%  { transform: rotate(14deg); }
  50%  { transform: rotate(-9deg); }
  68%  { transform: rotate(5deg); }
  84%  { transform: rotate(-2deg); }
  100% { transform: rotate(0); }
}
@media (prefers-reduced-motion: reduce) {
  #contact-mail svg.balance { animation: none; }
}

#contact-adresse {
  position: fixed;
  top: 58px;
  right: 26px;
  padding: 3px 8px;
  border-radius: 6px;
  background: #fff;   /* lisible aussi par-dessus la vidéo de Jouer */
  font-size: 13px;
  color: #6E6E73;
  z-index: 300;
}
#contact-adresse[hidden] { display: none; }

/* ── Nav gauche ───────────────────────────────────────────────────────────── */

.nav {
  position: fixed;
  left: 32px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 10;
}

.nav a {
  display: block;
  position: relative;
  font-size: 14px;
  font-weight: 400;
  color: #1C1C1E;
  line-height: 1.6;
  text-decoration: none;
  transition: opacity 0.25s ease;
}

.nav a:hover { opacity: 0.45; }

.nav a.active { color: #3700FF; }

/* Pastille du lien actif, posée dans la marge pour ne pas décaler le texte */
.nav a.active::before {
  content: '';
  position: absolute;
  left: -12px;
  top: 50%;
  transform: translateY(-50%);
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #3700FF;
}

/* ── Colonne centrale ─────────────────────────────────────────────────────── */

/* Les pages sont empilées au même endroit et glissent verticalement.
   Pas de display:none pour masquer l'inactive : le canvas de l'herbe et la
   vidéo ont besoin d'une taille réelle pour se dimensionner correctement (le
   même piège que le hero du portfolio, où visibility:hidden cassait le viewport
   de l'iframe). On les sort du cadre par transform, elles restent rendues. */
.page {
  position: fixed;
  inset: 0;
  will-change: transform;
  /* Les cinq pages occupent le même rectangle. Sans état initial en CSS, elles
     s'empilent toutes visiblement entre l'affichage du HTML et le premier
     passage de pages.js — sur un téléphone lent, ça se voit franchement.
     Chaque fichier généré marque sa propre page avec `data-page-active`, ce qui
     règle la question avant même que le JavaScript ne démarre. */
  opacity: 0;
}

.page[data-page-active] { opacity: 1; }

/* La ligne d'état parle des knobs : elle n'a de sens que sur Écouter. Elle vit
   hors des pages, en position fixe, donc rien ne la masque d'elle-même — et au
   chargement elle s'affichait par-dessus l'accueil. */
#status { opacity: 0; }
body[data-page="listen"] #status { opacity: 1; }

.stage {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 34px;
  padding: 40px 20px;
}

/* ── Page Jouer ───────────────────────────────────────────────────────────── */

.statement {
  margin: 0;
  /* Le texte se répartit tout seul : plus de coupure forcée après le
     deux-points, la ligne tombe où la largeur le veut. */
  max-width: var(--cover, 300px);
  /* Pas de `font-size` ici : ce paragraphe vit dans `.identity`, donc
     `.identity p` (0,1,1) l'emporte sur `.statement` (0,1,0). La taille
     déclarée ici n'a jamais rien peint. Sa taille est celle du corps commun,
     et c'est très bien ainsi : c'est le même registre de texte. */
  font-weight: 400;
  line-height: 1.5;
  color: #1C1C1E;
}

/* La vidéo occupe exactement son cadre, qui a la taille de la pochette
   d'Écouter. Elle a débordé par le passé, du temps où elle était blanche et
   clairsemée et où il fallait zoomer dans son sujet (voir app/video.js).
   `overflow: visible` reste par prudence : si un futur réglage la fait
   déborder à nouveau, autant le voir plutôt que de le découvrir coupé. */
#page-jouer .cover {
  position: relative;
  overflow: visible;
}

.cover video {
  position: absolute;
  top: 0;
  left: 0;
  /* Taille et position posées en pixels ENTIERS par video.js.
     Les pourcentages donnaient des dimensions fractionnaires (147.6 % de 300 =
     442.797 px) et le compositeur du navigateur rendait ce bord partiel comme
     un liseré clair. Ni `transform`, ni `scale`, ni `background` ici : chacun
     ajoutait sa propre frange — le scale par son interpolation, le fond par le
     pixel qu'il laisse dépasser quand la vidéo ne couvre pas exactement. */
  /* `cover` ne recadre plus rien : le fichier est livré en 1:1, déjà découpé
     au centre du 16:9 d'origine. On le garde comme filet, pour qu'une future
     vidéo au mauvais format remplisse le cadre au lieu de se déformer. */
  object-fit: cover;
  cursor: pointer;     /* la vidéo elle-même déclenche lecture/pause */
  z-index: 0;
}

/* Le texte et les commandes repassent devant la vidéo qui déborde. */
#page-jouer .identity,
#page-jouer .track,
#page-jouer .transport {
  position: relative;
  z-index: 1;
  /* La réserve de `.transport` vaut la hauteur d'une barre plus son nom, pour
     que la rangée d'Écouter garde la même hauteur quoi qu'elle contienne.
     Jouer n'a pas de barres, juste trois disques de 46 px : la réserve y
     laissait 66 px de vide, et c'est ce vide qui faisait déborder la page sur
     une fenêtre de 900 px. La règle existait déjà pour le téléphone, elle
     manquait sur bureau. */
  min-height: 0;
}

.research {
  margin: 0;
  font-size: 15px;
  line-height: 1.5;
  color: #1C1C1E;
}

.research a {
  color: #3700FF;          /* les noms dans le violet des liens du site, soulignés */
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}

.research a:hover { text-decoration-thickness: 2px; }

/* Disques noirs — mêmes que les knobs, pour que les commandes de la vidéo
   appartiennent à la même famille visuelle. */
.disc {
  flex-shrink: 0;
  width: 46px;
  height: 46px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: #1C1C1E;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.2s ease;
}

.disc svg { width: 26px; height: 26px; display: block; }
.disc:hover  { opacity: 0.75; }
.disc:active { opacity: 0.55; }
.disc:focus-visible { outline: 2px solid #3700FF; outline-offset: 3px; }

/* Le disque de lecture fait exactement la taille d'un knob de Composer : les
   deux pages partagent la même famille de commandes rondes. */

/* Jouer, sur un seul écran : le titre (la taille et la graisse de la phrase
   de l'accueil), le bouton du jeu (le disque noir de « Stay informed »), la
   recherche en une ligne grise. */
/* `.identity` devant : la règle `.identity h1` (le nom, 20 px) l'emportait sur
   le titre d'Écouter, qui est un h1. */
.identity .jouer-titre {
  margin: 0;
  font-size: 26px;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: #1C1C1E;
}
.eng-cta.jouer-cta {
  display: block;          /* toute la largeur, sous la vidéo */
  width: 100%;
  box-sizing: border-box;
  margin: 0 0 26px;        /* de l'air avant la ligne de la recherche */
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
}

/* Le lecteur sur la vidéo : le disque au milieu (en pause, ou juste après un
   clic), la barre de lecture en bas au survol (au doigt : après un toucher). */
.video-disc {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}
.video-disc.visible { opacity: 1; pointer-events: auto; }
/* Survol réservé aux appareils qui en ont un (souris, trackpad). Sur iPhone,
   un :hover qui fait apparaître quelque chose transforme le premier toucher en
   « survol » : la barre s'affichait, mais le clic ne partait pas, et il
   fallait toucher une seconde fois pour lancer ou arrêter la vidéo. Au doigt,
   la barre vient de `.actif` (video.js). */
@media (hover: hover) {
  .video-disc.visible:hover { opacity: 0.75; }
  #page-jouer .cover:hover .video-barre,
  .nl-media:hover .video-barre { opacity: 1; pointer-events: auto; }
  .video-barre:hover { height: 6px; }
}

.video-barre {
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: 14px;
  height: 4px;
  z-index: 2;
  border-radius: 2px;
  background: rgba(28, 28, 30, 0.28);
  cursor: pointer;
  opacity: 0;
  /* Cachée, elle ne prend aucun geste : au doigt, on la déplaçait sans la
     voir. Le toucher passe alors à la vidéo, qui ouvre le menu. */
  pointer-events: none;
  transition: opacity 0.25s ease, height 0.15s ease;
  touch-action: none;
}
/* Une zone de prise plus haute que le trait, pour l'attraper sans viser. */
.video-barre::before { content: ''; position: absolute; left: 0; right: 0; top: -10px; bottom: -10px; }
#page-jouer .cover.actif .video-barre,
.nl-media.actif .video-barre,
.video-barre:focus-visible { opacity: 1; pointer-events: auto; }
.video-barre-rempli {
  width: 0;
  height: 100%;
  border-radius: inherit;
  background: #3700FF;
  pointer-events: none;
}


.identity { text-align: left; width: var(--cover, 300px); }

.identity h1 {
  margin: 0;
  font-size: 20px;
  font-weight: 500;
  letter-spacing: -0.01em;
}

.identity p {
  margin: 2px 0 0;
  font-size: 15px;
  font-weight: 400;
}

/* ── Pochette ─────────────────────────────────────────────────────────────── */

.cover {
  width: var(--cover, 300px);
  height: var(--cover-h, var(--cover, 300px));
  flex-shrink: 0;
  will-change: transform;
  position: relative;
}

/* L'invite à toucher l'écran : au doigt seulement, tant que le son est coupé
   (player.js, majInviteSon). Elle laisse passer le toucher : c'est le geste sur
   la page qui ouvre le son, pas un clic sur elle. */
.son-invite { display: none; }
@media (pointer: coarse) {
  body:not(.son-actif) .son-invite {
    display: block;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    padding: 11px 18px;
    border-radius: 999px;
    background: #1C1C1E;
    color: #fff;
    font-size: 14px;
    font-weight: 500;
    white-space: nowrap;
    pointer-events: none;
  }
}

/* ── Carrousel des morceaux ───────────────────────────────────────────────── */
/* La carte courante vit dans le flux ; ses voisines sont clonées en position
   absolue de part et d'autre, hors du cadre. Le conteneur masque le débordement
   pour qu'on ne voie arriver la suivante qu'au moment du geste. */
.carousel {
  position: relative;
  /* Plus large que la carte pour laisser voir un bout des voisines — mais les
     bords s'effacent en dégradé, si bien qu'elles se devinent en arrivant au
     lieu de surgir d'un coup. La carte courante, elle, tient dans la zone
     pleinement opaque du milieu. */
  width: calc(var(--cover, 300px) * 2.1);
  display: flex;
  justify-content: center;
  /* Coupure franche et serrée : la carte courante occupe 25 %–75 % du conteneur,
     et la bascule vers le transparent se fait sur 5 % à peine de chaque côté
     (~36 px). La voisine reste donc invisible jusqu'au dernier moment, puis
     apparaît d'un coup au lieu de se deviner sur toute la largeur. */
  -webkit-mask-image: linear-gradient(90deg,
      transparent 20%, #000 25%, #000 75%, transparent 80%);
          mask-image: linear-gradient(90deg,
      transparent 20%, #000 25%, #000 75%, transparent 80%);
}

.slide {
  display: flex;
  flex-direction: column;
  gap: 34px;
  width: var(--cover, 300px);
  will-change: transform;
}

/* Les clones se superposent au flux sans le pousser. */
.slide.voisine {
  position: absolute;
  top: 0;
  left: 50%;
  margin-left: calc(var(--cover, 300px) / -2);   /* centrée comme la carte réelle */
  pointer-events: none;
}

/* La carte de Composer se saisit à la souris pour changer de morceau. */
#page-listen .slide { cursor: grab; }
#page-listen .slide:active { cursor: grabbing; }

.cover canvas { display: block; }

/* ── Bloc morceau ─────────────────────────────────────────────────────────── */

.track { width: var(--cover, 300px); }

.track-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.track-title {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.track-pos {
  font-size: 12px;
  font-weight: 400;
  color: #8a8a8e;
  font-variant-numeric: tabular-nums;
}

/* Crédit défilant, façon afficheur de gare : le texte fait le tour en continu
   sur la largeur de la pochette. Deux copies identiques se suivent et la piste
   glisse de -50 % : quand la première copie sort, la seconde est exactement à sa
   place, donc la boucle ne se voit pas. */
.track-credit {
  margin: 3px 0 0;
  width: var(--cover, 300px);
  overflow: hidden;
  white-space: nowrap;
  font-size: 14.5px;
  font-weight: 400;
  color: #1C1C1E;
  /* masque les bords : le texte s'efface au lieu d'être tranché net.
     Fondu court (2 %, soit ~6 px) : juste de quoi adoucir la coupe sans manger
     une lettre entière à chaque bout. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 2%, #000 98%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 2%, #000 98%, transparent);
}

.marquee-track {
  display: inline-flex;
  will-change: transform;
  animation: marquee var(--marquee-dur, 18s) linear infinite;
}

.marquee-item { padding-right: 3.5em; }

@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* Un texte qui bouge en permanence gêne certaines personnes — et le défilement
   n'apporte rien si tout tient déjà dans la largeur. */
/* ── La lueur des grands titres et des boutons noirs ─────────────────────── */
/* Derrière les grandes phrases (l'accueil, Jouer, Écouter, la citation de
   Composer) et autour des boutons noirs (Scroll down, Play the game, les
   flèches d'Écouter, S'inscrire) : un halo gris clair (#6E6E73, pour que la
   lettre garde son noir Apple au lieu de s'épaissir en noir), serré, qui
   scintille vite, par petits clignotements irréguliers (jamais deux pareils
   dans un cycle).

   Le halo est dessiné une fois, à son plus fort, sur un calque à part ; seule
   la transparence de ce calque clignote. Animer l'ombre elle-même obligeait le
   navigateur à redessiner le texte ou le bouton à chaque image, en permanence
   et sur toutes les pages : au téléphone, le site en ralentissait. Une
   transparence s'anime sans rien redessiner.
     - Titres : une copie du titre, invisible sauf son halo, posée juste
       derrière lui (app/lueur.js), `.lueur-calque`.
     - Boutons : un pseudo-élément de la taille du bouton, qui ne porte que
       l'ombre. */
@keyframes lueur {
  /* La transparence de chaque étape : l'intensité de l'ancien halo animé
     rapportée à son plus fort (31 %). */
  0%, 100% { opacity: 0.53; }
  9%       { opacity: 0.88; }
  17%      { opacity: 0.47; }
  31%      { opacity: 1; }
  38%      { opacity: 0.56; }
  54%      { opacity: 0.38; }
  63%      { opacity: 0.85; }
  71%      { opacity: 0.53; }
  86%      { opacity: 0.94; }
}

.lueur-calque {
  position: absolute;
  margin: 0;
  color: transparent;
  text-shadow: 0 0 7px rgba(110, 110, 115, 0.34), 0 0 14px rgba(110, 110, 115, 0.16);
  pointer-events: none;
  user-select: none;
  will-change: opacity;
  animation: lueur 1.8s linear infinite;
}
.lueur-calque * { color: transparent !important; }   /* les liens et le nom aussi */
.lueur-hote { position: relative; }   /* le titre et sa copie (app/lueur.js) */
/* Le tremblement : chaque lettre d'un titre qui brille est une balise à elle.
   `position: relative` (et pas un `inline-block`) : la lettre se décale sans
   rien changer à la coupure des lignes ni au crénage. app/lueur.js la pousse
   de moins d'un pixel, par instants, avec `left` et `top`. */
.lettre-tremble { position: relative; }

/* Le titre passe devant sa copie. */
#page-accueil .accueil-phrase h1,
#page-accueil .accueil-signature,
.identity .jouer-titre,
.eng-citation p {
  position: relative;
  z-index: 1;
}

#btn-descendre,
.eng-cta.jouer-cta,
.skip,
#form-newsletter button {
  isolation: isolate;
}
.eng-cta.jouer-cta,
.skip,
#form-newsletter button { position: relative; }   /* #btn-descendre est déjà placé */
#btn-descendre::after,
.eng-cta.jouer-cta::after,
.skip::after,
#form-newsletter button::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 0 7px rgba(110, 110, 115, 0.34), 0 0 14px rgba(110, 110, 115, 0.16);
  pointer-events: none;
  will-change: opacity;
  animation: lueur 1.8s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  /* La lueur reste, immobile. */
  .lueur-calque,
  #btn-descendre::after,
  .eng-cta.jouer-cta::after,
  .skip::after,
  #form-newsletter button::after {
    animation: none;
    opacity: 0.65;
  }

  /* La respiration s'arrête : c'est le texte qui porte l'information, pas le
     mouvement. */
  body[data-page="listen"]:not(.moteur-pret) #status { animation: none; opacity: 1; }

  .marquee-track { animation: none; }
  .track-credit { mask-image: none; -webkit-mask-image: none; text-overflow: ellipsis; }
}

/* ── Transport : prev — knobs — next ──────────────────────────────────────── */

.transport {
  width: var(--cover, 300px);
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-top: 4px;
  min-height: calc(var(--barre-h) + 24px);   /* les barres et leur nom */
}

/* Morceau précédent / suivant : un disque noir, l'icône blanche (la famille
   des disques de Jouer et des knobs). */
.skip {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  margin-top: calc(var(--barre-h) / 2 - 20px);   /* centre le disque sur le milieu des barres */
  padding: 0;
  border: none;
  border-radius: 50%;
  background: #1C1C1E;
  color: #F5F5F7;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.2s ease;
}
.skip svg { width: 18px; height: 18px; display: block; }

.skip:hover  { opacity: 0.75; }
.skip:active { opacity: 0.55; }
.skip:focus-visible { outline: 2px solid #3700FF; outline-offset: 3px; }

#knob-row {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 6px;
  flex: 1;
}

/* ── Knobs : barres verticales (app/knobs.js) ─────────────────────────────── */
/* Comme le volume de l'iPhone : une gélule grise qui se remplit de noir par
   le bas, et le nom du réglage en dessous. */

:root {
  --barre-l: 36px;
  --barre-h: 88px;
}

/* ── Les barres : un rail fin et un curseur rond ─────────────────────────────
 *
 * Elles ont d'abord été des pilules pleines, remplies de gris foncé sur un fond
 * gris clair. Deux gris pour une commande, c'était la seule zone du site à
 * fonctionner ainsi, et ça pesait lourd à l'oeil pour quatre réglages.
 *
 * Désormais : un rail de 2 px, la part réglée en violet du site, et un curseur
 * rond posé dessus. L'objet se lit comme un fader de console plutôt que comme
 * une jauge qui se remplit.
 *
 * LA ZONE DE SAISIE NE CHANGE PAS. `.knob-barre` garde ses 36 px de large, elle
 * devient seulement transparente : c'est elle qu'on attrape, et le rail n'est
 * qu'un décor dessiné au milieu. Réduire l'élément à la largeur du rail aurait
 * donné une cible de 2 px, intenable au doigt.
 *
 * `gap: 16px` et non 8 : le curseur est centré sur le haut de la part réglée,
 * donc il déborde sous le rail quand la barre est à zéro, de 6 px pour les
 * ronds et de 10 px pour le carré de « tension ». Il faut au moins autant
 * d'air avant le nom du knob, sinon les deux se touchent. La gouttière est
 * commune à toute la rangée et non réglée knob par knob : sinon les noms ne
 * seraient plus alignés entre eux.
 */
.knob {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  /* Les barres se PARTAGENT la rangée au lieu d'en réserver 64 px chacune.
     Une réserve fixe est un pari sur la longueur du mot, et ce pari est faux
     dans au moins une langue : « brighten » fait 47 px, « drift » en fait 23,
     et le chinois 25. Avec `flex`, la rangée tient par construction, quelle
     que soit la langue et quelle que soit la largeur de la colonne.
     `min-width: 0` est indispensable : sans lui, un élément flex refuse de
     passer sous la largeur de son contenu et la rangée déborde quand même. */
  flex: 1 1 0;
  min-width: 0;
}

.knob-barre {
  position: relative;
  width: var(--barre-l);      /* la cible du doigt, invisible */
  height: var(--barre-h);
  background: transparent;
  overflow: visible;          /* le curseur déborde aux deux extrêmes */
  cursor: grab;
  touch-action: none;
}

/* Le rail, dans le violet du site très atténué. */
.knob-barre::before {
  content: '';
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: 0;
  bottom: 0;
  width: 2px;
  border-radius: 1px;
  background: rgba(55, 0, 255, 0.22);
}

/* La part réglée : le même rail, en plein. `height` est écrit par knobs.js. */
.knob-remplissage {
  position: absolute;
  left: 50%;
  right: auto;
  bottom: 0;
  transform: translateX(-50%);
  width: 2px;
  border-radius: 1px;
  background: #3700FF;
  pointer-events: none;
}

/* Le curseur rond, centré sur le haut de la part réglée. */
.knob-remplissage::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 0;
  transform: translate(-50%, -50%);
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #3700FF;
  transition: width 0.15s ease, height 0.15s ease, box-shadow 0.15s ease;
}

/* C'est le curseur qui réagit, pas la barre entière : agrandir tout le bloc le
   faisait sauter d'un pixel au survol, ce qui se voyait sur un rail aussi fin. */
.knob-barre:hover .knob-remplissage::after,
.knob-barre.tiree .knob-remplissage::after {
  width: 16px;
  height: 16px;
}

.knob-barre.tiree { cursor: grabbing; }

/* L'anneau de focus se pose sur le curseur. Sur `.knob-barre` il dessinait un
   rectangle de 36 px autour de rien, l'élément étant devenu transparent. */
.knob-barre:focus-visible { outline: none; }
.knob-barre:focus-visible .knob-remplissage::after {
  box-shadow: 0 0 0 3px rgba(55, 0, 255, 0.3);
}

/* ── Le knob lourd ───────────────────────────────────────────────────────────
 *
 * « tension », sur Recade, résiste : il faut trois hauteurs de barre pour le
 * parcourir au lieu d'une (`resistance` dans app/knobs.js). C'est le seul
 * réglage qui déclenche quelque chose d'irréversible, le vacuum puis le drop
 * au tour de boucle suivant, et le seul dont la montée raconte une attente.
 *
 * Le poids doit donc se voir avant de se sentir, sinon le premier geste passe
 * pour une barre cassée. Le rail ne change pas, la part réglée reste du même
 * violet que les autres : la barre appartient à la série. C'est le CURSEUR qui
 * dit tout, un carré noir là où les autres ont un petit rond violet. Un angle
 * droit et une masse sombre, sur un rail de 2 px, ça pèse.
 *
 * Deux pistes écartées en chemin. Le curseur en anneau, creux au milieu : il
 * distinguait bien le knob, mais un anneau se lit comme plus LÉGER qu'une
 * forme pleine, l'inverse de ce qu'on voulait dire. Puis un rail épaissi et un
 * rond plus gros : trop discret, et ça abîmait l'alignement de la rangée.
 *
 * La classe est posée par knobs.js dès que `resistance` dépasse 1 : le dessin
 * suit le comportement au lieu d'être réglé à part, donc les deux ne peuvent
 * pas se contredire. */
.knob-lourd .knob-remplissage::after {
  width: 20px;
  height: 20px;
  border-radius: 0;          /* le carré, contre le rond des autres */
  background: #1C1C1E;
}

.knob-lourd .knob-barre:hover .knob-remplissage::after,
.knob-lourd .knob-barre.tiree .knob-remplissage::after {
  width: 24px;
  height: 24px;
}

.knob-label {
  white-space: nowrap;   /* un nom de réglage ne se coupe pas en deux */
  font-size: 12px;
  line-height: 1.25;
  text-align: center;
  color: #1C1C1E;
}

/* ── Accueil ──────────────────────────────────────────────────────────────── */
/* La phrase de présentation, à la place du portrait : grande, posée seule. */
#page-accueil .accueil-phrase { width: min(580px, 86vw); }
#page-accueil .accueil-phrase h1,
#page-accueil .accueil-signature {
  font-size: 26px;
  font-weight: 500;
  line-height: 1.38;
  letter-spacing: -0.01em;
  color: #1C1C1E;
}
/* L'auteur de la citation, en face de sa fin. */
#page-accueil .accueil-signature { margin: 16px 0 0; font-size: 18px; text-align: right; }
#page-accueil .accueil-signature .nom { white-space: nowrap; }   /* le nom ne se coupe jamais */

/* Bouton « Scroll down » : même disque noir que le CTA de Composer. */
/* Le bouton qui invite à descendre est posé en bas de l'écran : c'est un
   appel vers le bas. */
#btn-descendre {
  position: absolute;
  left: 50%;
  bottom: calc(30px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  margin: 0;
  white-space: nowrap;   /* « Swipe up to discover » sur une ligne */
}


/* ── Statut (chargement / invite au clic) ─────────────────────────────────── */

#status {
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translateX(-50%);
  font-size: 14px;
  color: #8a8a8e;
  transition: opacity 0.4s ease;
  pointer-events: none;
}

/* ── Format ───────────────────────────────────────────────────────────────── */

/* DEUX mesures, et c'est tout le sujet.
   `--cover` est la LARGEUR de la colonne : la pochette, le carrousel, le bloc
   de texte et la rangée de barres s'y accrochent tous.
   `--cover-h` est la HAUTEUR de la pochette, et elle seule.

   Les deux n'ont longtemps fait qu'une, et ça cassait. Une seule variable
   suivait la hauteur de la fenêtre, donc rétrécir la page en vertical
   rétrécissait aussi la colonne en horizontal. La rangée de barres de Recade,
   qui réclame 358 px pour ses quatre réglages et ses deux boutons, débordait
   alors par la droite sur TOUTE fenêtre de moins de 798 px de haut. Autant dire
   la plupart des fenêtres non maximisées. Une contrainte verticale volait de la
   place à une rangée qui n'a rien à voir avec la hauteur.

   Séparées, la pochette devient un RECTANGLE quand la fenêtre raccourcit, au
   lieu d'un carré plus petit. Le champ d'herbe s'y prête : `grass-cover.js`
   déduit sa hauteur de simulation du rapport du conteneur, donc une pochette
   plus basse dessine moins de rangées de brins, à taille de brin inchangée.
   On ne réduit rien, on recadre.

   Bénéfice qu'on n'avait pas cherché : la colonne ne se réorganise plus quand
   on redimensionne en vertical. Le titre du morceau et le crédit défilant
   gardaient leur largeur comme ils pouvaient, ils ne bougent plus.

   Les bornes. En largeur, 420 px au plus (au-delà la pochette écrase le texte
   qui l'accompagne) et 300 px au moins (en dessous, les blocs de texte se
   replient sur plus de lignes et la colonne se retourne contre elle-même :
   mesuré sur Jouer, passer de 300 à 260 rend 40 px de pochette et en reprend
   117 en texte). En hauteur, 220 px au moins : plus bas, le champ d'herbe n'est
   plus qu'un bandeau. Et jamais plus haut que la largeur, pour que la pochette
   ne devienne pas un portrait.

   Les 484 px retranchés à la hauteur sont ce que prennent le nom, le bloc
   morceau, le transport, les gouttières et les marges, mesurés sur JOUER qui
   est la page la plus chargée des trois. */
:root {
  --cover:   clamp(300px, calc(100vw - 400px), 420px);
  --cover-h: clamp(220px, calc(100vh - 484px), var(--cover));
}



/* ── Fenêtre courte ───────────────────────────────────────────────────────────
   Une fenêtre qu'on n'a pas maximisée fait vite 640 px de haut, et Jouer n'y
   tenait pas : 711 px de contenu pour 640 px de cadre, le texte du haut passait
   sous le bord. Le défaut est antérieur aux tailles de corps, il vient de la
   page elle-même, qui porte un paragraphe, une pochette, des liens et une barre
   de transport.

   On reprend sur les blancs, et sur eux seuls : contrairement à la colonne,
   ils ne changent pas la longueur du texte. Les gouttières passent de 34 à
   20 px et les marges hautes et basses de 40 à 24 px, soit 74 px récupérés.

   Le seuil est à 820 px parce que c'est là que Jouer commence à manquer d'air,
   pas à 700. Et la règle vaut pour les trois pages, pas pour la seule qui en a
   besoin : à hauteur égale elles doivent garder le même rythme, sinon l'écart
   se voit en passant de l'une à l'autre.

   Ça ne sauve pas tout. Sous ~710 px de fenêtre, Jouer déborde encore : elle
   porte un paragraphe, une vidéo, un bloc de liens et une barre de transport,
   et la colonne est déjà à sa borne basse. Le défaut est antérieur — avant ces
   réglages elle débordait sous ~711 px — mais il n'est pas réglé pour autant. */
@media (max-height: 820px) and (pointer: fine) {
  .stage {
    gap: 20px;
    padding: 24px 20px;
  }
  /* Barres plus courtes : le nom sous chaque barre ne doit pas passer sous la
     ligne d'état, fixée en bas de l'écran. */
  :root { --barre-h: 68px; }
}
@media (max-height: 700px) and (pointer: fine) {
  :root { --barre-h: 48px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Page Composer — Tension Engine

   Voir PAGE_ENGINE.md. Rien de nouveau côté identité : Inter, #1C1C1E sur
   blanc, accent #3700FF, disques noirs. Une seule liberté, décidée ensemble :
   le titre « Tension Engine », plus grand que tout le reste du site.
   Pas de filet noir entre les sections — l'espace fait la séparation.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Cette page défile sur elle-même, contrairement à Listen et Jouer qui
   tiennent dans un écran. */
.page-longue { overflow: hidden; }

.doc {
  height: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: none;
  /* La nav est en position fixe à gauche : sur les autres pages le contenu est
     centré dans la fenêtre et passe à côté, mais ici il occupe toute la
     largeur et passerait dessous. On lui réserve sa colonne. */
  /* Marges identiques des deux côtés : le contenu reste centré dans la
     fenêtre, et la nav, en position fixe, tient dans la marge de gauche. */
  padding: 0 var(--marge-laterale) 140px;
}

.doc::-webkit-scrollbar { display: none; }

/* ── Titre ──────────────────────────────────────────────────────────────── */

.eng-tete {
  /* Largeur propre, plus étroite que la grille : titre et disque se serrent
     l'un contre l'autre au centre, au lieu d'être poussés aux extrémités. */
  max-width: 760px;
  margin: 0 auto 130px;
  min-height: 70vh;
  display: grid;
  grid-template-columns: auto auto;
  justify-content: center;
  gap: 48px;
  align-items: center;
}

/* Disque d'herbe, calé sur la hauteur du titre sur deux lignes. */
.eng-rond {
  width: clamp(200px, 26vw, 320px);
  aspect-ratio: 1;
}

.eng-rond canvas { display: block; }

.eng-titre {
  margin: 0;
  font-size: clamp(44px, 7vw, 86px);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 0.98;
  color: #1C1C1E;
}

.eng-accroche {
  margin: 12px 0 0;
  max-width: 300px;
  font-size: clamp(17px, 1.8vw, 21px);
  font-weight: 400;
  color: #1C1C1E;
}

.eng-cta {
  margin-top: 26px;
  padding: 11px 26px;
  border: none;
  border-radius: 22px;
  background: #1C1C1E;
  color: #fff;
  font-family: inherit;
  font-size: 15.5px;
  cursor: pointer;
  transition: opacity 0.2s ease;
}

.eng-cta:hover { opacity: 0.75; }
.eng-cta:focus-visible { outline: 2px solid #3700FF; outline-offset: 3px; }

/* ── Citation ───────────────────────────────────────────────────────────── */

.eng-citation {
  max-width: 620px;
  margin: 0 auto 150px;
  text-align: center;
}

.eng-citation p {
  margin: 0;
  font-size: clamp(19px, 2.6vw, 27px);
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: -0.01em;
  color: #1C1C1E;
}

.eng-citation cite {
  display: block;
  margin-top: 20px;
  font-size: 15px;
  font-style: normal;
  color: #8a8a8e;
}

/* La signature est le logo d'Asakan plutôt que son nom écrit. Il reste petit :
   c'est la phrase qu'on doit lire, la signature ne fait que la créditer. Le
   fichier fourni ne mesure que 75 x 55 px, donc 27 px de haut le laisse à peu
   près au double de sa taille d'affichage, et il tient sur un écran fin. */
.eng-citation cite a {
  display: inline-block;
  line-height: 0;   /* pas d'interligne parasite sous l'image */
  transition: opacity 0.2s ease;
}

.eng-citation cite a:hover { opacity: 0.55; }
.eng-citation cite a:focus-visible { outline: 2px solid #3700FF; outline-offset: 4px; }

.eng-citation cite img {
  display: inline-block;
  height: 27px;
  width: auto;
}

/* ── Bandes : texte d'un côté, visuel de l'autre ────────────────────────── */

.eng-bande {
  max-width: var(--contenu);
  margin: 0 auto 150px;
  display: grid;
  /* La colonne de texte reste plus étroite que son visuel : une ligne trop
     longue se lit mal.

     Les proportions vont de pair avec la gouttière. Elle est passée de 96 à
     56 px, et les quarante pixels récupérés sont allés entièrement au texte :
     0,72/1,28 devient 0,77/1,23, ce qui laisse le visuel à sa taille exacte
     (630 px) et fait passer le texte de 354 à 394 px. Réduire la gouttière
     sans toucher aux proportions aurait élargi les deux colonnes à parts
     égales, donc n'aurait presque rien donné au texte. */
  grid-template-columns: 0.77fr 1.23fr;
  gap: var(--gouttiere);
  align-items: center;
}

/* Une bande sur deux inverse l'ordre : c'est l'alternance qui donne le rythme
   à la page. `order` plutôt qu'un second jeu de colonnes, pour que l'ordre de
   lecture du HTML reste celui du sens.
   Les proportions s'inversent aussi, sinon le visuel se retrouverait dans la
   colonne étroite et paraîtrait deux fois plus petit d'une section à l'autre. */
.eng-inverse             { grid-template-columns: 1.23fr 0.77fr; }
.eng-inverse .eng-mots   { order: 2; }
.eng-inverse .eng-visuel { order: 1; }

.eng-mots h2 {
  margin: 0 0 12px;
  font-size: clamp(21px, 2.4vw, 27px);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.015em;
}

.eng-mots p {
  margin: 0;
  font-size: 16.5px;
  line-height: 1.6;
  color: #1C1C1E;
}

.eng-visuel {
  margin: 0;
  border-radius: 10px;
  overflow: hidden;
  background: #f2f2f4;   /* le temps que le média arrive */
  position: relative;
}

.eng-visuel img,
.eng-visuel video {
  display: block;
  width: 100%;
  height: auto;
}

/* La vidéo couvre son image d'attente, et ne se montre qu'une fois lancée
   (engine-page.js) : c'est l'image qui donne sa taille au cadre. */
.eng-visuel video {
  position: absolute;
  inset: 0;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.25s ease;
}
.eng-visuel video.prete { opacity: 1; }

/* ── Compatibilité ──────────────────────────────────────────────────────── */

.eng-compat {
  max-width: 660px;
  margin: 0 auto 120px;
  text-align: center;
}

.eng-compat h2 {
  margin: 0 0 10px;
  font-size: clamp(19px, 2.2vw, 24px);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.eng-compat p {
  margin: 0 0 28px;
  font-size: 16px;
  color: #1C1C1E;
}

.eng-logos {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 26px 52px;
}

/* Les fichiers sont rognés au ras de l'encre : la hauteur ci-dessous est donc
   la hauteur réelle du logo, pas celle d'un cadre. Reste que les cinq marques
   n'ont pas la même construction — un logo empilé sur deux étages et un
   simple mot posé sur une ligne ne pèsent pas pareil à hauteur égale. D'où un
   réglage par logo, fait à l'œil.

   Deux familles : les logos empilés (symbole au-dessus du nom) montent haut,
   les logos d'une seule ligne restent bas. */
.eng-logos img {
  display: block;
  height: 42px;   /* Wwise : symbole au-dessus du mot, sert de référence */
  width: auto;
}

/* Unreal empile lui aussi, mais son nom est écrit en petites capitales sous le
   symbole : il lui faut la hauteur la plus grande pour rester lisible. */
.eng-logos .logo-haut { height: 62px; }

/* Godot : symbole et nom empilés, mais plus ramassés que ceux d'Unreal. */
.eng-logos .logo-carre { height: 44px; }

/* Les deux logos d'une seule ligne. Leur nom occupe toute la hauteur, donc une
   valeur basse suffit à leur donner le même poids optique que les empilés. */
.eng-logos .logo-ligne { height: 26px; }

/* FMOD est le plus étiré des cinq : à 26 px il mesurait 95 px de large contre
   71 px pour Unity, et c'est cette largeur qu'on lit, pas la hauteur. On le
   cale donc sur la largeur d'Unity plutôt que sur sa hauteur. */
.eng-logos .logo-fmod { height: 20px; }

/* ── Inscription ────────────────────────────────────────────────────────── */

.eng-inscription {
  max-width: 520px;
  margin: 0 auto 90px;
  text-align: center;
}

.eng-inscription h2 {
  margin: 0 0 10px;
  font-size: clamp(19px, 2.2vw, 24px);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.eng-inscription > p {
  margin: 0 0 24px;
  font-size: 16px;
}

#form-newsletter {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
}

#form-newsletter input {
  flex: 1 1 180px;
  padding: 11px 15px;
  border: 1px solid #d8d8dc;
  border-radius: 22px;
  font-family: inherit;
  font-size: 15.5px;
  color: #1C1C1E;
  background: #fff;
}

#form-newsletter input:focus {
  outline: none;
  border-color: #1C1C1E;
}

#form-newsletter button {
  padding: 11px 26px;
  border: none;
  border-radius: 22px;
  background: #1C1C1E;
  color: #fff;
  font-family: inherit;
  font-size: 15.5px;
  cursor: pointer;
  transition: opacity 0.2s ease;
}

#form-newsletter button:hover { opacity: 0.75; }

#nl-reponse {
  margin: 14px 0 0;
  min-height: 20px;
  font-size: 15px;
  color: #8a8a8e;
}

#nl-reponse.ok { color: #3700FF; }

/* ── Contacts ───────────────────────────────────────────────────────────── */
/* Même traitement que les liens de la page Jouer : bleu, flèche, sans filet. */

.eng-contact {
  max-width: 660px;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 28px;
  font-size: 15px;
}

.eng-contact a {
  color: #3700FF;
  text-decoration: none;
}

.eng-contact a:hover { text-decoration: underline; }

/* ── Format ─────────────────────────────────────────────────────────────── */

@media (max-width: 860px) {
  .eng-tete {
    grid-template-columns: 1fr;
    gap: 34px;
    min-height: 0;
    padding-top: 40px;
  }
  .eng-rond { width: min(60vw, 260px); }
  .eng-bande {
    grid-template-columns: 1fr;
    gap: 26px;
    margin-bottom: 90px;
  }
  /* En une seule colonne, l'alternance n'a plus de sens : le texte passe
     toujours avant son visuel. */
  .eng-inverse .eng-mots   { order: 0; }
  .eng-inverse .eng-visuel { order: 0; }
  .eng-tete { min-height: 58vh; margin-bottom: 76px; }
  .eng-citation { margin-bottom: 84px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Page Look : Few Notes et les travaux de design graphique

   Rubrique discrète. Elle n'est pas annoncée dans le menu : on y arrive en
   continuant de descendre après Composer, ou par un lien envoyé directement.
   Son entrée de menu n'apparaît qu'une fois qu'on y est, sinon le visiteur ne
   saurait pas où il a atterri.

   Pas de texte de présentation, pas de portrait, pas même de titre affiché :
   un nom par travail, et les images.
   ═══════════════════════════════════════════════════════════════════════════ */

/* L'entrée de menu ne paraît que lorsqu'on est sur la page. Le menu annonce
   donc quatre rubriques, et une cinquième se révèle quand on la découvre. */
.nav a.nav-cachee { display: none; }
body[data-page="look"] .nav a.nav-cachee { display: block; }

/* Colonne un peu plus étroite que le texte de Composer : une image se regarde
   d'un coup d'œil, elle n'a pas besoin de toute la largeur, et les marges la
   posent. */
/* Pas de titre affiché sur cette page : les travaux parlent d'eux-mêmes et le
   menu dit déjà où l'on est. C'est donc `.doc-look` qui porte la marge du
   haut, celle que prenait le titre. */
.doc-look { padding-top: 120px; padding-bottom: 120px; }

.look-oeuvre {
  max-width: 860px;
  margin: 0 auto 150px;
}

/* Le titre reste dans le document, hors de l'écran.

   Le supprimer serait plus simple, mais une page sans aucun titre n'a plus de
   nom : un moteur de recherche n'a que la balise `<title>` pour la décrire, et
   un lecteur d'écran qui liste les en-têtes ne trouve rien. Masqué de cette
   façon, il ne se voit pas et continue de servir aux deux.

   `clip-path` plutôt que `display: none` ou `visibility: hidden`, qui le
   retireraient aussi pour les lecteurs d'écran, soit exactement ce qu'on
   cherche à éviter. */
.look-entete {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.look-oeuvre:first-of-type { margin-top: 90px; }

/* Les noms des travaux sont des étiquettes, pas des titres : c'est l'image
   qu'on regarde. En gros caractères ils entraient en concurrence avec elle et
   avec le titre de la page. */
/* Le nom du travail et son « i » sur une même ligne de base. */
.look-tete {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
}

.look-titre {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
  letter-spacing: 0;
  color: #1C1C1E;
}

/* Même disque noir que les knobs, la vidéo et le bouton de langue, en plus
   petit : c'est le vocabulaire du site, on n'invente pas une forme de plus. */
.look-info {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: #1C1C1E;
  /* Le libellé lisible par un lecteur d'écran vit dans l'attribut aria-label ;
     à l'écran on ne veut que la lettre, dessinée ci-dessous. */
  font-size: 0;
  cursor: pointer;
  position: relative;
  transition: background 0.25s ease;
}

.look-info::after {
  content: 'i';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font: 600 11px/1 'Inter', sans-serif;
  color: #fff;
}

.look-info:hover,
.look-info.ouvert { background: #3700FF; }
.look-info:focus-visible { outline: 2px solid #3700FF; outline-offset: 3px; }

/* La notice se lit comme un texte de fond : colonne plus étroite que l'image,
   parce qu'une ligne longue se lit mal, et posée sous le titre pour qu'on
   sache de quoi elle parle. */
.look-notice {
  max-width: 620px;
  margin: 0 0 22px;
  font-size: 15.5px;
  line-height: 1.65;
  color: #1C1C1E;
}

/* Les images d'un même travail respirent entre elles, sans filet ni cadre :
   c'est l'espace qui les sépare, comme partout ailleurs sur le site. */
.look-oeuvre img,
.look-oeuvre picture {
  display: block;
  width: 100%;
  height: auto;
}

.look-oeuvre img + img,
.look-oeuvre picture + img,
.look-oeuvre img + picture { margin-top: 70px; }

/* Les canvas démarrent transparents : collage.js les révèle une fois les deux
   textures chargées, pour ne pas laisser voir un rectangle vide. */
/* Les vidéos de Composer sont des illustrations, pas des médias à consulter :
   ni commandes, ni bouton de lecture superposé par Safari. */
.eng-visuel video::-webkit-media-controls,
.eng-visuel video::-webkit-media-controls-start-playback-button {
  display: none !important;
  -webkit-appearance: none;
}

.eng-visuel video { pointer-events: none; }

.look-collage {
  display: block;
  width: 100%;
  height: auto;
  opacity: 0;
  transition: opacity 0.6s ease;
}

.look-collage + .look-collage { margin-top: 70px; }

/* ── Repères mobiles ─────────────────────────────────────────────────────────
   Masqués par défaut : ils ne servent que quand la nav de gauche s'efface. */

#mobile-page-name { display: none; }
#menu-mobile,
#menu-mobile-fond { display: none; }

/* ── Téléphone ───────────────────────────────────────────────────────────────
   Même critère que le portfolio : pointeur grossier ET écran plus haut que
   large. On vise l'appareil, pas la largeur — une fenêtre de bureau rétrécie
   garde la version bureau, qu'elle sait afficher, et un iPad en paysage aussi.
   ────────────────────────────────────────────────────────────────────────── */
@media (pointer: coarse) and (max-aspect-ratio: 1/1) {

  /* Les pages sont transformées pendant le geste : on prévient le compositeur. */
  .page { will-change: transform; }

  /* ── Nav ────────────────────────────────────────────────────────────────
     La colonne de liens supposait une largeur qu'un téléphone n'a pas. Elle
     se peignait par-dessus le titre : `position: static` annulait son
     `z-index`, et les pages, en `position: fixed`, passaient au même endroit.
     On ne la répare pas, on la remplace. */
  .nav { display: none !important; }

  /* Le nom de la page et sa position dans la série ouvrent le menu.
     `difference` les garde lisibles sur le blanc comme sur la vidéo de
     Jouer. Seuls les deux boutons reçoivent le doigt, la barre le laisse
     passer. */
  #mobile-page-name {
    display: flex;
    position: fixed;
    top: 22px;
    left: 0;
    right: 0;
    padding: 0 24px;
    align-items: center;
    z-index: 200;
    font-size: 13px;
    line-height: 1.6;
    color: #fff;
    mix-blend-mode: difference;
    -webkit-font-smoothing: antialiased;
    pointer-events: none;
  }

  /* Aligné sur le nom de page plutôt que dans le coin : les deux repères
     forment une seule barre en haut de l'écran. Un peu plus petit, la place
     est comptée. */
  .lang-cycle {
    top: 20px;          /* son milieu sur celui du nom de page */
    right: 18px;
    font-size: 12px;
  }
  #contact-mail { top: 15px; right: 44px; }
  #contact-adresse { top: 50px; right: 18px; }

  /* Le compteur reste centré sur l'écran entier ; on réserve la place du
     bouton à droite pour que le nom de page ne passe jamais dessous. */
  #mobile-page-name { padding-right: 64px; }

  /* Dans une lettre, le nom de la page devient le bouton retour, à la même place.
     Hors du repère : `difference` y changerait son violet. */
  #repere-retour {
    position: fixed;
    top: 12px;
    left: 14px;
    z-index: 200;
    width: auto;
    margin: 0;
    padding: 10px;
    font-size: 13px;
    font-weight: 400;
    line-height: 1.6;
    letter-spacing: normal;
    -webkit-font-smoothing: antialiased;
  }
  body.lettre-ouverte[data-page="newsletter"] #repere-retour { display: block; }
  body.lettre-ouverte[data-page="newsletter"] #mobile-page-bouton { visibility: hidden; }

  #mobile-page-counter {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
  }

  /* Des boutons qui restent du texte, avec une zone de toucher plus grande que
     le mot (la marge négative la rend sans déplacer le texte). */
  #mobile-page-bouton,
  #mobile-page-counter {
    padding: 14px 18px;
    border: 0;
    background: none;
    color: inherit;
    font-family: inherit;
    line-height: inherit;
    pointer-events: auto;
    -webkit-tap-highlight-color: transparent;
  }
  #mobile-page-bouton {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: -14px -18px -14px -24px;
    padding-left: 24px;
    font-size: inherit;
  }
  /* Les trois barres et la croix, dessinées comme l'icône mail. */
  #mobile-page-bouton svg,
  #menu-mobile-croix svg {
    display: block;
    flex: none;
    width: 18px;
    height: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
  }
  #mobile-page-counter { margin: -14px 0; }
  body.lettre-ouverte[data-page="newsletter"] #mobile-page-counter { pointer-events: none; }

  #menu-mobile-fond:not([hidden]) {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 400;
    touch-action: none;
  }

  #menu-mobile:not([hidden]) {
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 8px;
    left: 8px;
    z-index: 401;
    padding: 0 0 8px;
    background: #fff;
    border-radius: 14px;
    touch-action: none;
  }
  /* Ses marges posent la croix pile à la place des trois barres. */
  #menu-mobile-croix {
    align-self: flex-start;
    padding: 16px 30px 8px 16px;
    border: 0;
    background: none;
    color: #1c1c1e;
    -webkit-tap-highlight-color: transparent;
  }
  #menu-mobile a {
    display: block;
    padding: 14px 32px 14px 16px;
    font-size: 13px;      /* la taille du nom de page, dans la barre */
    line-height: 1.6;
    color: #1c1c1e;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
  }
  #menu-mobile a.active { color: #3700FF; }

  /* ── Pages d'un écran ───────────────────────────────────────────────────
     Le haut laisse passer le nom de page, le bas l'indice de geste. */
  .stage {
    gap: 22px;
    padding: 64px 24px 56px;
  }

  /* Sur téléphone, la colonne prend la largeur de l'écran, aux marges de
     base du site (celles de `.stage`, 24 px) : le texte, la vidéo de Jouer et
     l'herbe d'Écouter. La pochette garde sa hauteur d'avant, elle passe donc
     un peu en paysage. */
  :root { --cover: calc(100vw - 48px); --cover-h: min(70vw, 300px); --barre-h: 76px; }

  /* Jouer porte deux blocs de texte autour de la vidéo : à la taille du
     bureau, ils prenaient tout l'écran du téléphone. */
  #page-jouer .identity p,
  #page-jouer .research { font-size: 13px; line-height: 1.45; }
  .identity .jouer-titre { font-size: min(4.6vw, 19px); }   /* comme la phrase de l'accueil sur téléphone */
  /* Tous les boutons d'action à la même taille sur téléphone : 14 px, entre
     les 15,5 px du bureau (trop gros au doigt) et les 13 px qu'avait le
     bouton de Jouer. Celui-ci passe sur deux lignes équilibrées sur un écran
     trop étroit, plutôt que de déborder de la vidéo. */
  .eng-cta,
  #form-newsletter button { font-size: 14px; }
  .eng-cta.jouer-cta { padding: 11px 8px; white-space: normal; text-wrap: balance; }

  /* Quatre barres et leurs noms, plus les deux flèches : la rangée déborde
     de la pochette, elle prend la largeur de l'écran. */
  .transport { width: 100%; max-width: 360px; gap: 6px; }
  .knob { width: 54px; }   /* deux flèches, quatre barres et leurs écarts tiennent dans 327 px */
  /* Au doigt, la barre s'attrape bien au-delà de son rail : toute la largeur de
     sa colonne, un peu au-dessus, et en bas jusque sous son nom. Le geste reste
     relatif (knobs.js) : partir à côté du curseur ne le fait pas sauter. */
  .knob-barre { width: 100%; }
  .knob-barre::after {
    content: '';
    position: absolute;
    inset: -24px -3px -44px;
  }

  /* Accueil : le portrait, les contacts juste dessous (l'un sur l'autre)
     et le bouton descendent en bas de l'écran, où il y avait de la place.
     `margin-top: auto` plutôt que `flex-end` : sur un écran trop court, la
     marge tombe à 0 et rien n'est coupé en haut. */
  /* La phrase au milieu de la hauteur libre (plus en bas de l'écran), et
     assez petite pour que le nom tienne en entier. */
  #page-accueil .accueil-phrase { order: 2; margin: auto 0; width: 90vw; }
  #page-accueil .accueil-phrase h1 { font-size: min(4.6vw, 19px); }
  #page-accueil .accueil-signature { margin-top: 12px; font-size: min(3.7vw, 15px); }
  #page-accueil { padding-bottom: calc(110px + env(safe-area-inset-bottom, 0px)); }   /* la place du bouton, en bas */

  /* Jouer : centré dans la hauteur, comme Écouter (le titre au même niveau,
     de l'air en bas de page), et de la même largeur (les mêmes marges).
     Blocs plus serrés, et la rangée de lecture garde sa hauteur à elle (la
     hauteur des barres d'Écouter ne la concerne pas). */
  #page-jouer { gap: 16px; padding-bottom: 32px; }
  #page-jouer .transport { min-height: 0; }

  /* Une page plus haute que l'écran part du haut au lieu de déborder des
     deux côtés (le texte passait sous le nom de page). */
  .stage { justify-content: safe center; }

  /* ── Composer ───────────────────────────────────────────────────────────
     Sur bureau, `.doc` réserve 170 px de chaque côté pour que la nav fixe
     tienne dans la marge de gauche. Sans nav, cette réserve n'a plus d'objet,
     et sur 375 px elle laissait une colonne de texte de 122 px : deux mots par
     ligne. On repasse à une marge de page ordinaire. */
  .doc { padding: 0 24px 96px; }

  /* En une colonne, le titre et le disque se posent l'un sous l'autre : centrés,
     ils forment un axe, alors qu'alignés à gauche le disque pendait dans le
     vide à droite. C'est la seule page où l'on centre, et c'est pour ça. */
  .eng-tete {
    min-height: 0;
    padding-top: 72px;
    margin-bottom: 64px;
    gap: 26px;
    justify-items: center;
    text-align: center;
  }

  .eng-rond  { width: min(52vw, 210px); }

  /* « Tension Engine » d'un seul tenant. Le retour à la ligne du HTML sert le
     bureau, où le titre se cale à côté du disque sur deux lignes ; ici il
     coupait un nom de produit en deux pour rien. La taille est en `vw` pour
     que la ligne remplisse la largeur quel que soit le téléphone — 8,9 vw est
     la valeur mesurée qui la fait tenir entre les marges sur un 375. */
  .eng-titre    { font-size: 12vw; line-height: 1.05; }
  .eng-titre br { display: none; }

  /* `max-width: 300px` bridait la ligne sur bureau pour qu'elle passe sous le
     titre ; centrée sur toute la largeur du téléphone, elle tient d'elle-même. */
  .eng-accroche { max-width: none; font-size: 16px; }

  .eng-citation { margin-bottom: 76px; }
  .eng-citation p { font-size: 20px; }

  .eng-bande { gap: 22px; margin-bottom: 72px; }

  .eng-logos { gap: 22px 34px; }

  .eng-inscription { margin-bottom: 64px; }

  /* Look sur téléphone : l'image prend toute la largeur utile, les écarts se
     resserrent pour que le défilement ne s'éternise pas entre deux travaux. */
  .look-oeuvre { margin-bottom: 76px; }
  .look-oeuvre:first-of-type { margin-top: 54px; }
  .doc-look { padding-top: 72px; }
  .look-oeuvre img + img,
  .look-oeuvre picture + img,
  .look-oeuvre img + picture,
  .look-collage + .look-collage { margin-top: 34px; }
  .look-tete { margin-bottom: 14px; }
  .look-notice { font-size: 13px; margin-bottom: 18px; }

  /* Le formulaire s'empile. À 375 px, `flex: 1 1 180px` laissait le nom seul
     sur sa ligne puis serrait l'e-mail contre le bouton : trois éléments de
     largeurs différentes, sans alignement. Empilés, ils font une colonne, et
     chaque champ est assez large pour qu'on voie ce qu'on tape. */
  #form-newsletter { flex-direction: column; }
  #form-newsletter input,
  #form-newsletter button { width: 100%; flex: none; }

  /* ── Gestes ─────────────────────────────────────────────────────────────
     Le doigt navigue entre les pages et tourne les knobs : le navigateur ne
     doit pas interpréter les mêmes mouvements de son côté. Seule Composer
     garde le défilement natif, qui est le sien. */
  body { overscroll-behavior: none; }
  .stage { touch-action: none; }
  .doc   { touch-action: pan-y; }

  /* Pas d'état de survol sur un écran tactile : il resterait collé après le
     relâchement du doigt. */
  .nav a:hover,
  .eng-cta:hover { opacity: 1; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Page Newsletter : la liste des lettres, puis la lettre ouverte

   Rien de nouveau côté identité : le grand titre et les bandes de Composer, le
   disque noir de Jouer, le violet des liens. Pas de filet, l'espace sépare.
   Dans une lettre, le texte est en gris et ses phrases clés en noir : on peut
   la parcourir en ne lisant que le noir (l'e-mail d'origine le faisait avec une
   italique à empattements, le site n'a qu'Inter).
   ═══════════════════════════════════════════════════════════════════════════ */

.doc-newsletter { padding-top: 120px; }

.nl-tete,
.nl-liste { max-width: 860px; margin-left: auto; margin-right: auto; }

.nl-tete { margin-bottom: 110px; }
.nl-tete .eng-accroche { max-width: none; }

.nl-lettre + .nl-lettre { margin-top: 84px; }

/* ── Une ligne de la liste ── */

.nl-ligne {
  display: grid;
  grid-template-columns: 1fr 160px;
  gap: 56px;
  align-items: center;
  color: inherit;
  text-decoration: none;
}
.nl-ligne:focus-visible { outline: 2px solid #3700FF; outline-offset: 10px; }

.nl-ligne-mots { display: block; }

.nl-ligne time {
  display: block;
  margin-bottom: 12px;
  font-size: 14px;
  color: #8a8a8e;
}

.nl-ligne h2 {
  margin: 0;
  font-size: clamp(26px, 3.4vw, 38px);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.025em;
  text-wrap: balance;
  transition: color 0.2s ease;
}

.nl-resume {
  display: block;
  margin-top: 14px;
  max-width: 56ch;
  font-size: 16.5px;
  line-height: 1.55;
  color: #6e6e73;
}

.nl-lire {
  display: block;
  margin-top: 14px;
  font-size: 15px;
  color: #3700FF;
}

.nl-vignette {
  display: block;
  width: 160px;
  height: 160px;
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Une vignette rognée en disque : elle tourne au survol, le cercle garde sa
   forme pendant la rotation. */
.nl-vignette-ronde { border-radius: 50%; }

@media (hover: hover) {
  .nl-ligne:hover h2 { color: #3700FF; }
  .nl-ligne:hover .nl-vignette { transform: rotate(14deg) scale(1.05); }
  .nl-retour:hover { text-decoration: underline; }
  .nl-demo a:hover .nl-disque { transform: translate(-50%, -50%) scale(1.08); }
}

/* ── Liste ou lecture ── */

.nl-corps,
.nl-retour { display: none; }

.en-lecture .nl-tete,
.en-lecture .nl-lettre:not(.ouverte),
.en-lecture .nl-vignette,
.en-lecture .nl-resume,
.en-lecture .nl-lire { display: none; }

.en-lecture .nl-retour,
.en-lecture .nl-corps { display: block; }

.en-lecture .nl-corps { animation: nl-arrivee 0.45s cubic-bezier(0.22, 1, 0.36, 1); }
@keyframes nl-arrivee {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

.nl-retour {
  width: max-content;
  font-size: 15px;
  color: #3700FF;
  text-decoration: none;
}
/* En bas de la lettre, sous la signature : centré comme elle. */
.en-lecture .nl-retour-bas { margin: 72px auto 0; }

/* Le titre de la lettre : la ligne de liste devenue en-tête. */
.en-lecture .nl-liste { max-width: var(--contenu); }
.en-lecture .nl-ligne {
  display: block;
  margin-bottom: 44px;
  cursor: default;
}
.en-lecture .nl-ligne h2 {
  color: inherit;
  font-size: clamp(38px, 6vw, 72px);
  line-height: 1.02;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

/* ── Le texte ── */

.nl-corps p { margin: 0; }
.nl-corps em { font-style: normal; font-weight: 500; color: #1C1C1E; }

.nl-intro {
  margin-bottom: 120px;
  font-size: clamp(18px, 2vw, 22px);
  line-height: 1.45;
  letter-spacing: -0.01em;
}
.nl-intro p + p { margin-top: 12px; }
.nl-intro p:last-child { max-width: 640px; }

.nl-corps .eng-mots p { color: #6e6e73; }
.nl-corps .eng-mots p + p { margin-top: 18px; }

/* Les figures sont du trait noir sur blanc : sans fond ni cadre, elles se
   posent directement sur la page. */
.nl-figure { background: none; border-radius: 0; overflow: visible; }
.nl-figure figcaption,
.nl-corps .nl-signature { font-size: 14px; color: #8a8a8e; }
.nl-figure figcaption { margin-top: 10px; text-align: center; }
/* Une vidéo de lettre se pose sur son image d'attente, comme sur Composer.
   Le cadre est le seul `.nl-media`, pour que la vidéo, en position absolue,
   ne recouvre pas la légende de la figure. */
.nl-media { position: relative; }
/* Le clic sur la vidéo la lance ou l'arrête (video.js), comme sur Jouer. */
.nl-media video { pointer-events: auto; }

/* Le son de la vidéo (newsletter.js) : un petit haut-parleur juste après la
   légende (« sound here → »). Même trait que l'icône mail. Sans légende
   prévue pour lui, il se pose sous l'image, à droite. */
.nl-son {
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: 2px;
  padding: 8px;
  border: none;
  background: none;
  color: #1C1C1E;
  line-height: 0;
  cursor: pointer;
  transition: color 0.2s ease;
}
@media (hover: hover) {
  .nl-son:hover { color: #3700FF; }
}
.nl-son:focus-visible { outline: 2px solid #3700FF; outline-offset: 1px; }
.nl-son svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linejoin: round;
  stroke-linecap: round;
}
/* La légende de la vidéo en deux : le jeu à gauche, « sound here → » et le
   haut-parleur à droite, chacun calé sur un bord de l'image. */
.nl-figure .nl-legende-son {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  text-align: left;
}
.nl-son-ici { white-space: nowrap; }
.nl-legende-son .nl-son {
  position: static;
  margin: -8px -6px -8px 0;  /* la zone de clic déborde, l'icône reste au bord de l'image */
  padding: 8px 6px;
  vertical-align: middle;
}
.nl-son .son-ondes { display: none; }
.nl-son[aria-pressed="true"] .son-ondes { display: inline; }
.nl-son[aria-pressed="true"] .son-coupe { display: none; }
/* Un lien dans la question garde la couleur de la phrase, souligné finement. */
.nl-question-texte a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
}

/* Même texte que les bandes, sur toute la largeur de la grille : il annonce la
   vidéo qui suit, d'où un écart plus court qu'entre deux bandes. */
.nl-corps .nl-these {
  margin-bottom: 96px;
  font-size: 16.5px;
  line-height: 1.6;
  color: #6e6e73;
}
/* La conclusion d'une lettre, à la même voix que son ouverture (.nl-intro). */
.nl-corps .nl-these.nl-these-forte {
  font-size: clamp(18px, 2vw, 22px);
  line-height: 1.45;
  letter-spacing: -0.01em;
  color: inherit;
}

.nl-demo a {
  position: relative;
  display: block;
  border-radius: 10px;
  overflow: hidden;
}
.nl-demo a:focus-visible { outline: 2px solid #3700FF; outline-offset: 4px; }

.nl-disque {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: #1C1C1E;
  transform: translate(-50%, -50%);
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
.nl-disque::after {
  content: '';
  position: absolute;
  left: 29px;
  top: 23px;
  border-style: solid;
  border-width: 13px 0 13px 21px;
  border-color: transparent transparent transparent #fff;
}

/* La fin de la lettre, centrée : après les bandes, la question se pose seule. */
.nl-question {
  max-width: 760px;
  margin: 0 auto 110px;
  text-align: center;
}
.nl-corps .nl-question-avant,
.nl-corps .nl-question-apres { font-size: 16.5px; color: #6e6e73; }
.nl-question .nl-question-texte {
  margin: 26px 0;
  font-size: clamp(21px, 2.8vw, 31px);
  line-height: 1.32;
  letter-spacing: -0.015em;
  color: #6e6e73;
  text-wrap: balance;
}
.nl-question .eng-cta { display: inline-block; text-decoration: none; }
/* Le bouton de Play, posé dans la phrase à la place du lien : même noir, même
   lueur, mais à la largeur de ses mots et centré sur la ligne. */
.nl-question-texte .eng-cta.nl-jouer {
  display: inline-block;
  width: auto;
  margin: 0 0.1em 0 0;
  padding: 11px 22px;      /* Play, sur téléphone, le serre à 8px : pas ici */
  white-space: nowrap;
  vertical-align: 0.18em;
  color: #fff;
  letter-spacing: normal;
  line-height: normal;
}

.nl-corps .nl-signature {
  line-height: 1.6;
  text-align: center;
}

@media (prefers-reduced-motion: reduce) {
  .en-lecture .nl-corps { animation: none; }
  .nl-vignette, .nl-disque { transition: none; }
}

@media (max-width: 860px) {
  .doc-newsletter { padding-top: 72px; }
  .nl-tete { margin-bottom: 64px; }
  .nl-tete .eng-accroche { font-size: min(16px, 3.8vw); }   /* tient sur une ligne en anglais */
  .nl-lettre + .nl-lettre { margin-top: 56px; }
  /* La vignette dépasse de sa colonne et le bord de l'écran la coupe : on n'en
     voit qu'une partie, mais assez grande pour qu'on lise le dessin. */
  .nl-ligne { grid-template-columns: 1fr 70px; gap: 18px; }
  .nl-vignette { width: 230px; height: 230px; max-width: none; }
  .nl-intro { margin-bottom: 72px; }
  .nl-corps .nl-these { margin-bottom: 56px; }
  .nl-disque { width: 56px; height: 56px; }
  .nl-disque::after { left: 22px; top: 17px; border-width: 11px 0 11px 17px; }
  .nl-question { margin-bottom: 72px; }

  /* Sur téléphone, les textes suivent celui de Jouer (13 px) : un corps à
     14 px, des titres resserrés autour. */
  .eng-mots p,
  .nl-corps .nl-these,
  .nl-corps .nl-question-avant,
  .nl-corps .nl-question-apres,
  .nl-resume { font-size: 14px; line-height: 1.5; }
  .nl-corps .eng-mots p + p { margin-top: 14px; }
  .eng-accroche { font-size: 14.5px; }
  .nl-tete .eng-accroche { font-size: min(14.5px, 3.8vw); }
  .nl-intro,
  .nl-corps .nl-these.nl-these-forte { font-size: 16px; line-height: 1.45; }
  .eng-mots h2 { font-size: 18px; }
  .eng-titre { font-size: 9.5vw; }
  .eng-citation p { font-size: 17px; }
  .nl-question .nl-question-texte { font-size: 18px; }
  .nl-ligne h2 { font-size: 22px; }
  .en-lecture .nl-ligne h2 { font-size: 30px; }
  .nl-figure figcaption,
  .nl-corps .nl-signature,
  .nl-ligne time { font-size: 12.5px; }
  .nl-lire { font-size: 14px; }
}
