/* Interface locale du lecteur Instrumenpoche */
:root {
  --fond: #f6f7f9;
  --carte: #fff;
  --bord: #d7dce3;
  --texte: #1c2430;
  --doux: #5d6b7d;
  --accent: #1c6ea4;
  --accent-fonce: #175a87;
  --accent-clair: #e8f1f8;
  --ok: #2c7a4b;
  --alerte: #a8560f;
  --danger: #a3231b;

  /* Les surfaces des boutons ordinaires. Un gris-bleu pris dans la famille de
   * l'accent plutôt qu'un gris neutre : posé à côté du bleu de « Enregistrer »,
   * un gris pur tire au violet et les deux jurent. */
  --surface-douce: #e7edf4;
  --surface-douce-survol: #d8e2ec;
  --surface-douce-appui: #cbd8e5;
  --encre-bouton: #223140;
  --danger-doux: #fbe9e7;

  --rayon: 8px;
  --rayon-petit: 6px;

  /* L'anneau de focus. Il double la bordure au lieu de la remplacer : un
   * contour qui se contente de changer de couleur passe inaperçu. */
  --anneau: rgba(28, 110, 164, .28);
  /* hauteur commune aux boutons et aux champs d’une barre d’outils */
  --hauteur-controle: 2.25rem;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--fond);
  color: var(--texte);
  line-height: 1.45;
}

a { color: var(--accent); }

header.barre {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: .7rem 1.1rem;
  background: var(--carte);
  border-bottom: 1px solid var(--bord);
  position: sticky;
  top: 0;
  z-index: 10;
}

header.barre h1 {
  font-size: 1.05rem;
  margin: 0;
  font-weight: 600;
  white-space: nowrap;
}

header.barre .titre-anim {
  font-weight: 400;
  color: var(--doux);
  font-size: .95rem;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pousse { margin-left: auto; }

main { padding: 1.1rem; max-width: 1100px; margin: 0 auto; }

input[type="search"], input[type="text"] {
  padding: .4rem .7rem;
  /* même hauteur que les boutons : dans une barre d’outils, deux contrôles qui
   * ne s’alignent pas à un pixel près se voient tout de suite */
  min-height: var(--hauteur-controle);
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  font-size: .95rem;
  font-family: inherit;
  min-width: 16rem;
  color: var(--texte);
  background: var(--carte);
  transition: border-color .15s ease, box-shadow .15s ease;
}

input[type="search"]:hover, input[type="text"]:hover { border-color: #c2ccd8; }
input[type="search"]:focus, input[type="text"]:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--anneau);
}

/* --- boutons ---
 *
 * Une première tentative n'avait changé que le degré — même boîte blanche, même
 * filet gris, un rayon un peu plus grand — et ne se voyait pas. Ce qui suit
 * change de principe : **le bouton est une surface teintée, pas un contour**.
 *
 * C'est ce qui fait la différence à l'œil. Un filet gris autour de blanc
 * demande d'être cherché ; un aplat se voit sans effort, et laisse le contour
 * disponible pour dire autre chose — ici, l'anneau du focus clavier.
 *
 * Trois rôles, trois teintes, et rien de décoratif :
 *   - ordinaire : un gris-bleu doux, pris dans la même famille que l'accent ;
 *   - `.principal` : l'accent plein, pour l'action attendue ;
 *   - `.danger` : un rouge pâle, pour celle qui détruit.
 *
 * Trois états, et chacun dit quelque chose :
 *   - au survol la surface fonce d'un cran — la cible se désigne d'elle-même ;
 *   - à l'appui le bouton descend d'un pixel. C'est ce déplacement, plus qu'une
 *     couleur, qui fait sentir le clic ;
 *   - au focus **clavier** un anneau entoure le bouton. `:focus-visible` et non
 *     `:focus` : l'anneau sert à qui navigue au clavier, et ne vient pas salir
 *     l'écran après un clic à la souris.
 */
button, .bouton {
  font: inherit;
  font-weight: 550;
  line-height: 1.25;
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .4rem .9rem;
  min-height: var(--hauteur-controle);
  /* pas de filet : c'est le fond qui détache le bouton */
  border: 1px solid transparent;
  background: var(--surface-douce);
  color: var(--encre-bouton);
  border-radius: var(--rayon);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color .13s ease, color .13s ease,
              box-shadow .13s ease, transform .06s ease;
}

