:root { --rouge: #7a1414; color-scheme: light; }

html, body { margin: 0; background: #f0d5c2; font-family: Georgia, serif; cursor: url('cursor-arrow.png?v=4') 18 0, auto; }
a, button { cursor: url('cursor-hand.png?v=4') 9 1, pointer; }
/* Mesuré empiriquement (badges desktop agrandis à 50/104px, voir plus bas) :
   la nav (position:fixed) mesure jusqu'à 255px sur 641-799px (pire cas :
   comodoro/video/audio à 700px), 196px sur 800-1399px, puis 136px au-delà
   (une seule ligne). 74px laissait le bas des pages (copyright, mentions
   légales) se faire recouvrir par la bande fixe. On réserve large à chaque
   palier plutôt que de viser un seuil de repli exact et fragile. */
body:has(nav.menu) { padding-bottom: 280px; }
@media (min-width: 800px) {
  body:has(nav.menu) { padding-bottom: 220px; }
}
@media (min-width: 1400px) {
  body:has(nav.menu) { padding-bottom: 160px; }
}
html:has(body.home) { height: 100%; overflow: hidden; }
body.home { background: #160404; height: 100vh; height: 100dvh; display: flex; align-items: center; justify-content: center; overflow: hidden; position: fixed; inset: 0; width: 100%; cursor: url('cursor-arrow-white.png?v=3') 18 0, auto; }
body.home a, body.home button { cursor: url('cursor-hand-white.png?v=3') 9 1, pointer; }
body.home .scene { width: auto; max-width: 100vw; max-height: 100vh; aspect-ratio: 2296 / 1623; margin: 0; }
body.home .scene img { height: 100%; }
.visually-hidden { position: absolute; left: -9999px; }

/* accueil mobile : affiche en fond + badges fixes en bas à droite */
.scene-mobile { display: none; }

@media (max-width: 640px) {
  body.home .scene { display: none; }
  .scene-mobile { display: block; position: fixed; inset: 0; }
  .scene-mobile .poster-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
  /* zone invisible du titre, serrée à droite (porte claire / aplat sombre
     du nouveau visuel accueil-mobile.png), pour ne pas chevaucher la foule
     de visages à gauche. */
  .mobile-title-link { position: fixed; left: 5%; top: 1.5%; width: 90%; height: 11%; z-index: 10; }
  .mobile-title-img { display: block; width: 100%; height: 100%; object-fit: contain; }
  .mobile-badges { position: fixed; right: .8rem; bottom: .8rem; z-index: 10; display: flex; flex-direction: column; align-items: flex-end; gap: .55rem; }
  .mobile-badges a { display: block; text-decoration: none; transition: opacity .2s ease; }
  .mobile-badges a img { height: 44px; width: auto; display: block; filter: grayscale(1) contrast(10) brightness(1.1); }
  .mobile-badges a:hover, .mobile-badges a:focus-visible { opacity: .7; }
}

/* menu de secours (mobile, accessibilité, référencement) : les mêmes badges que les cartouches.
   Fixe en bas d'écran sur les pages secondaires, toujours accessible. */
nav.menu { position: fixed; left: 0; right: 0; bottom: 0; z-index: 10; background: #f0d5c2; box-shadow: 0 -2px 8px rgba(0,0,0,.15); display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: .6rem; padding: 1rem; }
nav.menu a { display: block; text-decoration: none; transition: opacity .2s ease; }
nav.menu a img { height: 42px; width: auto; display: block; }
nav.menu a[href^="index"] img { height: 90px; }
nav.menu a[href^="index"] { margin-right: auto; }
nav.menu a:hover, nav.menu a:focus-visible { opacity: .6; }

@media (min-width: 641px) {
  nav.menu a img { height: 50px; }
  nav.menu a[href^="index"] img { height: 104px; }
}

@media (max-width: 640px) {
  /* le bandeau (inchangé, forme et couleurs d'origine) peut s'étaler sur
     plusieurs lignes sur un petit écran ; on réserve assez de place en bas
     de page pour qu'il ne cache jamais le contenu, quel que soit le nombre
     de lignes sur lesquelles il s'étale. 310px au plus étroit (294px
     mesurés + marge), réduit par paliers ci-dessous car la nav se replie
     sur de moins en moins de lignes à mesure que l'écran s'élargit -
     300px fixe laissait un grand vide en bas sur la moitié haute de la
     plage mobile (ex. 480-640px, où la nav ne fait que 140px). */
  body:has(nav.menu) { padding-bottom: 310px; }
  /* "BACK TO INDEX" est nettement plus grand que les autres badges du
     bandeau ; sur petit écran ça prend trop de place en hauteur. */
  nav.menu a[href^="index"] img { height: 56px; }
}
@media (min-width: 361px) and (max-width: 640px) {
  body:has(nav.menu) { padding-bottom: 210px; }
}
@media (min-width: 540px) and (max-width: 640px) {
  body:has(nav.menu) { padding-bottom: 160px; }
}

@media (max-width: 640px) {
  /* les cartouches encrées contiennent quelques traits/taches qui ne font
     pas partie du mot (bavures, soulignés, marques parasites) : une fois
     réduits en noir et blanc pur, ces traits ressortent en blanc. On les
     rogne pour ne garder que l'écriture, sans toucher aux images d'origine
     (toujours utilisées telles quelles sur la version ordinateur). */
  .mobile-badges a img[src^="titre-audio"] { clip-path: inset(32% 0 22% 0); }
  .mobile-badges a img[src^="titre-video"] { clip-path: inset(36% 10% 0 0); }
  .mobile-badges a img[src^="titre-codex"] { clip-path: inset(32% 9% 0 0); }
  .mobile-badges a img[src^="titre-argumentum"] { clip-path: inset(21% 0 31% 0); }
  .mobile-badges a img[src^="titre-agenda"] { clip-path: inset(0 22% 0 0); }
  .mobile-badges a img[src^="titre-contact"] { clip-path: inset(0 0 37% 0); }
}

/* page d'accueil : image interactive */
.scene { position: relative; max-width: 1600px; margin: 0 auto; }
.scene img { display: block; width: 100%; height: auto; }
/* chaque zone affiche une image pré-calculée (même forme que l'encre rouge du dessin
   à cet endroit, en rouge plus clair et plus vif) qui apparaît au survol. */
.scene a.zone { position: absolute; display: block; background-size: 100% 100%; background-repeat: no-repeat; opacity: 0; transition: opacity .2s ease; }
.scene a.zone:hover, .scene a.zone:focus-visible, .scene a.zone.lit { opacity: 1; }

/* les images de survol ne sont utiles que sur la version ordinateur (la
   scène est masquée sur mobile) : en les déclarant seulement ici, dans un
   @media qui ne s'applique pas sur petit écran, le navigateur ne les
   télécharge pas du tout sur mobile (contrairement à un style="background-
   image:..." inline, qui serait toujours téléchargé même si masqué). */
@media (min-width: 641px) {
  .scene a.zone[data-glow="glow-video.png"] { background-image: url(glow-video.png?v=2); }
  .scene a.zone[data-glow="glow-audio.png"] { background-image: url(glow-audio.png?v=2); }
  .scene a.zone[data-glow="glow-contact.png"] { background-image: url(glow-contact.png?v=2); }
  .scene a.zone[data-glow="glow-agenda.png"] { background-image: url(glow-agenda.png?v=2); }
  .scene a.zone[data-glow="glow-codex.png"] { background-image: url(glow-codex.png?v=2); }
  .scene a.zone[data-glow="glow-argumentum.png"] { background-image: url(glow-argumentum.png); }
  .scene a.zone[data-glow="glow-comodoro.png"] { background-image: url(glow-comodoro.png); }
  .scene a.zone[data-glow="glow-btn-audio.png"] { background-image: url(glow-btn-audio.png?v=2); }
  .scene a.zone[data-glow="glow-btn-video.png"] { background-image: url(glow-btn-video.png?v=2); }
  .scene a.zone[data-glow="glow-btn-codex.png"] { background-image: url(glow-btn-codex.png?v=2); }
  .scene a.zone[data-glow="glow-btn-argumentum.png"] { background-image: url(glow-btn-argumentum.png?v=2); }
  .scene a.zone[data-glow="glow-btn-agenda.png"] { background-image: url(glow-btn-agenda.png?v=2); }
  .scene a.zone[data-glow="glow-btn-contact.png"] { background-image: url(glow-btn-contact.png?v=2); }
}

/* sous-pages encadrées (video, audio, comodoro, codex, contact, agenda) :
   même plafond de largeur partout (celui qui servait à la page audio, pour
   que .bandcamp-wrap - plafonné à 950px - ait la place d'atteindre son
   propre plafond), pour que le cadre ait la même taille sur toutes. */
.frame-page { position: relative; width: min(96vw, 1350px); aspect-ratio: 6994 / 9882; margin: 2.5rem auto 1rem; background: url(cadre.jpg?v=5) center / 100% 100% no-repeat; }
/* le cartouche : bande vide entre les deux filets ornés en haut du cadre */
.frame-title { position: absolute; left: 3.58%; top: 4.68%; width: 88.65%; height: 5.26%; display: flex; align-items: center; justify-content: center; }
.frame-title img { max-width: 100%; max-height: 100%; object-fit: contain; }
/* scrollbar-gutter:stable both-edges - quand le contenu dépasse en hauteur
   (fréquent sur téléphone) et qu'une scrollbar verticale apparaît, elle
   grignote la largeur utilisable d'un seul côté (droite) ; sans ça,
   align-items:center centre les enfants par rapport à cette largeur
   amputée, pas par rapport à la boîte visible entière, et tout paraît
   décalé à gauche. Réserver l'espace des deux côtés garde le centrage
   correct, scrollbar visible ou non. */
.frame-content { position: absolute; inset: 13%; overflow: auto; scrollbar-gutter: stable both-edges; -webkit-overflow-scrolling: touch; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1.3rem; text-align: center; container-type: inline-size; }
.codex-art-mobile { box-sizing: border-box; display: none; border: 3px solid #000; box-shadow: 0 4px 14px rgba(0,0,0,.25); }
@media (max-width: 640px) {
  /* sur petit écran, le contenu dépasse souvent la zone du cadre ; en le
     centrant (justify-content:center) le début du contenu devenait
     inaccessible au scroll. On aligne en haut pour pouvoir toujours
     tout faire défiler, du premier au dernier élément. */
  .frame-content { justify-content: flex-start; padding-top: .8rem; padding-bottom: .8rem; }
  /* les navigateurs mobiles n'ont pas de lecteur PDF pour <embed> : la zone
     reste vide/noire. On la masque et on mise sur le lien d'ouverture. */
  .frame-content embed { display: none; }
}
.frame-content-top { justify-content: flex-start; padding-top: 2rem; }
.frame-content p { color: #333; font-size: 1.05rem; margin: 0; }
.content-link { font-family: Arial, Helvetica, sans-serif; color: var(--rouge); font-weight: 700; text-decoration: none; font-size: clamp(1rem, 4.8vw, 1.6rem); overflow-wrap: anywhere; }
.phone { font-family: Arial, Helvetica, sans-serif; color: var(--rouge); font-weight: 700; font-size: clamp(1rem, 4.8vw, 1.6rem); white-space: nowrap; }

.frame-content embed { width: 100%; max-width: 500px; height: clamp(220px, 60vw, 420px); border: 1px solid #ccc; }

/* page codex : la flèche download (encre noire, intérieur rempli de blanc
   au pot de peinture) remplace le texte "Download scores in PDF". */
.codex-download { display: block; }
.codex-download .download-arrow { height: clamp(40px, 12vw, 90px); width: auto; }

/* titres "Burnin' Chamber Music (!) I/II" : redondants avec le PDF affiché
   dans <embed> sur ordinateur (le titre y figure déjà), mais nécessaires
   sur mobile où <embed> est masqué (pas de lecteur PDF) - seul repère entre
   les deux partitions. */
@media (min-width: 641px) {
  .codex-title { display: none; }
}
/* "Score"/"Partition"/... sous le titre : précise ce qu'on télécharge
   (sur mobile, le PDF n'est pas affiché, seul indice avant la flèche). */
.codex-subtitle { display: inline-block; }

/* petite figure décorative calée dans le coin bas-gauche du cadre, dans la
   marge vide entre le contenu (centré) et le filet d'encre - % du cadre
   pour rester à l'échelle, quelle que soit la largeur. Même inset que
   .frame-content (13%) pour ne jamais déborder sur le filet d'encre.
   mix-blend-mode:multiply - le fond blanc du jpg scanné devient transparent
   (se fond dans la couleur de fond de la page, quelle qu'elle soit) tandis
   que le trait noir reste noir. */
.codex-figure { position: absolute; left: 15%; bottom: 11%; width: 23%; height: auto; z-index: 1; mix-blend-mode: multiply; }
@media (max-width: 640px) {
  .codex-figure { width: 28%; left: 15%; bottom: 10%; }
}
/* sous ~360px (vieux iPhone SE...), le 2e titre + sa flèche de
   téléchargement n'ont plus assez de place en dessous pour une figure
   agrandie, quelle que soit sa position verticale - on la garde plus
   proche de sa taille d'origine ici plutôt que de chevaucher le texte.
   16% chevauchait déjà réellement le 2e titre à 320px (iPhone SE, le cas
   le plus étroit de cette tranche) - vérifié par détection de collision
   avec tous les éléments de contenu, pas seulement par inspection visuelle. */
@media (max-width: 360px) {
  .codex-figure { width: 14%; bottom: 9%; }
}
/* entre 641px et ~1200px, la fiche PDF (hauteur plafonnée à 420px, en px
   fixes) grandit moins vite que le cadre (en %) : à largeur égale ils se
   superposaient presque - on garde ici une taille/position plus proche de
   l'originale pour ne jamais chevaucher la 2e partition. */
@media (min-width: 641px) and (max-width: 1450px) {
  .codex-figure { width: 18.5%; bottom: 7.5%; }
}

/* niu.svg : calé dans la marge droite, au niveau de la 1re partition
   (centrée verticalement sur elle, comme .codex-figure dans la marge
   gauche en bas). right:15% est le minimum pour ne pas toucher le filet
   d'encre (irrégulier, dessiné à la main - il mordait sur la marge
   nominale de 13% à cette hauteur) ; mais à cette distance du bord,
   niu empiète dans .frame-content, où la 1re partition (plafonnée à
   500px) occupe déjà toute la largeur disponible entre 641px et
   ~1400px - jamais assez de place pour les deux en même temps dans
   cette fourchette. On masque niu uniquement là ; en dessous (mobile,
   partition masquée) et au-delà (partition à son plafond, de la place
   libère), aucun conflit. */
.codex-niu { position: absolute; right: 15%; top: 30.5%; transform: translateY(-50%); width: 16%; height: auto; z-index: 1; mix-blend-mode: multiply; }
@media (min-width: 641px) and (max-width: 1500px) {
  .codex-niu { display: none; }
}

/* les liens de contact doivent toujours tenir sur une seule ligne : une
   échelle (vw) calée sur la largeur réelle du cadre, pas sur celle de
   .content-link (calée sur la largeur du viewport), pour que l'adresse
   mail (la plus longue) ne passe jamais à la ligne. */
.social-link { display: inline-flex; align-items: center; gap: .55rem; font-size: clamp(.75rem, 4vw, 1.6rem); white-space: nowrap; }
/* centré dans l'espace libre sous les liens jusqu'au bas du cadre,
   pas juste collé sous Facebook (marges auto = centrage dans l'espace
   restant du conteneur flex, qui a une hauteur fixe via inset:13%). */
.contact-art { box-sizing: border-box; width: 100%; max-width: 680px; height: auto; margin: auto 0; border: 3px solid #000; box-shadow: 0 4px 14px rgba(0,0,0,.25); }
.social-icon { height: 1em; width: 1em; flex-shrink: 0; }
.agenda-art { box-sizing: border-box; display: block; max-width: 80%; max-height: 80%; width: auto; height: auto; margin: 0 auto; }

.content-link:hover, .content-link:focus-visible { color: #000; }
.bandcamp-link-below { margin: 0; }

/* cadre encré audio-frame.png : désormais un seul dessin où l'intérieur est
   déjà peint en noir à la main (plus besoin d'un fond CSS séparé) - posé en
   fond de .bandcamp-wrap, avec le lecteur Bandcamp incrusté par-dessus dans
   la zone noire, en retrait des filets du cadre pour ne jamais les
   recouvrir (marges vérifiées pixel par pixel sur le dessin). */
.bandcamp-wrap {
  /* agrandi (680 -> 950) pour que le lecteur, à marges % inchangées, ait
     assez de hauteur réelle pour afficher toute la tracklist plutôt que de
     rogner la liste des titres - grandir le cadre plutôt que forcer le
     lecteur à dépasser ses marges sûres. */
  position: relative; width: 100%; max-width: 950px; margin: 0 auto; flex-shrink: 0;
  aspect-ratio: 1762 / 2202;
  border-radius: 6px;
  background-image: url(audio-frame.png?v=4);
  background-repeat: no-repeat;
  background-size: 100% 100%;
}
.bandcamp-player {
  /* width/height en % explicites, pas left+right+auto : un iframe est un
     élément remplacé, et avec les 4 côtés posés + width/height:auto les
     navigateurs retombent sur sa taille par défaut (300x150) au lieu de
     calculer la taille depuis les contraintes - vérifié en headless Chrome
     (le lecteur Bandcamp s'affichait alors rabougri, UI dégradée).
     Marges verticales (top/height) reconverties par recherche dichotomique
     pixel par pixel sur audio-frame.png (le rectangle précédent, estimé à
     l'oeil, débordait sur les filets du cadre en haut et à gauche).
     Largeur délibérément plus étroite que le maximum sûr (57%) : la
     pochette Bandcamp (carrée) grandit avec la largeur de l'iframe, donc
     un lecteur trop large laisse moins de hauteur relative pour la liste
     des titres en dessous - testé en isolant l'iframe à différentes
     tailles, il faut un ratio hauteur/largeur d'au moins ~1.3 pour voir
     les deux titres ; 40% de large pour 55% de haut en donne ~1.72. */
  position: absolute;
  left: 30%; top: 22.5%;
  width: 40%; height: 55%;
  border: 0; min-width: 0; border-radius: 2px;
  background: #000;
}
@media (max-width: 640px) {
  /* sur mobile, .bandcamp-wrap est bien plus étroit (largeur de .frame-content,
     pas 950px) : à 40%/55%, l'iframe Bandcamp tombe à ~95x160px, trop petit
     pour que le lecteur Bandcamp affiche play/titre/tracklist sans son
     propre scroll interne. On agrandit (même ratio ~1.72, vérifié pixel par
     pixel sur audio-frame.png jusqu'à 18%/7% de marge sans toucher le filet
     d'encre) uniquement ici : le lecteur a déjà assez de place sur ordinateur. */
  .bandcamp-player { left: 18%; top: 7%; width: 64%; height: 86%; }
}

/* page argumentum : la colonne fait toute la largeur du manuscrit (1100px max) ;
   le texte courant (programme, bio, press kit...) reste calé sur son bord
   gauche mais garde une largeur de lecture confortable grâce à .presskit. */
.argumentum-page { max-width: 1100px; margin: 2.5rem auto 1rem; padding: 0 1rem; text-align: center; }
.argumentum-page img { max-width: 100%; height: auto; }
.argumentum-page img.manuscript { width: 100%; max-width: none; margin-left: 0; display: block; margin-bottom: 0; }
.legal-page h1 { font-size: clamp(1.4rem, 5vw, 2rem); color: var(--rouge); margin: 0 0 1.5rem; }
.legal-page .press-byline { margin-top: 2.5rem; }
.frame-content .legal-link { align-self: flex-end; font-size: .75rem; margin: 0; }
.legal-link .content-link { font-size: inherit; }
.manuscript-wrap { position: relative; display: block; }
.manuscript-face-hit { position: absolute; display: block; }
.manuscript-face-hit::before { content: ''; position: absolute; inset: -14px; }
.manuscript-face { display: block; width: 100%; height: auto; }
.manuscript-face-hit-mask { left: 73.76%; top: 36.46%; width: 11.03%; }
.manuscript-face-hit-viking { left: 81.57%; top: 53.27%; width: 14.24%; }
/* transcription/traduction en texte du manuscrit (image, donc non
   traduisible directement) - sous l'image, dans les langues où elle
   est fournie. Distincte du texte courant : italique, plus sobre. */
.manuscript-translation { width: 100%; margin: 1.4rem 0 0; text-align: left; font-style: italic; color: #555; line-height: 1.6; }
.manuscript-translation + .manuscript-translation { margin-top: .9rem; }
.press-sub { margin: 0 0 .6rem; color: #777; font-size: .92rem; }
/* flèche de téléchargement posée en tête de chaque colonne (Press Kit sur
   .press-col, Technical Rider sur .tech-col) : qu'elles soient côte à côte
   (grille 2 colonnes) ou empilées (mobile), chaque flèche précède toujours
   directement la section à laquelle elle correspond. */
.presskit-download-link { display: inline-flex; align-items: flex-start; gap: .5rem; white-space: nowrap; font-size: clamp(1rem, 4vw, 1.4rem); margin-bottom: 1.8rem; }
.argumentum-page .download-arrow { height: clamp(40px, 16vw, 112px); width: auto; flex-shrink: 0; }

.presskit { text-align: left; margin: 2.5rem 0; }
/* presse (programme, bio, version courte) à gauche, fiche technique à droite,
   comme deux colonnes de journal ; empilées sur petit écran. */
.presskit-cols { display: grid; grid-template-columns: 1fr; gap: 2.5rem; }
@media (min-width: 760px) {
  .presskit-cols { grid-template-columns: 1fr 1fr; align-items: start; }
}
.press-col { display: flex; flex-direction: column; gap: 1.8rem; }
.press-col .presskit-download-link { margin-bottom: 0; }
.press-col article + article { padding-top: 1.8rem; border-top: 1px solid #ddd; }
.presskit h3 { margin: 0 0 .6rem; font-size: 1.05rem; letter-spacing: .08em; text-transform: uppercase; color: var(--rouge); }
.presskit p { margin: 0 0 .7rem; line-height: 1.55; color: #222; }
.presskit p.press-lede { font-size: 1.3rem; color: var(--rouge); }
.presskit em { font-style: italic; }
.rider-grid { display: grid; grid-template-columns: 1fr; gap: 2rem; }
.rider dt { font-weight: 700; font-size: .82rem; letter-spacing: .05em; text-transform: uppercase; color: #777; margin-top: 1rem; }
.rider dt:first-child { margin-top: 0; }
.rider dd { margin: .2rem 0 0; line-height: 1.5; }
/* contact du rider technique : même taille que le reste du texte (pas la
   grande taille habituelle de .content-link/.phone utilisée ailleurs) */
.rider dd a.content-link, .rider dd .phone { font-size: inherit; }
.stage-plot { background: #f0d5c2; border: none; border-radius: 6px; padding: 1.2rem; text-align: center; }
.stage-label { margin: 0 0 1rem; font-size: .78rem; letter-spacing: .08em; text-transform: uppercase; color: #999; }
.stage-row { display: flex; justify-content: center; gap: 2.2rem; margin: 0 0 1rem; }
.stage-node { width: 82px; height: 82px; border-radius: 50%; background: #f0d5c2; border: 1px solid #bbb; display: flex; align-items: center; justify-content: center; font-size: .78rem; line-height: 1.2; text-align: center; }
.stage-audience { margin: 1rem 0 0; font-size: .8rem; color: #999; border-top: 1px solid #ddd; padding-top: .6rem; }
@media (min-width: 640px) { .rider-grid { grid-template-columns: 1.3fr 1fr; align-items: start; } }
.press-byline { text-align: right; color: #555; font-style: italic; font-size: .8rem; margin: 1.5rem 0 0; }
/* posé sous la fiche technique, dans sa colonne. */
.flyingx { display: block; width: clamp(92px, 16vw, 184px); height: auto; margin: 2rem auto 0; }

/* page video : silhouettes qui tombent (reprises du dessin de la page
   audio) à gauche, télé (cassée, écran-crâne) serrée à droite avec le lien
   youtube en légende dessous, puis le dessin des trois oiseaux en dessous. */
/* même largeur/centrage que .video-art juste en dessous (min(85%,540px),
   margin:0 auto) pour que la télé, alignée à droite dans cette rangée,
   tombe exactement sur le bord droit du cadre des oiseaux. */
.video-top-row { width: 100%; max-width: min(90%, 580px); margin: 0 auto; display: flex; align-items: flex-end; justify-content: flex-end; gap: 1.2rem; }
.video-figures { display: block; width: min(46%, 310px); height: auto; flex-shrink: 0; transform: scaleX(-1); }
.tv-wrap { display: flex; flex-direction: column; align-items: center; gap: .4rem; width: min(36%, 236px); margin: 0; flex-shrink: 0; }
/* miroir, mais la boîte .tv-wrap garde sa position (bord droit calé sur
   celui du dessin des oiseaux) : seul le dessin à l'intérieur est inversé. */
.tv-link { display: block; width: 100%; }
.tv-drawing { display: block; width: 100%; height: auto; transform: scaleX(-1); }
.tv-caption { font-size: clamp(.55rem, 2.2vw, .85rem); text-align: center; line-height: 1.25; }
.video-art { box-sizing: border-box; display: block; width: auto; max-width: min(90%, 580px); height: auto; margin: 0 auto; border: 3px solid #000; box-shadow: 0 4px 14px rgba(0,0,0,.25); }
.comodoro-art { box-sizing: border-box; display: block; width: min(58%, 340px); height: auto; margin: 0 auto; border: 3px solid #000; box-shadow: 0 4px 14px rgba(0,0,0,.25); }

/* tailles mobiles des illustrations, placées ici (après toutes les règles
   de base ci-dessus) exprès : à spécificité égale, une règle plus tardive
   dans le fichier gagne la cascade. Un essai précédent avait cette règle
   AVANT les règles de base ci-dessus, qui la regagnaient alors sur width/
   max-width (mais pas max-height, qu'elles ne définissent pas) — largeur
   et hauteur étaient alors plafonnées indépendamment l'une de l'autre,
   déformant l'image au lieu de la mettre à l'échelle proportionnellement. */
@media (max-width: 640px) {
  .contact-art, .video-art { width: auto; height: auto; max-width: 76vw; max-height: 60vw; }
  .video-top-row { max-width: 76vw; }
  /* en %, pas en vw : .comodoro-art doit aussi rester à l'échelle quand
     .frame-page est plafonné par la hauteur d'écran (page comodoro), pas
     seulement par la largeur — un % du cadre suit les deux cas, un vw
     (lié au viewport) ne suivrait que le premier. */
  .comodoro-art { width: auto; height: auto; max-width: 56%; max-height: 34%; }
  .codex-art-mobile { display: block; width: auto; height: auto; max-width: 74vw; max-height: 28vw; }
  /* cqw (largeur réelle de .frame-content), pas vw : sur un écran très
     étroit le texte/la flèche à plancher fixe (1rem/28px) ne rétrécissaient
     plus assez vite, et le contenu dépassait la zone noire du cadre -
     même principe que la page comodoro plus bas. */
  .codex-title { font-size: max(0.65rem, 4.0cqw); }
  .codex-download .download-arrow { height: max(16px, 10cqw); }
  /* le contenu (dessin + 2 titres + 2 flèches) dépassait légèrement la
     zone noire du cadre, forçant un petit scroll interne inutile - on
     resserre l'espacement vertical pour que tout tienne sans scroll. */
  body.codex-page .frame-content { gap: .5rem; padding-top: .4rem; padding-bottom: .4rem; }
  /* même principe que codex : la rangée figures+télé et le dessin des
     oiseaux dépassaient légèrement la zone noire, forçant un petit scroll
     interne inutile - on resserre et on plafonne un peu plus bas. */
  body.video-page .frame-content { gap: .8rem; padding-top: .5rem; padding-bottom: .5rem; }
  body.video-page .video-art { max-height: 50vw; }
  /* les 3 liens sociaux + le corbac dépassaient légèrement la zone noire
     du cadre, forçant un petit scroll interne inutile. Resserré encore
     (gap .5rem) depuis l'ajout du lien mentions légales, un 5e élément. */
  body.contact-page .frame-content { gap: .5rem; padding-top: .4rem; padding-bottom: .4rem; }
  /* rapproche le lien "Bandcamp" du lecteur agrandi, pour regagner un peu
     de hauteur sur les écrans mobiles les plus courts. */
  body.audio-page .frame-content { gap: .5rem; padding-top: .4rem; padding-bottom: .4rem; }
}
/* même limite physique que .codex-figure sous ~360px (iPhone SE...) :
   34% déborde sur cet écran plus court, on retombe à la valeur sûre
   la plus haute (25%) - cette règle doit suivre le bloc ≤640px dans le
   fichier pour le primer (même spécificité, l'ordre de source décide). */
@media (max-width: 360px) {
  .comodoro-art { max-height: 25%; }
}

/* entre 641px et ~1000px, le cadre est encore loin de son plafond de 1100px :
   la télé + les oiseaux empilés (dimensionnés en % du cadre) dépassent alors
   la hauteur du cadre. On y plafonne leur hauteur (vw, pas % : indépendant
   de la largeur du cadre lui-même). */
@media (min-width: 641px) and (max-width: 1100px) {
  /* width (pas max-height) : .tv-wrap est un <div>, pas une image — lui
     imposer une max-height sans largeur définie fait s'effondrer sa taille
     (bug constaté : 0x0). Une largeur directe en vw garde le calcul de la
     hauteur (height:auto sur l'image à l'intérieur) simple et fiable. */
  .tv-wrap { width: 15vw; }
  .video-figures { width: auto; max-width: 18.5vw; max-height: 22vw; }
  .video-art { max-height: 50vw; }
  .comodoro-art { max-height: 20vw; }
  .contact-art { max-height: 44vw; }
}

/* page comodoro (mobile) : doit tenir sur un seul écran, sans aucun scroll.
   Son bandeau de navigation a 7 badges (un de plus que les autres pages,
   qui n'affichent pas de lien vers elles-mêmes), donc plus haut une fois
   replié sur petit écran. On réduit d'autant la réserve de bas de page et,
   surtout, on plafonne la taille du cadre lui-même à la hauteur d'écran
   réellement disponible (100dvh tient compte de la barre du navigateur
   mobile) : normalement le cadre ne dépend que de la largeur (aspect-ratio
   fixe), ici on ajoute un troisième plafond basé sur la hauteur. */
@media (max-width: 640px) {
  /* comodoro.html a 7 liens dans la nav (contrairement aux 6 des autres
     pages, puisque comodoro n'est le lien "retour" d'aucune d'elles) : son
     bandeau replié est donc plus haut (jusqu'à 294px mesuré à 320px de
     large) que les 300px déjà réservés ailleurs - 230px était insuffisant
     et laissait le bandeau recouvrir le bas du cadre. */
  body.comodoro-page:has(nav.menu) { padding-bottom: 310px; }
  body.comodoro-page .frame-page { width: min(96vw, 1350px, calc((100dvh - 230px) / 1.4131)); }
  /* idem pour le texte (cqw, relatif à la largeur réelle de .frame-content,
     pas au viewport) : sur un écran très court, le cadre devient petit et
     le texte à taille fixe ne tiendrait plus. */
  body.comodoro-page .frame-content p { font-size: max(.58rem, 4.3cqw); }
  body.comodoro-page .frame-content { gap: 1.6cqw; padding-top: .2rem; padding-bottom: .2rem; }
}
/* même logique de paliers que la nav générale : la nav à 7 liens de
   comodoro se replie sur moins de lignes à mesure que l'écran s'élargit
   (243px à 361-413px, 191px à 414-599px, 140px à 600px+). */
@media (min-width: 361px) and (max-width: 640px) {
  body.comodoro-page:has(nav.menu) { padding-bottom: 260px; }
}
@media (min-width: 414px) and (max-width: 640px) {
  body.comodoro-page:has(nav.menu) { padding-bottom: 210px; }
}
@media (min-width: 600px) and (max-width: 640px) {
  body.comodoro-page:has(nav.menu) { padding-bottom: 160px; }
}

/* page comodoro (ordinateur) : les deux portraits + le texte dépassaient
   légèrement la zone noire du cadre, forçant un petit scroll interne
   inutile - on resserre l'espacement et on plafonne un peu les portraits
   pour que tout tienne sans scroll. */
@media (min-width: 641px) {
  body.comodoro-page .frame-content { gap: .9rem; }
  /* width ET height en auto, avec max-width/max-height comme plafonds
     (jamais width fixe + max-height ensemble) : sinon le navigateur
     applique le plafond de hauteur sans réduire la largeur en retour,
     et les deux dessins - de ratios différents - se retrouvent étirés
     à la même taille, déformés. auto/auto laisse le navigateur choisir
     la contrainte la plus stricte des deux tout en gardant le ratio. */
  body.comodoro-page .comodoro-art { width: auto; height: auto; max-width: min(58%, 420px); max-height: 38vw; }
}

/* sélecteur de langue (drapeaux) : version ordi uniquement, en dehors du
   dessin/cadre - coin haut-droit, fixe, au-dessus de tout le reste. */
.lang-selector {
  display: flex; gap: .35rem; position: fixed; top: .6rem; right: .6rem; z-index: 50;
}
.lang-selector a { display: block; line-height: 0; opacity: .78; transition: opacity .2s ease, transform .2s ease; }
.lang-selector a img { width: 26px; height: auto; display: block; border-radius: 2px; box-shadow: 0 2px 6px rgba(0,0,0,.3); }
.lang-selector a:hover, .lang-selector a:focus-visible { opacity: 1; transform: translateY(-2px); }
.lang-selector a.current { opacity: 1; }
.lang-selector a.current img { box-shadow: 0 0 0 2px #7a1414, 0 2px 6px rgba(0,0,0,.3); }
@media (min-width: 641px) {
  .lang-selector { gap: .45rem; top: 1rem; right: 1rem; }
  .lang-selector a img { width: 34px; }
}

/* loupe : les dessins s'agrandissent au clic/tap (lightbox.js) */
img.lightbox-trigger, .lightbox-trigger { cursor: url('cursor-zoom-in.png?v=2') 11 11, zoom-in; }
.lightbox-overlay {
  position: fixed; inset: 0; z-index: 999;
  display: flex; align-items: safe center; justify-content: safe center;
  padding: 5vmin;
  background: #f0d5c2;
  opacity: 0; pointer-events: none;
  transition: opacity .2s ease;
  overflow: auto;
}
.lightbox-overlay.is-open { opacity: 1; pointer-events: auto; }
.lightbox-img {
  /* pas de max-height : une image haute et étroite (ex. contact-crow.jpg,
     1400x1971) serait alors plafonnée par 90vh et pourrait s'afficher plus
     petite que sa taille déjà affichée dans le cadre (bug constaté : le clic
     "rétrécissait" l'image). On ne plafonne que la largeur ; si l'image est
     plus haute que l'écran, l'overlay devient scrollable (overflow: auto). */
  max-width: 90vw;
  cursor: url('cursor-zoom-out.png?v=2') 10 10, zoom-out;
  box-shadow: 0 10px 40px rgba(0,0,0,.5);
}
body.lightbox-locked { overflow: hidden; }
