/* ------------------------------------------------------------------
   styles.css — interface principale.

   Deux modes, deux zones. Exploration : le signe à gauche, sous trois
   vues, les réglages à droite, réduits à un noyau. Construction : le
   même aperçu à gauche, et la casse de caractères à la place des
   réglages.

   La police de l'interface est **Baskemo Sans**, une fonte de la maison,
   vendorisée dans `fonts/` : deux `.woff2`, aucun build, aucune requête
   vers l'extérieur. Le rendu ne dépend donc plus de ce que la machine a
   d'installé — c'est l'inverse de la règle précédente, et c'est voulu.
   Voir `docs/adr/0028`.
   ------------------------------------------------------------------ */

/*
 * Deux fichiers suffisent : la famille n'a que le romain et l'italique, et
 * rien n'est gras. `font-display: block` parce que le fichier est **local** :
 * il arrive en une fraction de milliseconde, et le montrer après coup ferait
 * sauter toute la mise en page sous l'œil.
 */
@font-face {
  font-family: 'BaskemoSans';
  src: url('../fonts/BaskemoSans-Regular.woff2') format('woff2');
  font-weight: normal;
  font-style: normal;
  font-display: block;
}

@font-face {
  font-family: 'BaskemoSans';
  src: url('../fonts/BaskemoSans-Italic.woff2') format('woff2');
  font-weight: normal;
  font-style: italic;
  font-display: block;
}