button:hover, .bouton:hover { background: var(--surface-douce-survol); }
button:active, .bouton:active { transform: translateY(1px); background: var(--surface-douce-appui); }

button:focus-visible, .bouton:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--anneau);
}

button.principal {
  background: var(--accent);
  color: #fff;
}
/* un accent plus sombre plutôt qu'un filtre de luminosité : le filtre éclaircit
 * aussi le texte blanc, et le contraste y perd */
button.principal:hover { background: var(--accent-fonce); }
button.principal:active { background: #134b72; }

/* Une action qui détruit doit se lire comme telle avant d'être cliquée. */
button.danger { background: var(--danger-doux); color: var(--danger); }
button.danger:hover { background: #f8dcd9; }
button.danger:active { background: #f2c9c5; }

button:disabled {
  opacity: .45;
  cursor: not-allowed;
}
button:disabled:hover, button:disabled:active {
  background: var(--surface-douce);
  transform: none;
}

/* Le mouvement est une aide, pas un dû : qui le refuse garde tout le reste. */
@media (prefers-reduced-motion: reduce) {
  button, .bouton, input[type="search"], input[type="text"] { transition: none; }
  button:active, .bouton:active { transform: none; }
}

/* --- arbre de la bibliothèque --- */
.rubrique { margin-bottom: .4rem; }

.rubrique > summary {
  cursor: pointer;
  padding: .5rem .7rem;
  background: var(--carte);
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  font-weight: 600;
  list-style: none;
}

.rubrique > summary::-webkit-details-marker { display: none; }
.rubrique > summary::before { content: "▸ "; color: var(--doux); }
.rubrique[open] > summary::before { content: "▾ "; }
.rubrique > summary .compte { font-weight: 400; color: var(--doux); font-size: .85rem; }

.rubrique .contenu { padding: .3rem 0 .3rem 1.2rem; }

.anim {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .35rem .6rem;
  border-bottom: 1px solid #eceff3;
}

.anim:hover { background: var(--accent-clair); border-radius: 4px; }
.anim .nom { flex: 1; min-width: 0; }
.anim .actions { display: flex; gap: .35rem; flex-shrink: 0; }
/* Dans une liste de 159 lignes, trois pastilles teintées par ligne feraient un
 * damier. Ici le fond disparaît et il ne reste que le mot, en bleu : le texte
 * suffit à dire que c'est cliquable, et il reste lisible au repos — un bouton
 * qui n'apparaît qu'au survol n'existe pas sur un écran tactile. La surface
 * revient sous le pointeur, ce qui donne la cible. */
.anim .bouton {
  padding: .25rem .6rem;
  min-height: 1.75rem;
  font-size: .85rem;
  font-weight: 500;
  border-radius: var(--rayon-petit);
  background: transparent;
  color: var(--accent);
}
.anim .bouton:hover { background: var(--surface-douce-survol); color: var(--accent-fonce); }
.anim .bouton:active { background: var(--surface-douce-appui); }

/* Pastilles teintées plutôt que pleines : à côté de boutons clairs, un aplat
 * saturé attire l'œil plus que l'action, alors qu'il ne fait qu'informer. */
.etiquette {
  font-size: .72rem;
  font-weight: 500;
  padding: .1rem .5rem;
  border-radius: 999px;
  background: #fdf1e3;
  color: var(--alerte);
  border: 1px solid #f0d7ba;
  flex-shrink: 0;
}
.etiquette.neuf { background: #e6f4ec; color: var(--ok); border-color: #b8dcc6; }

.vide { color: var(--doux); padding: 2rem; text-align: center; }

.note {
  background: var(--carte);
  border: 1px solid var(--bord);
  border-left: 3px solid var(--accent);
  border-radius: var(--rayon);
  padding: .7rem .9rem;
  margin-bottom: 1rem;
  font-size: .9rem;
  color: var(--doux);
}

/* --- lecteur --- */
.scene {
  background: #fff;
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  position: relative;
  overflow: auto;
}

.plein .scene { height: calc(100vh - 4.2rem); border-radius: 0; border: none; }
.plein main { max-width: none; padding: 0; }

/* --- éditeur --- */
.atelier {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: .8rem;
  height: calc(100vh - 4.2rem);
  padding: .8rem;
}

/* --- la fenêtre XML : un calque coloré sous un textarea transparent ---
 *
 * Les deux éléments sont superposés au pixel près. Toute propriété qui influe
 * sur la position d'un caractère doit donc être déclarée UNE fois, pour les
 * deux : c'est ce que fait la règle commune ci-dessous. Y toucher d'un seul
 * côté décale la coloration du texte saisi.
 *
 * Une propriété échappe à cette règle et ne peut pas être partagée : le
 * défilement. Le champ le porte, le calque le subit — et le champ réserve de la
 * place à ses barres, ce que le calque ne fait pas. C'est public/js/coloration.js
 * qui rend au calque les pixels manquants ; sans quoi il ne peut pas descendre
 * aussi bas que le champ, et la sélection déraille en fin de fichier.
 */
/* Le nombre de chiffres du dernier numéro de ligne — posé par coloration.js,
 * qui seul le connaît. Zéro tant qu'il n'y a rien à numéroter : la colonne
 * disparaît alors d'elle-même.
 *
 * `--largeur-gouttiere` en découle, et c'est elle qui compte : la colonne prend
 * cette largeur, et les deux autres calques décalent leur texte d'autant. Écrire
 * la formule deux fois avait suffi à cacher le premier caractère de chaque
 * ligne — la colonne mesurait huit pixels de plus que le décalage du texte. */
.editeur-xml {
  position: relative;
  flex: 1;
  min-height: 0;
  --gouttiere: 0ch;
  --largeur-gouttiere: calc(.6rem + var(--gouttiere) + .5rem);
}

.editeur-xml > textarea,
.editeur-xml > pre {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: .6rem;
  /* Le texte commence après la gouttière — pour les deux calques à la fois,
   * sans quoi la coloration se décalerait du texte saisi. */
  padding-left: var(--largeur-gouttiere);
  border: 1px solid transparent;
  border-radius: var(--rayon);
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 12.5px;
  line-height: 1.5;
  tab-size: 2;
  white-space: pre;
  word-break: normal;
  overflow-wrap: normal;
}

.editeur-xml > pre {
  border-color: var(--bord);
  background: var(--carte);
  color: var(--texte);
  overflow: hidden; /* c'est le textarea qui porte les barres de défilement */
  pointer-events: none;
}

/* --- la gouttière des numéros de ligne ---
 *
 * Un troisième calque, aux mêmes métriques que les deux autres : c'est ce qui
 * fait que le numéro 42 se trouve exactement en face de la ligne 42. Il défile
 * avec eux, verticalement seulement — les numéros restent visibles quand on
 * part à droite d'une longue ligne.
 *
 * Il est déclaré **après** le calque coloré dans le HTML, donc peint par-dessus :
 * le fond opaque de celui-ci le recouvrirait sinon, et l'on verrait une colonne
 * vide à la place des numéros. */
.editeur-xml > #lignes {
  right: auto;
  width: var(--largeur-gouttiere);
  padding-left: .6rem;
  padding-right: .5rem;
  border-right: 1px solid var(--bord);
  border-radius: var(--rayon) 0 0 var(--rayon);
  background: var(--fond);
  color: var(--doux);
  text-align: right;
  /* les chiffres ne doivent pas danser d'une ligne à l'autre */
  font-variant-numeric: tabular-nums;
  user-select: none;
}

.editeur-xml > textarea {
  width: 100%;
  height: 100%;
  resize: none;
  background: transparent;
  /* le texte visible est celui du calque ; ici on ne garde que le curseur */
  color: transparent;
  caret-color: var(--texte);
  overflow: auto;
}

/* La sélection doit laisser voir ce qu'elle sélectionne.
 *
 * Le texte du champ est transparent — c'est le calque du dessous qui porte les
 * couleurs. Or le navigateur peint le fond de sélection sur le calque du
 * **dessus**, celui du champ : avec une couleur opaque, il recouvrait le texte
 * coloré et l'on ne voyait plus qu'un rectangle bleu vide.
 *
 * Une couleur translucide règle la chose sans rien déplacer : le fond marque
 * l'étendue de la sélection, et le texte continue de se lire au travers.
 */
.editeur-xml > textarea::selection { background: rgba(28, 110, 164, .26); }
/* le texte du champ est transparent : sans cette règle, l'invite le serait aussi */
.editeur-xml > textarea::placeholder { color: var(--doux); }
.editeur-xml > textarea:focus { outline: none; }
/* le calque étant sous le champ, c'est lui qui porte la marque du focus */
.editeur-xml:focus-within > pre { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }

/* --- les jetons ---
 * Teintes empruntées aux thèmes clairs classiques : la balise porte l'œil, la
 * valeur ressort, le reste s'efface.
 */
.x-declaration { color: #7a4fbd; }
.x-commentaire { color: #6f7f8c; font-style: italic; }
.x-balise { color: #1c6ea4; font-weight: 600; }
.x-attribut { color: #9a4b1e; }
.x-valeur { color: #2c7a4b; }
.x-ponctuation { color: #8a97a6; }
.x-texte { color: var(--texte); }

/* Dans une valeur : le balisage maison, le LaTeX et les entités XML ne sont pas
 * du texte ordinaire — les distinguer évite de les casser par mégarde. */
.x-balisage { color: #b3651a; background: #fdf3e7; border-radius: 2px; }
.x-maths { color: #7a4fbd; background: #f4eefc; border-radius: 2px; }
.x-entite { color: #6f7f8c; }

/* Une couleur se montre : on la souligne de la teinte qu'elle produira.
 * Une ombre intérieure n'occupe aucune place — l'alignement au caractère près
 * tient. Le liseré gris sous la teinte n'est pas décoratif : « blanc » est une
 * valeur courante dans ces scripts (elle sert à rendre un point invisible), et
 * sans lui elle serait indiscernable du fond. */
.x-couleur {
  color: #2c7a4b;
  box-shadow: inset 0 -2px 0 0 var(--teinte), inset 0 -3px 0 0 #c9d2dc;
}
.x-couleur-fausse { color: #a3231b; text-decoration: underline wavy; }

.colonne { display: flex; flex-direction: column; gap: .5rem; min-height: 0; }
.colonne .entete { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.colonne .entete .titre { font-weight: 600; font-size: .9rem; }
.colonne > .editeur-xml, .colonne > .scene { flex: 1; min-height: 0; }

@media (max-width: 900px) {
  .atelier { grid-template-columns: 1fr; height: auto; }
  .atelier .scene { height: 70vh; }
  /* Le calque de coloration et le champ sont positionnés en absolu : la boîte
   * qui les porte n'a donc aucune hauteur propre. Tant que l'atelier occupe
   * tout l'écran, « flex: 1 » suffit ; une fois les colonnes empilées et la
   * hauteur laissée libre, il faut la lui donner explicitement — et remettre
   * « flex: none » avec, car sous « flex: 1 » la base vaut zéro et c'est elle,
   * non la hauteur, qui décide de la taille sur l'axe principal.
   *
   * Ce bloc doit rester APRÈS la règle « .colonne > … » ci-dessus : à
   * spécificité égale, c'est l'ordre qui tranche. */
  .colonne > .editeur-xml { flex: none; height: 60vh; }
}

.message {
  padding: .4rem .7rem;
  border-radius: var(--rayon);
  font-size: .88rem;
  display: none;
}
.message.visible { display: block; }
.message.ok { background: #e6f4ec; color: var(--ok); border: 1px solid #b8dcc6; }
.message.ko { background: #fdeceb; color: #a3231b; border: 1px solid #f2c3bf; }
.message.info { background: var(--accent-clair); color: var(--accent); border: 1px solid #bcd8ea; }

/* --- police des animations ---
 *
 * Carlito est auto-hébergée plutôt que simplement citée dans une pile, pour une
 * raison mesurable : les textes des animations sont placés en coordonnées
 * absolues dans un cadre de 800x600. Une police plus large déborde.
 *
 * Mesuré sur une phrase d'étape typique, par rapport au rendu d'origine :
 *   Carlito / Calibri  +0,6 %      Segoe UI          +9,6 %
 *   Arial / Helvetica  +12,2 %     DejaVu Sans      +26,7 %
 *
 * Or Arial est le repli courant sur macOS et DejaVu Sans celui de nombreuses
 * distributions Linux. S'en remettre aux polices du système ferait donc rendre
 * les mêmes animations différemment selon la machine, avec un risque réel de
 * débordement. En livrant la police, tout le monde voit exactement la même chose.
 *
 * Carlito est le clone libre de Calibri, aux mêmes métriques (SIL OFL 1.1).
 * Les noms qui suivent dans la pile ne servent qu'au cas où le chargement
 * échouerait, et sont classés du plus proche au plus éloigné en largeur.
 */
@font-face {
  font-family: Carlito;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/vendor/carlito/carlito-latin-400-normal.woff2') format('woff2');
}
@font-face {
  font-family: Carlito;
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/vendor/carlito/carlito-latin-400-italic.woff2') format('woff2');
}
@font-face {
  font-family: Carlito;
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/vendor/carlito/carlito-latin-700-normal.woff2') format('woff2');
}
@font-face {
  font-family: Carlito;
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url('/vendor/carlito/carlito-latin-700-italic.woff2') format('woff2');
}

/* Le lecteur ne connaît que deux sources de police, et aucune n'est l'attribut
 * « police » des scripts — celui-ci n'est jamais lu, vestige de l'époque Flash.
 *
 *  1. Pour les textes simples, aucun font-family n'est posé : l'élément hérite
 *     de « .svgIep { font-family: Serif } », injecté depuis le bundle du lecteur.
 *     Un sélecteur d'un cran plus spécifique suffit à reprendre la main, le
 *     style du lecteur étant injecté après cette feuille.
 *
 *  2. Pour les textes contenant du balisage HTML (gras, italique, souligné),
 *     le lecteur écrit « font-family: "Times New Roman", Times, serif » en style
 *     inline sur chaque tspan, sauf si le texte porte une balise <font face="…">.
 *     Un style inline ne se surcharge pas autrement que par !important — d'où
 *     son usage ici, qui ne piétine aucune déclaration voulue.
 */
svg.svgIep,
svg.svgIep text,
svg.svgIep tspan {
  font-family: Carlito, Calibri, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif !important;
}

/* --- la barre de contrôle du lecteur -------------------------------------
 *
 * Le lecteur dessine sa propre barre — lecture, pause, pas à pas, XML — en SVG,
 * dans le cadre de l'animation : dix-neuf boutons de 32 px, chacun un
 * `<circle r="15">` surmonté d'une icône blanche. Son aspect bombé ne vient pas
 * d'une image mais de deux choses qu'on peut défaire :
 *
 *   - un dégradé radial, « radialfonce » quand le bouton est actif,
 *     « radialclair » quand il ne l'est pas ;
 *   - un filtre `feDiffuseLighting` qui simule un éclairage ponctuel, et donne
 *     le relief plastique des interfaces d'il y a vingt ans.
 *
 * ## Pourquoi en CSS et pas dans le lecteur
 *
 * `npm run vendor` reconstruit `public/vendor/iep/` depuis les sources de
 * Sésamath : toute retouche du bundle serait perdue à la première mise à jour.
 * La feuille de style, elle, survit — c'est déjà la raison pour laquelle la
 * police des animations se règle ici.
 *
 * ## Pourquoi des sélecteurs d'attribut, et pourquoi !important
 *
 * Ces cercles n'ont ni classe ni identifiant : le seul point d'accroche est
 * leur style en ligne, d'où `[style*="radialfonce"]`. Et un style en ligne ne
 * se surcharge pas autrement que par `!important`. Les deux sont ici des
 * conséquences du code amont, pas des facilités.
 */
:root {
  --lecteur-actif: #1c6ea4;
  --lecteur-actif-survol: #14547f;
  --lecteur-inactif: #cdd7e0;
  /* Le rouge du bouton qui réclame une action : l'animation s'est arrêtée et
   * attend qu'on la relance. Il fonce vers le rouge de `.danger` au survol,
   * pour que le lecteur et l'interface parlent la même langue. */
  --lecteur-attente: #c0392b;
  --lecteur-attente-survol: var(--danger);
}

/* le fond des boutons : aplat franc, plus de dégradé ni de relief simulé */
svg.svgIep circle[style*="radialfonce"] {
  fill: var(--lecteur-actif) !important;
  filter: none !important;
}
svg.svgIep circle[style*="radialclair"] {
  fill: var(--lecteur-inactif) !important;
  filter: none !important;
}
/* Le lecteur a un troisième dégradé, qu'on oublie facilement parce qu'il ne
 * paraît qu'en cours de route : quand une action `pause` arrête l'animation,
 * le bouton Lecture est remplacé par un jumeau rouge qui réclame un clic.
 * Sans cette règle il restait bombé, seul vestige au milieu d'une rangée à
 * plat. */
svg.svgIep circle[style*="radialrouge"] {
  fill: var(--lecteur-attente) !important;
  filter: none !important;
}

/* Le survol manquait complètement : rien ne distinguait un bouton cliquable
 * d'un bouton éteint tant qu'on n'avait pas cliqué. */
svg.svgIep svg:hover circle[style*="radialfonce"] {
  fill: var(--lecteur-actif-survol) !important;
}
svg.svgIep svg:hover circle[style*="radialrouge"] {
  fill: var(--lecteur-attente-survol) !important;
}
svg.svgIep svg:has(circle[style*="radialfonce"]),
svg.svgIep svg:has(circle[style*="radialrouge"]) { cursor: pointer; }

/* --- la bascule Lecture / Pause ---
 *
 * Cinq éléments se partagent une seule place : un jumeau allumé et un éteint
 * pour chacun des deux boutons, plus le rouge de l'attente. Le lecteur les fait
 * alterner par l'attribut `visibility` — et non par un style en ligne, ce qui
 * permet de suivre son état en CSS, sans observateur. public/js/barre.js pose
 * les étiquettes `data-bascule` et `data-eteint`.
 *
 * Deux règles suffisent. La seconde tient au cas qu'un masquage en dur ratait :
 * **en fin d'animation**, le lecteur éteint tous les allumés et ne montre plus
 * que les gris. Sans elle, la place restait vide au lieu d'afficher un bouton
 * désactivé. */
svg.svgIep svg[data-bascule="pause"][data-eteint] { display: none; }

svg.svgIep g:has(> svg[data-bascule][visibility="visible"]:not([data-eteint]))
  > svg[data-bascule="lecture"][data-eteint] { display: none; }

/* Pendant la lecture, le lecteur éteint tout sauf Pause. public/js/barre.js
 * rebranche les autres — un clic met en pause puis exécute l'action — et pose
 * cet attribut sur ceux qu'il a rendus au service. Ils ne doivent alors plus
 * avoir l'air éteints : un bouton gris qui répond est un mensonge.
 *
 * D'où la condition : **seulement pendant la lecture**, que l'on reconnaît à
 * l'icône Pause allumée. À l'arrêt, le gris du lecteur veut dire tout autre
 * chose — il n'y a rien au bout de ce bouton-là — et il doit rester gris. Le
 * mensonge serait alors dans l'autre sens. */
svg.svgIep g:has(> svg[data-bascule="pause"][visibility="visible"]:not([data-eteint]))
  svg[data-utilisable] { cursor: pointer; }
svg.svgIep g:has(> svg[data-bascule="pause"][visibility="visible"]:not([data-eteint]))
  svg[data-utilisable] circle[style*="radialclair"] {
  fill: var(--lecteur-actif) !important;
}
svg.svgIep g:has(> svg[data-bascule="pause"][visibility="visible"]:not([data-eteint]))
  svg[data-utilisable]:hover circle[style*="radialclair"] {
  fill: var(--lecteur-actif-survol) !important;
}

/* Le bouton « XML » ouvre le source de l'animation dans une fenêtre à part.
 * L'éditeur le donne déjà, et sur le domaine public il n'a rien à faire là.
 *
 * On le désigne par ce qui le distingue vraiment — c'est le seul dont l'icône
 * est un mot, un `<text>`, et non une forme — plutôt que par sa position dans
 * la rangée, qu'une future version du lecteur pourrait changer. Le
 * `[width="32"]` écarte les SVG de MathJax, qui contiennent parfois du texte
 * eux aussi mais se mesurent en pixels.
 */
svg.svgIep svg[width="32"]:has(> text) { display: none; }

/* Le placement des boutons restants — refermer ce trou-ci, et celui que laisse
 * la fusion de Lecture et Pause — est calculé dans public/js/barre.js. Deux
 * décalages écrits en CSS finissaient par s'additionner sur le même bouton. */

/* Les icônes sont tracées en blanc par le lecteur ; on ne fait que les affiner,
 * les traits d'origine étant épais pour compenser le relief qu'on vient d'ôter. */
svg.svgIep svg > polygon,
svg.svgIep svg > rect,
svg.svgIep svg > path {
  stroke-linejoin: round;
  stroke-linecap: round;
}

/* Les deux boutons de zoom, eux, sont de vrais <button> posés par le lecteur
 * par-dessus la scène. Ils héritaient du style des boutons de l'application,
 * dont la hauteur minimale les déformait. */
.scene > button {
  min-height: 0;
  padding: 0;
  font-size: 1.05rem;
  line-height: 1;
  border-radius: 999px;
  opacity: .85;
}
.scene > button:hover { opacity: 1; }