:root {
  /* `color-scheme` n'est pas décoratif : c'est lui qui décide du dessin des
     commandes natives — barres de défilement, cases à cocher, listes
     déroulantes. Sans lui, le thème sombre garde des ascenseurs blancs. */
  color-scheme: light;

  --fond: #f4f4f2;
  --fond-panneau: #ffffff;
  --encre: #131313;
  --bordure: #dedddb;
  --texte-doux: #6d6c69;

  /* Ce qui se pose **sur** l'encre : le libellé d'un bouton plein, le nom du
     mode courant. Ce n'est pas `--fond`, c'est son contraire — et c'est pour
     cela que les deux basculent ensemble. */
  --sur-encre: #ffffff;
  --ombre: 0 6px 18px rgba(0, 0, 0, 0.12);

  /* La **seule couleur** de l'interface : le signe choisi dans l'aperçu. Un
     bleu franc, assez sombre pour tenir sur le fond clair ; sur le fond
     sombre, le même bleu éclairci, sans quoi il s'éteindrait au lieu de
     marquer. */
  --selection: #1b5ed8;
  --rayon: 6px;
  /* Le petit rayon des éléments serrés dans un coin : un cran sous `--rayon`.
     Il n'était pas nommé, et se répétait en clair quatre fois. */
  --rayon-petit: 4px;
  /* La hauteur d'une commande — bouton d'icône, menu, champ. Elle revient dix
     fois dans la feuille, et c'est elle qui fait tomber les boutons du haut à
     10 px du bord comme ceux du bas. */
  --hauteur-commande: 34px;
  --police: 'BaskemoSans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --police-mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

/*
 * Le thème **sombre**.
 *
 * Il suit le système tant qu'aucun choix n'a été fait — c'est le cas de
 * `html:not([data-theme])` — puis le choix l'emporte. L'attribut est posé sur
 * `<html>` par `interface.js`, et rangé par `preferences.js` : il ne va pas
 * dans `michaux.json`, un thème n'ayant rien à faire dans un fichier de
 * travail. Voir `docs/adr/0029`.
 *
 * La palette est écrite deux fois, une fois pour le système et une fois pour
 * le choix explicite, faute de pouvoir poser une condition sur un média et un
 * attribut à la fois. `light-dark()` le ferait d'un coup, mais il demande un
 * navigateur de 2024 : la page doit continuer de s'ouvrir partout.
 */
@media (prefers-color-scheme: dark) {
  html:not([data-theme]) {
    color-scheme: dark;
    --fond: #171716;
    --fond-panneau: #1f1f1e;
    --encre: #ededea;
    --bordure: #3b3b38;
    --texte-doux: #9c9c97;
    --sur-encre: #171716;
    --ombre: 0 6px 18px rgba(0, 0, 0, 0.55);
    --selection: #78a9ff;
  }
}

html[data-theme="sombre"] {
  color-scheme: dark;
  --fond: #171716;
  --fond-panneau: #1f1f1e;
  --encre: #ededea;
  --bordure: #3b3b38;
  --texte-doux: #9c9c97;
  --sur-encre: #171716;
  --ombre: 0 6px 18px rgba(0, 0, 0, 0.55);
  --selection: #78a9ff;
}

/* Un choix explicite de thème clair l'emporte sur un système sombre. */
html[data-theme="clair"] {
  color-scheme: light;
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  background: var(--fond);
  color: var(--encre);
  font-family: var(--police);
  font-size: 14px;
  line-height: 1.4;
  /* Les trois règles de BaskemoSans, posées une fois pour toutes : capitales,
     interlignage ouvert, et **rien en gras** — la famille n'a qu'un romain et
     un italique, et un gras synthétique abîmerait le dessin. La hiérarchie
     passe par la taille et par la couleur, pas par la graisse. */
  font-weight: normal;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

/*
 * Un contrôle de formulaire **n'hérite pas** de `text-transform` : la feuille
 * du navigateur le force à `none` sur `button`, `input`, `select` et
 * `textarea`. Mesuré : `span=uppercase` mais `button=none`. Les boutons sont
 * donc des libellés d'interface comme les autres, et reprennent les capitales
 * à la main — sans quoi la page serait en capitales partout **sauf** sur ce
 * qui se clique.
 */
button {
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

/*
 * Le « reset » des zones qui ne sont pas de l'interface : ce qui se lit comme
 * une phrase ou comme une donnée — un message, un nom de caractère, un nom de
 * style tapé par l'utilisateur, le « i » du bouton rond — garde sa casse et son
 * espacement. Une capitale sur un point de code serait un contresens, et une
 * capitale sur un nom propre une faute.
 *
 * Les champs de saisie sont nommés un par un, pour la raison inverse de
 * ci-dessus : leur `none` ne vient pas de l'héritage, il faut le leur redire.
 */
.casse-note,
.styles-note,
.typo-note,
.projet-etat,
.fonte-chapeau,
.fonte-chasse,
.cellule-caractere,
.style-libelle,
.style-ligne-nom,
.i,
input,
select,
textarea,
::placeholder {
  text-transform: none;
  letter-spacing: 0;
}

/* Le `hidden` de l'HTML doit gagner sur les `display` posés plus bas */
[hidden] {
  display: none !important;
}

/*
 * Trois rangs : la barre du haut, la zone d'aperçu, la barre du bas — et le
 * panneau de droite, qui les traverse tous les trois.
 *
 * Les deux barres n'occupent que la **colonne de gauche** : les commandes
 * appartiennent à l'aperçu, et une barre qui court sous les réglages donnerait
 * à ceux-ci une bande d'outils qu'ils n'ont pas. Voir `docs/adr/0031`.
 */
.interface {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  /* Le rang du milieu est borné à la hauteur de la fenêtre. Sans le
     `minmax(0, 1fr)`, il est de hauteur automatique : la grille de signes
     l'allonge, le `height: 100%` de la zone gauche ne résout plus, et c'est
     toute la page qui défile au lieu de la seule grille. */
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "haut   droite"
    "signe  droite"
    "bas    droite";
  height: 100vh;
  height: 100dvh;
}

/* --- Les deux barres ------------------------------------------------ */

/*
 * Une barre est un rang de commandes posé dans l'aperçu. Elle n'a **ni fond ni
 * filet** : elle prend celui de la page, comme la zone de signes qu'elle
 * encadre, et les icônes ont l'air de flotter dessus. Ce qu'elle contient se
 * suffit : un bouton a déjà sa bordure, et le vide autour fait le reste.
 */
.barre {
  display: flex;
  align-items: center;
  gap: 8px;
  /* Le rembourrage est plus court que celui de l'aperçu : la colonne a perdu
     la moitié de sa largeur, et ces quelques pixels sont ceux qui font tenir
     le rang du bas d'un seul tenant. */
  padding: 10px 16px;
}

/*
 * La barre du haut est une grille, et non un rang flexible. Les deux groupes
 * sont dans les deux pistes `1fr`, qui reçoivent **la même largeur** : le nom,
 * au milieu, tombe donc exactement au centre de la barre, et non au milieu de
 * l'espace libre — un simple `space-between` le décalait du côté du groupe le
 * plus étroit, et la vue compte trois boutons contre deux au mode.
 *
 * La piste du milieu est `minmax(0, auto)`, et c'est ce qui la rend sûre : elle
 * se dimensionne sur le nom tant qu'il y a la place, mais son minimum est zéro,
 * donc un nom très long se coupe au lieu de pousser les deux groupes hors de la
 * colonne. Les deux `1fr`, eux, ne descendent jamais sous leur contenu : les
 * boutons ne sont jamais rognés.
 */
.barre-haut {
  grid-area: haut;
  display: grid;
  grid-template-columns: 1fr minmax(0, auto) 1fr;
  align-items: center;
  gap: 12px;
}

/*
 * La barre du bas ne porte plus que le rang des commandes : les messages sont
 * partis debout sur le bord gauche. Sa hauteur est donc celle d'un bouton et de
 * son rembourrage — la même que celle du haut — et les deux barres se
 * répondent. `align-items: stretch` et le pli en colonne restent : c'est la
 * règle de grand écran, plus bas, qui coupe la rangée.
 */
.barre-bas {
  grid-area: bas;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  /* Un rang qui ne se coupe pas débordera un jour : il défile en travers
     plutôt que de rogner la dernière commande. */
  overflow-x: auto;
}

/* --- Les boutons d'icône -------------------------------------------- */

/*
 * Un bouton qui ne porte qu'un dessin. La largeur est fixe pour que le rang
 * reste régulier, et la hauteur est la même pour tous : boutons, cases à
 * cocher, croix et menu s'alignent ainsi sans y penser.
 *
 * Le carré fait 34 : la colonne de l'aperçu n'a plus que la moitié de la page,
 * et quatre pixels par bouton valent bien une commande de plus qui reste
 * visible.
 *
 * Le libellé disparu est redit par le `title` — au survol — et par un
 * `aria-label` sur la commande, sans quoi le bouton n'aurait plus de nom.
 */
.bouton-icone {
  position: relative;
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--hauteur-commande);
  height: var(--hauteur-commande);
  padding: 0;
  font: inherit;
  color: var(--texte-doux);
  background: var(--fond-panneau);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  cursor: pointer;
}

.bouton-icone:hover {
  color: var(--encre);
  border-color: var(--encre);
}

/* Le focus se lit sur le bouton, jamais sur la commande cachée qu'il porte :
   une case à cocher invisible ne montrerait son contour nulle part. */
.bouton-icone:focus-visible,
.bouton-icone:has(input:focus-visible) {
  outline: 2px solid var(--encre);
  outline-offset: 2px;
}

/* Le geste principal garde l'encre pleine : c'est la hiérarchie d'avant. */
.bouton-icone-principal {
  color: var(--sur-encre);
  background: var(--encre);
  border-color: var(--encre);
}

.bouton-icone-principal:hover {
  color: var(--sur-encre);
  border-color: var(--encre);
  opacity: 0.86;
}

.bouton-icone:disabled,
.bouton-icone:disabled:hover {
  opacity: 0.4;
  cursor: default;
  border-color: var(--bordure);
}

/* Le dessin des icônes : un trait de 1,5 dans une boîte de 16, qui prend la
   couleur du bouton et suit donc l'état actif comme le thème. */
.icone {
  display: block;
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Un point plein — les pips du dé, les nœuds de la courbe — ne se dessine pas
   au trait : il se remplit. */
.icone .plein {
  fill: currentColor;
  stroke: none;
}

/*
 * Le bouton de thème porte les deux dessins, et `interface.js` dit lequel se
 * montre par `data-theme-vers`. L'icône annonce ce que le clic **donnera** —
 * la lune sur une page claire — comme le libellé d'avant, qui annonçait déjà le
 * thème à venir et non celui qu'on voyait.
 */
.icone-lune {
  display: none;
}

[data-theme-vers="sombre"] .icone-soleil {
  display: none;
}

[data-theme-vers="sombre"] .icone-lune {
  display: block;
}

/* --- Les modes ------------------------------------------------------ */

/*
 * Deux modes, deux dessins, au bout droit de la barre du haut : Exploration,
 * l'interface d'avant, et Construction, où le signe se range dans une casse.
 * Le mode n'est ni une vue ni un réglage — il décide de ce que fait la page —
 * et il reste orthogonal aux trois vues, posées à l'autre bout.
 *
 * Les deux boutons se touchent : ils disent la même chose — dans quel mode on
 * est — et le cadre unique le montre, exactement comme la barre des vues. C'est
 * le procédé du sélecteur segmenté, à une différence près : ici l'étiquette
 * **est** le bouton, elle n'est pas enveloppée d'un `<span>`.
 */
.modes {
  display: flex;
  justify-self: end;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  overflow: hidden;
  background: var(--fond-panneau);
}

/* Le radio et la case restent dans le DOM, donc accessibles au clavier, mais
   invisibles : c'est l'étiquette entière qui fait le bouton. */
.mode input,
.case input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

/*
 * Un mode **dans son cadre** perd sa bordure et ses coins : c'est le cadre du
 * groupe qui les porte. Seul le second garde un filet, celui qui les sépare.
 */
.mode {
  border: 0;
  border-radius: 0;
  background: transparent;
}

.mode + .mode {
  border-left: 1px solid var(--bordure);
}

/* Le mode courant se lit d'un coup d'œil : le bouton entier passe à l'encre */
.mode:has(input:checked) {
  color: var(--sur-encre);
  background: var(--encre);
}

/* Le focus se lit **dans** le cadre : un contour décalé serait rogné par le
   `overflow: hidden` du groupe. Même règle que les vues. */
.mode:has(input:focus-visible) {
  outline: 2px solid var(--encre);
  outline-offset: -2px;
}

/* --- Le style courant, au milieu de la barre du haut ---------------- */

/*
 * Ce que le menu des styles annonçait, réduit à l'essentiel : le signe du style
 * en petit, puis son nom. Pas de cadre, pas de fond — c'est un bouton, mais il
 * se lit comme un titre, et le clic ouvre la liste au lieu de dérouler un menu.
 * Voir `docs/adr/0035`.
 */
.style-courant {
  justify-self: center;
  min-width: 0;
  max-width: 100%;
}

.style-nom {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
  max-width: 100%;
  padding: 4px 8px;
  font: inherit;
  color: var(--texte-doux);
  background: none;
  border: 0;
  border-radius: var(--rayon);
  cursor: pointer;
}

.style-nom:hover {
  color: var(--encre);
}

.style-nom:focus-visible {
  outline: 2px solid var(--encre);
  outline-offset: 2px;
}

/*
 * Le nom vient d'un fichier ou d'un champ de saisie : il garde sa casse — d'où
 * le `text-transform: none` du bloc de remise à zéro en tête de ce fichier — et
 * se coupe par des points de suspension quand la fenêtre se rétrécit, plutôt
 * que de pousser les deux groupes hors de la colonne.
 */
.style-libelle {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 14px;
}

/* La vignette : le signe du style, à la taille d'une icône. Elle est toujours
   montrée, même sans style chargé — c'est alors le signe en cours, celui qui
   s'enregistrera. Un cadre très léger la sépare du fond sans la border. */
.vignette-style {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  overflow: hidden;
}

.vignette-style .signe {
  width: 100%;
  height: 100%;
}

/* --- Zone gauche : les trois vues ---------------------------------- */

.zone-signe {
  grid-area: signe;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  height: 100%;
  min-width: 0;
  padding: 24px;
  /* La place du rail de transformations est réservée **dans les deux modes**,
     et non seulement en Construction où le rail se montre. Réservée seulement
     là, elle rétrécissait la boîte d'aperçu au passage d'un mode à l'autre :
     le signe glissait de 34 px vers la gauche. Mesuré avant correction. Voir
     `docs/adr/0017` : une piste qui suit son contenu plutôt que la place
     qu'on lui donne finit toujours par déplacer ce qu'on regarde.
     
     Elle vaut 64 : les 12 px du bord, les 34 px d'un bouton désormais carré,
     puis 18 px d'air. Le rail portait des lettres et des mots larges de 62 px ;
     depuis qu'il est en icônes, la réserve a suivi. Mesuré : le signe ne glisse
     pas d'un mode à l'autre, et ne touche pas le rail. */
  padding-right: 64px;
}

/*
 * Les transformations vivent sur le bord droit de l'aperçu, en colonne : les
 * trois gestes collés en haut, « reprendre » à part sous eux — il appartient à
 * un autre propos. Le rail est **absolu** pour ne pas entrer dans la colonne de
 * la zone — l'aperçu doit rester centré et les actions à leur place — et il
 * ne vit qu'en Construction, devant un signe seul.
 *
 * Le rembourrage de la zone le paie — **dans les deux modes**, et non
 * seulement quand le rail se montre : sans lui, le rail mangerait le bord du
 * signe le plus large, et la réserve qui va et vient ferait glisser l'aperçu.
 * Voir `docs/adr/0050`.
 */
.transformations {
  position: absolute;
  top: 50%;
  right: 12px;
  display: none;
  flex-direction: column;
  gap: 8px;
  transform: translateY(-50%);
}

/*
 * Les transformations ne paraissent que devant **un signe seul** : ce sont des
 * gestes portés sur un dessin, et une vue qui en montre quatre ou trois cents
 * ne dit pas lequel on retourne. La vue est donc lue elle aussi, par
 * `data-vue`, écrit sur `<main>` comme le mode. Voir `docs/adr/0057`.
 */
.interface[data-mode="construction"][data-vue="signe"] .transformations {
  display: flex;
}

/*
 * Un bouton de transformation : la même case que les autres icônes de la page,
 * et la même épaisseur de trait. Le rail a donc la largeur d'une colonne de
 * boutons, là où les lettres et les mots qu'il portait demandaient 62 px.
 */
.transformation {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--hauteur-commande);
  height: var(--hauteur-commande);
  padding: 0;
  font: inherit;
  color: var(--texte-doux);
  background: var(--fond-panneau);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  cursor: pointer;
}

.transformation:hover {
  color: var(--encre);
  border-color: var(--texte-doux);
}

.transformation:focus-visible {
  outline: 2px solid var(--encre);
  outline-offset: 2px;
}

/* Une symétrie active est un **état**, pas un geste : elle reste allumée, et se
   lit d'un coup d'œil sans avoir à retourner le signe pour vérifier. */
.transformation[aria-pressed="true"] {
  color: var(--sur-encre);
  background: var(--encre);
  border-color: var(--encre);
}

/* Base : le signe est posé au centre de la zone. */
.vue {
  flex: 1;
  width: 100%;
  min-height: 0;
}

/* --- Les vues ------------------------------------------------------- */

/*
 * Les deux vues à cases souples passent par flexbox, pas par une grille.
 * Une piste de grille `auto` se dimensionne sur la contribution intrinsèque
 * de son contenu : un SVG en `aspect-ratio` y contribue une hauteur de
 * quelques pixels, et les cases se chevauchent. En flex, la hauteur se déduit
 * d'une largeur déjà résolue.
 */

.vue-signe,
.vue-quatre {
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  justify-content: center;
  gap: 14px;
  max-width: min(100%, 74vh);
}

/* Un signe, aussi grand que la zone le permet */
.vue-signe .signe {
  height: min(100%, 62vh);
  aspect-ratio: 1 / 1;
}

/* Quatre signes : la famille, sous les yeux */
.vue-quatre .signe {
  width: calc(50% - 7px);
  aspect-ratio: 1 / 1;
}

/*
 * La grille s'allonge, et c'est elle qui défile. Quatre colonnes, toujours :
 * les cases se partagent la largeur disponible plutôt que d'avoir une taille
 * fixe — une taille fixe ne tiendrait pas quatre colonnes sur une fenêtre
 * étroite, et forcerait un défilement horizontal. `minmax(0, 1fr)` borne la
 * piste par le bas : sans ce `0`, le contenu dicterait la largeur et les
 * cases se chevaucheraient.
 */
.vue-grille {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: auto;
  align-content: start;
  gap: 10px;
  /* De l'air sur les côtés : le conteneur défile en vertical, donc il coupe
     aussi en horizontal à sa boîte de padding. Cette marge est la place
     laissée aux signes de bord qui débordent de leur case. */
  padding: 0 18px;
  overflow-y: auto;
  /* La barre de scroll n'a rien à dire : le défilement reste actif, elle
     reste juste invisible. */
  scrollbar-width: none;
}

.vue-grille::-webkit-scrollbar {
  display: none;
}

/* La réserve du rail de transformations ne vaut que devant un signe seul :
   la grille n'a pas de rail, et mérite toute la largeur de la zone. */
.interface[data-vue="grille"] .zone-signe {
  padding-right: 24px;
}

/* Une case carrée dont le côté suit la largeur de la piste. */
.vue-grille .signe {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
}

/* Un signe peut dépasser de sa case : il est centré dedans, mais rien ne le
   coupe. Le débordement est voulu — le redimensionner donnerait à chaque
   signe une épaisseur différente. Voir `docs/adr/0017`. */
.signe {
  display: block;
  overflow: visible;
  /* Les chemins héritent de cette couleur via currentColor */
  color: var(--encre);
}

/*
 * Le signe qu'on vient de cliquer, dans les vues à plusieurs signes.
 *
 * Il passe **entier** au bleu : `currentColor` fait le travail, et rien d'autre
 * ne change — ni la taille, ni la place, ni le tracé. C'est la seule couleur de
 * la page, et elle n'a qu'un sens : « c'est celui-là ». Voir `docs/adr/0042`.
 */
.signe.choisi {
  color: var(--selection);
}

/* --- Boutons -------------------------------------------------------- */

/*
 * Le rang des commandes du bas. Il ne se coupe pas : la barre qui l'encadre
 * lui donne la place, et un rang unique se lit d'un regard. Le projet part à
 * l'autre bout par une marge automatique — c'est un geste rare, il ne
 * s'intercale pas entre les commandes du signe.
 *
 * `min-width: 0` reste par prudence : si la colonne ne peut plus rien donner,
 * c'est la barre qui défile en travers, jamais le panneau qui déborde.
 */
.actions {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  /* L'écart entre les **groupes** : c'est lui qui dit où l'un finit et où
     l'autre commence, les boutons d'un même groupe se touchant. */
  gap: 14px;
  min-width: 0;
}

/*
 * Un groupe de boutons qui vont ensemble : ils se touchent. Le collage se fait
 * par un chevauchement d'un pixel — chaque bouton garde sa bordure, et celle du
 * suivant recouvre celle du précédent — puis les coins intérieurs sont
 * redressés. Un groupe d'un seul bouton n'est donc pas touché : il garde ses
 * quatre coins, ce qui est voulu.
 *
 * Les deux sélecteurs s'appuient sur la position réelle dans le DOM : le champ
 * de fichier du projet, qui est `hidden`, est donc posé **hors** du groupe, sans
 * quoi il compterait comme un dernier enfant et le bouton « Ouvrir » perdrait
 * son coin droit sans rien avoir à sa droite.
 */
/*
 * Le même principe que `.groupe-boutons`, mais **debout** : les boutons d'une
 * même colonne se chevauchent d'un pixel et leurs coins mitoyens s'aplatissent,
 * ce qui n'en laisse qu'un seul cadre. Le premier et le dernier gardent leur
 * arrondi, donc le groupe se lit comme un seul bouton coupé en trois.
 */
.groupe-colonne {
  display: flex;
  flex-direction: column;
}

.groupe-colonne > * + * {
  margin-top: -1px;
}

.groupe-colonne > *:not(:first-child) {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

.groupe-colonne > *:not(:last-child) {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

.groupe-boutons {
  display: flex;
  align-items: center;
}

.groupe-boutons > * + * {
  margin-left: -1px;
}

.groupe-boutons > *:not(:first-child) {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

.groupe-boutons > *:not(:last-child) {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.projet-barre {
  margin-left: auto;
}

.bouton {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 18px;
  font: inherit;
  color: var(--sur-encre);
  background: var(--encre);
  border: 1px solid var(--encre);
  border-radius: var(--rayon);
  cursor: pointer;
}

.bouton:hover {
  opacity: 0.86;
}

.bouton:focus-visible {
  outline: 2px solid var(--encre);
  outline-offset: 2px;
}

/* Action secondaire : même forme que « Régénérer », mais en clair. Les deux
   boutons ne font pas la même chose — l'un retire un signe, l'autre change
   tous les réglages — et la hiérarchie visuelle doit le dire. */
.bouton-clair {
  color: var(--encre);
  background: var(--fond-panneau);
  border-color: var(--bordure);
}

.bouton-clair:hover {
  border-color: var(--encre);
  opacity: 1;
}

/*
 * Un bouton éteint reste à sa place, mais il ne promet plus rien. Sans cette
 * règle, un `.bouton` désactivé garde l'encre pleine du bouton principal et
 * semble cliquable : « Assigner » sans case choisie en est le cas.
 */
.bouton:disabled,
.bouton:disabled:hover,
.bouton-clair:disabled,
.bouton-clair:disabled:hover {
  opacity: 0.4;
  cursor: default;
}

.bouton-clair:disabled,
.bouton-clair:disabled:hover {
  border-color: var(--bordure);
}

/*
 * Les deux cases à cocher — points et poignées, repères typographiques — ont
 * perdu leur case visible : **le bouton entier se remplit** quand l'option est
 * active, comme le mode courant. Le dessin porte seul le sens, et le `title`
 * le redit. La règle est plus spécifique que le survol, donc l'état actif ne
 * s'efface pas sous la souris.
 */
.case {
  user-select: none;
}

.case:has(input:checked) {
  color: var(--sur-encre);
  background: var(--encre);
  border-color: var(--encre);
}

/* --- Sélecteur segmenté (les vues) ---------------------------------- */

/*
 * Trois vues, trois dessins, dans un seul cadre : les cases se touchent, ce
 * qui dit qu'elles s'excluent. C'est l'ancienne barre segmentée, sans ses
 * libellés. Le mode, à l'autre bout, se dessine exactement pareil — deux
 * groupes qui se répondent.
 */
.segments {
  display: flex;
  justify-self: start;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  overflow: hidden;
  background: var(--fond-panneau);
}

.segment {
  position: relative;
}

.segment + .segment {
  border-left: 1px solid var(--bordure);
}

/* Le radio reste dans le DOM, donc accessible au clavier, mais invisible */
.segment input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.segment span {
  display: flex;
  align-items: center;
  justify-content: center;
  /* La même case que les boutons d'icône : les deux groupes du haut se
     répondent, et le sélecteur ne prend pas plus de place que nécessaire. */
  width: var(--hauteur-commande);
  height: var(--hauteur-commande);
  cursor: pointer;
}

.segment input:checked + span {
  color: var(--sur-encre);
  background: var(--encre);
}

.segment input:focus-visible + span {
  outline: 2px solid var(--encre);
  outline-offset: -2px;
}

/* --- Zone droite : trois panneaux, un seul montré -------------------- */

/*
 * La colonne de droite en porte trois : les réglages en Exploration, la casse
 * en Construction, et la liste des styles — celle-ci n'appartenant à aucun
 * mode, elle se pose devant celui qui est courant. Un seul est visible à la
 * fois, et c'est `afficherPanneau` qui tranche, non le mode. C'est ce bloc qui
 * porte le fond et le filet, et non les panneaux : changer de panneau ne doit
 * pas déplacer la bordure de la fenêtre. Voir `docs/adr/0056`.
 */
.zone-droite {
  grid-area: droite;
  display: flex;
  min-width: 0;
  /* Le panneau traverse les trois rangs ; sans ce `0`, sa hauteur minimale
     suivrait son contenu et ferait grandir la fenêtre au lieu de défiler. */
  min-height: 0;
  background: var(--fond-panneau);
  border-left: 1px solid var(--bordure);
}

/* Le panneau visible remplit la colonne et défile seul. Les trois partagent
   cette charpente : seul leur contenu les distingue. */
.zone-reglages,
.zone-casse,
.zone-styles {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
  min-height: 0;
  padding: 32px;
  overflow-y: auto;
}

/*
 * Le panneau des réglages ne défile **pas** lui-même : sa barre de pli reste
 * immobile en tête, et c'est la liste des catégories qui défile sous elle.
 * `overflow: hidden` est ce qui fait tenir les deux — sans lui, la barre
 * remonterait avec le contenu. Le rembourrage reste ici, comme pour la casse :
 * la barre et la liste partagent donc exactement la même largeur utile.
 *
 * Le haut vaut 10 px, celui des barres de la page : c'est ce qui met les deux
 * boutons de pli à la hauteur des boutons de vue, en face. Voir `docs/adr/0050`.
 */
.zone-reglages {
  padding: 10px 32px 0;
  overflow: hidden;
}

/* La liste, seule partie qui défile. Le rembourrage du bas voyage avec elle,
   pour que la dernière catégorie ne colle pas au bord. */
.sections {
  flex: 1;
  min-height: 0;
  padding-bottom: 32px;
  overflow-y: auto;
}

/* --- Les styles rangés ----------------------------------------------- */

/*
 * Le panneau des styles prend la place de celui du mode : sa barre en haut —
 * une seule croix, à la même place que le « i » de la typographie, donc à
 * 10 px du haut et 16 px du bord — puis la liste, seule à défiler. Voir
 * `docs/adr/0056`.
 */
.zone-styles {
  padding: 10px 24px 20px;
  overflow: hidden;
}

.styles-barre-haut {
  display: flex;
  flex: none;
  justify-content: flex-start;
  margin-left: -8px;
}

/* Le panneau n'a pas de titre : le nom du style qu'on a cliqué est en haut de
   la page, et le répéter ici ne dirait rien de plus. */
.styles-vide {
  margin: 0;
  padding: 20px 0;
  font-size: 13px;
  color: var(--texte-doux);
}

/* --- La casse ------------------------------------------------------- */

/*
 * La casse : la **grille en tête**, puis le bloc *Typographie* replié, puis ce
 * que le panneau garde sous les yeux. Seule la grille défile — le panneau, lui,
 * ne bouge pas — donc la barre du bas reste immobile sous les cellules, comme
 * la barre de pli reste immobile au-dessus des réglages. Voir `docs/adr/0040`
 * et `docs/adr/0044`.
 */
.zone-casse {
  /* Le haut vaut 10 px, celui des barres de la page : le « i » tombe ainsi à
     la hauteur des boutons de vue, en face. Voir `docs/adr/0050`. */
  padding: 10px 24px 20px;
  overflow: hidden;
}

/*
 * La ligne du haut, en deux bouts : le « i » à gauche — qui tombe exactement
 * sous les boutons de la colonne de gauche : 10 px du haut comme les barres de
 * la page, et 16 px du bord, le panneau étant rembourré de 24, d'où les 8 px
 * rendus ici —, et la typographie ouverte à droite. Voir `docs/adr/0050`.
 */
.casse-barre-haut {
  display: flex;
  flex: none;
  align-items: center;
  gap: 8px;
  margin-left: -8px;
}

/*
 * La typographie ouverte : son nom, et les gestes qui la gèrent.
 *
 * Les gestes **ne se montrent qu'au survol** de ce bloc — nom compris, sans
 * quoi on ne pourrait pas les atteindre — ou quand le clavier y entre. Ils
 * gardent leur place en attendant (`visibility`, et non `display`), donc le nom
 * ne bouge pas d'un pixel quand ils paraissent. Voir `docs/adr/0053`.
 */
.typo-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  min-width: 0;
}

.typo-actions-boutons {
  display: flex;
  align-items: center;
  gap: 6px;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.14s ease;
}

.typo-actions:hover .typo-actions-boutons,
.typo-actions:focus-within .typo-actions-boutons {
  opacity: 1;
  visibility: visible;
}

/*
 * Ce que le panneau garde sous les yeux : les **glyphes alternatifs** de la
 * case choisie, puis ses messages. Tout le reste est dans la fenêtre de la
 * typographie. Elle prend la hauteur de son contenu — `flex: none` — et l'écart
 * de 14 px reprend celui du panneau.
 */
.casse-barre {
  display: flex;
  flex: none;
  flex-direction: column;
  gap: 14px;
}

.casse {
  flex: 1;
  min-height: 0;
  padding-bottom: 6px;
  overflow-y: auto;
}


/*
 * Le champ qui ajoute une case : le champ prend la place, le bouton garde la
 * sienne. C'est une commande de la casse, pas un réglage — elle est donc écrite
 * ici et non déduite des schémas du moteur.
 */
.casse-ajout {
  display: flex;
  gap: 10px;
}

.casse-ajout-champ {
  flex: 1;
  min-width: 0;
  padding: 10px 12px;
  font: inherit;
  font-size: 13px;
  color: var(--encre);
  background: var(--fond-panneau);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
}

.casse-ajout-champ::placeholder {
  color: var(--texte-doux);
}

.casse-ajout-champ:focus-visible {
  border-color: var(--encre);
  outline: 2px solid var(--encre);
  outline-offset: 1px;
}

/*
 * Les messages de la page — état du projet, notes de la bibliothèque et de la
 * casse — **debout** le long du bord gauche de l'aperçu.
 *
 * La colonne traverse **toute la hauteur** de la page, en-tête et barre du bas
 * comprises : c'est la seule façon de loger les plus longs messages, et elle
 * longe le bord sans rien rencontrer — les commandes commencent à 16 px, les
 * lettres de la colonne vivent avant.
 *
 * Chacun est **tourné d'un quart de tour** : `vertical-rl` écrit de haut en
 * bas, le demi-tour le remet dans l'autre sens, et le texte monte le long du
 * bord comme un dos de livre. `overflow: hidden` : un message plus long que la
 * page se coupe plutôt que de déborder sur les commandes, et les deux
 * avertissements de stockage ont été raccourcis pour que ça n'arrive pas.
 *
 * `pointer-events: none` : la colonne longe le bord, et rien de ce qu'on
 * saisit dans l'aperçu ne doit s'y arrêter.
 */
.notes-verticales {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  z-index: 1;
  /* La marge du texte : les lettres tombent à 16 px du bord, exactement sous
     le bord gauche des boutons de vue. Le rembourrage est sur la colonne et
     non sur ses messages, sans quoi le demi-tour les ferait glisser. */
  padding-left: 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  overflow: hidden;
  pointer-events: none;
}

.notes-verticales > * {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  max-height: 100%;
  margin: 0;
  font-size: 11px;
  color: var(--texte-doux);
  white-space: nowrap;
}

/* Ce qui n'est pas une information passagère se dit plus fort. */
.notes-verticales > .avertissement,
.notes-verticales > .en-attente {
  color: var(--encre);
}

/*
 * Les sections de la casse, l'une sous l'autre : un titre, puis ses cellules.
 * Le titre est collant — il reste en haut de la zone qui défile — parce qu'il
 * sert à se repérer dans trois cents cellules, et qu'un repère qu'on a dépassé
 * ne sert plus à rien.
 */
.bloc + .bloc {
  margin-top: 26px;
}

.bloc-titre {
  position: sticky;
  top: 0;
  z-index: 1;
  margin: 0 0 10px;
  padding: 6px 0;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--texte-doux);
  background: var(--fond-panneau);
}

/*
 * Les cellules : six colonnes, carrées comme le cadre d'un signe. Le nombre de
 * colonnes est posé par `interface.js` dans `--casse-colonnes`, et c'est la
 * même constante qui sert aux flèches du clavier : les deux ne peuvent pas
 * diverger. `minmax(0, 1fr)` borne la piste par le conteneur, donc
 * `aspect-ratio` est sûr ici — c'est le piège de l'ADR 0017.
 */
.cellules {
  display: grid;
  grid-template-columns: repeat(var(--casse-colonnes, 6), minmax(0, 1fr));
  gap: 6px;
}

.cellule {
  display: flex;
  flex-direction: column;
  aspect-ratio: 1 / 1;
  padding: 4px;
  font: inherit;
  color: var(--encre);
  background: var(--fond-panneau);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  cursor: pointer;
}

.cellule:hover {
  border-color: var(--texte-doux);
}

.cellule:focus-visible {
  outline: 2px solid var(--encre);
  outline-offset: -2px;
}

/* La case choisie : c'est elle que visera l'assignation, et c'est elle qui
   porte le focus clavier de la casse. */
.cellule.choisie {
  border-color: var(--encre);
  box-shadow: inset 0 0 0 1px var(--encre);
}

/* Une case qui contient quelque chose se creuse : le rangé se distingue du libre
   d'un coup d'œil, sur trois cents cases. */
.cellule.assignee {
  background: var(--fond);
}

/*
 * La case **ouverte dans l'aperçu** — celle qu'on est en train de fabriquer.
 *
 * Elle se marque autrement que la case choisie, et plus fort : les deux peuvent
 * différer, puisque le clavier déplace la sélection sans rien ouvrir. Un cadre
 * de deux pixels plutôt qu'un, parce que c'est celle-là qui répond à la question
 * « qu'est-ce que je regarde ? », et la réponse doit tenir sur trois cents cases.
 */
.cellule.ouverte {
  background: var(--fond);
  box-shadow: inset 0 0 0 2px var(--encre);
}

/*
 * L'aperçu : la place du signe, vide tant que la case n'est pas assignée.
 *
 * Il **coupe** ce qui dépasse, contrairement aux vues de gauche qui laissent
 * déborder (ADR 0017). À trois cents cases, un signe qui sort de la sienne
 * empiéterait sur ses voisines et la casse deviendrait illisible : une case est
 * un casier, pas un cadre.
 *
 * Le SVG garde ses proportions : son `viewBox` est carré et l'aperçu ne l'est
 * pas tout à fait, donc il se centre de lui-même dans la place laissée.
 */
.cellule-apercu {
  display: block;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.cellule-apercu .signe {
  width: 100%;
  height: 100%;
}

/* Le pied : le caractère seul, centré sous l'aperçu. Le point de code n'y est
   plus — c'est la ligne de sélection qui le dit, et le lecteur d'écran avec
   elle. Ce qu'on regarde dans une casse, c'est ce qu'elle contient, pas ses
   étiquettes. */
.cellule-pied {
  display: flex;
  align-items: baseline;
  justify-content: center;
  min-width: 0;
  color: var(--texte-doux);
}

.cellule-caractere {
  overflow: hidden;
  font-size: 12px;
  line-height: 1.1;
  white-space: nowrap;
}

/* --- La typographie et sa fonte -------------------------------------- */

/*
 * La fenêtre de la typographie. Plus large que celle des styles : elle porte
 * une grille de quatre métriques et huit champs d'identité. Son corps
 * **défile** — `min-height: 0` est ce qui l'y autorise, sans quoi la fenêtre
 * grandirait jusqu'à sortir de l'écran. Voir `docs/adr/0046` et
 * `docs/adr/0053`.
 */
#typo-modale {
  width: min(560px, calc(100vw - 32px));
}

#typo-modale[open] {
  display: flex;
  flex-direction: column;
}

.typo-corps {
  display: flex;
  flex-direction: column;
  gap: 18px;
  min-height: 0;
  padding: 16px;
  overflow-y: auto;
}

/*
 * Une section de la fenêtre : ce qu'elle mesure, ce que la casse contient, ce
 * que la fonte dira d'elle-même. Le filet sépare les trois, et le titre les
 * nomme — la fenêtre se lit alors sans chercher à quoi sert chaque champ.
 */
.typo-section {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.typo-section + .typo-section {
  padding-top: 18px;
  border-top: 1px solid var(--bordure);
}

.typo-section-titre {
  margin: 0;
  font-size: 11px;
  font-weight: normal;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--texte-doux);
}

/* La chasse qui découle des approches : c'est elle qu'on règle sans la voir. */
.fonte-chasse {
  margin: 0;
  font-size: 12px;
  color: var(--texte-doux);
}

/* Ce que la fonte contiendra : le compte des cases et la chasse. */
.fonte-chapeau {
  margin: 0;
  font-size: 12px;
  line-height: 1.35;
  color: var(--texte-doux);
}

.fonte-approches,
.fonte-infos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 10px 14px;
  /* Par le bas : un libellé qui tient sur deux lignes — « Hauteur de
     capitale » — poussait sa case plus bas que ses voisines. Alignées par le
     bas, les cases se suivent quel que soit le nombre de lignes du libellé. */
  align-items: end;
}

/* La description prend toute la largeur : c'est la seule à pouvoir être longue. */
.fonte-large {
  grid-column: 1 / -1;
}

.fonte-champ {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  font-size: 11px;
  color: var(--texte-doux);
}

/*
 * `min-width: 0` n'est pas décoratif : un champ de saisie a une largeur
 * **intrinsèque** — celle de son attribut `size`, une bonne centaine de pixels —
 * et un `width: 100%` ne la réduit pas. Sans ce zéro, la colonne de la grille
 * refuse de descendre sous cette largeur, et le panneau déborde avant que le
 * champ n'ait commencé à rétrécir. C'est la règle générale des enfants de
 * grille et de flexbox, pas une mesure : elle vaut ici comme ailleurs.
 */
.fonte-champ input {
  width: 100%;
  min-width: 0;
  padding: 8px 10px;
  font: inherit;
  font-size: 13px;
  color: var(--encre);
  background: var(--fond-panneau);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
}

.fonte-champ input:focus-visible {
  border-color: var(--encre);
  outline: 2px solid var(--encre);
  outline-offset: 1px;
}

/*
 * Le « i » d'un bouton d'icône : la lettre seule, en chasse fixe et en
 * italique — le même dessin que l'ancien bouton rond, dont il ne reste que ça.
 * Il n'est pas mis en capitale, d'où sa place dans la liste de remise à zéro.
 */
.bouton-icone .i {
  font-family: var(--police-mono);
  font-size: 14px;
  font-style: italic;
  line-height: 1;
}

/* --- Le glisser d'un signe vers une case ---------------------------- */

/*
 * En Construction, un signe de l'aperçu se saisit : le curseur le dit avant
 * l'essai. `touch-action: none` est ce qui permet au geste d'exister au doigt —
 * sans lui, le navigateur fait défiler la page au lieu de prêter le signe.
 */
.interface[data-mode="construction"] .vue .signe {
  cursor: grab;
  touch-action: none;
}

body.glisser-en-cours,
body.glisser-en-cours .vue .signe {
  cursor: grabbing;
}

/*
 * Rotation armée : le geste dans l'aperçu ne prête plus le signe à une case, il
 * le tourne. Le curseur le dit avant l'essai — d'autant plus utile que le même
 * glisser fait deux choses selon l'outil. Le glisser en cours garde la main,
 * d'où la règle plus spécifique au-dessus.
 */
body.rotation-armee .interface[data-mode="construction"] .vue,
body.rotation-armee .interface[data-mode="construction"] .vue .signe {
  cursor: crosshair;
}

body.glisser-en-cours.rotation-armee .interface .vue .signe {
  cursor: grabbing;
}

/*
 * Le fantôme : une copie du signe, centrée sur le pointeur. Il ne reçoit aucun
 * événement — sans quoi il masquerait la case qu'il survole, et le dépôt ne
 * trouverait jamais sa cible.
 */
.glisser-fantome {
  position: fixed;
  z-index: 10;
  width: 132px;
  height: 132px;
  transform: translate(-50%, -50%);
  color: var(--encre);
  background: var(--fond-panneau);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  box-shadow: var(--ombre);
  opacity: 0.9;
  pointer-events: none;
}

.glisser-fantome .signe {
  width: 100%;
  height: 100%;
}

/* La case sous le doigt : celle qui recevra le signe si on lâche maintenant. */
.cellule.survol {
  border-color: var(--encre);
  box-shadow: inset 0 0 0 2px var(--encre);
}

.reglage {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

/*
 * Un réglage sans effet dans le mode de rendu courant : grisé et désactivé,
 * jamais masqué, pour que le panneau ne se réorganise pas sous l'œil au moment
 * où on bascule la matière. Voir `docs/adr/0020`.
 */
.reglage.inactif {
  opacity: 0.4;
}

.reglage.inactif input,
.reglage.inactif select {
  cursor: default;
}

/* --- Le verrou d'un réglage ----------------------------------------- */

/*
 * L'en-tête d'un réglage : le cadenas, puis le nom et sa valeur. Le cadenas est
 * hors du `<label>` — un bouton dans une étiquette déclencherait aussi le champ.
 */
.entete {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

/*
 * Discret tant qu'il est ouvert : il doit exister, puisque c'est lui qui rend la
 * fonction trouvable, sans peser sur la lecture des noms. Il s'affirme au
 * survol, et reste franc une fois fermé.
 */
.cadenas {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 0;
  color: var(--texte-doux);
  background: none;
  border: none;
  border-radius: 3px;
  cursor: pointer;
  opacity: 0.35;
}

.cadenas:hover,
.cadenas:focus-visible {
  color: var(--encre);
  background: var(--fond);
  opacity: 1;
}

.cadenas:focus-visible {
  outline: 2px solid var(--encre);
  outline-offset: 1px;
}

/*
 * Fermé : le cadenas passe à l'encre pleine et le nom du réglage aussi. Le
 * verrou se lit donc sans chercher le petit glyphe, et sans teinter la rangée —
 * le panneau en compte dix-huit.
 */
.reglage.verrouille .cadenas,
.reglage.verrouille .etiquette {
  color: var(--encre);
}

.reglage.verrouille .cadenas {
  opacity: 1;
}

/* Un réglage gelé ne se bouge pas : le curseur le dit avant l'essai. */
.reglage.verrouille input[type="range"],
.reglage.verrouille select {
  cursor: default;
}

/* --- Catégories et rangées du panneau ------------------------------- */

/*
 * La barre de pli du panneau : deux boutons d'icône, **en haut à gauche**. Elle
 * tient la place qu'occupait le titre du panneau, désormais retiré, et tombe
 * sous les boutons de vue : 10 px du haut comme les barres de la page, et 16 px
 * du bord — le panneau est rembourré de 32, d'où les 16 px rendus ici. Voir
 * `docs/adr/0050`.
 *
 * Elle ne se colle pas : elle est **hors** de la liste qui défile. Un `sticky`
 * aurait suffi à la garder à l'écran, mais il l'aurait fait bouger de quelques
 * pixels au premier cran de molette — mesuré — et c'est ce mouvement qui se
 * voyait. Ici, rien ne bouge : c'est le contenu qui passe dessous.
 */
.pli-tout-barre {
  display: flex;
  flex: none;
  justify-content: flex-start;
  margin-left: -16px;
}

/*
 * Une catégorie est repliable et **repliée au départ** : le panneau s'ouvre sur
 * quatre titres, pas sur dix-huit curseurs. Le filet sépare donc des titres, et
 * non des blocs pleins — d'où un écart plus court qu'avant.
 */
.section-reglages + .section-reglages {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--bordure);
}

/*
 * Toute la ligne du titre est cliquable. Le marqueur natif du `<summary>` est
 * retiré : sa taille et sa place changent d'un moteur à l'autre, et c'est le
 * chevron qui dit le pli.
 */
.section-entete {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 0;
  list-style: none;
  cursor: pointer;
}

.section-entete::-webkit-details-marker {
  display: none;
}

.section-entete:focus-visible {
  outline: 2px solid var(--encre);
  outline-offset: 2px;
}

.section-titre {
  margin: 0;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--texte-doux);
}

.section-entete:hover .section-titre,
.section-entete:focus-visible .section-titre {
  color: var(--encre);
}

/*
 * Le chevron tombe quand la catégorie est ouverte, et se couche sur la droite
 * quand elle est fermée. Aucun état en JavaScript : l'attribut `open` du
 * `<details>` suffit. Pas de transition — rien d'autre ne bouge dans la page.
 */
.chevron {
  flex: none;
  color: var(--texte-doux);
  transform: rotate(-90deg);
}

.section-reglages[open] .chevron {
  transform: rotate(0deg);
}

/* Le premier rang ne respire sous son titre que lorsque celui-ci ouvre. */
.section-reglages[open] .section-entete {
  margin-bottom: 14px;
}

/*
 * Une rangée : les curseurs d'une même ligne, à largeur égale. `auto-fit`
 * avec un minimum de 150px les garde côte à côte tant que la place le
 * permet, puis les empile d'eux-mêmes — pas de point de rupture à écrire.
 */
.rangee {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 16px 18px;
}

.rangee + .rangee {
  margin-top: 16px;
}

/* Le nom et sa valeur : l'étiquette prend la place laissée par le cadenas. */
.etiquette {
  display: flex;
  flex: 1;
  justify-content: space-between;
  gap: 8px;
  min-width: 0;
  font-size: 12px;
  color: var(--texte-doux);
}

.reglage output {
  font-family: var(--police-mono);
  color: var(--encre);
}

/* --- La bibliothèque des styles ------------------------------------- */

/*
 * Le style n'a plus qu'une commande dans la barre du bas : le signet qui
 * enregistre, sous un nom demandé dans une fenêtre. Le choix entre les styles
 * rangés est passé dans le nom affiché en haut de la page, qui ouvre la liste —
 * un menu déroulant ici ne disait rien que le nom ne dise déjà. Voir
 * `docs/adr/0023` et `docs/adr/0035`.
 */

/*
 * Ce que la bibliothèque a à dire, sous la rangée d'actions : style rangé,
 * style supprimé, stockage refusé. Une seule ligne, et rien quand il n'y a rien
 * à dire — le `hidden` de l'HTML s'en charge.
 */
/* --- Le projet -------------------------------------------------------- */

/*
 * Les deux gestes du projet ferment le rang du bas, à l'autre bout : c'est un
 * geste plus rare que les commandes du signe, qui ne s'y intercale pas. Le
 * `margin-left: auto` qui les pousse à droite est posé avec `.actions`, et le
 * collage des deux boutons vient de `.groupe-boutons` — rien à redire ici.
 * Voir `docs/adr/0026`.
 */

/*
 * Où en est le projet : à jour, ou des changements en attente. C'est un
 * **état**, pas une note : il ne s'efface pas tout seul, sinon on ne saurait
 * plus si le fichier dit la vérité.
 */
/* --- Les typographies ------------------------------------------------- */

/*
 * Le menu des typographies, à droite de la ligne du haut. Sa largeur est
 * **fixe** : c'est lui qui ancre la ligne, et il ne doit pas s'allonger d'une
 * typographie à l'autre — un nom de soixante caractères déplacerait les
 * boutons de gestion à chaque changement. Le texte long s'y coupe.
 *
 * Sa hauteur est celle d'un bouton d'icône — 34 px — et non celle que lui
 * donnerait son rembourrage : mesuré, `6px 8px` autour d'un texte de 13 px
 * faisait 30 px, et le menu se lisait comme un corps étranger dans la ligne.
 * Le rembourrage passe donc à l'horizontale seule.
 */
.typo-choix {
  flex: none;
  width: 190px;
  height: var(--hauteur-commande);
  min-width: 0;
  padding: 0 8px;
  font-size: 13px;
}

/* --- Les candidats d'une case ----------------------------------------- */

/*
 * La bande des candidats : les signes essayés pour la case choisie, dont un
 * est choisi pour l'export. Elle ne s'affiche qu'à partir de **deux** — un seul
 * signe, c'est la case elle-même — et se pose dans la barre du bas, sous la
 * grille.
 *
 * Elle défile horizontalement : une case peut porter beaucoup de candidats, et
 * la colonne n'est pas large. Voir `docs/adr/0027` et `docs/adr/0046`.
 */
.candidats {
  flex: 1;
  min-width: 0;
  overflow-x: auto;
}

.candidats-bande {
  display: flex;
  gap: 6px;
  padding-bottom: 4px;
}

/* Le cadre du candidat : la seule vignette. Le clic choisit le signe pour
   l'export, `Suppr` le retire. */
.candidat {
  flex: none;
  width: 64px;
  height: 64px;
}

.candidat-choix {
  width: 100%;
  height: 100%;
  padding: 4px;
  background: var(--fond-panneau);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  cursor: pointer;
}

.candidat-choix:hover {
  border-color: var(--texte-doux);
}

.candidat-choix:focus-visible {
  outline: 2px solid var(--encre);
  outline-offset: -2px;
}

/* Le candidat choisi : c'est lui que la fonte exportera. Un cadre plein, plus
   lisible à cette taille qu'une bordure fine. */
.candidat.choisi .candidat-choix {
  border-color: var(--encre);
  box-shadow: inset 0 0 0 2px var(--encre);
}

/* La vignette coupe ce qui dépasse, comme une case de la casse : à cette
   taille, un signe qui sort empiéterait sur ses voisins. */
.candidat-apercu {
  display: block;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.candidat-apercu .signe {
  width: 100%;
  height: 100%;
}

/* --- Le curseur ------------------------------------------------------ */

/*
 * Les curseurs sont **dessinés**, plus natifs. `accent-color` ne teintait que
 * le pouce, et laissait le rail au gris du moteur : deux pièces rapportées au
 * milieu d'un panneau qui n'a ni fond ni filet ailleurs. On ne garde donc rien
 * de l'apparence d'origine — ni la piste, ni le pouce, ni le fond du champ,
 * dont le gris se verrait sous le rail.
 *
 * Le dessin est celui du reste de la page : un rail de 2 px qui reprend la
 * couleur des filets, et un point d'encre. Le point est cerclé de la couleur
 * du **panneau**, pas du fond : c'est ce cerne qui le détache du rail quand il
 * passe dessus, sans ombre ni contour ajouté.
 *
 * Les deux moteurs demandent chacun leur jeu de pseudo-éléments, et le pouce
 * de WebKit se place à la main — d'où `margin-top`, calculé pour une piste de
 * 2 px et un pouce de 14 px (`(2 - 14) / 2`). Firefox, lui, centre son pouce
 * tout seul.
 */
input[type="range"] {
  width: 100%;
  /* La hauteur ne se voit pas : elle fait la zone de clic, qui serait sinon
     celle du seul rail, et donc très mince. */
  height: 18px;
  margin: 0;
  background: transparent;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

input[type="range"]::-webkit-slider-runnable-track {
  height: 2px;
  background: var(--bordure);
  border-radius: 1px;
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  margin-top: -6px;
  background: var(--encre);
  border: 2px solid var(--fond-panneau);
  border-radius: 50%;
}

input[type="range"]::-moz-range-track {
  height: 2px;
  background: var(--bordure);
  border-radius: 1px;
}

input[type="range"]::-moz-range-thumb {
  width: 14px;
  height: 14px;
  background: var(--encre);
  border: 2px solid var(--fond-panneau);
  border-radius: 50%;
}

/* Le rail s'assombrit sous le doigt, comme les titres de section au survol :
   rien ne bouge, mais on sait que la cible est vivante. */
input[type="range"]:hover::-webkit-slider-runnable-track {
  background: var(--texte-doux);
}

input[type="range"]:hover::-moz-range-track {
  background: var(--texte-doux);
}

input[type="range"]:focus-visible {
  outline: 2px solid var(--encre);
  outline-offset: 2px;
}

select {
  width: 100%;
  padding: 8px 10px;
  font: inherit;
  font-size: 13px;
  color: var(--encre);
  background: var(--fond-panneau);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  cursor: pointer;
}

/* --- Le panneau de la liste des styles ------------------------------ */

/*
 * La liste des styles a d'abord été une fenêtre **native** — `<dialog>`, posée
 * au-dessus de tout, le fond assombri par `::backdrop`. Elle est devenue un
 * **panneau** de la colonne de droite, qui prend la place de celui du mode
 * courant : on garde ainsi le signe sous les yeux pendant qu'on choisit. Le
 * voile, la modale et Échap sont partis avec la fenêtre. Voir `docs/adr/0035`
 * et `docs/adr/0056`.
 */
.modale {
  width: min(420px, calc(100vw - 32px));
  max-height: min(72vh, 560px);
  padding: 0;
  color: var(--encre);
  background: var(--fond-panneau);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  box-shadow: var(--ombre);
}

.modale::backdrop {
  background: rgba(0, 0, 0, 0.4);
}

/*
 * La tête : le titre à gauche, la croix à droite. La croix est un bouton de
 * 34 px comme les autres commandes de la page, et sans mot — son `title` le
 * redit, et son nom accessible est donné à part.
 */
.modale-tete {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 10px 12px 16px;
  border-bottom: 1px solid var(--bordure);
}

.modale-titre {
  margin: 0;
  font-size: 14px;
  font-weight: normal;
}

.modale-fermer {
  margin-left: auto;
  width: var(--hauteur-commande);
  height: var(--hauteur-commande);
  padding: 0;
  font: inherit;
  font-size: 18px;
  line-height: 1;
  color: var(--texte-doux);
  background: none;
  border: 0;
  border-radius: var(--rayon);
  cursor: pointer;
}

.modale-fermer:hover,
.modale-fermer:focus-visible {
  color: var(--encre);
}

.modale-fermer:focus-visible {
  outline: 2px solid var(--encre);
  outline-offset: 2px;
}

/* Rien de rangé : la phrase prend la place de la liste. */
/*
 * La liste des styles : un rang par style, qui défile si la bibliothèque
 * s'allonge. Le rembourrage court est l'air laissé au survol des lignes, dont
 * le fond se pose dans les coins de la fenêtre.
 */
.styles-liste {
  flex: 1;
  min-height: 0;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  list-style: none;
}

.style-ligne {
  display: flex;
  align-items: center;
  gap: 2px;
  border-radius: var(--rayon);
}

.style-ligne + .style-ligne {
  margin-top: 6px;
}

/* Le style chargé : un trait d'encre sur le bord gauche, plutôt qu'un fond —
   un fond ne laisserait plus rien à voir au survol. */
.style-ligne.courant {
  box-shadow: inset 3px 0 0 var(--encre);
}

/*
 * Charger le style : la ligne entière est le bouton. C'est le geste qu'on fait
 * en parcourant la liste, donc il ne demande pas de viser.
 */
.style-ligne-charger {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  gap: 14px;
  min-width: 0;
  padding: 8px;
  font: inherit;
  color: var(--encre);
  text-align: left;
  background: none;
  border: 0;
  border-radius: var(--rayon);
  cursor: pointer;
}

.style-ligne-charger:hover,
.style-ligne-charger:focus-visible {
  background: var(--fond);
}

.style-ligne-charger:focus-visible {
  outline: 2px solid var(--encre);
  outline-offset: -2px;
}

/* La vignette d'une ligne : c'est elle qui fait reconnaître le style, et la
   liste a la place de la montrer en grand. */
.styles-liste .vignette-style {
  width: 56px;
  height: 56px;
}

/* Le nom du style : il vient d'un fichier, donc il garde sa casse, et il
   s'élide plutôt que de pousser la croix hors de la ligne. */
.style-ligne-nom {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  font-size: 14px;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* La marque du style chargé, à droite du nom. */
.style-ligne-marque {
  flex: none;
  font-size: 11px;
  color: var(--texte-doux);
}

/*
 * La croix de la ligne : elle supprime le style. Elle est toujours visible —
 * contrairement à celle d'un candidat, qui se montre au survol — parce qu'une
 * ligne de liste n'a pas de dessin à protéger.
 */
.style-ligne-retirer {
  flex: none;
  width: 32px;
  height: 32px;
  margin-right: 2px;
  padding: 0;
  font: inherit;
  font-size: 15px;
  line-height: 1;
  color: var(--texte-doux);
  background: none;
  border: 0;
  border-radius: var(--rayon);
  cursor: pointer;
}

.style-ligne-retirer:hover,
.style-ligne-retirer:focus-visible {
  color: var(--encre);
  background: var(--fond);
}

.style-ligne-retirer:focus-visible {
  outline: 2px solid var(--encre);
  outline-offset: -2px;
}

/* --- Petits écrans : les zones s'empilent --------------------------- */

@media (max-width: 900px) {
  .interface {
    grid-template-columns: 1fr;
    grid-template-areas:
      "haut"
      "signe"
      "droite"
      "notes"
      "bas";
    /* Empilé, on rend la main à la page : c'est elle qui défile */
    grid-template-rows: auto;
    height: auto;
    min-height: 100vh;
    min-height: 100dvh;
  }

  /*
   * Empilé, la colonne debout n'a plus de bord à longer : `top: 0; bottom: 0`
   * la ferait courir sur toute la page, et ses messages se perdraient au
   * milieu. Elle reprend donc sa place dans le flux, **couchée**, entre le
   * panneau et la barre du bas — c'est la disposition d'avant, et elle reste
   * la bonne quand il n'y a plus de colonne à gauche.
   */
  .notes-verticales {
    grid-area: notes;
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 6px 14px;
    padding: 0 16px 10px;
    pointer-events: auto;
  }

  .notes-verticales > * {
    writing-mode: horizontal-tb;
    transform: none;
    white-space: normal;
  }

  /*
   * Le rang unique du bas est une règle de grand écran : à cette largeur, neuf
   * commandes ne tiennent plus sur une ligne, et le défilement en travers
   * cacherait justement la dernière. Ici, donc, la rangée se coupe.
   */
  .barre-bas {
    overflow-x: visible;
  }

  .actions {
    flex-wrap: wrap;
  }

  .projet-barre {
    margin-left: 0;
  }

  .zone-signe {
    height: auto;
    min-height: 70vh;
  }

  .zone-droite {
    border-left: none;
    border-top: 1px solid var(--bordure);
  }
}

/*
 * Le mouvement se retire à la demande.
 *
 * La page n'a qu'une transition — l'apparition des commandes de la
 * typographie au survol — et une seule animation nulle part ailleurs. Qui a
 * réglé son système sur « réduire les animations » n'a donc presque rien à
 * gagner ici, mais la règle dit que c'est à nous de demander, pas à lui de
 * subir.
 */
@media (prefers-reduced-motion: reduce) {
  .typo-actions-boutons {
    transition: none;
  }
}
